首页 > 编程语言 >C#调用C++类库的几种方式

C#调用C++类库的几种方式

时间:2023-11-25 22:05:00浏览次数:39  
标签:类库 SampleCppClass C# pContext void C++ int __ SampleCppWrapper

1、  直接调用C++类库中的公共方法

使用DllImport特性对方法进行调用,比如一个C++类库SampleCppWrapper.dll中的公共方法:

extern "C" __declspec(dllexport) int __stdcall Add(int n1, int n2);

__stdcall表示调用约定:参数都是从右向左通过堆栈传递, 函数调用在返回前要由被调用者清理堆栈。

在C#中,调用如下:

[DllImport("SampleCppWrapper.dll")]
private static extern int Add(int n1, int n2);

注意参数的类型,之后,可直接在C#编程中使用这个方法。

 

2、  调用C++类库中的类的方法

C#不能直接调用C++类库中的类,需要一种变通的解决方式,通过再做一个C++类库把要调用的类成员方法暴露出来,比如下面这个C++类:

SampleCppClass.h

复制代码
#pragma once

class __declspec(dllexport) SampleCppClass
{
public:
    SampleCppClass(void);
    ~SampleCppClass(void);
    
    int Add(int n1, int n2);
    int Sub(int n1, int n2);
};
复制代码

SampleCppClass.cpp

复制代码
#include "SampleCppClass.h"

SampleCppClass::SampleCppClass(void)
{
}

SampleCppClass::~SampleCppClass(void)
{
}

int SampleCppClass::Add(int n1, int n2)
{
    return n1 + n2;
}

int SampleCppClass::Sub(int n1, int n2)
{
    return n1 - n2;
}
复制代码

我们要调用SampleCppClass中的Add和Sub两个方法,所以我们再写一个C++类库,通过公共方法间接调用类成员方法:

SampleCppWrapper.h

复制代码
#pragma once

#include "..\SampleCppClass\SampleCppClass.h"

namespace SampleCppWrapper
{
    extern "C" __declspec(dllexport) int __stdcall AddF(int n1, int n2);
    extern "C" __declspec(dllexport) int __stdcall SubF(int n1, int n2);
}
复制代码

SampleCppWrapper.cpp

复制代码
#include "SampleCppWrapper.h"

namespace SampleCppWrapper
{
    SampleCppClass* g_pObj = new SampleCppClass();

    int __stdcall AddF(int n1, int n2)
    {
        return g_pObj->Add(n1, n2);
    }

    int __stdcall SubF(int n1, int n2)
    {
        return g_pObj->Sub(n1, n2);
    }
}
复制代码

在C#中,再调用SampleCppWrapper.dll中的公共方法:

[DllImport("SampleCppWrapper.dll")]
private static extern int AddF(int n1, int n2);
[DllImport("SampleCppWrapper.dll")]
private static extern int SubF(int n1, int n2);

3、  使用C++类库中的回调函数

C++的回调函数是一种事件响应机制,和C#的委托相似,比如一个C++类中的回调函数:

SampleCppClass.h

复制代码
#pragma once

typedef void (*LoopCallback)(void* pContext);

class __declspec(dllexport) SampleCppClass
{
public:
    SampleCppClass(void);
    ~SampleCppClass(void);
    
    void SetCallbackFunc(LoopCallback callback);
    void SetCallbackContext(void* pContext);
    void Loop();
private:
    LoopCallback m_callback;
    void* m_pContext;
};
复制代码

SampleCppClass.cpp

复制代码
#include "SampleCppClass.h"

SampleCppClass::SampleCppClass(void)
{
}

SampleCppClass::~SampleCppClass(void)
{
}

void SampleCppClass::SetCallbackFunc(LoopCallback callback)
{
    m_callback = callback;
}

void SampleCppClass::SetCallbackContext(void* pContext)
{
    m_pContext = pContext;
}

void SampleCppClass::Loop()
{
    for (int i=0; i<10; i++)
    {
        if (m_callback != NULL)
        {
            m_callback(m_pContext);
        }
    }
}
复制代码

我们通过C++再写一个类库进行封装,把类中的方法暴露出来:

SampleCppWrapper.h

复制代码
#pragma once

#include "..\SampleCppClass\SampleCppClass.h"

namespace SampleCppWrapper
{
    typedef void (__stdcall *LoopCallbackWrapper)(void* pContext);

    extern "C" __declspec(dllexport) void __stdcall SetCallbackFunc(LoopCallbackWrapper callback);
    extern "C" __declspec(dllexport) void __stdcall SetCallbackContext(void* pContext);
    extern "C" __declspec(dllexport) void __stdcall Loop();
}
复制代码

SampleCppWrapper.cpp

复制代码
#include "SampleCppWrapper.h"

namespace SampleCppWrapper
{
    LoopCallbackWrapper g_callbackWrapper;
    SampleCppClass* g_pObj = new SampleCppClass();

    void LoopCallbackFunc(void* pContext);

    void __stdcall SetCallbackFunc(LoopCallbackWrapper callback)
    {
        g_callbackWrapper = callback;
        g_pObj->SetCallbackFunc(LoopCallbackFunc);
    }

    void __stdcall SetCallbackContext(void* pContext)
    {    
        g_pObj->SetCallbackContext(pContext);
    }

    void __stdcall Loop()
    {
        g_pObj->Loop();
    }

    void LoopCallbackFunc(void* pContext)
    {
        if (g_callbackWrapper != NULL)
        {
            g_callbackWrapper(pContext);
        }
    }
}
复制代码

然后,在C#中进行调用:

复制代码
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace SampleCsTest
{
    public partial class Form1 : Form
    {
        [StructLayout(LayoutKind.Sequential)]
        private class Context
        {
            public Form1 Form { get; set; }
        }

        private delegate void LoopCallbackHandler(IntPtr pContext);
        private static LoopCallbackHandler callback = LoopCallback;

        [DllImport("SampleCppWrapper.dll")]
        private static extern void SetCallbackFunc(LoopCallbackHandler callback);
        [DllImport("SampleCppWrapper.dll")]
        private static extern void SetCallbackContext(IntPtr pContext);
        [DllImport("SampleCppWrapper.dll")]
        private static extern void Loop();

        private Context ctx = new Context();

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            SetCallbackFunc(callback);
            ctx.Form = this;
            IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ctx));
            Marshal.StructureToPtr(ctx, ptr, false);
            SetCallbackContext(ptr);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Loop();
        }

        private static void LoopCallback(IntPtr pContext)
        {
            Context ctx = (Context)Marshal.PtrToStructure(pContext, typeof(Context));
            ctx.Form.textBox1.Text += "callback" + Environment.NewLine;
        }
    }
}
复制代码

 

 

【出处】:https://www.cnblogs.com/lgyup/p/7116162.html

=======================================================================================

标签:类库,SampleCppClass,C#,pContext,void,C++,int,__,SampleCppWrapper
From: https://www.cnblogs.com/mq0036/p/17856177.html

相关文章

  • 大量索引场景下 Easysearch 和 Elasticsearch 的吞吐量差异
    最近有客户在使用Elasticsearch搜索服务时发现集群有掉节点,并且有master收集节点信息超时的日志,节点的负载也很高,不只是data节点,master和协调节点的cpu使用率都很高,看现象集群似乎遇到了性能瓶颈。查看了Hot_threads,发现大量线程被权限验证相关的类和方法占用,主要在......
  • 15、SpringMVC之常用组件及执行流程
    15.1、常用组件15.1.1、DispatcherServletDispatcherServlet是前端控制器,由框架提供,不需要工程师开发;作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求。15.1.2、HandlerMappingHandlerMapping是处理器映射器,由框架提供,不需要工程师开发;......
  • 第二篇Scrum冲刺博客
    一、项目进度成员昨日进度今日进度赵继业努尔艾力·亚森登录功能数据库表创建艾里扎提·买买提前端UI设计前端UI设计邱政阳前端UI设计前端UI设计扎恩哈尔学生功能模块学生功能模块赛尔达尔·艾思开尔老师功能模块数据库表创建艾孜买提·艾......
  • ACM常用STL函数
    max()min()找多个元素的最大值和最小值max(a,b)比较两个元素mx=max({a,b,c,d});比较多个元素lower_bound()upper_bound()寻找第序列第n小的值的地址//在a数组中查找第一个大于等于x的元素,返回该元素的地址int*p=lower_bound(a,a+n,x);//在a数组中查找第一个大于x......
  • OSS Scan,Mend,BlackDuck,FOSS,ECCN 的概念
    1.OSSScanOSSScan是一个用于扫描开源软件(OpenSourceSoftware,简称OSS)的工具。它的主要目的是找出软件中可能存在的安全问题,包括但不限于漏洞、许可证冲突、违反的法规等。一个OSSScan的例子是OWASP的Dependency-Check工具,它能够检测项目中使用的开源库是否存在已知......
  • Spartacus 6.0 baseSites API 的准确触发位置
    启动Spartacus后,第一个调用的API是BaseSiteAPI。BaseSiteAPI是SAPCommerceCloud中非常重要的一个API,它主要的作用包括:获取网站基本信息:BaseSiteAPI用于从SAPCommerceCloud中获取网站的基本信息,如网站的名称、ID、默认语言、默认货币、时间区等。这些信息对......
  • 什么是 SAP ABAP 的 Conversion Exits
    ConversionExits是ABAP中的一种技术,用于在数据库和用户界面之间转换数据。这是一个非常重要的概念,因为在不同的系统和应用中,相同的数据可能需要以不同的形式进行表示。例如,日期在数据库中可能以一种格式存储,但在用户界面上可能需要以另一种更易于理解的格式显示。ConversionE......
  • AcwSpringbootke3,导航栏
    点击导航栏就跳转到我们的网址,网址用路由跳转到我们的每一个页面组件注意1一般vue命名两个字母大写2style加scope可以不会影响我们组件以外的部分js3index.js加入我们写的路劲4router代表传到这个路劲path我调用哪个页面name,组件是哪个component5注意router是从上往下匹......
  • docker导出、导入
    先来看看我们在运行的容器:#dockerps导出容器:#dockerexporte96a98d5902c>ubuntu14_ruby2.tar.gz导入到本地镜像:#dockerimportubuntu14_ruby2.tar.gz查看本地镜像:#dockerimages这个没有tag的就是我们刚刚导入的,现在我们给他打一个tag:#dockertagfd2e33845352ubuntu14_ruby2:......
  • vue 根据js的变量来设置css 里面的属性的属性值
    1.通过动态绑定style,声明css变量"--fontColor",把变量”fontColor”赋给“--fontColor”2.在css中使用var函数读取“--fontColor”变量点击查看代码<template><divclass="wen_style":style="{'--fontColor':fontColor}">当前字体的颜色......