【问题标题】:Passing an array using COM?使用 COM 传递数组?
【发布时间】:2010-09-22 15:27:30
【问题描述】:

我是一个用 ATL 编写的 COM 对象,用于 C++ 应用程序,我想在两者之间传递一个 BYTE 数组。到目前为止,我对 COM/IDL 的体验仅限于传递简单类型(BSTR、LONG 等)。

有没有一种相对简单的方法可以让 COM 对象将数组传递给调用者?例如,我想传递原始图像 (TIFF) 而不是弄乱临时文件。

【问题讨论】:

  • 成为一个 COM 对象一定很有趣。 :-)

标签: c++ com


【解决方案1】:

尝试将安全数组变体传递给 COM 对象。像这样将 BYTE 数组放入 safearray 变体中......

bool ArrayToVariant(CArray<BYTE, BYTE>& array, VARIANT& vtResult)
{
SAFEARRAY FAR*  psarray;
SAFEARRAYBOUND sabounds[1]; 

sabounds[0].lLbound=0;
sabounds[0].cElements = (ULONG)array.GetSize();

long nLbound;

psarray = SafeArrayCreate(VT_UI1, 1, sabounds);
if(psarray == NULL)
    return false;

for(nLbound = 0; nLbound < (long)sabounds[0].cElements ; nLbound++){
    if(FAILED(SafeArrayPutElement(psarray, &nLbound, &array[nLbound]))){
        SafeArrayDestroy(psarray);
        return false;
    }
}

VariantFree(vtResult);
vtResult.vt = VT_ARRAY|VT_UI1;
vtResult.parray = psarray;
return true;
}

【讨论】:

  • 谢谢 - 我发现了一个非常有用的 ATL 类,称为 CComSafeArray,它使这变得非常容易(旧版本的 MFC 可以使用 COleSafeArray)。
【解决方案2】:

如果您想要符合 OLE-Automation 标准,SAFEARRAY 是您的最佳选择,并且可能使用来自其他语言(例如 VB6)的 COM 接口。但在 IDL 中有一个替代方案,例如:-

void Fx([in] long cItems, [in, size_is(cItems)] BYTE aItems[]);

这描述了一种方法,编组代码可以通过检查第一个参数的值来推断要传输的字节数。

如果您的客户端都是用 C/C++ 编写的,这很好,但我认为包含它的接口不符合自动化要求,因此无法从 VB6 中使用,并且可能 标准封送处理程序将无法进行封送处理,因此您需要从 IDL 生成您自己的代理/存根 DLL。做起来不难,但比使用 SAFEARRAY 难一点。

【讨论】:

    【解决方案3】:

    使用safearrays 结帐。下面是一些示例代码:

    安全数组作为指向 VARIANT 的指针返回

    [id(1), helpstring("LogCache")] HRESULT LogCache([out,retval] VARIANT* logCache);
    

    Safearray 非常易于使用。下面是一些示例代码,它缓存了某个应用程序的最新 1000 条日志消息:

       safearray_t<bstr_t> m_logCache;
       ...
       if (m_logCache.size() > 1000)
       {
           m_logCache.pop_back();
       }
    
       m_logCache.push_front(Msg.str(), 0);
    
    
        variant_t LogCache()
        {
            if (!m_logCache.is_empty())
            {
                variant_t cache(m_logCache);
                return cache;
            }
        }
    

    请注意,由于我使用的是comet COM library,因此您的语法几乎肯定会有所不同,但想法/概念是相同的。

    【讨论】:

      【解决方案4】:

      您可以使用 BSTR 传递字节数组。

      BYTE array[buffer_size];
      ...
      BSTR toBePassed = SysAllocStringByteLen((OLECHAR*)array,length);
      YourCOMMethod(toBePassed);
      SysFreeString(toBePassed);
      

      在你的方法中:

      BYTE* pData = (BYTE*)bstrPassed;
      DWORD dataLength = SysStringByteLen(bstrPassed);
      

      【讨论】:

      • 不要这样做。数组内容可能会从它们的 ANSI 代码页转换为 Unicode,反之亦然,从而导致二进制值发生变化。客户端应用程序可能并不总是知道何时发生这种情况,它们会发现自己的数据已损坏。
      • 澄清:即使程序员打算让数组保存二进制数据,但各种系统例程并不知道程序员的意图。 BSTR 旨在保存 Unicode 字符串,系统例程会做出这样的假设。
      • OLECHAR 是一个宽字符,即 16 位,一个字节/普通字符是 8 位。这行不通。
      猜你喜欢
      • 2011-01-02
      • 2012-05-25
      • 1970-01-01
      • 2015-12-25
      • 2012-08-21
      • 2018-07-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多