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
我風 閱讀(7160)
評論(0) 編輯 收藏 引用