1、C#中调用 C+的 dll 的参数为指针类型的导出函数点击: 发布日期:2007-6-28 7:29:00 进入论坛严格来说这篇文章算不上 C+范围的,不过还是挂了点边,还是在自己的 blog 中记录一下吧。 C+中使用指针是家常便饭了,也非常的好用,这也是我之所以喜欢 C+的原因之一。但是在 C#中就强调托管的概念了,指针就不用想了。本来如果就在 C#的世界里面写代码,也还算舒服,但是万事万物总有联系,这不,现在公司的另外一个用 C#作的项目就碰到问题了,要调用之前用 C+写的一个 DLL 中的一些函数,很多函数的参数都是指针类型的,这下可麻烦咯,公司里做 C#的都是刚起步,C+又只有我最熟
2、悉,这项技术研究工作又光荣的落到我身上。 我对 C#也不甚熟悉,所以也许我的方法不一定是最直接的,但是测试的结果是满足了这个调用需要了的。下面我就详细介绍一下。 使用 unsafe、fix 等关键字应该是能够实现的,但是他们项目组要求不用这个,所以我也没深入去试验。除了这个方法,应该来说是有两个思路的,第一个思路可能看起来比较直接,使用 ref,ref 这个关键字似乎有点特殊性,字面上理解似乎应该和 C+中的引用类型相对应,不过似乎它还是有一定特殊性的,貌似以前看到过一篇文章说 ref 会自己去判断是引用类型还是指针,我尝试了一下,果然是可行的。但是对于有二级指针的情况 ref也就不灵了这就导
3、出了我的另一个思路,使用 Marshal。 下面我们还是代码说明问题: 以下是 C+DLL 中的代码片断,主要是使用到的两个结构的定义,以及导出函数TestFunction 的定义。 C+ DLL 中的代码片断 #pragma pack(push) #pragma pack(1) typedef struct EmmStruct int len; EMMSTRUCT, *LPEMMSTRUCT; typedef struct MyStruct int iParam; long size; LPEMMSTRUCT lpEmmStructArr; MYSTRUCT, *LPMYSTRUCT; #p
4、ragma pack(pop) extern “C“ void _declspec(dllexport) _stdcall TestFunction(LPMYSTRUCT lpMyStruct) lpMyStruct-iParam = 100; lpMyStruct-size = 10; lpMyStruct-lpEmmStructArr = new EMMSTRUCTlpMyStruct-size; for(int i=0;isize;i+) lpMyStruct-lpEmmStructArri.len = i; 那么再来看看 C#中调用的代码: C#中调用的代码片断 using Syste
5、m; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; /使用 C#导入 dll 必须的 namespace csharptest /StructLayout 和 FieldOffset 这些设置不是必须的,只是为了防止对齐的问题最好加上,这样自己心里有数对齐到哪一位 StructLayout(LayoutKind.Explicit) public struct EmmStruct FieldOffset(0) public int len; StructLayo
6、ut(LayoutKind.Explicit) public struct MyStruct FieldOffset(0) public int iParam; FieldOffset(4) public int size; FieldOffset(8) public IntPtr ptrEmmStruct; class Program / dll 中导出函数的声明 DllImport(“dllforcsharp.dll“, CallingConvention=CallingConvention.Winapi) public extern static void TestFunction(In
7、tPtr ptr); static void Main(string args) try MyStruct s = new MyStruct(); IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(s); Marshal.StructureToPtr(s, ptr, false); TestFunction(ptr); s = (MyStruct)Marshal.PtrToStructure(ptr, typeof(MyStruct); EmmStruct ret; for (int i = 0; i s.size; i+) IntPtr ptr
8、2 = new IntPtr(s.ptrEmmStruct.ToInt32() + 4 * i); ret = (EmmStruct)Marshal.PtrToStructure(ptr2, typeof(EmmStruct); Marshal.FreeHGlobal(ptr); catch (Exception e) string str = e.Message; finally 代码也不多,而且从字面的意思就能知道是干什么的了,所以我就没写注释。用这种方法就实现了参数中含有二级指针的情况。要注意的就是 C#中的 long 和 C+中不同,它占 8字节。所以一般情况下 C+中 long 的,C# 里面用 int 或者 int32 就 ok 了。我自己对 C#不是特别熟悉,所以可能也未能完全讲解清楚,甚至可能存在漏洞,有高人见到的话,可以指点指点。