Marshalling a VARIANT back from COM to C++ client

谁说胖子不能爱 提交于 2019-12-24 18:59:18

问题


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 implementation 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?


回答1:


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.



来源:https://stackoverflow.com/questions/4204488/marshalling-a-variant-back-from-com-to-c-client

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!