Should we consider the BSTR type in COM as a value or reference?

I knew from the ATL Internals book that BSTR is different from OLECHAR *, and there are CComBSTR and CString for BSTR.

According to the MSDN Allocation and Release of Memory for BSTR , I knew the responsibility of managing memory for the caller / called party.

Take this line from MSDN,

HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)

I still don't know how to properly handle bstrin my implementation. Since I still have a basic question for BSTR, should I consider it bstras a value (e.g. int) or as a reference (e.g. int *), at least at the border of the COM interface.

I want to convert BSTR to CString / CComBSTR in my implementation as quickly as possible. Value or reference semantics will be a completely different case for conversion. I dug in CComBSTR.Attach, CComBSTR.AssignBSTR etc. But the code cannot solve my doubts.

MSDN CComBSTR.Attach has some piece of code, I feel that it is erroneous as it does not obey Allocation and freeing memory for BSTR . ATL Internals said that SetSysString "will free the original BSTR passed to", if I used it, it would violate the BSTR argument convention, like CComBSTR.Attach.

In general, I want to use CString to handle the raw BSTR in the implementation, but I don’t know the right way ... I wrote some simple working codes in my projects, but I'm always nervous, I know how much I am right.

HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)
{
// What I do NOT know
CString str1;  // 1. copy bstr (with embeded NUL)
CString str2;  // 2. ref bstr

// What I know
CComBSTR cbstr1;
cbstr1.AssignBSTR(bstr); // 3. copy bstr 
CComBSTR cbstr2;
cbstr2.Attach(bstr); // 4. ref bstr, do not copy

// What I do NOT know
// Should we copy or ref bstr ???
}
+5
2

CComBSTR RAII raw BSTR. raw BSTR BSTR, , , (.. BSTR) ..

BSTR - input, const wchar_t* ( , , NUL L'\0') . BSTR NUL, CString, , CString. CString BSTR. std:: wstring ( , std::wstring NUL).

void DoSomething(BSTR bstrInput)
{
    std::wstring myString(bstrInput);
    // ... work with std::wstring (or CString...) inside here
}

, BSTR - output, , .. BSTR*. CComBSTR::Detach() BSTR, CComBSTR, :

HRESULT DoSomething( BSTR* pbstrOut )
{
    // Check parameter pointer
    if (pbstrOut == nullptr)
        return E_POINTER;

    // Guard code with try-catch, since exceptions can't cross COM module boundaries.
    try
    {
        std::wstring someString;
        // ... work with std::wstring (or CString...) inside here

        // Build a BSTR from the ordinary string     
        CComBSTR bstr(someString.c_str());

        // Return to caller ("move semantics", i.e. transfer ownership
        // from current CComBSTR to the caller)
        *pbstrOut = bstr.Detach();

        // All right
        return S_OK;
    }
    catch(const std::exception& e)
    {
        // Log exception message...
        return E_FAIL;
    }
    catch(const CAtlException& e)
    {
        return e; // implicit cast to HRESULT
    }
}

, , BSTR ( RAII, CComBSTR) , std::wstring CString.

" ", BSTR.

+11

BSTR , . CString :

CString sValue(bstr);

, Unicode MBCS:

CStringW sValue(bstr);

, [out], ( ):

VOID Foo(/*[out]*/ BSTR* psValue)
{
  CString sValue;
  *psValue = CComBSTR(sValue).Detach();
}

:

STDMETHODIMP Foo(/*[out]*/ BSTR* psValue)
{
    _ATLTRY
    {
        ATLENSURE_THROW(psValue, E_POINTER); // Parameter validation
        *psValue = NULL; // We're responsible to initialize this no matter what
        CString sValue;
        // Doing our stuff to get the string value into variable
        *psValue = CComBSTR(sValue).Detach();
    }
    _ATLCATCH(Exception)
    {
        return Exception;
    }
    return S_OK;
}
+4

All Articles