Marshalling a VARIANT back from COM to C++ client
I'm attempting to marshal a safearray of BSTRs from a COM object, back to a C++ client application.
My IDL definition of the function involved:
[id(5), helpstring("method GetStreams")]
HRESULT GetStreams( [out,retval] VARIANT* pvarStreamNames );
Here's my implement开发者_运维百科ation of the GetStreams() function:
STDMETHODIMP CArchiveManager::GetStreams(VARIANT* pvarStreamNames)
{
CComSafeArray<BSTR, VT_BSTR> saStreamNames;
CComVariant varOutNames;
Stream* pNext = NULL;
int nNumStreams = m_Streams.NumStreams();
if( nNumStreams == 0 )
return S_OK;
for(int x = 0; x < nNumStreams; x++)
{
pNext = m_Streams.GetAt(x);
if( pNext )
saStreamNames.Add( pNext->StreamName() );
}
if( saStreamNames.GetCount() > 0 )
{
varOutNames.vt = VT_ARRAY;
varOutNames.parray = saStreamNames.m_psa;
varOutNames.Detach(pvarStreamNames);
}
return S_OK;
}
Here's how the C++ client program calls the GetStreams() function:
VARIANT varStreamNames;
hr = spArchiveMgr->GetStreams( &varStreamNames );
I trace through the program using the interactive debugger and everything appears to work correctly (safearray populates correctly, etc) until the GetStreams() function returns. At that point, I get an "unhandled exception reading location" message.
advice on how to debug/solve this?
There're two problems. The first one is
VARIANT varStreamNames;
is unitialized, so when
varOutNames.Detach(pvarStreamNames);
runs it calls VariantClear() on an uninitialized variable and this leads to undefined behavior - your program crashes.
You have to call VariantInit() on varStreamNames before invoking the COM method or just use CComVariant type for varStreamNames.
The second one is:
CComSafeArray<BSTR, VT_BSTR> saStreamNames;
CComVariant varOutNames;
varOutNames.vt = VT_ARRAY;
varOutNames.parray = saStreamNames.m_psa;
perfoms shallow copy of the safe array - now both saStreamNames and varOutNames own the safe array and so when saStreamNames gets destroyed at the end of the scope the safe array is released.
Since you've copied the same safe array address into pvarStreamNames you've now got a variant with a dangling safe array pointer. Trying to access that safe array is undefined behavior. You should use Detach() method of CComSafeArray to release ownership.
加载中,请稍侯......
精彩评论