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知道该类型. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |