将VARIANT从COM调回C ++客户端 [英] Marshalling a VARIANT back from COM to C++ client

查看:225
本文介绍了将VARIANT从COM调回C ++客户端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我正在尝试从COM对象中封装一个BSTR的安全版本,返回到C ++客户端应用程序。 p>

  [id(5),helpstring(method GetStreams)] 
HRESULT GetStreams([out,retval] VARIANT * pvarStreamNames);

这是我的GetStreams()函数的实现:

  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 {
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;
}

以下是C ++客户端程序调用GetStreams()函数的方法:

  VARIANT varStreamNames; 
hr = spArchiveMgr-> GetStreams(& varStreamNames);

我使用交互式调试器跟踪程序,一切似乎都正常工作),直到GetStreams()函数返回。在这一点上,我得到一个未处理的异常读取位置消息。



建议如何调试/解决这个问题?

解决方案

有两个问题。第一个是

  VARIANT varStreamNames; 

已被单位化,因此

  varOutNames.Detach(pvarStreamNames); 

运行它调用 VariantClear()



你必须调用 VariantInit() on varStreamNames 在调用COM方法之前,或者使用 CComVariant 键入 varStreamNames



第二个是:

  CComSafeArray< BSTR, VT_BSTR> saStreamNames; 
CComVariant varOutNames;

varOutNames.vt = VT_ARRAY;
varOutNames.parray = saStreamNames.m_psa;

perfoms安全数组的浅拷贝 - 现在 saStreamNames varOutNames 拥有安全数组,所以当 saStreamNames



由于您已将相同的安全阵列地址复制到 pvarStreamNames 与一个悬挂的安全数组指针。尝试访问该安全数组是未定义的行为。您应该使用 CComSafeArray Detach()方法释放所有权。


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?

解决方案

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.

这篇关于将VARIANT从COM调回C ++客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆