我目前正在用C / CLI编写一个DLL,它将充当非托管程序和另一个C#DLL之间的“代理” . 调用程序需要我的“代理DLL”来实现将由非托管程序调用的各种过程 . 到目前为止,没问题 .
但是:其中一个功能有以下原型:
extern "C" __declspec ( dllexport ) long Execute(unsigned long command, long nInBytes, byte bInData[], long nOutBytes, long* pnUsedOutBytes, byte bOutData[])
好吧,我的代理DLL只是调用C#DLL,它提供了以下函数原型(也是由调用程序的文档给出的):
unsafe public UInt32 Execute(UInt32 command, Int32 nInBytes, byte* pInData, Int32 nOutBytes, Int32* pnUsedOutBytes, byte* pOutData);
编译器在参数5 pnUsedOutBytes
处抛出错误(C2664)并告诉我, long*
无法转换为 int*
. 好的, long
和 int
目前具有相同的实现,可能在将来的某个时候发生变化,因此抛出的错误是可以理解的(尽管非指针长期使用不会引发错误?) .
回到实际问题:调用C#函数的最佳解决方案是什么?我已经读过(当然)最好的解决方案是在调用.NET函数时使用.NET类型 . 那么:在调用函数时进行简单的类型转换是否安全,或者在这种类型转换不起作用的任何不良情况下是否安全?
使用这一行可以使编译器平静下来,但它真的安全吗?
curInstance->Execute(command, nInBytes, pInData, nOutBytes, (System::Int32*)pnUsedOutBytes, pOutData);
提前致谢!
2 回答
不,不要使用那个演员 . 假设
pnUsedOutBytes
的实际值大于2 ^ 32 . 最好的情况是,对Execute
的调用将覆盖低字节并将这些位单独留在32以上,从而导致错误的答案 .解决方案是使用指向32位数据类型的指针调用
Execute
. 在代理中创建一个,如果需要,给它一个明智的起始值,进行调用,并将结果值复制到pnUsedOutBytes
指向的pnUsedOutBytes
.哦,不要解释错误信息 . 错误消息确实 not 说你不能 cast
long*
到int*
;您可以 . 几乎可以肯定地说,编译器不能 convertlong*
到int*
. 这是正确的:两种类型之间没有 implicit 转换 . 添加转换会告诉编译器执行此操作;你有一个 explicit 转换 .最简单的解决方案是修复导出函数的签名:
LoadLibrary
将不会对int32_t
和int
与long
之间的区别产生任何不满,因为它们都是32位整数类型 .(实际上,
LoadLibrary
使用不兼容的类型赢了't give you any grief for a bunch of actual errors either, ... but in this case you aren')