我正在尝试将来自 COM 对象的 BSTR 安全数组编码回 C++ 客户端应用程序。
涉及函数的IDL定义:
[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 < 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;
}
C++ 客户端程序调用 GetStreams() 函数的方式如下:
VARIANT varStreamNames;
hr = spArchiveMgr->GetStreams( &varStreamNames );
我使用交互式调试器跟踪整个程序,一切似乎都正常工作(safearray 正确填充等),直到 GetStreams() 函数返回。那时,我收到一条“未处理的异常读取位置”消息。
有关如何调试/解决此问题的建议?
最佳答案
有两个问题。第一个是
VARIANT varStreamNames;
是单元化的,所以当
varOutNames.Detach(pvarStreamNames);
运行它调用VariantClear()
在未初始化的变量上,这会导致未定义的行为 - 您的程序崩溃。
您必须调用 VariantInit()
在 varStreamNames
在调用 COM 方法之前或只使用 CComVariant
输入 varStreamNames
.
第二个是:
CComSafeArray<BSTR, VT_BSTR> saStreamNames;
CComVariant varOutNames;
varOutNames.vt = VT_ARRAY;
varOutNames.parray = saStreamNames.m_psa;
执行安全数组的浅拷贝 - 现在都是 saStreamNames
和 varOutNames
拥有安全阵列等saStreamNames
在释放安全数组的范围末尾被销毁。
由于您已将相同的安全数组地址复制到 pvarStreamNames
中你现在有一个带有悬空安全数组指针的变体。尝试访问该安全数组是未定义的行为。你应该使用 Detach()
CComSafeArray
的方法|释放所有权。
关于c++ - 将 VARIANT 从 COM 编码回 C++ 客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4204488/