C#调用C++DLL方法

最近使用海康的某平台SDK,但是提供的demo没有C#版本,只有C++的,在转换过程中遇到很多问题,简单记录一下.

目录

1.参数为基本类型,例如 int,float,char等。

2.参数为基本类型 + 指针, 例如int*, float*, char*等

3. 参数为结构体

4. 参数为结构体指针

5.参数为结构体, 并且结构体还嵌套结构体

6. 参数为结构体, 并且结构体还嵌套结构体指针或者双指针

 由于嵌套指针的使用比较复杂,需要借助一些手段才能够确保正常调用DLL方法


 


1.参数为基本类型,例如 int,float,char等。

[C++]
void fun(int value);
void fun(float vaue);
void fun(char ch);

[C#]
[DllImport("xxx.dll")]
public static extern void fun(Int32 value);
[DllImport("xxx.dll")]
public static extern void fun(float value);
[DllImport("xxx.dll")]
public static extern void fun(char ch);

2.参数为基本类型 + 指针, 例如int*, float*, char*等

[C++]
void fun(int* value);
void fun(float* vaue);
void fun(char* ch);

[C#]
[DllImport("xxx.dll")]
public static extern void fun(ref Int32 value);
[DllImport("xxx.dll")]
public static extern void fun(ref float value);

参数为char*,在C#中有几种实现方式

A. public static extern void fun(string ch);		//ch内容不会改变
B. public static extern void fun(StringBuilder ch);	//ch内容会改变

3. 参数为结构体

[C++]
struct point
{
	int value;			//基本类型
	char ch;			//基本类型
	int number[100];	//数组
	char buffer[100];	//字符串数组	
};
void fun(point pt);

[C#]
[StructLayout(LayoutKind.Sequential)]
public struct point
{
	public Int32 value;
	public char ch;
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
	public Int32[] number;
	[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
	public char[] buffer;
}
[DllImport("xxx.dll")]
public static extern void fun(point pt);

4. 参数为结构体指针

[C++]
void fun(point* pt);

[C#]
[DllImport("xxx.dll")]
public static extern void fun(ref point pt);

5.参数为结构体, 并且结构体还嵌套结构体

[C++]
struct point
{
	int value;			//基本类型
	char ch;			//基本类型
	int number[100];	//数组
	char buffer[100];	//字符串数组	
	struct point pt;	//嵌套结构体
};
void fun(point pt);

[C#]
[StructLayout(LayoutKind.Sequential)]
public struct point
{
	public Int32 value;
	public char ch;
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
	public Int32[] number;
	[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
	public char[] buffer;
	public point pt;
}
[DllImport("xxx.dll")]
public static extern void fun(point pt);

6. 参数为结构体, 并且结构体还嵌套结构体指针或者双指针

[C++]
struct point
{
	int value;			//基本类型
	char ch;			//基本类型
	int number[100];	//数组
	char buffer[100];	//字符串数组	
	struct point* p1;	//嵌套结构体指针
	struct point** p2;	//嵌套结构体双指针
};
void fun(point pt);

[C#]
[StructLayout(LayoutKind.Sequential)]
public struct point
{
	public Int32 value;
	public char ch;
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
	public Int32[] number;
	[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
	public char[] buffer;
	public IntPtr p1;	//使用IntPtr替代嵌套指针
	public IntPtr p2;	//使用IntPtr替代嵌套指针
}
[DllImport("xxx.dll")]
public static extern void fun(point pt);

7.回调函数使用

[c++]
typedef void (__stdcall *pStreamCallback)(long lSession, int iStreamType, const char* data, int dataLen, void* pUser);
HIKPT_EXTERN long HIKPT_API HikPt_StartPreview(const char* szCameraIndexCode, void* hWnd, pStreamCallback pFun, void* pUserData, HIK_STREAM_TYPE nStreamType);
[c#]

public delegate void   pStreamCallback(long lSession, int iStreamType, string data, int dataLen, IntPtr pUser);
 [DllImport("xxxx.dll", CharSet = CharSet.Ansi, EntryPoint = "DPSDK_Pt_StartPreview", ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
 public static extern long Pt_StartPreview(string szIndexCode, IntPtr hWnd, pStreamCallback pFun, IntPtr pUserData, HIK_STREAM_TYPE nStreamType);

 

由于嵌套指针的使用比较复杂,需要借助一些手段才能够确保正常调用DLL方法

[C#]
class Program
{
	[StructLayout(LayoutKind.Sequential)]
	public struct point
	{
		public Int32 value;
		public char ch;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
		public Int32[] number;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
		public char[] buffer;
		public IntPtr p1;	//使用IntPtr替代嵌套指针
		public IntPtr p2;	//使用IntPtr替代嵌套指针
	}
	[DllImport("xxx.dll")]
	public static extern void fun(point pt);
	
	static void Main(string[] args)
	{
		point pt = new point();
		pt.p1 = Marshal.AllocHGlobal(Marshal.Sizeof(typeof(point)));
		pt.p2 = Marshal.AllocHGlobal((Marshal.SizeOf(typeof(point))) * 2);
		
		try
		{
			pt.value = 1;
			   
			//实现给p1赋值
			point ptt = new point();
            ptt.value = 1;
			    
            Marshal.StructureToPtr(ptt, pt.p1, false);
			//实现给p2赋值
			//由于双指针不能够直接传值,需要用到中间结构的数组指针
			IntPtr[] ptr = new IntPtr[2];
			ptr[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(point)));
			ptr[1] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(point)));
			
			try
			{
				Marshal.StructureToPtr(ptt, ptr[0], false);
				Marshal.Copy(ptr, 0, pt.p2, 2);
			
				fun(pt);
				//测试返回的指针值是否正确
				ptt = (point)Marshal.PtrToStructure(pt.p1, typeof(point));
				Marshal.Copy(pt.p2, ptr, 0, 2);
				ptt = (point)Marshal.PtrToStructure(ptr[0], typeof(point));
				ptt = (point)Marshal.PtrToStructure(ptr[1], typeof(point));
			}
			catch(System.Exception e)
			{
				string str = e.Message;
			}
			finally
			{
				Marshal.FreeHGlobal(ptr[0]);
				Marshal.FreeHGlobal(ptr[1]);
			}
		}
		catch(System.Exception e)
		{
			string str = e.Message;
		}
		finally
		{
			Marshal.FreeHGlobal(pt.p1);
			Marshal.FreeHGlobal(pt.p2);
		}
	}
}

更详细一些的

C++中的DLL函数原型为
extern "C" __declspec(dllexport) bool 方法名一(const char* 变量名1, unsigned char* 变量名2)
extern "C" __declspec(dllexport) bool 方法名二(const unsigned char* 变量名1, char* 变量名2) 
C#调用C++的DLL搜集整理的所有数据类型转换方式,可能会有重复或者多种方案,自己多测试
c++:HANDLE(void *) ---- c#:System.IntPtr
c++:Byte(unsigned char) ---- c#:System.Byte
c++:SHORT(short) ---- c#:System.Int16
c++:WORD(unsigned short) ---- c#:System.UInt16
c++:INT(int) ---- c#:System.Int16
c++:INT(int) ---- c#:System.Int32
c++:UINT(unsigned int) ---- c#:System.UInt16
c++:UINT(unsigned int) ---- c#:System.UInt32
c++:LONG(long) ---- c#:System.Int32
c++:ULONG(unsigned long) ---- c#:System.UInt32
c++:DWORD(unsigned long) ---- c#:System.UInt32
c++:DECIMAL ---- c#:System.Decimal
c++:BOOL(long) ---- c#:System.Boolean
c++:CHAR(char) ---- c#:System.Char
c++:LPSTR(char *) ---- c#:System.String
c++:LPWSTR(wchar_t *) ---- c#:System.String
c++:LPCSTR(const char *) ---- c#:System.String
c++:LPCWSTR(const wchar_t *) ---- c#:System.String
c++:PCAHR(char *) ---- c#:System.String
c++:BSTR ---- c#:System.String
c++:FLOAT(float) ---- c#:System.Single
c++:DOUBLE(double) ---- c#:System.Double
c++:VARIANT ---- c#:System.Object
c++:PBYTE(byte *) ---- c#:System.Byte[]

c++:BSTR ---- c#:StringBuilder
c++:LPCTSTR ---- c#:StringBuilder
c++:LPCTSTR ---- c#:string
c++:LPTSTR ---- c#:[MarshalAs(UnmanagedType.LPTStr)] string
c++:LPTSTR 输出变量名 ---- c#:StringBuilder 输出变量名
c++:LPCWSTR ---- c#:IntPtr
c++:BOOL ---- c#:bool
c++:HMODULE ---- c#:IntPtr
c++:HINSTANCE ---- c#:IntPtr
c++:结构体 ---- c#:public struct 结构体{};
c++:结构体 **变量名 ---- c#:out 变量名 //C#中提前申明一个结构体实例化后的变量名
c++:结构体 &变量名 ---- c#:ref 结构体 变量名


c++:WORD ---- c#:ushort
c++:DWORD ---- c#:uint
c++:DWORD ---- c#:int

c++:UCHAR ---- c#:int
c++:UCHAR ---- c#:byte
c++:UCHAR* ---- c#:string
c++:UCHAR* ---- c#:IntPtr

c++:GUID ---- c#:Guid
c++:Handle ---- c#:IntPtr
c++:HWND ---- c#:IntPtr
c++:DWORD ---- c#:int
c++:COLORREF ---- c#:uint


c++:unsigned char ---- c#:byte
c++:unsigned char * ---- c#:ref byte
c++:unsigned char * ---- c#:[MarshalAs(UnmanagedType.LPArray)] byte[]
c++:unsigned char * ---- c#:[MarshalAs(UnmanagedType.LPArray)] Intptr

c++:unsigned char & ---- c#:ref byte
c++:unsigned char 变量名 ---- c#:byte 变量名
c++:unsigned short 变量名 ---- c#:ushort 变量名
c++:unsigned int 变量名 ---- c#:uint 变量名
c++:unsigned long 变量名 ---- c#:ulong 变量名

c++:char 变量名 ---- c#:byte 变量名 //C++中一个字符用一个字节表示,C#中一个字符用两个字节表示
c++:char 数组名[数组大小] ---- c#:MarshalAs(UnmanagedType.ByValTStr, SizeConst = 数组大小)] public string 数组名; ushort

c++:char * ---- c#:string //传入参数
c++:char * ---- c#:StringBuilder//传出参数
c++:char *变量名 ---- c#:ref string 变量名
c++:char *输入变量名 ---- c#:string 输入变量名
c++:char *输出变量名 ---- c#:[MarshalAs(UnmanagedType.LPStr)] StringBuilder 输出变量名

c++:char ** ---- c#:string
c++:char **变量名 ---- c#:ref string 变量名
c++:const char * ---- c#:string
c++:char[] ---- c#:string
c++:char 变量名[数组大小] ---- c#:[MarshalAs(UnmanagedType.ByValTStr,SizeConst=数组大小)] public string 变量名;

c++:struct 结构体名 *变量名 ---- c#:ref 结构体名 变量名
c++:委托 变量名 ---- c#:委托 变量名

c++:int ---- c#:int
c++:int ---- c#:ref int
c++:int & ---- c#:ref int
c++:int * ---- c#:ref int //C#中调用前需定义int 变量名 = 0;

c++:*int ---- c#:IntPtr
c++:int32 PIPTR * ---- c#:int32[]
c++:float PIPTR * ---- c#:float[]


c++:double** 数组名 ---- c#:ref double 数组名
c++:double*[] 数组名 ---- c#:ref double 数组名
c++:long ---- c#:int
c++:ulong ---- c#:int

c++:UINT8 * ---- c#:ref byte //C#中调用前需定义byte 变量名 = new byte();


c++:handle ---- c#:IntPtr
c++:hwnd ---- c#:IntPtr


c++:void * ---- c#:IntPtr
c++:void * user_obj_param ---- c#:IntPtr user_obj_param
c++:void * 对象名称 ---- c#:([MarshalAs(UnmanagedType.AsAny)]Object 对象名称



c++:char, INT8, SBYTE, CHAR ---- c#:System.SByte
c++:short, short int, INT16, SHORT ---- c#:System.Int16
c++:int, long, long int, INT32, LONG32, BOOL , INT ---- c#:System.Int32
c++:__int64, INT64, LONGLONG ---- c#:System.Int64
c++:unsigned char, UINT8, UCHAR , BYTE ---- c#:System.Byte
c++:unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR , __wchar_t ---- c#:System.UInt16
c++:unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT ---- c#:System.UInt32
c++:unsigned __int64, UINT64, DWORDLONG, ULONGLONG ---- c#:System.UInt64
c++:float, FLOAT ---- c#:System.Single
c++:double, long double, DOUBLE ---- c#:System.Double

Win32 Types ---- CLR Type

unsigned char对应public byte

 

 

文章是抄的,可以用,如果各位大虾在使用过程中发现不对地方,我会优先测试,然后更新。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值