微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 客户端获取从C COM dll返回的字节数组

我在C COM头文件和IDL文件中有这个声明:

//Header file:
#define MAX_LENGTH      320
typedef BYTE            PRE_KEY [MAX_LENGTH];

//IDL file:
#define MAX_COUNT       10
HRESULT Save([in] DWORD dwCommand,[in]float fdata[MAX_COUNT],[out] PRE_KEY* phKey);

这是C#客户端代码

//After C# interop compilation,the method's signature in C# becomes:
Save(uint dwCommand,float[] fdata,out byte[] phKey);

//The code to call the C++ COM server:    
uint dwCommand = 2;
float[] fdata = new float[dwCommand];

fdata[0] = 1; 
fdata[1] = 2;

byte[] phKey = new byte[320];

save(dwCommand,fdata,out phKey);

调用返回C#之前,代码将在ntdll.dll中崩溃,但C服务器已经完成处理并且不再在堆栈中.

任何人都可以弄清楚如何解决这个问题?因为我正在使用互操作编译来编译idl文件生成C#signaure,所以我无法在C IDL文件中执行某些操作并手动更改C#签名.

有趣的是,我有一个类似的调用,返回从C到C#的完全相同的phKey,它完美地工作.唯一的区别在于,调用phKey在一个结构中,整个结构是一个'[out]’参数.真的不明白为什么这可以在一个结构中返回但不能直接作为一个参数.

解决方法

IDL声明中的[out]属性一个严重的互操作问题.这意味着您的COM服务器将分配数组,调用者需要释放它.这很少有好结果,无法保证您的服务器和客户端使用相同的堆.当你将C运行时分配器与malloc()函数或new []运算符一起使用时,它总是会失败,CRT使用它自己的私有堆,调用者永远无法访问它,除非它们共享完全相同的CRT版本.通常情况下,这种情况非常小,当您通过CLR进行互操作时为零.

这就是它轰炸的原因,CLR知道它需要在将数据复制到托管数组后释放它.它将使用CoTaskMemFree(),使用为COM互操作分配保留的堆.当然你没有使用CoTaskMemAlloc()来分配数组.

这个问题的一般解决方案是让调用者提供数组,被调用者填充它.这需要[in,out]参数.还有一个额外的参数,用于指示传递数组的大小,[sizeis]告诉编组人员.效率很高,无需分配.使用自动SAFEARRAY类型可以避免必须指定额外的参数,CLR知道该类型.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐