CComBSTR を使用したプログラミング (ATL)
ATL クラス CComBSTR は、BSTR データ型を囲むラッパーを提供します。 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] パラメーターとして渡すと、メモリ リークが発生します。
次の例では、MyGoodFunction
関数が文字列 "Initialized"
を置き換えたときに、文字列を保持するために割り当て済みの文字列がリークされます。
CComBSTR bstrLeak(L"Initialized");
HRESULT hr = MyGoodFunction(&bstrLeak);
リークを回避するには、アドレスを [out] パラメーターとして渡す前に、既存の CComBSTR
オブジェクトで Empty
メソッドを呼び出します。
関数のパラメーターが [in, out] の場合は、同じコードでもリークが発生しない点にご注意ください。