C++ 我们应该将COM中的BSTR类型视为值还是参考?
从ATL Internal一书中,我知道BSTR不同于OLECHAR*,BSTR有CComBSTR和CString 根据MSDN,我知道主叫方/被叫方的内存管理职责 从MSDN获取这条线路C++ 我们应该将COM中的BSTR类型视为值还是参考?,c++,com,atl,cstring,bstr,C++,Com,Atl,Cstring,Bstr,从ATL Internal一书中,我知道BSTR不同于OLECHAR*,BSTR有CComBSTR和CString 根据MSDN,我知道主叫方/被叫方的内存管理职责 从MSDN获取这条线路 HRESULT CMyWebBrowser::put_StatusText(BSTR BSTR) 我仍然不知道如何在我的实现中正确处理bstr。因为我仍然有一个关于BSTR的基本问题——我们应该将BSTR视为一个值(比如int)还是一个引用(比如int*),至少在COM接口边界上是这样 在我的实现中,我希望尽
HRESULT CMyWebBrowser::put_StatusText(BSTR BSTR)
我仍然不知道如何在我的实现中正确处理bstr
。因为我仍然有一个关于BSTR的基本问题——我们应该将BSTR
视为一个值(比如int)还是一个引用(比如int*),至少在COM接口边界上是这样
在我的实现中,我希望尽快将BSTR转换为CString/CComBSTR。值或引用语义的转换情况将完全不同。我已经深入研究了CComBSTR.Attach、CComBSTR.AssignBSTR等,但代码无法解决我的疑问
附加有一些代码剪贴,我觉得它是错误的,因为它是不遵守。ATL内部说SetSysString将“释放传入的原始BSTR”,如果我使用它,它将违反BSTR参数约定,就像CComBSTR.Attach一样
总之,我想在实现中使用CString来处理原始的BSTR,但不知道正确的方法……我在项目中编写了一些just-work代码,但我总是感到紧张,因为我不知道自己是否正确
让我谈谈编码语言
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
只是一个粗略的BSTR
。因此,您可以随意使用CComBSTR
而不是原始BSTR
来帮助编写异常安全的代码,这使得泄漏资源(即原始BSTR)变得更加困难,等等
如果BSTR
是一个输入参数,它就像一个const wchar\u t*
(带有长度前缀,并且可能包含一些NUL
sL'\0'
字符)。如果BSTR
中没有嵌入NUL
s,您只需将其传递给CString
构造函数,该构造函数将对其进行深度复制,并且您可以在本地使用CString
。对该CString
的修改在原始BSTR
上不可见。您也可以使用std::wstring(请注意,std::wstring
也可以处理嵌入式NUL
s)
相反,如果BSTR
是一个输出参数,则使用另一个间接级别,即BSTR*
传递它。在这种情况下,您可以在方法中使用CComBSTR::Detach()
,释放安全包装到CComBSTR
中的BSTR
,并将其所有权转移给调用方:
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
(包装在类似CComBSTR
的RAII类中),并使用std::wstring
或CString
执行本地工作
作为一个“反弹读数”,考虑.< /P> < P>在输入上有<代码> BSTR < /代码>,你不负责释放它。转换到
CString
很容易:
CString值(bstr)代码>
或者,如果您希望在MBCS build上保留Unicode字符:
CStringW sValue(bstr)代码>
如果您需要在具有[out]
参数时转换回,您可以这样做(简单版本):
完整版本为:
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;
}
我的大问题是我们应该复制还是参考bstr?小问题是如何使用CString引用bstr?如何使用嵌入的NULL复制bstr?使用copy或ref是什么意思?如果是按值传递的输入参数,则“按指针”传递。如果嵌入了NUL
s,则可以将其复制到std::wstring
中,而不是CString
中。也许您从错误的角度观察问题。。。设想一个BSTR
像const wchar\u t*
一样,分配了一个特殊的COM分配器,并带有长度前缀(因此它可以嵌入NUL
s)。
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;
}