Должны ли мы рассматривать тип BSTR в COM как значение или ссылку?

Из книги ATL Internals, Я знал, что BSTR отличается от OLECHAR *, и для BSTR есть CComBSTR и CString.

По данным MSDN Выделение и освобождение памяти для BSTR, Я знал ответственность за управление памятью для абонента / вызываемого абонента.

Возьми эту строку из MSDN,

HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)

Я до сих пор не знаю, как справиться bstr правильно в моей реализации. Так как у меня все еще есть основной вопрос для BSTR — мы должны рассматривать bstr как значение (например, int) или как ссылка (например, int *), по крайней мере, на границе интерфейса COM.

Я хочу преобразовать BSTR как можно скорее в CString / CComBSTR в моей реализации. Значение или ссылка семантика будет совершенно другой случай для преобразования. Я копался в CComBSTR.Attach, CComBSTR.AssignBSTR и т. Д. Но код не может решить мои сомнения.

MSDN CComBSTR.Attach имеет некоторый фрагмент кода, я чувствую, что это неправильно, так как он не подчиняется Выделение и освобождение памяти для BSTR. ATL Internals сказал, что SetSysString «освободит исходный переданный BSTR», если я его использую, он нарушит соглашение об аргументах BSTR, как CComBSTR.Attach.

В общем, я хочу использовать CString для обработки необработанных BSTR при реализации, но не знаю, как это правильно … Я написал в своих проектах просто рабочий код, но я всегда нервничаю, так как не знаю, Я прав

Позвольте мне говорить на языке программирования

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

Решение

CComBSTR это просто Обертка RAII вокруг сырье BSTR, Так что не стесняйтесь использовать CComBSTR вместо сырья BSTR чтобы помочь в написании кода, исключающего исключительные ситуации, который затруднит утечку ресурсов (т. е. необработанный BSTR) и т. д.

Если BSTR является вход параметр, это так же, как const wchar_t* (с префиксом длины, и, возможно, некоторые NULs 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 является выход параметр, затем он передается с использованием другого уровня косвенности, т.е. 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.

12

Другие решения

имеющий 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

По вопросам рекламы [email protected]