C#调用C++编写的COM DLL
2008-10-07 17:44
726 查看
在C#调用C++编写的COM DLL封装库时会出现两个问题:
1. 数据类型转换问题
2. 指针或地址参数传送问题
[align=left] 首先是数据类型转换问题。因为C#是.NET语言,利用的是.NET的基本数据类型,所以实际上是将C++的数据类型与.NET的基本数据类型进行对应。[/align]
[align=left] [/align]
[align=left] 例如C++的原有函数是:[/align]
[align=left] [/align]
[align=left]int __stdcall FunctionName(unsigned char param1, unsigned short param2)[/align]
[align=left] [/align]
[align=left] 其中的参数数据类型在C#中,必须转为对应的数据类型。如:[/align]
[align=left] [/align]
[align=left][DllImport(“ COM DLL path/file ”)][/align]
[align=left]extern static int FunctionName(byte param1, ushort param2)[/align]
[align=left] [/align]
[align=left] 因为调用的是__stdcall函数,所以使用了P/Invoke的调用方法。其中的方法FunctionName必须声明为静态外部函数,即加上extern static声明头。我们可以看到,在调用的过程中,unsigned char变为了byte,unsigned short变为了ushort。变换后,参数的数据类型不变,只是声明方式必须改为.NET语言的规范。[/align]
[align=left] [/align]
[align=left] 我们可以通过下表来进行这种转换:[/align]
[align=left] [/align]
[align=left] [/align]
[align=left] 之后再将CLR的数据类型表示方式转换为C#的表示方式。这样一来,函数的参数类型问题就可以解决了。[/align]
[align=left] [/align]
[align=left] 现在,我们再来考虑下一个问题,如果要调用的函数参数是指针或是地址变量,怎么办?[/align]
[align=left] [/align]
[align=left] 对于这种情况可以使用C#提供的非安全代码来进行解决,但是,毕竟是非托管代码,垃圾资源处理不好的话对应用程序是很不利的。所以还是使用C#提供的ref以及out修饰字比较好。[/align]
[align=left] [/align]
[align=left] 同上面一样,我们也举一个例子:[/align]
[align=left] [/align]
[align=left]int __stdcall FunctionName(unsigned char ¶m1, unsigned char *param2)[/align]
[align=left] [/align]
[align=left] 在C#中对其进行调用的方法是:[/align]
[align=left] [/align]
[align=left][DllImport(“ COM DLL path/file ”)][/align]
[align=left]extern static int FunctionName(ref byte param1, ref byte param2)[/align]
[align=left] [/align]
[align=left] 看到这,可能有人会问,&是取地址,*是传送指针,为何都只用ref就可以了呢?一种可能的解释是ref是一个具有重载特性的修饰符,会自动识别是取地址还是传送指针。[/align]
[align=left] [/align]
[align=left] 在实际的情况中,我们利用参数传递地址更多还是用在传送数组首地址上。[/align]
[align=left]如:byte[] param1 = new param1(6);[/align]
[align=left] [/align]
[align=left] 在这里我们声明了一个数组,现在要将其的首地址传送过去,只要将param1数组的第一个元素用ref修饰。具体如下:[/align]
[align=left] [/align]
[align=left][DllImport(“ COM DLL path/file ”)][/align]
extern static int FunctionName(ref byte param1[1], ref byte param2)
C#调用DLL文件时参数对应表
1. 数据类型转换问题
2. 指针或地址参数传送问题
[align=left] 首先是数据类型转换问题。因为C#是.NET语言,利用的是.NET的基本数据类型,所以实际上是将C++的数据类型与.NET的基本数据类型进行对应。[/align]
[align=left] [/align]
[align=left] 例如C++的原有函数是:[/align]
[align=left] [/align]
[align=left]int __stdcall FunctionName(unsigned char param1, unsigned short param2)[/align]
[align=left] [/align]
[align=left] 其中的参数数据类型在C#中,必须转为对应的数据类型。如:[/align]
[align=left] [/align]
[align=left][DllImport(“ COM DLL path/file ”)][/align]
[align=left]extern static int FunctionName(byte param1, ushort param2)[/align]
[align=left] [/align]
[align=left] 因为调用的是__stdcall函数,所以使用了P/Invoke的调用方法。其中的方法FunctionName必须声明为静态外部函数,即加上extern static声明头。我们可以看到,在调用的过程中,unsigned char变为了byte,unsigned short变为了ushort。变换后,参数的数据类型不变,只是声明方式必须改为.NET语言的规范。[/align]
[align=left] [/align]
[align=left] 我们可以通过下表来进行这种转换:[/align]
[align=left] [/align]
[align=center]Win32 Types[/align] | [align=center]CLR Type[/align] |
[align=left]char, INT8, SBYTE, CHAR [/align] | [align=left]System.SByte[/align] |
[align=left]short, short int, INT16, SHORT[/align] | [align=left]System.Int16[/align] |
[align=left]int, long, long int, INT32, LONG32, BOOL , INT [/align] | [align=left]System.Int32[/align] |
[align=left]__int64, INT64, LONGLONG[/align] | [align=left]System.Int64[/align] |
[align=left]unsigned char, UINT8, UCHAR , BYTE[/align] | [align=left]System.Byte[/align] |
[align=left]unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR , __wchar_t[/align] | [align=left]System.UInt16[/align] |
[align=left]unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT[/align] | [align=left]System.UInt32[/align] |
[align=left]unsigned __int64, UINT64, DWORDLONG, ULONGLONG[/align] | [align=left]System.UInt64[/align] |
[align=left]float, FLOAT[/align] | [align=left]System.Single[/align] |
[align=left]double, long double, DOUBLE[/align] | [align=left]System.Double[/align] |
[align=left] 之后再将CLR的数据类型表示方式转换为C#的表示方式。这样一来,函数的参数类型问题就可以解决了。[/align]
[align=left] [/align]
[align=left] 现在,我们再来考虑下一个问题,如果要调用的函数参数是指针或是地址变量,怎么办?[/align]
[align=left] [/align]
[align=left] 对于这种情况可以使用C#提供的非安全代码来进行解决,但是,毕竟是非托管代码,垃圾资源处理不好的话对应用程序是很不利的。所以还是使用C#提供的ref以及out修饰字比较好。[/align]
[align=left] [/align]
[align=left] 同上面一样,我们也举一个例子:[/align]
[align=left] [/align]
[align=left]int __stdcall FunctionName(unsigned char ¶m1, unsigned char *param2)[/align]
[align=left] [/align]
[align=left] 在C#中对其进行调用的方法是:[/align]
[align=left] [/align]
[align=left][DllImport(“ COM DLL path/file ”)][/align]
[align=left]extern static int FunctionName(ref byte param1, ref byte param2)[/align]
[align=left] [/align]
[align=left] 看到这,可能有人会问,&是取地址,*是传送指针,为何都只用ref就可以了呢?一种可能的解释是ref是一个具有重载特性的修饰符,会自动识别是取地址还是传送指针。[/align]
[align=left] [/align]
[align=left] 在实际的情况中,我们利用参数传递地址更多还是用在传送数组首地址上。[/align]
[align=left]如:byte[] param1 = new param1(6);[/align]
[align=left] [/align]
[align=left] 在这里我们声明了一个数组,现在要将其的首地址传送过去,只要将param1数组的第一个元素用ref修饰。具体如下:[/align]
[align=left] [/align]
[align=left][DllImport(“ COM DLL path/file ”)][/align]
extern static int FunctionName(ref byte param1[1], ref byte param2)
C#调用DLL文件时参数对应表
Wtypes.h 中的非托管类型 | 非托管 C 语言类型 | 托管类名 | 说明 |
HANDLE | void* | System.IntPtr | 32 位 |
BYTE | unsigned char | System.Byte | 8 位 |
SHORT | short | System.Int16 | 16 位 |
WORD | unsigned short | System.UInt16 | 16 位 |
INT | int | System.Int32 | 32 位 |
UINT | unsigned int | System.UInt32 | 32 位 |
LONG | long | System.Int32 | 32 位 |
BOOL | long | System.Int32 | 32 位 |
DWORD | unsigned long | System.UInt32 | 32 位 |
ULONG | unsigned long | System.UInt32 | 32 位 |
CHAR | char | System.Char | 用 ANSI 修饰。 |
LPSTR | char* | System.String 或System.StringBuilder | 用 ANSI 修饰。 |
LPCSTR | Const char* | System.String 或System.StringBuilder | 用 ANSI 修饰。 |
LPWSTR | wchar_t* | System.String 或System.StringBuilder | 用 Unicode 修饰。 |
LPCWSTR | Const wchar_t* | System.String 或System.StringBuilder | 用 Unicode 修饰。 |
FLOAT | Float | System.Single | 32 位 |
DOUBLE | Double | System.Double | 64 位 |
类别 | 类名 | 说明 | Visual Basic 数据类型 | C# 数据类型 | C++ 托管扩展数据类型 | JScript 数据类型 |
整数 | Byte | 8 位的无符号整数。 | Byte | byte | char | Byte |
SByte | 8 位的有符号整数。 不符合 CLS。 | SByte 无内置类型。 | sbyte | signed char | SByte | |
Int16 | 16 位的有符号整数。 | Short | short | short | short | |
Int32 | 32 位的有符号整数。 | Integer | int | int - 或 - long | int | |
Int64 | 64 位的有符号整数。 | Long | long | __int64 | long | |
UInt16 | 16 位的无符号整数。 不符合 CLS。 | UInt16 无内置类型。 | ushort | unsigned short | UInt16 | |
UInt32 | 32 位的无符号整数。 不符合 CLS。 | UInt32 无内置类型。 | uint | unsigned int - 或 - unsigned long | UInt32 | |
UInt64 | 64 位的无符号整数。 不符合 CLS。 | UInt64 无内置类型。 | ulong | unsigned __int64 | UInt64 | |
浮点 | Single | 单精度(32 位)浮点数字。 | Single | float | float | float |
Double | 双精度(64 位)浮点数字。 | Double | double | double | double | |
逻辑 | Boolean | 布尔值(真或假)。 | Boolean | bool | bool | bool |
其他 | Char | Unicode(16 位)字符。 | Char | char | wchar_t | char |
Decimal | 96 位十进制值。 | Decimal | decimal | Decimal | Decimal | |
IntPtr | 大小取决于基础平台(32 位平台上为32 位值,64 位平台上为 64 位值)的有符号整数。 | IntPtr 无内置类型。 | IntPtr 无内置类型。 | IntPtr 无内置类型。 | IntPtr | |
UIntPtr | 大小取决于基础平台的无符号整数(32 位平台上为 32位值,64 位平台上为 64 位值)。 不符合 CLS。 | UIntPtr 无内置类型。 | UIntPtr 无内置类型。 | UIntPtr 无内置类型。 | UIntPtr | |
类对象 | Object | 对象层次结构的根。 | Object | object | Object* | Object |
String | Unicode 字符的不变的定长串。 |
相关文章推荐
- com调用的几种方法 及 C#调用C++编写的的COM DLL收藏
- C#调用C++编写的COM DLL
- C#调用C++编写的COM DLL
- C#调用C++编写的COM DLL封装库的问题解决方案
- C++与C#编写的DLL/COM的各种调用方法
- C#调用C++编写的COM DLL
- C#调用C++编写的COM DLL
- C#调用C++编写的COM DLL
- C++与C#编写的DLL/COM的各种调用方法
- com调用的几种方法 及 C#调用C++编写的的COM DLL
- VC6.0和VS2005:C++和C#编写调用COM组件
- C++调用C#之C++DLL调用C# COM控件
- 在VS2008环境下编写C语言DLL,并在C++和C#项目下调用
- 编写C#调用的C++DLL
- C++如何调用C#编写的DLL
- C++调用C#编写的COM组件
- 【转】 编写C#调用的C++DLL
- 在VS2008环境下编写C语言DLL,并在C++和C#项目下调用 (转载)
- c#.net下成功调用c++编写的标准dll
- (学习笔记)C++编写dll C#调用注意事项