C#程序无法从C++ COM程序正确获取返回字节数组的问题咨询
问题原因
- 单指针版本IDL(
BYTE *pImageBytes)的核心问题:COM互操作层没有收到数组长度关联声明,无法识别pImageBytes是长度和pImageSize绑定的字节数组,不会把C++侧写入的内容同步回C#托管数组,所以你拿到的数组是空的。 - 双指针版本IDL(
BYTE **pImageBytes)的核心问题:你拿到的IntPtr本身就是C++侧分配的字节数组的首地址,你没有做非托管内存到托管数组的拷贝操作,所以只能拿到内存地址而非实际数据。
解决方案
方案1:C#预分配内存(推荐,内存管理逻辑更简单)
第一步:修改IDL签名,补充数组长度关联属性
给pImageBytes添加size_is声明,告诉COM互操作层该数组的长度由pImageSize指向的值决定:
[id(5)] HRESULT GetFlawImage( [in] ULONG flawID, [in] USHORT station, [in, out] ULONG *pImageSize, [out, size_is(*pImageSize)] BYTE *pImageBytes );
第二步:修改C#调用代码
数组参数不要用out修饰,改为ref传递你提前分配好的数组:
uint imageSize = 待获取图像的字节数; byte[] arr = new byte[imageSize]; _wiCore.GetFlawImage(1, 0, ref imageSize, ref arr);
C++侧实现要求
直接往传入的pImageBytes地址拷贝对应长度的字节即可,不需要自行分配内存,也不需要释放传入的指针。
方案2:C++侧分配内存
第一步:修改IDL签名,补充数组长度关联属性
[id(5)] HRESULT GetFlawImage( [in] ULONG flawID, [in] USHORT station, [out] ULONG *pImageSize, [out, size_is(, *pImageSize)] BYTE **pImageBytes );
第二步:C#侧调用并手动拷贝非托管内存
uint imageSize = 0; IntPtr pImageBuf = IntPtr.Zero; _wiCore.GetFlawImage(1, 0, out imageSize, out pImageBuf); // 将非托管内存数据拷贝到托管数组 byte[] arr = new byte[imageSize]; System.Runtime.InteropServices.Marshal.Copy(pImageBuf, arr, 0, (int)imageSize); // 必须释放C++侧分配的内存,释放方式要和C++的分配方式匹配 // 若C++用CoTaskMemAlloc分配内存,用以下方法释放 System.Runtime.InteropServices.Marshal.FreeCoTaskMem(pImageBuf); // 若C++用new/malloc分配,需要额外导出对应的释放接口调用,避免内存泄漏
内容的提问来源于stack exchange,提问作者Bill
相关产品推荐
相关产品推荐

