天天看點

C#調用C/C++的dll須知

1. C#類型與C/C++類型的對應關系

基本資料類型(C# <—> C/C++)

  • System.Int32,int <—> int, long
  • System.Int64,int64 <—> long long, __int64
  • System.Char, char <—> char, byte, unsigned char
  • System.Int16, short <—> short
  • System.UInt32, uint <—> unsigned int, unsigned long
  • System.UInt16, ushort <—> unsigned short, DWORD
  • System.String, string <—> char[], char *, const char *
  • System.IntPtr <—> void *, [Type]*
  • Sytem.Boolean, bool <—> bool, BOOL

2. C/C++函數參數類型與C#類型對應關系

① 基本的資料類型對應關系與1相同,但是也有一些不一樣的地方

② const char * 一般作為輸入參數, C#直接使用string類型即可(StringBuilder也可以)

③ char *作為輸入參數的時候, C#需要使用ref string類型或者StringBuilder類型

④ 結構體指針做輸入參數的時候, C#一般使用ref + 對應的結構體類型

3. C/C++結構體與C#結構體的成員類型對應關系

A. 如果C/C++結構體成員類型是基本資料類型, C#中對應的結構體成員類型使用1中的對應關系即可, 如:

C/C++代碼

struct Some
{
   	int number;
   	char character;
   	char name[32];	
}
           

C#代碼

struct Some
{
   	int number;
   	char charactor;
   	[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
   	string name;
}
           

B. 如果C/C++的結構體成員中包含的成員仍然是結構體(單個,非數組), 則對應的C#結構體隻需要同樣包含結構體, 如:

C/C++代碼

struct A
{
    int number;
};
struct B
{
   struct A a;
   int otherNumber;
};
           

對應的C#代碼

public struct A
{
    public int number;
}

public struct B
{
   public A a;
   public int otherNumber;
}
           

###C. 如果C/C++結構體成員中包含數組(長度固定),則C#結構體中也使用數組對應的類型, 如:

C/C++代碼

struct A
{
int number;
};
struct B 
{
int numbers[10];
struct A alist[5];
};
           

對應的C#代碼

public struct A 
{
	int number;
}
public struct B
{
	[MarshalAs(UnmanagedType.ByValArray, SizeConst=10, ArraySubType=UnmanagedType.SysInt)]	
	public int[] numbers;
	[MarshalAs(UnmanagedType.ByValArray, SizeConst=10, ArraySubType=UnmanagedType.Struct)]
	public A[] alist;
}
           

###D. 如果C/C++的結構體成員中包含另一個結構體的指針,C#對應的結構體中一律使用IntPtr類型, 如:

C/C++代碼

struct A
{
 int number;
};
struct B
 {
 int tag;
 struct A *pA;
}
           

對應的C#代碼

public struct A
{
 public int number;
}
public struct B
{
 public int tag;
 public IntPtr pA;
 }
           

然後在使用的時候需要用到Marshal類的StructureToPtr和PtrToStructure方法進行轉換

轉換方法如下:

(1)結構體轉換成IntPtr

A a = new A();
B b = new B();
IntPtr pA= Marshal.AllocHGlobal(Marshal.SizeOf(a));
Marshal.StructureToPtr(a, pA, false);
b.pA = pA;
           

(2)IntPtr 轉換成結構體

B b = new B();
//...省略中間的操作過程
A aInB = (A)Marshal.PtrToStructure(b.pA, typeof(A))
//或者
A aInB = new A();
Marshal.PtrToStructure(b.pA, aInB);
           

4. 關于類型轉換中的數組長度

  • C/C++中,如果是char類型的數組(一般表示最大長度不超過某個數字的字元串),那麼在進行參數傳遞的時候,如果C#中的string字元串位元組數超過了C/C++中的最大位元組數,則會發生截斷, 如C/C++中, char name[3]; 但是在C#中卻使用了string name = “Jack”,實際傳到C/C++中, name中的内容為“Ja”,多餘的部分沒有填充進來
  • C/C++中使用的數組為定長數組,在參數傳遞過程中,如果C#中使用的數組長度比C/C++中數組長度短,則會發生System.ArgumentException異常,提示“未能封送類型,因為嵌入數組執行個體的長度與布局中聲明的長度不比對“(C#的string到C/C++的char 數組不會,但是C#char[]到C/C++的char數組會有此異常),是以, 我們要定義相同長度的數組才能正常工作(C#數組長度更大的時候,會忽略多餘的部分)