小弟目前在用C#做一个调用C++开发的DLL的功能模块。其中数据类型转换的问题不是太懂。在这里请教一下各位大侠。 运行一直报错:“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。” 先贴一下代码吧。 /** 注册平台. @param IN nPDLLHandle SDK句柄 @param IN pLoginInfo 用户登录信息 @param IN nTimeout 超时时长,单位毫秒 @return 函数返回错误类型,参考dpsdk_retval_e @remark int32_t 定义为 int */ DPSDK_DLL_API int32_t DPSDK_CALL_METHOD DPSDK_Login( IN int32_t nPDLLHandle, IN Login_Info_t* pLoginInfo, IN int32_t nTimeout = DPSDK_CORE_DEFAULT_TIMEOUT ); /** nPDLLHandle 在初始化得到值为1 **/ /** 其中Login_Info 的结构如下 **/ // 登录信息 typedef struct tagLoginInfo { char szIp[DPSDK_CORE_IP_LEN]; // 服务IP,或者是域名DPSDK_CORE_IP_LEN为48 uint32_t nPort; // 服务端口 char szUsername[DPSDK_CORE_USER_NAME_LEN]; // 用户名DPSDK_CORE_USER_NAME_LEN为64 char szPassword[DPSDK_CORE_PASSWORD_LEN]; // 密码DPSDK_CORE_PASSWORD_LEN为64 dpsdk_protocol_version_e nProtocol; // 协议类型 uint32_t iType; // 登陆类型,1为PC客户端, 2为手机客户端 }Login_Info_t; /** 枚举 dpsdk_protocol_version_e 代码如下 **/ // 协议版本 typedef enum { DPSDK_PROTOCOL_VERSION_I = 1, // 一代协议 DPSDK_PROTOCOL_VERSION_II = 2, // 二代协议 }dpsdk_protocol_version_e; // C#代码如下 /// <summary> /// 登录 /// </summary> /// <param name="m_nDLLHandle">SDK句柄</param> /// <param name="stuLoginInfo">用户登录信息</param> /// <param name="timeout">无响应超时时间</param> /// <returns>登录状态</returns> [DllImport("C:\DLLSDK\DPSDK_Core.dll", CharSet = CharSet.Auto, SetLastError = true)]//, CallingConvention = CallingConvention.Cdecl , CallingConvention = CallingConvention.StdCall public static extern int DPSDK_Login(int m_nDLLHandle, Login_Info_t stuLoginInfo, int timeout = 10000); //定义 Login_Info_t 结构体如下: /// <summary> /// 用户登录信息 /// </summary> [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct Login_Info_t { /// <summary> /// IP /// </summary> [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] public char[] szIp; /// <summary> /// 端口 /// </summary> public uint nPort; /// <summary> /// 登录用户名 /// </summary> [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public char[] szUsername; /// <summary> /// 登录密码 /// </summary> [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public char[] szPassword; /// <summary> /// 协议类型 /// </summary> public dpsdk_protocol_version_e nProtocol; /// <summary> /// 登陆类型,1为PC客户端, 2为手机客户端 /// </summary> public uint iType; } //定义枚举如下: /// <summary> /// 协议类型 /// </summary> public enum dpsdk_protocol_version_e { /// <summary> /// 一代协议 /// </summary> DPSDK_PROTOCOL_VERSION_I = 1, // 一代协议 /// <summary> /// 二代协议 /// </summary> DPSDK_PROTOCOL_VERSION_II = 2, // 二代协议 } //实现登录方法如下: /// <summary> /// 登录平台 /// </summary> /// <param name="strIp">平台IP</param> /// <param name="strUserName">用户名</param> /// <param name="strPassword">密码</param> /// <param name="strPort">端口号</param> /// <param name="nProtocol">协议类型</param> /// <param name="iType">登录类型</param> /// <returns></returns> public int DLLSDK_Login(string strIp, string strUserName, string strPassword, uint strPort, dpsdk_protocol_version_e nProtocol = dpsdk_protocol_version_e.DPSDK_PROTOCOL_VERSION_II, uint iType = 1) { //用户登录信息 Login_Info_t login_info = new Login_Info_t(); login_info.szIp = StringToCharArray(strIp,48); login_info.szUsername = StringToCharArray(strUserName, 64); login_info.szPassword = StringToCharArray(strPassword, 64); login_info.nPort = strPort; login_info.nProtocol = nProtocol; login_info.iType = iType; //登录 m_Dll_Hanlde 为全局变量 已经赋值为1 int result = DPSDK_Login(m_Dll_Hanlde, login_info, 5000); return result; } /// <summary> /// 字符串转换成指定长度的字符数组 /// </summary> /// <param name="str"></param> /// <param name="ToLength"></param> /// <returns></returns> public char[] StringToCharArray(string str, int ToLength) { char[] newArray = new char[ToLength]; if (str != null) { if (str.Length > ToLength) { str = str.Substring(0, ToLength - 1); } char[] oldArray = str.ToCharArray(); //byte[] buffer = Encoding.ASCII.GetBytes(str); //string s = Encoding.ASCII.GetString(buffer); //oldArray = s.ToCharArray(); int i = 0; foreach (char item in oldArray) { newArray[i] = item; i++; } } return newArray; } |
|
自己先顶一下
|
|
60分 |
stuLoginInfo
这个参数类型应该用IntPtr 通过Mashal.StructureToPtr把你的结构转换了再传进去 |
我对C++和C#的转换还是个小白,请问能说具体点吗或者能给我贴个示例代码吗? |
|
//用户登录信息 Login_Info_t login_info = new Login_Info_t(); login_info.szIp = StringToCharArray(strIp, 48);//StringToCharArray(strIp, 48); login_info.szUsername = StringToCharArray(strUserName, 64); login_info.szPassword = StringToCharArray(strPassword, 64); login_info.nPort = strPort; login_info.nProtocol = nProtocol; login_info.iType = iType; int nSizeOfLogin = Marshal.SizeOf(login_info); IntPtr intPtr = Marshal.AllocHGlobal(nSizeOfLogin); //将数据从托管对象封送到非托管内存块,该内存块开始地址为intPtr Marshal.StructureToPtr(login_info, intPtr, true); //登录 int result = -1; try { result = DaHua_SDK_API.DPSDK_Login(m_Dll_Hanlde, intPtr, 5000); } catch { result = -2; } finally { Marshal.FreeHGlobal(intPtr); //free tha memory } return result; 我这样做了一下好像还是不行。。 |
|
可以了。。不过需要将 C++ Login_Info_t 结构体中的 char 类型 定义为C# 中的 byte[] 类型 /// <summary> /// 字符串转换成指定长度的字符数组 /// </summary> /// <param name="str"></param> /// <param name="ToLength"></param> /// <returns></returns> public byte[] StringToByteArray(string str, int ToLength) { byte[] newArray = new byte[ToLength]; if (str != null) { if (str.Length > ToLength) { str = str.Substring(0, ToLength - 1); } byte[] buffer = Encoding.ASCII.GetBytes(str); int i = 0; foreach (byte item in buffer) { newArray[i] = item; i++; } } return newArray; } /// <summary> /// 登录平台 /// </summary> /// <param name="strIp">平台IP</param> /// <param name="strUserName">用户名</param> /// <param name="strPassword">密码</param> /// <param name="strPort">端口号</param> /// <param name="nProtocol">协议类型</param> /// <param name="iType">登录类型</param> /// <returns></returns> public int DLLSDK_Login(string strIp, string strUserName, string strPassword, uint strPort, dpsdk_protocol_version_e nProtocol = dpsdk_protocol_version_e.DPSDK_PROTOCOL_VERSION_II, uint iType = 1) { //用户登录信息 Login_Info_t login_info = new Login_Info_t(); login_info.szIp = StringToByteArray(strIp, 48);//StringToCharArray(strIp, 48); login_info.szUsername = StringToByteArray(strUserName, 64); login_info.szPassword = StringToByteArray(strPassword, 64); login_info.nPort = strPort; login_info.nProtocol = nProtocol; login_info.iType = iType; int nSizeOfLogin = Marshal.SizeOf(login_info); IntPtr intPtr = Marshal.AllocHGlobal(nSizeOfLogin); //将数据从托管对象封送到非托管内存块,该内存块开始地址为intPtr Marshal.StructureToPtr(login_info, intPtr, true); //登录 int result = -1; try { result =DPSDK_Login(m_Dll_Hanlde, intPtr, 5000); } catch { result = -2; } finally { Marshal.FreeHGlobal(intPtr); //free tha memory } return result; } |