将结构中的字节数组传递给 com 对象
Pass byte array within struct to a com object
我编写了一个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]
没有帮助,因为指针仍然以NULL
的形式到达foo
。
什么是解决方案,1.最好是客户端最简单的解决方案,因为界面将被各种用户使用2。如果 C# 客户端 3 使用接口,是否会有不同的解决方案。如果data
需要脱离结构(我希望不需要),是否有对完整示例的引用。
正如其他人在评论中提到的,您不能以这种方式传递原始数组。至少,您必须将字节数组复制到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)
和/或将生成的安全数组放入VARIANT
中。尝试最简单的方法,先使用SAFEARRAY(BYTE)
,因为这是开销最小的方法。(SAFEARRAY(VARIANT)
使用的内存比SAFEARRAY(BYTE)
多 16 倍,因为VARIANT
的长度为 16 个字节。并且您必须手动将每个字节转换为/从VARIANT
,而不是下面显示的简单memcpy
调用。
将字节数组打包到SAFEARRAY
中:(请注意,这会将字节数组复制到SAFEARRAY
中。你可以使用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
中解压缩字节数组:(请注意,这会从SAFEARRAY
复制字节数组。你可以使用SAFEARRAY
结构的内部来防止复制,但你会以非标准的方式做事。此外,您可以选择直接从SAFEARRAY
使用数据,方法是将使用代码放在SafeArrayAccessData
和SafeArrayUnaccessData
之间。
/// <summary>Unpacks an array of bytes from a SAFEARRAY.</summary>
/// <param name="safearray">The source SAFEARRAY.</param>
/// <param name="pCount">A pointer to a ULONG that will receive the number of bytes.</param>
/// <param name="ppData">A pointer to a BYTE* that will receive a reference to the new byte array.
/// This array must be deallocated (delete []) when the caller is done with it.</param>
HRESULT UnpackBytes(LPSAFEARRAY safearray, /*[out]*/ ULONG* pCount, /*[out]*/ BYTE** ppData)
{
// initialize output parameters
*pCount = 0;
*ppData = NULL;
// validate the safearray element type (must be VT_UI1)
VARTYPE vartype;
HRESULT hr = SafeArrayGetVartype(safearray, &vartype);
if (FAILED(hr))
return hr;
if (vartype != VT_UI1)
return E_INVALIDARG;
// validate the number of dimensions (must be 1)
UINT dim = SafeArrayGetDim(safearray);
if (dim != 1)
return E_INVALIDARG;
// get the lower bound of dimension 1
LONG lBound;
hr = SafeArrayGetLBound(safearray, 1, &lBound);
if (FAILED(hr))
return hr;
// get the upper bound of dimension 1
LONG uBound;
hr = SafeArrayGetUBound(safearray, 1, &uBound);
if (FAILED(hr))
return hr;
// if the upper bound is less than the lower bound, it's an empty array
if (uBound < lBound)
return S_OK;
// calculate the count of the bytes
ULONG count = uBound - lBound + 1;
// create buffer
BYTE* pData = new BYTE[count];
if (!pData)
return E_OUTOFMEMORY;
// begin accessing the safearray data
BYTE* safearrayData;
hr = SafeArrayAccessData(safearray, reinterpret_cast<LPVOID*>(&safearrayData));
if (FAILED(hr))
{
delete[] pData;
return hr;
}
// copy the data
memcpy(pData, safearrayData, count);
// finish accessing the safearray data
hr = SafeArrayUnaccessData(safearray);
if (FAILED(hr))
{
delete[] pData;
return hr;
}
// set output parameters
*pCount = count;
*ppData = pData;
// success
return S_OK;
}
- COM :是否可以查看是否存在对我的某个 COM 对象的进程外引用?我可以释放它吗?
- 如何在C++非托管/本机 DLL 中从注册免费 COM C# 托管 DLL 创建 COM 对象
- 从 WinRT C++组件访问 COM 对象
- 通过 COM 对象连接 x64 应用程序时出现问题
- 我如何知道COM对象与不同的COM UUIDS兼容
- 如何访问从 COM 对象返回的 VARIANT 数据类型中的安全数组C++?
- 2 个 COM 对象,并在另一个对象中使用其中一个对象的接口
- 尝试向 COM 对象添加另一个接口时出现静态强制转换错误 C2440
- 在没有共享 COM 对象的情况下使用 COM STA 或 MTA?
- 初始化com对象的问题
- UI自动化回调中com对象的所有权
- 从 COM 对象快速读取西里尔字母
- 如果从函数返回指向指针 COM 对象的指针,我是否需要 AddRef()?
- 使用 com 对象删除计划任务
- 如何使用OlesetClipboard将我的COM对象放置在剪贴板上时解决问题
- 在自定义源和 SmartTee 之间插入筛选器会泄漏 COM 对象
- COM 对象中的回调
- 如何在使用C++打开隐藏的 COM 对象时隐藏控制台窗口
- 将结构中的字节数组传递给 com 对象
- COM对象,并返回QVariant强制转换问题