CComBSTR
是
ATL
提供的
BSTR
包装类,是
VC 6
中提供的最完善的
BSTR wrapper
。就像
MFC CString
提供了对
TCHAR
的封装,
CComBSTR
提供了对
BSTR
的封装。
Table 1 CComBSTR Methods
列出了
CComBSTR
的主要方法。
CComBSTR Method
|
Description
|
CComBSTR
|
多个版本的构造函数用来创建新的
BSTR
。可以使用的参数包括
LPCOLESTR, LPCSTR, CComBSTR
。
|
~CComBSTR, Empty
|
释放内部封装的
BSTR.
|
Attach, Detach, Copy
|
Attach
把一个已经存在
BSTR
加入类中。
Detach
把劣种的
BSTR
剥离,以便在超出作用域的时候,析构函数不会释放
BSTR
。
Detach
用于把
CComBSTR
赋给
[out]
参数。
Copy
用于产生一个
BSTR
的副本。一般用于用于把
CComBSTR
内容赋给
[out]
参数。
|
operator BSTR, operator&
|
允许直接操作内部的
BSTR
。
operator BSTR
用于把
CComBSTR
传给
BSTR
输入
[in]
参数。
operator&
用于把
CComBSTR
传给
BSTR*
类型输出
[out]
参数。
|
operator=, operator+=, operator<, operator==, operator>
|
重载运算符,用于赋值、字符串连接、简单比较。
|
Append, AppendBSTR
|
字符串连接
|
Length
|
计算字符串长度
|
LoadString
|
利用字符串资源初始化
BSTR
。
|
ToLower, ToUpper
|
字符串大小写转换。
|
WriteToStream,ReadFromStream
|
从
IStream
中读
/
写
BSTR
。
|
下面的伪代码展示了
CComBSTR
的典型用法:
HRESULT CMyObject::MyMethod(IOtherObject* pSomething)
{
CComBSTR bstrText(L"Hello");
bstrText += " again"; // LPCSTR conversion
bstrText.ToUpper();
pSomething->Display(bstrText); // [in] parameter
MessageBoxW(0, bstrText, L"Test", MB_OK); // Assumes Windows NT
}
对于熟悉
MFC
的程序员,
CComBSTR
让人失望。很多
CString
提供的方便的特性
CComBSTR
都没有提供。重要的缺省列在了
Table 2 Notable CComBSTR Omissions
中。
简而言之,
CComBSTR
没有提供完整的字符串操作。它的主要用途是把
LPCTSTR
转换成
BSTR
,同时提供一个操作
BSTR
的类,使程序员可以不使用
COM SysXXXXString APIs
。如果需要使用复杂的字符串操作,可以使用
STL
提供的
wstring
类。
Table
2
Notable CComBSTR Omissions
Features Not Included in CComBSTR
|
Explanation
|
LPCSTR extraction
|
CComBSTR
可以把一个单字节字符串转换成
BSTR
,但是没有提供反向转换的功能。
_bstr_t
提供了
LPCTSTR operator
。
|
String manipulation (including Replace, Insert, Delete, Remove, Find, Mid, Left, Right, and so on)
|
CComBSTR
没有提供这些方法。如果需要,可以使用
STL
中的
wstring
。
|
Language-sensitive collation
|
CComBSTR
提供的字符串比较
(<, >, ==)
按照是
byte-by-byte
方式进行的。没有提供语言相关的比较
(language-specific collation)
。如果需要可以使用
wstring.
|
使用
CComBSTR
时需要考虑的问题。
·
CComBSTR
初始化
CComBSTR
提供了一个长度初始化函数,
CComBSTR(int nSize)
。所以简单给
CComBSTR
初始化成
NULL
会发生意想不到的调用。
// CComBSTR(int nSize) is called
。
CComBSTR bstr1 = NULL;
CComBSTR bstr2(NULL);
// CComBSTR(LPCOLESTR pSrc) is called.
CComBSTR bstr3 = static_cast<
LPCOLESTR>(NULL);
CComBSTR bstr4(static_cast<
LPCOLESTR>(NULL));
上面的例子中,
bstr1/bstr2
被初始化成长度为
0
的
BSTR
,也就是说
CComBSTR::m_str
是有内容的。
bstr3/bstr4
的值被初始化成
NULL
,也就是说
CComBSTR::m_str == 0
。这样,
bstr1/bstr2
在被赋新的值前需要考虑是否需要释放其中的
BSTR
。
·
字符集转换
尽管某些
CComBSTR
方法可以自动把
ANSI
字符串转换成
Unicode
。所有的接口返回的都是
Unicode
字符串。如果需要转回
ANSI
,可以使用
ATL
或
MFC
转换类,或者
Windows API
。如果使用文字串修改
CComBSTR
,使用宽字节字符串。可以减少不必要的转换。例如:
// Declare a CComBSTR object. Although the argument is ANSI,
// the constructor converts it into UNICODE.
CComBSTR bstrMyString( "Hello World" );
// Convert the string into an ANSI string
CW2CT szMyString( bstrMyString );
// Display the ANSI string
MessageBox( NULL, szMyString, _T("String Test"), MB_OK );
// The following converts the ANSI string to Unicode
CComBSTR bstr("Test");
// The following uses a Unicode string at compile time
CComBSTR bstr(L"Test");
·
变量作用域
(Scope)
象所有设计完整的类一样,
CComBSTR
会在离开作用域的时候释放资源。如果一个函数返回一个指向
CComBSTR
的指针,可能会带来问题:指针有可能指向已经被释放的内存。此时应该使用
Copy
或
Detach
方法。参考下面的例子。
HRESULT CMyObject::MyMethod3(/*[out, retval]*/ BSTR* pbstr)
{
CComBSTR bstrText(L"Hello");
bstrText += " again";
*pbstr = bstrText; // No! Call Detach instead!
}
通过复制语句
*pbstr = bstrText
,被
bstrText
封装的
BSTR
的指针作为传出
[out]
参数传递。在
MyMethod3 return
时,
bstrText
离开作用域,
CComBSTR destructor
毁掉用
SysFreeString
释放这个
BSTR
。因此,调用者得到了一个指向已经被释放的内存的指针,可能导致意想不到的结果。因为
bstrText
即将超出作用域,所以必须使用
CComBSTR Copy
或
Detach
给
*pbstr
赋值。
CComBSTR Copy
生成字符串的一格副本,
Detach
简单的把
BSTR
移出包装类。这样,在
bstrText
离开作用域的时候就不会被释放。
HRESULT CMyObject::MyMethod4(/*[out, retval]*/ BSTR* pbstr)
{
CComBSTR bstrText(L"Hello");
bstrText += L" again";
//*pbstr = bstrText.Copy(); // Better!
*pbstr = bstrText.Detach(); // Much better!
}
在这个例子中,从效率考虑,最好使用
Detach
而不是
Copy
。
Detach
不需要产生一个额外副本的开销。当
CComBSTR
必须在复制之后保持自己的内容的时候,例如
CComBSTR
是一个成员变量,必须使用
Copy
。
·
显式释放
CComBSTR
内容
程序员可以在
CComBSTR
超出作用域范围前显示释放
CComBSTR
中的字符串。一旦释放了,
CComBSTR
内容就无效了。
CComBSTR
提供了
operator BSTR
,所以代码中可以显示的释放其中的
BSTR
。
HRESULT CMyObject::MyMethod1()
{
CComBSTR bstrText(L"This is a test");
::SysFreeString(bstrText);
// The string will be freed a second time
// when the CComBSTR object goes out of scope,
// which is invalid.
// CComBSTR::Empty() should be used in order to
// explicitly free the BSTR
}
在这段代码中,bstrText 中的BSTR被释放了。但是,bstrText 仍然没有超出作用域,看起来仍然可以使用。当bstrText 最终超出作用域的时候,SysFreeString 被第二次调用。为了防止这种意外,需要把operator BSTR 从类中删除。但这样没有办法把它用于需要BSTR类型输入[in]参数的地方,会使CComBSTR 几乎没有任何用处。
·
外部
CComBSTR
用作
[out]
参数
把一个已经初始化好的
CComBSTR
的地址传给一个函数作为
[out]
参数会导致内存泄漏。当把
CComBSTR
用于
BSTR*
类型的传出参数
[out]
时,必须首先调用
Empty
方法清空字符串的内容。
HRESULT CMyObject::MyMethod2(ISomething* p)
{
CComBSTR bstrText;
bstrText = L"Some assignment"; // BSTR is allocated.
bstrText.Empty(); // Must call empty before
pSomething->GetText(&bstrText); // using as an [out] parameter.
if(bstrText != L"Schaller")
bstrText += "Hello"; // Convert from LPCSTR.
}
在把
CComBSTR
作为
[out]
参数传递前,调用
Empty
释必须的。因为按照
COM
标准中的
[out]
参数的使用规则
-
被调用方法不应该在覆盖
BSTR
的内容前调用
SysFreeString
。如果你忘记调用
Empty
,调用前
BSTR
的内容占用的资源就会泄漏。
对于相同的代码,如果参数类型是
[in, out]
,就不会有泄漏。因为函数会在复制之前,
Free
原有的串。
·
用
CComBSTR
给
BSTR
变量赋值
在下面的代码中,
CStringTest
使用
CComBSTR
作为成员变量保存
BSTR
属性。
class CStringTest
{
CComBSTR m_bstrText;
// IStringTest
public:
STDMETHOD(put_Text)(/*[in]*/ BSTR newVal)
{
m_bstrText = newVal;
return S_OK;
}
STDMETHOD(get_Text)(/*[out, retval]*/ BSTR *pVal)
{
*pVal = m_bstrText; // Oops! Call m_bstrText.Copy
// instead.
return S_OK;
}
};
由于
m_bstrText
在
get_Text
结束没有超出作用域,你可能认为在
the *pVal = m_bstrText
赋值时,不需要调用
Copy
。这是不对的。按照
COM
规则,调用者负责释放传出
[out]
参数的内容。由于
*pVal
指向了
m_bstrText
封装的
BSTR
,而不是一个副本,调用者和
m_bstrText
析构函数都会企图删除字符串。
·
循环中使用
CComBSTR Objects
尽管
CComBSTR
可以分配
buffer
完成一些操作,例如:
+= operator
或
Append
。但是,不推荐在一个小循环内部使用
CComBSTR
完成字符串操作。这种情况下,
CString
能提供更好的性能。
// This is not an efficient way
// to use a CComBSTR object.
CComBSTR bstrMyString;
while (bstrMyString.Length()<1000)
{
bstrMyString.Append(L"*");
}
_bstr_t
是微软
C++ COM
扩展的一部分。
_bstr_t
封装了
BSTR
数据类型。
_bstr_t
通过
SysAllocString and SysFreeString
等
BSTR APIs
管理资源的分配和释放。
_bstr_t
提供了内部引用计数来减少额外负担。
Construction
|
Version
|
|
_bstr_t
|
|
Constructs a _bstr_t object.
|
Operations
|
|
|
Assign
|
|
Copies a BSTR into the BSTR wrapped by a _bstr_t.
|
Attach
|
VC 7
|
Links a _bstr_t wrapper to a BSTR.
|
copy
|
|
Constructs a copy of the encapsulated BSTR.
|
Detach
|
VC 7
|
Returns the BSTR wrapped by a _bstr_t and detaches the BSTR from the _bstr_t.
|
GetAddress
|
VC 7
|
Points to the BSTR wrapped by a _bstr_t.
|
GetBSTR
|
VC 7
|
Points to the beginning of the BSTR wrapped by the _bstr_t.
|
length
|
|
Returns the number of characters in the _bstr_t.
|
Operators
|
|
|
operator =
|
|
Assigns a new value to an existing _bstr_t object.
|
operator +=
|
|
Appends characters to the end of the _bstr_t object.
|
operator +
|
|
Concatenates two strings.
|
operator !
|
|
Checks if the encapsulated BSTR is a NULL string.
|
operator ==, !=, <, >, <=, >=
|
|
Compares two _bstr_t objects.
|
operator wchar_t* | char*
|
|
Extract the pointers to the encapsulated Unicode or multibyte BSTR object.
|
|
|
|
VC6
中
_bstr_t
缺少了几个重要的方法:
Attach/Detach/GetAddress/GetBSTR
,所以比
CComBSTR
简单,使得
_bstr_t
的应用场合非常有限。而且,
_bstr_t
使用了引用计数在不同的对象间共享
BSTR
,内部实现比
CComBSTR
复杂。使用注意事项可以参考
CComBSTR
的类似函数。
建议只用于下面的情况:
·
BSTR
的作用域管理
解决
BSTR
变量超出作用域范围的自动回收。
(1)
构造简单的
BSTR
对象,对
BSTR
进行基本字符串操作,作为输入
[in]
参数传递给被调用者。
{
_bstr_t bs1(L"first ");
bs1 += L"second ";
SetBs(bs1); // void SetBs(BSTR bs)
}
(2)
作为
BSTR
的
wrapper
,解决
[out]
参数
BSTR
的生命周期之后的回收问题。
HRESULT BetterMethod()
{
BSTR val = NULL;
GetBs(&val); //void GetBs(/* [out] */ BSTR*)
_bstr_t bsVal(val, false);
// false is IMPORTANT. Other constructor could
// store the BSTR, too. But you must free the
// BSTR later.
}
HRESULT GoodMethod()
{
BSTR val = NULL;
GetBs(&val); //void GetBs(/* [out] */ BSTR*)
// All the function create a copy of BSTR.
// But you must free the BSTR immediately.
_bstr_t bsVal2(val);
_bstr_t bsVal3;
bsVal3 = val;
SysFreeString(val);
}
·
使用范围
完成简单的BSTR字符串连接、比较等操作。
from:http://blog.csdn.net/pkrobbie/archive/2007/01.aspx
posted on 2007-01-26 16:10
我风 阅读(7129)
评论(0) 编辑 收藏 引用