C#调用返回_DEVICE_INFO结构体的C++ DLL函数结果为空,求解决
C#调用C++ DLL结构体指针返回空的解决方案
核心问题分析
你的代码存在三个关键错误,导致无法正确获取设备信息:
- 函数签名不匹配:C++函数接收并返回结构体指针,但C#代码以值类型传递参数并返回值类型,封送层无法正确转换指针与值类型的映射。
- 缺少字符集指定:C++的
TCHAR依赖字符集配置,未显式指定会导致字符串封送错误。 - 调用约定未显式声明:C++函数使用
__stdcall,C#默认虽可能匹配,但显式声明可避免栈不平衡问题。
修正后的代码实现
1. 结构体定义(添加字符集)
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] struct _DEVICE_INFO { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string chDeviceName; public int nCommPort; public int nECGPos; public int nNumberOfChannel; public int nESUType; public int nTymestampType; public int nDeviceHandle; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string chDeviceID; }
若C++库使用ANSI字符集(
TCHAR为char),将CharSet.Unicode改为CharSet.Ansi。
2. DLL导入函数定义(匹配指针与调用约定)
[DllImport(@"\BAlertSDK\ABM_Athena.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)] static extern IntPtr GetDeviceInfoKeepConnection(ref _DEVICE_INFO deviceInfo);
用
IntPtr接收C返回的结构体指针,用ref关键字传递结构体,确保C能修改传入的结构体内容。
3. 调用示例
void Test_Click() { _DEVICE_INFO d = new _DEVICE_INFO(); IntPtr resultPtr = GetDeviceInfoKeepConnection(ref d); // 检查返回指针是否有效(非空表示成功) if (resultPtr != IntPtr.Zero) { // 此时d已被C++函数填充,可直接使用 Console.WriteLine($"设备名称:{d.chDeviceName}"); Console.WriteLine("设备信息获取成功"); } else { Console.WriteLine("设备信息获取失败"); } }
额外注意事项
- 如果C++函数返回的是新分配的结构体内存(而非修改传入的结构体),需要手动封送指针到结构体,并调用DLL提供的内存释放函数(通常会有对应
FreeDeviceInfo之类的函数),避免内存泄漏:// 假设存在释放函数 [DllImport(@"\BAlertSDK\ABM_Athena.dll", CallingConvention = CallingConvention.StdCall)] static extern void FreeDeviceInfo(IntPtr deviceInfoPtr); // 调用示例 IntPtr resultPtr = GetDeviceInfoKeepConnection(IntPtr.Zero); // 若参数可传空 if (resultPtr != IntPtr.Zero) { _DEVICE_INFO deviceInfo = (_DEVICE_INFO)Marshal.PtrToStructure(resultPtr, typeof(_DEVICE_INFO)); // 使用设备信息... FreeDeviceInfo(resultPtr); // 释放内存 }
内容的提问来源于stack exchange,提问作者Jose Eduardo
相关产品推荐
相关产品推荐

