使用_bstr_t在函数中传递BSTR *类型的参数

时间:2010-12-03 15:06:59

标签: c++ bstr

这样做的正确方法是什么:

_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);

由于

5 个答案:

答案 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 的经验得出的结论。