Marshal在C#中的應用(void *指針到IntPtr的轉化)


  C#調用C語言的API時一般把void *指針轉換成IntPtr,但這經常遠遠不夠的。在C語言中void *是個萬金油,尤其是一些老的c語言程序,所有的參數就一個void*指針,里面包羅萬象,然后在程序中來一個switch,甚至多個switch來處理不同的參數。最近筆者就碰到了這個問題,不得不來研究一下怎么把void *指針轉換成IntPtr。

1.void *指針到IntPtr的簡單轉化。

c語言函數原型:

int SetConfig(int type, void *p);

這里假設p的所傳遞的參數式是結構體A:

struct A			
{
	wchar_t osdbuffer[100];				
	unsigned short ix;						
	unsigned short iy;						
};

 那么在C#中原型可以定義如下:

int SetConfig(int type, IntPtr p);

結構體A 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		public struct A {
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
			public string osdbuffer;		
			public ushort ix;						//顯示坐標x
			public ushort iy;						//顯示坐標y
		}

  注意這里的CharSet,它由c中wchar_t決定的,如果c程序編譯時使用Unicode,這里就用CharSet.Unicode,否則使用CharSet.Ansi。關於字符串的編碼問題如果不懂可以去網上查一下。至於怎么知道C語言是用Unicode還是Ansi編譯,我是經過調用它的API測試出來的,調用成功了就說明他的編碼和我的調用代碼一致。

  這里還有一個很重要的問題,那就是內存在編譯時的分配問題。一般默認情況下,內存的分配是4byte的整數倍,在這里我省略了,但為了便於理解,補充一下。結構體A完整一點的定義:(注意Pack的值)

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode,Pack = 4)]
		public struct A {
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
			public string osdbuffer;		
			public ushort ix;						//顯示坐標x
			public ushort iy;						//顯示坐標y
		}

c語言是用的是非托管代碼,c#使用的是托管代碼,c#的調用代碼如下:

    A s_a = new A();
  int lenght = Marshal.SizeOf(s_a); IntPtr pA= Marshal.AllocHGlobal(lenght); Marshal.StructureToPtr(s_a, pA, true); int type = 1;
int ret = SetConfig( type, pA); Marshal.FreeHGlobal(pA);

2.void *指針到IntPtr的復雜轉化。

在這里結構體A變得復雜一點,如果它內部包含一個指向另一個結構體B的指針

struct A            
{
    wchar_t osdbuffer[100];            
    unsigned short ix;            
    unsigned short iy;、
    B *pB;            
};
struct B            
{
    wchar_t title[20];     
};

在C#中你要做的也就稍微復雜一點,也就是說你不但要為A分配內存,也要為B分配內存

  B s_b = new B();
  //賦值省略
  int
lenght1 = Marshal.SizeOf(s_b); IntPtr pB= Marshal.AllocHGlobal(lenght1); Marshal.StructureToPtr(s_b, pB, true);   A s_a = new A();
  s_a.pB = pB;
  //其他賦值
  //
  int
lenght2 = Marshal.SizeOf(s_a);   IntPtr pA= Marshal.AllocHGlobal(lenght2); Marshal.StructureToPtr(s_a, pA, true); int type = 1;
int ret = SetConfig( type, pA); Marshal.FreeHGlobal(pB); Marshal.FreeHGlobal(pA);

萬變不離其宗,只要掌握了原理,不管void *指針傳遞的參數有多么復雜,都可以搞定。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM