【发布时间】:2014-09-22 21:04:24
【问题描述】:
我正在尝试为现有(黑盒)客户端研究和重新实现(黑盒)COM 服务器。通过导入类型库并创建实现服务器接口的 .NET 类,我成功地 registered 一个虚拟实现。
我有一个有问题的签名,在客户端调用时似乎不起作用:
这是 IDL 定义:
[id(0x00000007), helpstring("method GetFoo")]
HRESULT GetFoo(VARIANT* vector);
导入的 .NET 定义:
[DispId(7)]
void GetFoo(ref object vector);
注意:vector 参数是一个输出参数。
客户端可以成功调用实现该接口的我的服务器。在此调用期间,我可以看到 vector 参数包含一个 16 字节的数组。但是,我在数组中设置的数据似乎没有正确发送到客户端。我已经对原始服务器进行了逆向工程,并找到了它期望参数的确切 VARIANT 标志。使用这些信息,我创建了一个 C++ 客户端,它在调用原始服务器时获取输出参数中的数据:
const int TABLE_LENGTH = 16;
SAFEARRAY* table = SafeArrayCreateVector(VT_I1, 0, TABLE_LENGTH);
VARIANT val; VariantInit(&val);
val.vt = VT_BYREF | VT_ARRAY | VT_I1 | VT_NULL;
val.pparray = &table;
realServer->GetFoo(&val);
// now table contains valid data
如果我使用这个客户端调用我的服务器,我会得到一个SafeArrayTypeMismatchException在方法中的断点将被命中。
我的问题是:如何实现 .NET 方法,以便上述客户端可以获取我在 ref 参数中设置的数据?
【问题讨论】:
-
您是否尝试将其编组为非托管类型数组?
-
@MikeofSST 我该怎么做?我无法更改 .NET 定义,它来自生成的互操作程序集。
-
您可以尝试:
IntPtr dataPtr = Marshal.AllocCoTaskMem(16);然后 dataPtr 将是数组的句柄,如果需要,您可以将其编组到托管数组中。请注意,“16”与您在问题中使用的幻数相同。 -
@MikeofSST 谢谢。不幸的是仍然抛出同样的异常。
-
您是否将客户端数据从
vector复制到dataPtr 的未管理内存中?我认为 Marshal.Copy() 是执行此操作的 API。