CComBSTR を使用したプログラミング
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] の場合、同じコードでもリークは発生しません。