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 Add(int n1, int n2);
extern "C" __declspec(dllexport) int __stdcall Sub(int n1, int n2);
}

SampleCppWrapper.cpp

#include "SampleCppWrapper.h"

namespace SampleCppWrapper
{
SampleCppClass* g_pObj = new SampleCppClass(); int __stdcall Add(int n1, int n2)
{
return g_pObj->Add(n1, n2);
} int __stdcall Sub(int n1, int n2)
{
return g_pObj->Sub(n1, n2);
}
}

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

[DllImport("SampleCppWrapper.dll")]
private static extern int Add(int n1, int n2);
[DllImport("SampleCppWrapper.dll")]
private static extern int Sub(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=; i<; 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;
}
}
}

C#调用C++类库的几种方式的更多相关文章

  1. 【.Net】调用Web API的几种方式

    引言 记录一下调用Web API的几种方式,以调用百度API为例. HttpWebRequest HttpWebRequest位于System.Net命名空间,是常用的调用Web API类库. str ...

  2. 调用sed命令的三种方式

    调用sed命令的三种方式 调用sed有三种方式,一种为Shell命令行方式,另外两种是将sed命令写入脚本文件,然后执行该脚本文件. 三种方式的命令格式归纳如下: 一.在Shell命令行输入命令调用s ...

  3. Python调用API接口的几种方式 数据库 脚本

    Python调用API接口的几种方式 2018-01-08 gaoeb97nd... 转自 one_day_day... 修改 微信分享: 相信做过自动化运维的同学都用过API接口来完成某些动作.AP ...

  4. Python调用API接口的几种方式

    Python调用API接口的几种方式 相信做过自动化运维的同学都用过API接口来完成某些动作.API是一套成熟系统所必需的接口,可以被其他系统或脚本来调用,这也是自动化运维的必修课. 本文主要介绍py ...

  5. Java异步调用转同步的5种方式

    1.异步和同步的概念 同步调用:调用方在调用过程中,持续等待返回结果. 异步调用:调用方在调用过程中,不直接等待返回结果,而是执行其他任务,结果返回形式通常为回调函数. 2 .异步转为同步的概率 需要 ...

  6. 【Java EE 学习 80 下】【调用WebService服务的四种方式】【WebService中的注解】

    不考虑第三方框架,如果只使用JDK提供的API,那么可以使用三种方式调用WebService服务:另外还可以使用Ajax调用WebService服务. 预备工作:开启WebService服务,使用jd ...

  7. C#动态调用WCF接口,两种方式任你选。

    写在前面 接触WCF还是它在最初诞生之处,一个分布式应用的巨作. 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去研究,最近自己做一个项目时用到了WCF. 从这 ...

  8. C# 调用 C++ dll的两种方式

    目录: 1.非托管方式 2.托管方式 3.介绍 extern "C" 4.介绍   DllImport 1.非托管方式 第一种,非托管方式:调用类和方法https://www.co ...

  9. 动态调用WebService接口的几种方式

    一.什么是WebService? 这里就不再赘述了,想要了解的====>传送门 二.为什么要动态调用WebService接口? 一般在C#开发中调用webService服务中的接口都是通过引用过 ...

随机推荐

  1. deep learning 自编码算法详细理解与代码实现(超详细)

    在有监督学习中,训练样本是有类别标签的.现在假设我们只有一个没有带类别标签的训练样本集合 ,其中 .自编码神经网络是一种无监督学习算法,它使用了反向传播算法,并让目标值等于输入值,比如 .下图是一个自 ...

  2. 数组中累加和为k的最大子数组的长度

    package com.hzins.suanfa; import java.util.HashMap; public class demo { /** * 数组中累加和为k的最大子数组的长度 * @p ...

  3. 总结的一些MySQL数据库面试题

    1.sql语句应该考虑哪些安全性? 1.防止sql注入,对特殊字符进行转义,过滤或者使用预编译的sql语句绑定变量. 2.最小权限原则,特别是不要用root账户,为不同的类型的动作或者组建使用不同的账 ...

  4. How To Uninstall Software Using The Ubuntu Command Line

    How To Uninstall Software Using The Ubuntu Command Line Uninstall Ubuntu Software Using The Terminal ...

  5. Python学习笔记 - MySql的使用

    一.安装MySql模块 Python2.X pip install MySQLdb Python3.X pip install pymysql 二.数据库连接接口 由于Python统一了数据库连接的接 ...

  6. hihoCoder#1095(二分搜索)

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Little Hi and Little Ho are playing a drinking game called HI ...

  7. HDOJ1016(标准dfs)

    Prime Ring Problem Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  8. java继承如何理解呢??

    总结:我把他弄的无语了.他是诺基亚公司的软件开发师,大学毕业就可以进那么好的公司.实力 package com.bc; //普通类 class yt { public void price() { S ...

  9. DCloud-流应用:杂项

    ylbtech-DCloud-流应用:杂项 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返回顶部   8.返回顶部   9.返回 ...

  10. TCS3200颜色传感器测试实验

    TCS3200颜色传感器测试实验 2013-08-02 17:18:24 分享: 标签:  Arduino  TCS3200  传感器 TCS3200颜色传感器是一款全彩的颜色检测器,包括了一块TAO ...