1 How to use BSTR
1.1 BSTR分析
BSTR
设计对于
C++
程序员好坏参半。一方面,
BSTR
可以被用于大多数需要
OLECHAR
数组作为参数的函数。另一方面,不能用熟悉的
C/C++
函数进行对
BSTR
的分配、释放和处理,例如
malloc, free, new, delete, lstrcat, and lstrlen
等函数不能用于处理
BSTR
。就像对接口指针和类指针的处理不一样,对
BSTR
的处理和对
TCHAR*
的处理也不一样。
BSTR
是一种
C
语言方式的类型定义方式,这种定义方式提高了
BSTR
在
C++
的应用效率,但是也带来了很多的潜在风险,它使程序员失去了利用编译器检查潜在问题的机会。
1.2 BSTR使用基本规则
- 在对BSTR进行读取操作的时候,可以把BSTR看作OLECHAR数组。BSTR可以用于const wchar_t*(LPCTSTR/ LPCWSTR/ cosnt TCHAR*/ cosnt WCHAR* in Unicode project),不能用于需要wchar_t* (LPTSTR/ LPWSTR/ TCHAR*/ WCHAR* in Unicode project)的地方。
- 如果有相应的BSTR处理函数,必须使用BSTR处理函数,不要使用普通字符串函数。特别是一个BSTR包含多个字符串(也就是,包含多个0结束符)的情况。在对BSTR进行修改(包括创建和释放时),必须使用BSTR的专用函数。主要要保证对字符长度前缀的正确修改。不要直接读取BSTR的长度域,应该使用BSTR处理函数计算长度。
String Manipulation Functions
|
Descriptions
|
SysAllocString
|
Creates and initializes a string.
|
SysAllocStringByteLen
|
Creates a zero-terminated string of a specified length.
|
SysAllocStringLen
|
Creates a string of a specified length.
|
SysFreeString
|
Frees a previously created string.
|
SysReAllocString
|
Changes the size and value of a string.
|
SysReAllocStringLen
|
Changes the size of an existing string.
|
SysStringByteLen
|
Returns the length of a string in bytes.
|
SysStringLen
|
Returns the length of a string.
|
- NULL是BSTR的有效值。按照约定,它可以被看作含有0个字符的字符串。BSTR变量必须等于NULL,或者正确分配的BSTR指针。在改变BSTR变量的之前,必须释放原来指向的BSTR。不要把BSTR直接初始化成常量字符指针,例如,BSTR bs = L””。
- Automation会cache BSTR使用的空间,以提高SysAllocString/SysFreeString 的性能,会给测试发现问题带来困难。如果可能推荐在调试时使用Compuware DevPartner 7.x及更高版本的工具。
1.3 BSTR参数使用
多数时候,
BSTR
是被用于函数参数。关于
BSTR
参数的使用规则是
BSTR
类型的基础。只有熟练掌握,才能分析
warpper
类或转换函数的正确性。
基本原则:在给
by-reference[in/out]
参数赋一个新的值前,被调用者负责释放。其他情况,都是调用者负责释放。
调用者使用
BSTR
的规则如下:
·
释放被调用函数返回的
BSTR
,或者被调用函数通过
by-reference
返回的
BSTR
。
HRESULT IWebBrowser2::get_StatusText( BSTR FAR* pbstr );
//...
BSTR bstrStatus;
pBrowser->get_StatusText( &bstrStatus );
// shows using the Win32 function
// to freee the memory for the string:
::SysFreeString( bstrStatus );
·
释放通过
by-value
方式传给其他函数的
BSTR.
//.h
HRESULT IWebBrowser2::put_StatusText( BSTR bstr );
//.cpp
// shows using the Win32 function
// to allocate memory for the string:
BSTR bstrStatus = ::SysAllocString( L"Some text" );
if (bstrStatus == NULL)
return E_OUTOFMEMORY;
pBrowser->put_StatusText( bstrStatus );
// Free the string:
::SysFreeString( bstrStatus );
//...
被调用者按照如下规则处理
BSTR
:
·
如果一个
BSTR
参数是
by-reference
方式,在给参数赋新值之前,
Free
以前的值。如果没有给参数赋的新值,不要
Free
传入值。
void RefreshBSTR(BSTR& bs)
// bs is an [in/out] parameter. BSTR* is the same
{
// using the bs here
Dosomething(bs);
// if (bs is about to be updated)
ASSERT(bs != NULL);
::SysReallocString(bs, _T(“NEW STRING”));
// SysReallocString will call SysFreeString and
// SysAllocString in sequence
// If bs is only [out] parameter, SysAllocString
// should be called here.
}
·
不要
Free
通过
by-value
传入的
BSTR
。
void SetBSTR(BSTR bs)
// bs is an [in] parameter. BSTR* is the same
{
// using the bs here
Dosomething(bs);
::SysFreeString(bs); //ERROR
}
·
不要
Free
返回给调用者的
BSTR .
BSTR GetBSTR1()
{
BSTR bs = ::SysAllocString(_T(“test”));
::SysFreeString(bs); //ERROR
return bs;
}
void GetBSTR2(BSTR* pBs)
{
CComBSTR bs(_T(“test”));
*pBS = (BSTR) bs; //ERROR: pBS will be freed automatically
}
·
如果需要保存传入的
BSTR
,被调用着需要用
SysAllocString()
生成一个新的副本,并保存。输入的
BSTR
会被调用者释放。
void MyClass::SetBSTR(BSTR bs)
{
//BSTR m_bs;
m_bs = bs; //ERROR
m_bs = ::SysReAllocString(bs);
}
·
如果需要返回一个已经存储的
BSTR
,返回
BSTR
的一个拷贝。调用者释放返回的
BSTR
拷贝。
void MyClass::GetBSTR(BSTR* pbs)
{
//BSTR m_bs;
*pbs = m_bs; //ERROR
*pbs = ::SysAllocString(m_bs);
}