将VARIANT从COM调回C ++客户端 [英] Marshalling a VARIANT back from COM to C++ client
问题描述
我正在尝试从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屋!