将结构中的字节数组传递给com对象

时间:2019-03-04 12:58:27

标签: c++ com

我编写了一个C ++ COM服务器(进程外)和客户端,因此:

idl(接口为IDispatch):

typedef[uuid(0952A366-20CC-4342-B590-2D8920D61613)]
    struct MyStruct{
    LONG                id;
    BYTE*               data;
    } MyStruct;

[helpstring("")] HRESULT foo([out] MyStruct* pStreamInfo);

服务器:

STDMETHODIMP foo(MyStruct* myStruct)
{
  myStruct.id = 7;
  myStruct.data = pData; // pData is a pointer to some data of variable length
  return S_OK;
}

客户端:

MyStruct ms;
hr = comObj->foo(&ms);

除了添加myStruct.data = pData;行会使服务器崩溃之外,该代码将正常工作。在客户端中分配内存ms.data = new BYTE[1000]无济于事,因为指针仍然以foo到达NULL

这将是一个解决方案,1.最好是最简单的客户端解决方案,因为接口将被各种用户使用。2.如果C#客户端使用接口,则解决方案是否会不同3.如果data需要要脱离结构(我希望不是),这里有一个完整示例的引用。

1 个答案:

答案 0 :(得分:0)

正如其他人在评论中提到的那样,您不能以这种方式传递原始数组。至少,您必须将字节数组复制到SAFEARRAY个字节(在IDL中为SAFEARRAY(BYTE))。我只是使用自定义代理/存根(由midl.exe生成的P / S代码编译)测试了以下代码,并且能够通过网络获取数据。

如果您要使用标准的P / S,例如PSDispatch{00020420-0000-0000-C000-000000000046})或PSOAInterface{00020424-0000-0000-C000-000000000046}),或者要将VBA用作客户端,则可能必须将其转换为SAFEARRAY(VARIANT)和/或将生成的safearray放入VARIANT。首先尝试仅使用SAFEARRAY(BYTE)的最简单方法,因为那是开销最少的方法。 (SAFEARRAY(VARIANT)使用的内存比SAFEARRAY(BYTE)多16倍,因为VARIANT的长度为16个字节。而且,您必须手动将每个字节与VARIANT进行相互转换,如下所示:与下面显示的简单memcpy调用相反。)

将字节数组包装到SAFEARRAY 中:(请注意,这会将字节数组复制到SAFEARRAY中。您可以仔细研究{{1 }}的结构以防止复制,但是您将以非标准的方式进行操作。)

SAFEARRAY

/// <summary>Packs an array of bytes into a SAFEARRAY.</summary> /// <param name="count">The number of bytes.</param> /// <param name="pData">A reference to the byte array. Not read if count is 0.</param> /// <param name="pResult">Receives the packed LPSAFEARRAY on success.</param> HRESULT PackBytes(ULONG count, const BYTE* pData, /*[ref]*/ LPSAFEARRAY* pResult) { // initialize output parameters *pResult = NULL; // describe the boundaries of the safearray (1 dimension of the specified length, starting at standard index 1) SAFEARRAYBOUND bound{ count, 1 }; // create the safearray LPSAFEARRAY safearray = SafeArrayCreate(VT_UI1, 1, &bound); if (!safearray) return E_OUTOFMEMORY; // when there is actually data... if (count > 0) { // begin accessing the safearray data BYTE* safearrayData; HRESULT hr = SafeArrayAccessData(safearray, reinterpret_cast<LPVOID*>(&safearrayData)); if (FAILED(hr)) { SafeArrayDestroy(safearray); return hr; } // copy the data into the safearray memcpy(safearrayData, pData, count); // finish accessing the safearray data hr = SafeArrayUnaccessData(safearray); if (FAILED(hr)) { SafeArrayDestroy(safearray); return hr; } } // set output parameters *pResult = safearray; // success return S_OK; } 拆包字节数组:(请注意,这是从SAFEARRAY复制字节数组。您可以仔细研究{{1 }}的结构可以防止复制,但是您将以非标准的方式进行操作,此外,您还可以通过将消耗代码放在SAFEARRAY之间来选择直接从SAFEARRAY使用数据和SAFEARRAY。)

SafeArrayAccessData