C#调用C/C++的dll须知

原文链接:
https://blog.csdn.net/oyoung_2012/article/details/54631165

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++代码

1
2
3
4
5
6
struct Some
{
int number;
char character;
char name[32];
}

C#代码

1
2
3
4
5
6
7
struct Some
{
int number;
char charactor;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
string name;
}

B. 如果C/C++的结构体成员中包含的成员仍然是结构体(单个,非数组), 则对应的C#结构体只需要同样包含结构体, 如:

C/C++代码

1
2
3
4
5
6
7
8
9
struct A
{
int number;
};
struct B
{
struct A a;
int otherNumber;
};

对应的C#代码

1
2
3
4
5
6
7
8
9
10
public struct A
{
public int number;
}

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

C. 如果C/C++结构体成员中包含数组(长度固定),则C#结构体中也使用数组对应的类型, 如:

C/C++代码

1
2
3
4
5
6
7
8
9
struct A
{
int number;
};
struct B
{
int numbers[10];
struct A alist[5];
};

对应的C#代码

1
2
3
4
5
6
7
8
9
10
11
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++代码

1
2
3
4
5
6
7
8
9
struct A
{
int number;
};
struct B
{
int tag;
struct A *pA;
}

对应的C#代码

1
2
3
4
5
6
7
8
9
public struct A
{
public int number;
}
public struct B
{
public int tag;
public IntPtr pA;
}

然后在使用的时候需要用到Marshal类的StructureToPtr和PtrToStructure方法进行转换
转换方法如下:
(1)结构体转换成IntPtr

1
2
3
4
5
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 转换成结构体

1
2
3
4
5
6
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#数组长度更大的时候,会忽略多余的部分)

感谢您对本站的支持.