简述:
在C/S架构设计下,客户端与服务端进行通信有多种方式可选,常用的就是SDK,最大的有点便是便于厂家间平台对接。本篇将从多个方面详尽描述如何使用C#调用C++ SDK。
目录:
调用Dll
如何调用C++ Dll接口
C++数据类型与C#数据类型对照表
结构体转换
多级嵌套结构体转换
回调函数转换
1.调用Dll
首先确定C++提供的Dll文件,一般厂家或是自己部门服务端部分都会提供详尽的Dll、h、lib文件及接口使用文档。对于C#开发只需使用Dll文件即可。此处我将假设开发者是将Dll文件放置于与可执行文件在同一目录下,比如你的可执行文件在C:\,那么将Dll文件也放置于这个目录下,便于开发调试。
2.如何调用C++ Dll接口
Dll接口定义格式简述:
C++ : extern + 返回类型 + _stdcall + 函数名称(参数定义);
C# : [Dllmport("接口所在Dll",SetLastError = true)]
public static extern +返回类型 + 函数名称(参数定义);
确定Dll中提供的接口部分,举例我使用的服务端提供的Dll名称为:CMS_ClientComm.dll,那么我调用此Dll中一个接口:CMS_Init()
C++ :extern int __stdcall CMS_Init();
C#: [DllImport("CMS_ClientComm.dll", SetLastError = true)]
public static extern int CMS_Init();
3.C++数据类型与C#数据类型对照表
C++ c#
int int
unsigned int uint
bool byte
float float
OUT float& ref float
OUT int& ref int
long* long[]
Out char* ref string
OUT char * byte[]
char* byte[]
void* IntPtr
__int64 long
unsigned short ushort
3.C++结构体类型与C#结构体类型对照表
C++里面结构体定义没有什么可讲的,主要是很多编程人员的编程习惯是直接使用结构体定义一个结构体指针来用,此时会让很多人在转换的时候不知所措,此时主要看接口中的参数是使用的结构体还是结构体指针,那此时对应到C#里面也就是是否加ref的问题。另外有点结构体在转换时C#端还需要加入Pack = 1的声明,否则会出现明显的错位问题,这个可以通过调试明显看到。
类型1:正常使用结构体
C++:
struct CMS_LOCAL_RECORD_SET
{
char szFilePath[256];
int iFileType;
int iTimeLen;
bool bAudio;
unsigned int uiReserved[4];
};
extern int __stdcall CMS_StartRecordLiveStreamAsFile(IN CAMERA_HANDLE hCamera,IN CMS_LOCAL_RECORD_SET set);
C#:
[StructLayout(LayoutKind.Sequential,Pack= 1)]
public struct CMS_LOCAL_RECORD_SET
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] szFilePath;
public int iFileType;
public int iTimeLen;
public byte bAudio;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public uint[] uiReserve;
};
[DllImport("CMS_ClientComm.dll", SetLastError = true)]
public static extern int CMS_StartRecordLiveStreamAsFile(IntPtr cameraHandle, CMS_LOCAL_RECORD_SET set);
类型2:(正常转换,只需注意数组转换时使用ByValArray,并注明数组大小。结构体参数其实为指针,对应的C#转换用引用类型)
C++:
typedef struct CMS_LogonData
{
char cSvrIP[64];
char cUser[64];
char cPwd[64];
}*LPCMS_LogonData;
C#:
[StructLayout(LayoutKind.Sequential)]
public struct CMS_LogonData
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] cSvrIP;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] cUser;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] cPwd;
};
此时接口中的调用:
C++:
extern void* __stdcall CMS_Logon(IN LPCMS_LogonData pData);
C#:(加ref引用标示)
[DllImport("CMS_ClientComm.dll", SetLastError = true)]
public static extern IntPtr CMS_Logon(ref CMS_LogonData logonData);
类型3:(有时需要加Pack = 1,否则会出现字符错位问题)
C++:
typedef struct CMS_NAME_FILE_RULE_SET
{
char szSuffix[10];
char szPrefix[40];
bool bIncludeCameraName;
bool bIncludeBeginTime;
unsigned int uiReserved[2];
}*PCMS_NAME_FILE_RULE_SET;
C#
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CMS_NAME_FILE_RULE_SET
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte[] szSuffix;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public byte[] szPrefix;
public byte bIncludeCameraName;
public byte bIncludeBeginTime;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public uint[] uiReserved;
}
4.多级嵌套结构体转换
一般用于返回多组查询结果中。
C++:
struct CMS_DATE
{
unsigned short wYear;
unsigned short wMonth;
unsigned short wDay;
};
struct CMS_TIME
{
unsigned short wHour;
unsigned short wMinute;
unsigned short wSecond;
};
typedef struct CMS_DeviceRecordPlan
{
void * hRecord;
char cType;
CMS_TIME cmsStartTime;
CMS_TIME cmsEndTime;
CMS_DATE cmsDate;
int nWeek[7];
char cName[48];
int nSyncAudio;
}*LPCMS_DeviceRecordPlan;
typedef struct CMS_RecordPlanRes
{
int unPlanNum;
CMS_DeviceRecordPlan sRecordPlan[1024];
}*LPCMS_RecordPlanRes;
extern int __stdcall CMS_GetRecordPlan(IN void* hCamera,OUT LPCMS_RecordPlanRes *pData);
C#:
[StructLayout(LayoutKind.Sequential)]
public struct CMS_TIME
{
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
};
[StructLayout(LayoutKind.Sequential)]
public struct CMS_DATE
{
public ushort wYear;
public ushort wMonth;
public ushort wDay;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CMS_DeviceRecordPlan
{
public IntPtr hRecord;
public byte cType;
public CMS_TIME cmsStartTime;
public CMS_TIME cmsEndTime;
public CMS_DATE cmsDate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public int[] nWeek;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)]
public byte[] cName;
public int nSyncAudio;
};
[StructLayout(LayoutKind.Sequential,Pack = 1)]
public struct CMS_RecordPlanRes
{
public int unPlanNum;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
public CMS_DeviceRecordPlan[] sRecordPlan;
};
[DllImport("CMS_ClientComm.dll", SetLastError = true)]
public static extern int CMS_GetRecordPlan(IntPtr cameraHandle, ref CMS_RecordPlanRes[] recordPlans);
5.回调函数转换
C++:
typedef struct CMS_MessageEx
{
void* hSer;
int nEventType;
char cDesc[260];
void* pContext;
long* pReserve;
long* pReserve1;
}*LPCMS_MessageEx;
typedef void (__stdcall *pfnRecvMsgEx)(LPCMS_MessageEx pLog);
extern int __stdcall CMS_SetCB_RecvMsgEx(IN SERVER_HANDLE hLID,IN pfnRecvMsgEx pLogFuncEx,IN void* pContext);
C#:
[StructLayout(LayoutKind.Sequential)]
public struct CMS_MessageEx
{
public IntPtr hSer;
public int nEventType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)]
public byte[] cDesc;
public IntPtr pContext;
public IntPtr pReserve;
public IntPtr pReserve1;
};
public delegate void CallBackRecvMsgEx(ref CMS_MessageEx pLog);
[DllImport("CMS_ClientComm.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern int CMS_SetCB_RecvMsgEx(IntPtr serverHandle, CallBackRecvMsgEx pLogFunc, IntPtr pContext);
标签:struct,Invoke,int,C++,C#,CMS,public From: https://www.cnblogs.com/xietianjiao/p/16771729.html