我有一个 C++ COM 服务器,我最近将其重新编译为 64 位。此 COM 服务器有一个方法,该方法包含一个结构参数,该参数包含一些整数和一个 BSTR 以及另一个结构。现在,我正尝试从 64 位 .Net C# 应用程序调用此 COM 服务器。只要我不尝试填充任何字符串参数,我就可以成功加载我的 COM 服务器并调用此方法。如果我尝试在 int 成员中传递有效值,它们最终会在 COM 对象实现结束时被破坏。似乎结构的编码方式是错误的。此代码在 32 位应用程序中运行良好。
以下是在 C++ 端定义 idl 的一般方式:(忽略愚蠢的 typedef,这是一些遗留代码)
[helpstring("method Method1")] HRESULT Method1([in] STRUCT1* pStruct, [in, out] DWORD* inparm1, [out]USHORT* outparm2);
typedef struct _Struct2
{
USHORT p1;
BSTR s1;
BSTR s2;
BSTR s3;
BSTR s4;
DWORD p2;
DWORD p3;
} STRUCT2;
typedef struct _Struct1
{
DWORD p1;
DWORD p2;
BSTR s1;
BOOL p3;
STRUCT2 struct2;
}STRUCT1;
尝试填充 STRUCT2 中的成员会导致未定义的行为和崩溃。谁能看出为什么这在 64 位代码和 32 位代码中会成为问题?我需要实现一些编码魔法吗?此外,我似乎没有解决编码问题的工具。关于解决编码(marshal)拆收器在幕后所做的事情的好方法有什么建议吗?
最佳答案
结构是 COM 的致命弱点。结构成员的实际布局高度依赖于编译器。在他们想出 IRecordInfo hack 之前,他们在 COM 自动化中不支持很长一段时间。在这里不习惯。
在非托管代码中,#pragma pack 指令非常重要。对于类型库,midl.exe 的/pack 参数是必不可少的。如果不是 8 或者你没有使用 64 位版本的 midl 那么你肯定会遇到这种问题。 BSTR 成员是将其丢弃的成员,它们是 32 位或 64 位指针,具体取决于位数。并对齐 4 的倍数用于 32 位版本的 midl,8 的倍数用于 64 位版本。只要该结构不包含任何 double ,您就可以通过传递/pack 4 来拯救它。但请先尝试 64 位版本的 midl.exe。或者摆脱结构并用接口(interface)指针替换它们,这才是真正的解决方法。
关于.net - 解决 x64 com 互操作编码(marshal)处理问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4082522/