使用 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);
为了避免泄漏,请先对现有 CComBSTR
对象调用 Empty
方法,然后再将地址作为 [out] 参数传递。
请注意,如果函数的参数为 [in, out],则同一代码不会造成泄漏。