Из книги 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 ???
}
CComBSTR
это просто Обертка RAII вокруг сырье BSTR
, Так что не стесняйтесь использовать CComBSTR
вместо сырья BSTR
чтобы помочь в написании кода, исключающего исключительные ситуации, который затруднит утечку ресурсов (т. е. необработанный BSTR) и т. д.
Если BSTR
является вход параметр, это так же, как const wchar_t*
(с префиксом длины, и, возможно, некоторые NUL
s 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.
имеющий 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;
}