CComBSTR を使用したプログラミング
更新 : 2007 年 11 月
ATL クラス CComBSTR は、BSTR データ型を扱うラッパーを提供します。CComBSTR は便利ですが、次の場合は注意が必要です。
変換の問題
スコープの問題
CComBSTR オブジェクトの明示的な解放
ループでの CComBSTR オブジェクトの使用
メモリ リークの問題
変換の問題
CComBSTR のいくつかのメソッドでは、ANSI 文字列の引数が自動的に Unicode に変換されますが、常に Unicode の書式指定文字列が返されます。出力文字列を変換して ANSI に戻すには、ATL 変換クラスを使用します。ATL 変換クラスの詳細については、「ATL と MFC の文字列変換マクロ」を参照してください。
例
// 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
CW2A szMyString(bstrMyString);
// Display the ANSI string
MessageBoxA(NULL, szMyString, "String Test", MB_OK);
CComBSTR オブジェクトの変更でリテラル文字列を使用している場合は、ワイド文字列を使用します。ワイド文字列を使用すると、不要な変換が行われません。
例
// The following converts the ANSI string to Unicode
CComBSTR bstr1("Test");
// The following uses a Unicode string at compile time
CComBSTR bstr2(L"Test");
スコープの問題
ほかの正しく動作するクラスと同様に、CComBSTR はスコープ外に出るときにリソースを解放します。関数が CComBSTR 文字列へのポインタを返す場合は、ポインタが既に解放されたメモリを参照するため、問題が発生する可能性があります。この場合は、次のように Copy メソッドを使用します。
例
// The wrong way to do it
BSTR * MyBadFunction()
{
// Create the CComBSTR object
CComBSTR bstrString(L"Hello World");
// Convert the string to uppercase
HRESULT hr;
hr = bstrString.ToUpper();
// Return a pointer to the BSTR. ** Bad thing to do **
return &bstrString;
}
// The correct way to do it
HRESULT MyGoodFunction(/*[out]*/ BSTR* bstrStringPtr)
{
// Create the CComBSTR object
CComBSTR bstrString(L"Hello World");
// Convert the string to uppercase
HRESULT hr;
hr = bstrString.ToUpper();
if (hr != S_OK)
return hr;
// Return a copy of the string.
return bstrString.CopyTo(bstrStringPtr);
}
CComBSTR オブジェクトの明示的な解放
CComBSTR オブジェクトに格納されている文字列は、オブジェクトがスコープ外に出る前に明示的に解放できます。文字列が解放されると、CComBSTR オブジェクトは無効になります。
例
// Declare a CComBSTR object
CComBSTR bstrMyString(L"Hello World");
// Free the string explicitly
::SysFreeString(bstrMyString);
// The string will be freed a second time
// when the CComBSTR object goes out of scope,
// which is invalid.
ループでの CComBSTR オブジェクトの使用
CComBSTR クラスでは、+= 演算子や Append メソッドなどの特定の操作の実行時にバッファを割り当てるため、ループでは文字列を操作しないことをお勧めします。このような場合は CStringT を使用するとパフォーマンスが向上します。
例
// This is not an efficient way to use a CComBSTR object.
CComBSTR bstrMyString;
HRESULT hr;
while (bstrMyString.Length() < 1000)
hr = bstrMyString.Append(L"*");
メモリ リークの問題
初期化された CComBSTR のアドレスを [out] パラメータとして関数に渡すと、メモリ リークが発生します。
次の例で、"Initialized" を保持するように割り当てられた文字列は、MyGoodFunction 関数がこの文字列を置換したときにリークします。
CComBSTR bstrLeak(L"Initialized");
HRESULT hr = MyGoodFunction(&bstrLeak);
リークを防ぐには、アドレスを [out] パラメータとして渡す前に、既存の CComBSTR オブジェクトで Empty メソッドを呼び出します。
関数のパラメータが [in, out] の場合、同じコードでもリークは発生しません。