10

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

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

谢谢

4

6 回答 6

8

BSTR 是引用计数的,我严重怀疑如果您使用 GetAddress() 是否可以正常工作。可悲的是,源代码不可用于仔细检查。我一直这样做:

BSTR temp = 0;
HRESULT hr = p->GetDescription(&temp);
if (SUCCEEDED(hr)) {
    _bstr_t wrap(temp, FALSE);
    // etc..
}
于 2010-12-03T15:39:45.407 回答
4

要跟进@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..
}
于 2010-12-03T16:41:42.723 回答
4

可能不适用于较早(或更高)版本的 Visual Studio 的较晚答案;但是,VS 12.0 具有_bstr_t内联实现,显然在调用处女时Data_t会使用 1 创建一个内部实例。因此,您的第一个示例中的生命周期看起来没问题:m_RefCountGetBSTR()_bstr_t_bstr_t

_bstr_t description;
errorInfo->GetDescription( &description.GetBSTR() );

但如果_bstr_t是脏的,现有的内部m_wstr指针将被覆盖,泄漏它引用的先前内存。

通过使用以下,可以使用operator&脏,因为它首先通过 清除。重载还提供了使用地址运算符而不是;的便利。_bstr_tAssign(nullptr)GetBSTR()

BSTR *operator&(_bstr_t &b) {
    b.Assign(nullptr);
    return &b.GetBSTR();
}

因此,您的第一个示例可能如下所示:

_bstr_t description(L"naughty");
errorInfo->GetDescription(&description);

此评估基于comutil.hVS 12.0。

于 2016-07-19T04:38:27.767 回答
1

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

由于用户 'caoanan' 对这个解决方案提出了质疑,我将源代码贴在这里 Microsoft:

inline BSTR* _bstr_t::GetAddress()
{
    Attach(0);
    return &m_Data->GetWString();
}

inline wchar_t*& _bstr_t::Data_t::GetWString() throw()
{
    return m_wstr;
}

inline void _bstr_t::Attach(BSTR s)
{
    _Free();

    m_Data = new Data_t(s, FALSE);
    if (m_Data == NULL) {
        _com_issue_error(E_OUTOFMEMORY);
    }
}

inline _bstr_t::Data_t::Data_t(BSTR bstr, bool fCopy)
    : m_str(NULL), m_RefCount(1)
{
    if (fCopy && bstr != NULL) {
        m_wstr = ::SysAllocStringByteLen(reinterpret_cast<char*>(bstr),
                                         ::SysStringByteLen(bstr));

        if (m_wstr == NULL) {
            _com_issue_error(E_OUTOFMEMORY);
        }
    }
    else {
        m_wstr = bstr;
    }
}
于 2021-03-08T12:08:03.437 回答
-1
    int GetDataStr(_bstr_t & str) override {
    BSTR data = str.Detach();
    int res = m_connection->GetDataStr( &data );
    str.Attach(data);
    return res;
}
于 2021-11-30T08:47:54.557 回答
-1

我的回答也晚了。假设你有签名HRESULT PutDescription (BSTR NewDescription);。在这种情况下,请执行以下操作

_bstr_t NewAdvice = L"Great advice!";
HRESULT hr1 = PutDescription(NewAdvice.GetBSTR());

根据 COM 的规则,该函数PutDescription不允许更改甚至破坏传递的BSTR.

相反,通过函数HRESULT GetDescription (BSTR *pActualDescription);传递处女:_bstr_tGetAddress()

_bstr_t GetAdvice;
HRESULT hr2 = GetDescription(GetAdvice.GetAddress());

该函数GetAddress()释放任何现有字符串并返回新分配的字符串的地址。所以,如果你传递一个_bstr_t有一些内容的,这个内容将被释放并因此丢失。所有_bstr_t共享相同的 s 都会发生同样的情况BSTR。但我认为这是一件愚蠢的事情。为什么将带有内容的参数传递给应该更改该内容的函数?

_bstr_t GetAdvice = L"This content will not survive the next function call!";
HRESULT hr = GetDescription(GetAdvice.GetAddress());

一个真正的白痴甚至可能会传递一个_bstr_t分配给 raw 的 a 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得到预期值,但内容Bst是不可预测的。

于 2020-03-12T09:55:54.737 回答