Ray*_*ond 5 c++ com atl bstr cstring
从书籍ATL Internals,我知道BSTR与OLECHAR*不同,并且BSTR有CComBSTR和CString.
根据MSTR为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 ???
}
Run Code Online (Sandbox Code Playgroud)
Mr.*_*C64 12
CComBSTR仅仅是一个RAII包装围绕原料 BSTR.所以随意使用CComBSTR而不是raw BSTR来帮助编写异常安全的代码,这会使资源泄漏更加困难(即原始BSTR)等.
如果BSTR是一个输入参数,它就像一个const wchar_t*(长度前缀,可能还有一些NULs L'\0'字符).如果内部BSTR没有NUL嵌入s,你可以简单地将它传递给CString构造函数,这将构建它的深层副本,并且你可以在本地使用你的CString.对CString原件的修改将不会在原件上显示BSTR.您也可以使用std :: wstring(并注意也std::wstring可以处理嵌入式NULs).
void DoSomething(BSTR bstrInput)
{
std::wstring myString(bstrInput);
// ... work with std::wstring (or CString...) inside here
}
Run Code Online (Sandbox Code Playgroud)
相反,如果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
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,这个想法是仅在边界使用BSTR(包含在类似RAII类中CComBSTR),并使用或执行本地工作.std::wstringCString
作为"读书",请考虑Eric Lippert的BSTR语义指南.