c#编程指南(十三) 平台调用P-INVOKE完全掌握, 结构体和结构体指针
2010-09-30 22:46:05 来源:WEB开发网第二。C++导出函数和C# P-INVOKE函数的对应。
C++:
1 static Test _test;
2 void SetTest(Test test)
3 {
4 _test = test;
5 PrintTest();
6 }
7
8 void SetTestPointer(Test * lptest)
9 {
10 _test = * lptest;
11 PrintTest();
12 }
13
14 Test GetTest()
15 {
16 return _test;
17 }
18
19 Test * GetTestPointer()
20 {
21 return &_test;
22 }
C#: 注意结构体作为返回值的P-INVOKE声明是不是很奇怪。不过运行很正常。下一篇结合反汇编说。
1 [DllImport("TestDll")]
2 public static extern void SetTest(Test test);
3
4 [DllImport("TestDll")]
5 public static extern void SetTestPointer(IntPtr lptest);
6
7 [DllImport("TestDll")]
8 public static extern void GetTest(IntPtr lptest); //注意声明。
9
10 [DllImport("TestDll")]
11 public static extern IntPtr GetTestPointer();
第三:看下C#如何调用,这里用到了Marshal.AllocHGlobal 方法,和Alloc功能基本一样,会造成内存泄露,使用完了记住使用Marshal.FreeHGlobal函数释放申请的内存。
1 private Test _test = new Test();
2
3 public void Run()
4 {
5 InitTest();
6 //#########################
7 SetTest(_test);
8 Console.WriteLine("-------------------------------------------------------------\n");
9 //#########################
10 _test._base.BaseInt = 9999;
11 //Marshal.AllocHGlobal 和WIN32 API, Alloc功能基本一样,
12 //这个方法不要多用,可能造成内存泄露。
13 //记住使用Marshal.FreeHGlobal函数释放申请的内存
14 IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Test)));
15 Marshal.StructureToPtr(_test,p,false);
16 SetTestPointer(p);
17 Console.WriteLine("-------------------------------------------------------------\n");
18 //#########################
19 IntPtr pp = GetTestPointer();
20 Test temp = (Test)Marshal.PtrToStructure(pp, typeof(Test));
21 PrintTest(temp);
22 Console.WriteLine("-------------------------------------------------------------\n");
23
24 //#########################
25 IntPtr pp2 = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Test)));
26 GetTest(pp2);
27 Test temp2 = (Test)Marshal.PtrToStructure(pp2, typeof(Test));
28 PrintTest(temp2);
29
30 }
总结一下:Marshal.StructureToPtr从托管类复制数据到未托管的内存中,Marshal.PtrToStructure恰好相反。Marshal.AllocHGlobal申请非托管内存,Marshal.FreeHGlobal函数释放非托管内存。使用 Marshal.Read系列读写指针,使用Marshal.ReadIntPtr来读写二级指针。
更多精彩
赞助商链接