首页 > 其他分享 >P/Invoke(五)

P/Invoke(五)

时间:2022-10-09 12:33:55浏览次数:24  
标签:struct Invoke int C++ C# CMS public

简述:

在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

相关文章

  • P/Invoke(二)
    最恶心的是**int[]指针的指针..后来发现其实操作最麻烦的也就是类型的对应,这个**int[] 最后竟然使用IntPtr[]接收成功了。有意思。单个IntPtr接收不了。。(主要是......
  • P/invoke(三)
    前言让拖管代码对象和非托管对象协同工作的过程称为互用性(Interoperability),通常简称为Interop。P/Invoke在托管代码与非托管代码交互式时产生一个事务(Tran......
  • P/Invoke(一)
    编写目的           我们曾经熟悉的WindowsAPI, 我们曾经花费了大量精力写的代码,难道我们就要轻易放弃吗 不过当下微软已经把向下兼容性放在很重要的位置.  ......
  • 004 反射机制——反射机制概念——Java的反射API——反射的步骤——创建对象的2种方式
    2.3.2反射机制的概念(什么是反射)反射机制指在程序运行过程中,对任意一个类都能获取其所有属性和方法,并且任意一个对象都能调用其任意一个方法。这种动态获取类和对象的信......
  • php 魔术方法 __tostring() __invoke()
    //__tostring()用于屏蔽错误信息,当需要输出错误信息时,用本函数内返回的字符串代替//__invoke()用于屏蔽错误信息,当把对象当作函数调用时,会执行本函数<?phpheader("Co......
  • 【mybatis框架学习】三、invoke方法逻辑编排
    上一篇一直有提高一个词,编排。都说编程,编程,编排也就容易理解了。 像我们常用的框架,spring、mybatis,都是将一些固有的流程,简化,抽象,编排起来,在留有可拓展的接口之后,全部......
  • android程序报错Attempt to invoke virtual method 'boolean java.lang.String.equals
    android程序报错运行报以下错误:Attempttoinvokevirtualmethod'booleanjava.lang.String.equals(java.lang.Object)'onanullobjectreference可能原因:1、可能布......
  • Invoke-PSImage 使用简介
    github:​​peewpw/Invoke-PSImage​​简介:EncodesaPowerShellscriptinthepixelsofaPNGfileandgeneratesaonelinertoexecuteInvoke-PSImagetakesaPowerSh......
  • C#中使用Invoke和BeginInvoke跨线程更新UI控件示例代码
    在多线程开发过程中,有时候需要更新UI控件内容,但是在c#多线程Task、Thread、BackgroundWork中不能直接更新UI控件,否则会报调用线程不能访问此对象,因为它由另一个线程拥有The......
  • CVE-2017-12149 JBoss JMXInvokerServlet 反序列化漏洞
    一、漏洞概述     2017年8月30日,厂商Redhat发布了一个JBOSSAS5.x的反序列化远程代码执行漏洞通告。该漏洞位于JBoss的HttpInvoker组件中的ReadOnlyAccessFil......