这里有些混乱。
如果您的目标不是自动化友好,请将您的 IDL 更改为:
[size_is=iWidth*iHeight] unsigned short* pxxxData;
并且不要在此使用 SAFEARRAY API。对于编组,您必须编译代理/存根 DLL 并注册它。
如果您的目标是自动化友好,请将您的 IDL 更改为:
SAFEARRAY(short) pxxxData;
并在此使用SAFEARRAY API。对于编组,您必须编译一个类型库(可选地,嵌入它)并注册它。这也启用了早期绑定(例如 VB6、tlbimp)。
这适用于支持用户定义类型的语言/环境。对于那些没有的(例如脚本语言),您必须使用基于 oleautomation/dual/IDispatch 的接口而不是结构(并在服务器中实现)。
编辑:根据您对问题所做的更改。
您应该将pData参数声明为outonly,GetImageData将填充它,不使用它并可能替换它。它也只需要在返回时编组,而不是在调用时。这里有一个建议:
[id(16)] HRESULT GetImageData([out] VARIANT* pData);
您的客户端代码有内存泄漏,它总是会创建一个 xxxData。这里有一个建议:
// If pData is in-out, this is not safe, use CoTaskMemAlloc(sizeof(VARIANT)) instead.
// The callee may override the buffer by assuming it was CoTaskMemAlloc'ed, thus
// assuming it can CoTaskMemFree the original location and set the pointer to a new
// CoTaskMemAlloc'ed location.
// The callee may be a proxy.
// Assuming it's out only, we can provide any location with enough space for a VARIANT.
VARIANT vData;
VariantInit( &vData );
xxxData* data; // remove memory leak
HRESULT hr = mpCOMEvents->GetImageData(&vData);
// error handling removed for clarity (I hope)
data = (xxxData*)(vData.pvRecord);
int length = data->iWidth * data->iHeight;
// ... use data ...
// Don't forget to clear the variant, or there'll be a memory leak
// It implies:
// vData.pRecInfo->RecordDestroy(vData.pvRecord);
// This should recursively release memory allocated in each field
// and finally release the memory allocated for the struct itself.
// vData.pRecInfo->Release();
VariantClear( &vData );
// don't use data past this point
您的服务器代码设置pData->pvRecord为指向堆栈,这意味着它可能会被调用者或其他调用的函数覆盖。这里有一个建议:
xxxData* data; // Changed to pointer
IRecordInfo *pRI;
HRESULT hr;
// data.iHeight = 100; // removed
// data.iWidth = 100; // removed
hr = GetRecordInfoFromGuids(LIBID_xxxLib, 1, 0, 0x409, _uuidof(xxxData), &pRI);
// error handling removed for clarity (I hope)
VariantInit(pData);
// This will allocate memory for the struct itself
// For fields that require memory allocation, follow "normal" COM rules,
// such as using CoTaskMemAlloc for buffers, SysAllocString or similar for BSTRs,
// etc.
// For each inner (pointed to) structure, you should call RecordCreate on the
// respective IRecordInfo instance for that type.
data = (xxxData*)pRI->RecordCreate();
data->iHeight = 100; // new
data->iWidth = 100; // new
// If pData is in-out, this will leak, use VariantClear instead.
// Assuming it's out only, use VariantInit as it points to (allocated) garbage.
VariantInit(pData);
pData->vt = VT_RECORD;
pData->pvRecord = data; // data is already a pointer
pData->pRecInfo = pRI;
pRI = NULL;
// This won't (normally) leak, the caller must call VariantClear on the out VARIANT.
// The caller may be a stub.