【发布时间】:2010-09-22 15:27:30
【问题描述】:
我是一个用 ATL 编写的 COM 对象,用于 C++ 应用程序,我想在两者之间传递一个 BYTE 数组。到目前为止,我对 COM/IDL 的体验仅限于传递简单类型(BSTR、LONG 等)。
有没有一种相对简单的方法可以让 COM 对象将数组传递给调用者?例如,我想传递原始图像 (TIFF) 而不是弄乱临时文件。
【问题讨论】:
-
成为一个 COM 对象一定很有趣。 :-)
我是一个用 ATL 编写的 COM 对象,用于 C++ 应用程序,我想在两者之间传递一个 BYTE 数组。到目前为止,我对 COM/IDL 的体验仅限于传递简单类型(BSTR、LONG 等)。
有没有一种相对简单的方法可以让 COM 对象将数组传递给调用者?例如,我想传递原始图像 (TIFF) 而不是弄乱临时文件。
【问题讨论】:
尝试将安全数组变体传递给 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;
}
【讨论】:
如果您想要符合 OLE-Automation 标准,SAFEARRAY 是您的最佳选择,并且可能使用来自其他语言(例如 VB6)的 COM 接口。但在 IDL 中有一个替代方案,例如:-
void Fx([in] long cItems, [in, size_is(cItems)] BYTE aItems[]);
这描述了一种方法,编组代码可以通过检查第一个参数的值来推断要传输的字节数。
如果您的客户端都是用 C/C++ 编写的,这很好,但我认为包含它的接口不符合自动化要求,因此无法从 VB6 中使用,并且可能 标准封送处理程序将无法进行封送处理,因此您需要从 IDL 生成您自己的代理/存根 DLL。做起来不难,但比使用 SAFEARRAY 难一点。
【讨论】:
使用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,因此您的语法几乎肯定会有所不同,但想法/概念是相同的。
【讨论】:
您可以使用 BSTR 传递字节数组。
BYTE array[buffer_size];
...
BSTR toBePassed = SysAllocStringByteLen((OLECHAR*)array,length);
YourCOMMethod(toBePassed);
SysFreeString(toBePassed);
在你的方法中:
BYTE* pData = (BYTE*)bstrPassed;
DWORD dataLength = SysStringByteLen(bstrPassed);
【讨论】: