调用的基本原理:
调用时应注意的两个问题:
1.基本数据类型的传递问题
2.指针或地址参数传送问题
C#和C++两种语言定义的基本数据类型有一些不同,在调用时必须先搞清楚基本数据类型在不同语言间的传递问题。也就是说C++的定义的数据类型,必须找到c#所对应的基本数据类型。才能获取相应数据集。下图显示了C++基本数据类型对应的c#基本数据类型,但是对于有些基本数据类型,没有直接对应的数据类型,需要一定的处理。
两种常用的调用方法:
1、 封装COM组件库
将C/C++的函数封装成COM组件,在c#中调用就比较方便,但是COM组件需要注册,而且多次注册也可能会导致一些问题。
2、可以使用动态链接库
可以使用动态链接库直接调用C/C++函数库,使用起来比较方便,可以动态加载和调试。
注:这里需要说明下COM组件和普通dll的区别:
1.普通dll不能通过regsvr32.exe来注册,而Com组件能通过regsvr32.exe注册。
2.Com组件是微软的一个协议,满足com组件协议的dll文件就是com组件,这种协议为了跨语言、跨平台使用,dll组件需要编译后使用,Com组件注册后即可使用,而dll是动态链接库,是一个可以导出函数的集合。
3.Com组件可以是exe也可以是dll文件。
用动态链接库静态调用C++的.dll文件
C++中.dll的源代码:
.h头文件
.cpp源文件
.ref模板定义文件
最终生成的dll文件
C#中调用c++的dll文件
最终结果:
CreateDll为文件路径和文件名,test01为函数名。后面的其他参数详见msdn文档。该程序实现了c#获取dll程序集的函数计算和获取一个字符串数组。
关于DIIImport其他参数的说明:
用动态链接库动态调用C++的.dll文件
这个类是加载动态链接库需要的源程序,也可以写成工厂类。
关于这三个函数的说明:
在C#中动态调用 C++的dll程序集的代码如下:
结果如下:
这里需要说明的是IntPtr这个数据类型:MSDN上给出的解释是用于表示指针或句柄的平台特定类型。因为c++当中的char*无法直接对应c#中的某一类基本数据类型。
C#拿到C++的.dll的类对象和结构体数组
以上介绍的是用c#来获取c++中的简单的数据类型,对于类对象和结构体数组等比较复杂的数据类型,在C#中没有一一对应的数据类型,获取方式就有些不同,另外要注意的是在c++中数组的内存是连续存放,而c#是不连续的。这时候还要考虑内存分配的问题。
C++中的源代码:
.h文件:
这里定义了一个C++类,定义一个人的姓名、年龄和身高。
.cpp文件
这里定义一个结构体User,在类初始化的时候给对象辅助,并将数据赋值给结构体。在生成完dll后调用,c#中会报错,显示内存已破坏,后来,经过查找资料,必须要用Marsh指定空间,然后再传递。于是加了[MarshalAs(UnmanagedType.ByValTStr,SizeConst = 32)]。
编译以后在c#中的调用的方式如下:
这里需要说明的是要将c++的结构体数据获取出来,必须在c#中也定义相应的结构体,然后通过Intptr句柄将数据映射到c#结构体数组中,通过调用Marshal.PtrToStructure()方法即可将其转化为结构体类型。
结果如下: