这样做的正确方法是什么:
_bstr_t description;
errorInfo->GetDescription( &description.GetBSTR() );
或:
_bstr_t description;
errorInfo->GetDescription( description.GetAddress() );
IError:GetDescription
定义为:
HRESULT GetDescription (BSTR *pbstrDescription);
我知道我可以很容易地做到这一点:
BSTR description= SysAllocString (L"Whateva"));
errorInfo->GetDescription (&description);
SysFreeString (description);
由于
答案 0 :(得分:8)
BSTR是引用计数,我严重怀疑如果你使用GetAddress()将会正常工作。可悲的是,源代码无法进行仔细检查。我总是这样做:
BSTR temp = 0;
HRESULT hr = p->GetDescription(&temp);
if (SUCCEEDED(hr)) {
_bstr_t wrap(temp, FALSE);
// etc..
}
答案 1 :(得分:5)
要跟进@Hans的答案 - 构建_bstr_t
的适当方法取决于GetDescription
是否会返回您拥有的BSTR
,或者是否会引用您所记忆的记忆的SysFreeString
必须释放。
此处的目标是最小化副本数量,但也避免对返回的数据进行BSTR temp = 0;
HRESULT hr = p->GetDescription(&temp);
if (SUCCEEDED(hr)) {
_bstr_t wrap(temp, false); // do not copy returned BSTR, which
// will be freed when wrap goes out of scope.
// Use true if you want a copy.
// etc..
}
的任何手动调用。我会修改代码,如图所示澄清:
{{1}}
答案 2 :(得分:2)
可能不适用于Visual Studio早期版本(或更高版本)的迟到答案;然而,
VS 12.0内联obj.B::show()
实现,显然,在处女pip install <packahename.whl>
上调用_bstr_t
时,内部Data_t
实例的m_RefCount
为{1}}。因此,第一个示例中的GetBSTR()
生命周期看起来没问题:
_bstr_t
但是如果_bstr_t
是脏的,现有的内部_bstr_t description;
errorInfo->GetDescription( &description.GetBSTR() );
指针将被覆盖,泄漏它引用的先前内存。
通过使用以下_bstr_t
,可以使用脏m_wstr
,因为它首先通过operator&
清除。重载还提供了使用地址运算符而不是_bstr_t
;
Assign(nullptr)
因此,您的第一个示例可能如下所示:
GetBSTR()
此评估基于VS 12.0的BSTR *operator&(_bstr_t &b) {
b.Assign(nullptr);
return &b.GetBSTR();
}
。
答案 3 :(得分:0)
我的回答也来晚了。假设您具有签名HRESULT PutDescription (BSTR NewDescription);
。在这种情况下,请执行以下操作
_bstr_t NewAdvice = L"Great advice!";
HRESULT hr1 = PutDescription(NewAdvice.GetBSTR());
根据COM的规则,不允许PutDescription
函数更改甚至销毁传递的BSTR
。
对于相反的HRESULT GetDescription (BSTR *pActualDescription);
,通过函数_bstr_t
传递纯正的GetAddress()
:
_bstr_t GetAdvice;
HRESULT hr2 = GetDescription(GetAdvice.GetAddress());
函数GetAddress()
释放所有现有字符串,并返回新分配的字符串的地址。因此,如果您传递包含某些内容的_bstr_t
,则该内容将被释放并因此丢失。共享同一_bstr_t
的所有BSTR
都发生相同的情况。但是我认为这是一件愚蠢的事情。为什么将带有内容的参数传递给应该更改该内容的函数?
_bstr_t GetAdvice = L"This content will not survive the next function call!";
HRESULT hr = GetDescription(GetAdvice.GetAddress());
一个真正的白痴甚至可能会通过一个分配给原始_bstr_t
的{{1}}:
BSTR
在这种情况下,BSTR Bst = ::SysAllocString(L"Who would do that?");
_bstr_t GetDescr;
GetDescr.Attach(Bst);//GetDescr wraps Bst, no copying!
HRESULT hr = GetDescription(GetDescr.GetAddress());
获得了期望值,但是GetDescr
的内容是不可预测的。
答案 4 :(得分:0)
_bstr_t(及其 ATL 兄弟 CComBSTR)是 BSTR 的资源所有者。从代码中可以看出,“GetAddress”似乎是专门为使用 BSTR 输出参数的用例而设计的,其中预期客户端释放 BSTR。
在 _bstr_t 已经拥有 BSTR 的情况下,使用 'GetAddress()' 不等同于使用 '&GetBSTR()'。 MSDN 声明:“释放任何现有字符串并返回新分配字符串的地址。”。
_bstr_t bstrTemp;
HRESULT hr = p->GetDescription(bstrTemp.GetAddress());
警告:文档中没有说明“GetAddress”的这个特定用例;这是我从查看源代码和使用其 ATL 计数器部分 CComBSTR 的经验得出的结论。