c#编程指南(十一) 平台调用P-INVOKE完全掌握, 指针大全

时间:2022-08-28 08:04:32

这篇是讲述P-INVOKE中,应对各种指针的方法。包括普通指针,字符串指针,二级指针,指针数组,函数指针,结构体指针。篇幅估计有点长,大家耐心点看。嘿嘿~~

 

第一:普通指针,包括char *,short *,int *,__int64 *,这些指针进行平台调用是都对应C#的IntPtr类型,然后使用Marshal.ReadXXX()系列函数读取就可,写内存时使用Marshal.WriteXXX()系列函数就行。

 

c++:

  
  
  

28   static int test5 = 100 ;
29   int * __stdcall ReadInt()
30 {
31 return & test5;
32 }

 

c#:注意Marshal.ReadXXX()系列函数的使用

  
  
  

15 [DllImport( " TestDll " )]
16 public static extern IntPtr ReadInt();
29 // ##############################
42 IntPtr p5 = ReadInt();
43 Console.WriteLine(Marshal.ReadInt32(p5));
44 IntPtr p6 = ReadUint();
45 Console.WriteLine(Convert.ToUInt32(Marshal.ReadInt32(p6)));

 

 

第二:字符串指针上一篇已经有过讨论,可以使用marshalAs返回值,当然也可以用Marshal.PtrToStringAuto()来读取字符串。个人推荐第一个。

 

c++:

  
  
  
1 static char * test9 = " you are very very bad bad girl, gaga! " ;
2   char * __stdcall ReadString()
3 {
4 return test9;
5 }
6
7
8   static wchar_t * test10 = TEXT( " you are very very bad bad girl, gaga! " );
9 wchar_t * __stdcall ReadStringW()
10 {
11 return test10;
12 }

 

c#:注意Marshal.PtrToStringAuto()函数的使用。

  
  
  
1 [DllImport( " TestDll " )]
2 [ return : MarshalAs(UnmanagedType.LPStr)]
3 public static extern string ReadString();
4
5 [DllImport( " TestDll " )]
6 public static extern IntPtr ReadStringW();
7 // #########################
8 Console.WriteLine(ReadString());
9
10 IntPtr p9 = ReadStringW();
11 Console.WriteLine(Marshal.PtrToStringAuto(p9));

 

 

第三:函数指针,C#的委托就对应C++的__stdcall调用协议的函数指针。前面也有讨论。

c++:

  
  
  
1 typedef void (__stdcall * FunctionPoint)( void );
2 void __stdcall TestFunction(){printf( " you are very very bad bad girl, gaga!\n " );}
3 FunctionPoint __stdcall GetFunctionPointer()
4 {
5 return TestFunction;
6 }

 

c#:

  
  
  
1 public delegate void FunctionPointer();
2 [DllImport( " TestDll " )]
3 public static extern FunctionPointer GetFunctionPointer();
4 // #########################
5 FunctionPointer pointer = GetFunctionPointer();
6 pointer();

 

 

第四:指针的指针,也就是二级指针,要使用Marshal.ReadIntPtr()来读取。

c++:

  
  
  
1 static int test11 = 555 ;
2 static int * test12 = & test11;
3 int ** __stdcall ReadPoint2()
4 {
5 return & test12;
6 }

 

c#:

  
  
  
1 [DllImport( " TestDll " )]
2 public static extern IntPtr ReadPoint2();
3 // #########################
4 IntPtr p10 = ReadPoint2();
5 IntPtr p11 = Marshal.ReadIntPtr(p10);
6 int test10 = Marshal.ReadInt32(p11);
7 Console.WriteLine(test10);

 

第五:指针数组没有太直接的方法,因为C++所有指针都是4BYTE所以这里我是这么读的。

C++:

  
  
  
1 static int test13 = 666 ;
2 static int test14 = 777 ;
3 static int * test15[ 3 ] = { 0 };
4 int ** __stdcall ReadPointArray()
5 {
6 test15[ 0 ] = & test11;
7 test15[ 1 ] = & test13;
8 test15[ 2 ] = & test14;
9 return test15;
10 }

 

C#:

  
  
  
1 [DllImport( " TestDll " )]
2 public static extern IntPtr ReadPointArray();
3 // #########################
4 IntPtr p12 = ReadPointArray();
5 int test11 = p12.ToInt32();
6 Console.WriteLine(Marshal.ReadInt32(Marshal.ReadIntPtr(p12)));
7 Console.WriteLine(Marshal.ReadInt32(Marshal.ReadIntPtr( new IntPtr(test11 + 0 ))));
8 Console.WriteLine(Marshal.ReadInt32(Marshal.ReadIntPtr( new IntPtr(test11 + 4 ))));
9 Console.WriteLine(Marshal.ReadInt32(Marshal.ReadIntPtr( new IntPtr(test11 + 8 ))));

 

 

最后: 结构体的指针,用C#建立对应C++的结构体,并使用   [StructLayout(LayoutKind.Sequential)]属性,

使用Marshal.PtrToStructure()读取。

c++:

  
  
  
1 struct Test
2 {
3 int test;
4 };
5
6 static Test test16;
7 Test * __stdcall ReadStruct()
8 {
9 test16.test = 1234 ;
10 return & test16;
11 }

 

c#:

  
  
  
1 [StructLayout(LayoutKind.Sequential)]
2 public struct Test
3 {
4 public int test;
5 }
6
7 [DllImport( " TestDll " )]
8 public static extern IntPtr ReadStruct();
9 // #########################
10
11 IntPtr p13 = ReadStruct();
12 Test test13 = (Test)Marshal.PtrToStructure(p13, typeof (Test));
13 Console.WriteLine(test13.test);