一、问题集合
- 跨语言中涉及的数据类型的对应问题
- C#如何接收C++中的返回值
- C++导出函数类型为非void的,C#如何接收
- 如何查看C++生成的DLL中有哪些函数
- 数据参数类型无误,调用的DLL返回值收不到
二、解决方案
- 在跨语言中,有时候数据类型所占用的字节数是不一样的。因此,数据类型的传输是讲究一个对仗的。通俗的说就是我们要保持在C#调用C++的时候函数参数占的字节数是一致的,如果不一致会导致数据传输失败。在C#端会进行相应的错误提示,例如:未处理DllNotFoundException:无法加载 DLL“EKFLib.dll”: 内存位置访问无效。 (异常来自 HRESULT:0x800703E6) 如出现这个提示,大概率就是你在C#端中设置的参数数据类型出错导致。
- 数据类型的对应关系
C++
- HANDLE(void *) ---- c#:System.IntPtr
- Byte(unsigned char) ---- c#:System.Byte
- SHORT(short) ---- c#:System.Int16
- WORD(unsigned short) ---- c#:System.UInt16
- INT(int) ---- c#:System.Int16
- INT(int) ---- c#:System.Int32
- UINT(unsigned int) ---- c#:System.UInt16
- UINT(unsigned int) ---- c#:System.UInt32
- LONG(long) ---- c#:System.Int32
- ULONG(unsigned long) ---- c#:System.UInt32
- DWORD(unsigned long) ---- c#:System.UInt32
- DECIMAL ---- c#:System.Decimal
- BOOL(long) ---- c#:System.Boolean
- CHAR(char) ---- c#:System.Char
- LPSTR(char *) ---- c#:System.String
- LPWSTR(wchar_t *) ---- c#:System.String
- LPCSTR(const char *) ---- c#:System.String
- LPCWSTR(const wchar_t *) ---- c#:System.String
- PCAHR(char *) ---- c#:System.String
- BSTR ---- c#:System.String
- FLOAT(float) ---- c#:System.Single
- DOUBLE(double) ---- c#:System.Double
- VARIANT ---- c#:System.Object
- PBYTE(byte *) ---- c#:System.Byte[] //c++:BSTR ---- c#:StringBuilder
- LPCTSTR ---- c#:StringBuilder
- LPCTSTR ---- c#:string
- LPTSTR ---- c#:[MarshalAs(UnmanagedType.LPTStr)] string
- LPTSTR 输出变量名 ---- c#:StringBuilder 输出变量名
- LPCWSTR ---- c#:IntPtr
- BOOL ---- c#:bool
- HMODULE ---- c#:IntPtr
- HINSTANCE ---- c#:IntPtr
- 结构体 ---- c#:public struct 结构体{};
- 结构体 变量名 ---- c#:out 变量名 //C#中提前申明一个结构体实例化后的变量名
- 结构体 &变量名 ---- c#:ref 结构体 变量名
- WORD ---- c#:ushort
- DWORD ---- c#:uint
- DWORD ---- c#:int //c++:UCHAR ---- c#:int
- UCHAR ---- c#:byte
- UCHAR ---- c#:string
- UCHAR ---- c#:IntPtr //c++:GUID ---- c#:Guid
- Handle ---- c#:IntPtr
- HWND ---- c#:IntPtr
- DWORD ---- c#:int
- COLORREF ---- c#:uint
- unsigned char ---- c#:byte
- unsigned char * ---- c#:ref byte
- unsigned char * ---- c#:[MarshalAs(UnmanagedType.LPArray)] byte[]
- unsigned char * ---- c#:[MarshalAs(UnmanagedType.LPArray)] Intptr
- unsigned char & ---- c#:ref byte
- unsigned char 变量名 ---- c#:byte 变量名
- unsigned short 变量名 ---- c#:ushort 变量名
- unsigned int 变量名 ---- c#:uint 变量名
- unsigned long 变量名 ---- c#:ulong 变量名
- char 变量名 ---- c#:byte 变量名 //C++中一个字符用一个字节表示,C#中一个字符用两个字节表示
- char 数组名[数组大小] ---- c#:MarshalAs(UnmanagedType.ByValTStr, SizeConst = 数组大小)] public string 数组名;
- ushort char * ---- c#:string //传入参数
- char * ---- c#:StringBuilder//传出参数
- char *变量名 ---- c#:ref string 变量名
- char *输入变量名 ---- c#:string 输入变量名
- char *输出变量名 ---- c#:[MarshalAs(UnmanagedType.LPStr)] StringBuilder 输出变量名
- char ** ---- c#:string
- char *变量名 ---- c#:ref string 变量名
- const char * ---- c#:string
- char[] ---- c#:string
- char 变量名[数组大小] ---- c#:[MarshalAs(UnmanagedType.ByValTStr,SizeConst=数组大小)] public - string 变量名;
- c++:struct 结构体名 变量名 ---- c#:ref 结构体名 变量名 委托 变量名 ---- c#:委托 变量名
- int ---- c#:int
- int ---- c#:ref int
- int & ---- c#:ref int
- int * ---- c#:ref int //C#中调用前需定义int 变量名 = 0;
- int ---- c#:IntPtr
- int32 PIPTR * ---- c#:int32[]
- float PIPTR * ---- c#:float[]
- double 数组名 ---- c#:ref double 数组名
- double[] 数组名 ---- c#:ref double 数组名
- long ---- c#:int
- ulong ---- c#:int
在查找数据类型的时候,看到这些会感觉头昏眼花,再此总结一些本人在项目开发中常用的数据类型
C++
| C++ | C# |
|---|---|
| int | int |
| char* | string |
| const char* | string |
- 接收参数的返回值用ref
- 在DLL中已经封装好的带返回值的函数在接收时,是否需要统一数字类型呢?这个问题对于新手来说,是一个比较困惑的问题。在此,应该了解一下C#是没有指针这个概念的,如需要接收指针就要用IntPtr对其进行接收
举个例子:
在C++中导出DLLEXPORT char* GetPath(char* path);,在C#端中写成[DllImport("ClientAdapter.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern void GetPatternPath(ref byte path);
- 使用depends.exe,打开后,点击File把dll导入
如上图所示Function中的就是dll中封装的函数
- 方法一:使用两端打log的方式查找问题出在哪;方法二:检查C#或者C++中传递的参数是否正确;方法三:当存在多参数时,用控制变量法去对其进行一一排除,注意内部数据类型互转可能出现的问题。