关于C#调用C++的Dll接口
首先,制作一个普通的Dll(非COM的),API到处接口声明定义如下:
>>>>>> C++
.h: _declspec(dllexport) void mymath(int* a);
.cpp:
void mymath(int* a)
{
*a = 1010;
return;
}
我们制作一个Dll(假定名字"ExportFun.dll"),此时的Dll C++/C程序调用没有问题,就是动态Dll使用的那几个办法。
问题是,如何让C#来调用呢?
-------------------------------------------
>>>>>> C#
using System.Runtime.InteropServices; //使用运行时Interop
namespace TestSharp
{
class Program
{
//API 声明,使用DllImport,在C#程序运行时会载入Dll
//同时,声明要使用的接口
[DllImport("ExportFun.dll", EntryPoint = "mymath")]
private static extern void mymath(IntPtr a); //与C++声明不太一致
static void Main(string[] args)
{
IntPtr pb = Marshal.AllocHGlobal(0);
mymath(pb);
int bb = Marshal.ReadInt32(pb);
Console.WriteLine(bb.ToString());
}
}
}
-----------------------------------------------
这样C#Code就可以调用C++的Dll接口了,其中,基本数据类型没有问题,关键是指针,句柄什么的。
如上,C#声明mymath的参数不是int*, 因为C#是托管类代码,int*是非托管类的,所以这类类型都要
用IntPtr代替。
然后,就是由于Dll操作的是Native的Code,所以C#调用这个接口时,是要做一些转换操作,那就是
Marshal。 首先,用Marshal分配一块Native的内存,然后传入给mymath(),此时Dll中对内存操作就
OK了,然后再用Marshal读取这个内存位置的数据,就可以得到结果1010了。
好了,这是一个比较简单的数据类型,如果是结构体呢?
我们要注意,.Net与Native对数据在内存上的排列不太一样。
假如,我定义一个结构体
>>>> C++
.h
struct MYSTRUCT_T
{
int a;
int b;
char c;
};
_declspec(dllexport) MYSTRUCT_T* mymath3();
.cpp
MYSTRUCT_T* mymath3()
{
MYSTRUCT_T* pT = new MYSTRUCT_T();
pT->a = 500;
pT->b = 600;
pT->c = 'A';
return pT;
}
一个比较简单的结构体类型,接口函数返回该结构体指针
-----------------------------------------------
>>>> C#
[StructLayout(LayoutKind.Explicit)]
public struct myStruct_t
{
[FieldOffset(0)] //就是起始地址,所以位移为0
public int a;
[FieldOffset(4)] //相对于起始地址,位移一个int,32位机上是4个字节
public int b;
[FieldOffset(8)] //相对于起始地址,位移2个int,就是8个字节
public char c;
}
[DllImport("ExportFun.dll", EntryPoint = "mymath3")]
private static extern IntPtr mymath3();
IntPtr pT = mymath3();
myStruct_t mt = new myStruct_t();
mt = (myStruct_t)Marshal.PtrToStructure(pT, mt.GetType());
在这里我们看到了,在C#中一定要在重新定义一下接口中的结构体,同时要指定各成员的排列情况(假定C++Dll是在32位机上编译的)。
然后,同样,mymath3()的返回值类型声明为IntPtr,使用时直接调用mymath3(),此时,pT指向的内存地址是Native的,非托管类型。然后,定义一个C#的结构体变量,之后调用Marshal.PtrToStructure操作,将Native上的结构体数据内容拷贝至托管数据mt上。
所以,C#定义结构体时要指定Native上的内存的排列,否则无法将有效数据Copy至托管类变量上。
当然,如果结构体char c后面还有成员变量,那就要注意内存对齐的问题了。(至少默认情况下编译器时会进行内存对齐的,这个问题我之前的文章提到过了)
还有复杂的数据,以后再添加了。

浙公网安备 33010602011771号