COM interface接口定义,并且不希望额外提供custom marshaling库(MDIL生成或开发人员自己订制),必须使用BSTR传递字符串。使用C/C++类型的字符串在COM DLL传递字符串,表面上可以使用,但违背了COM的基本规则,并且给以后的扩展留下了隐患。例如,把一个In-process COM Object(简单说COM DLL)改成out-of-process object(COM EXE)。理论上,客户端的代码应该不做任何改变。但如果是用了C/C++字符串,又希望只使用系统的automation mashaller(Oleaut32.dll),就会出错。
1How to use BSTR1.1BSTR分析BSTR设计对于C++程序员好坏参半。一方面,BSTR可以被用于大多数需要OLECHAR数组作为参数的函数。另一方面,不能用熟悉的C/C++函数进行对BSTR的分配、释放和处理,例如malloc, free, new, delete, lstrcat, and lstrlen 等函数不能用于处理BSTR。就像对接口指针和类指针的处理不一样,对BSTR的处理和对TCHAR*的处理也不一样。BSTR是一种C语言方式的类型定义方式,这种定义方式提高了BSTR在C++的应用效率,但是也带来了很多的潜在风险,它使程序员失去了利用编译器检查潜在问题的机会。1.2BSTR使用基本规则
在对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)的地方。
1.3BSTR参数使用多数时候,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.//.hHRESULT 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 hereDosomething(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 hereDosomething(bs);::SysFreeString(bs); //ERROR·不要Free返回给调用者的 BSTR .BSTR GetBSTR1()BSTR bs = ::SysAllocString(_T(“test”));::SysFreeString(bs); //ERRORreturn 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; //ERRORm_bs = ::SysReAllocString(bs);·如果需要返回一个已经存储的BSTR,返回BSTR的一个拷贝。调用者释放返回的BSTR拷贝。void MyClass::GetBSTR(BSTR* pbs)//BSTR m_bs;*pbs = m_bs; //ERROR*pbs = ::SysAllocString(m_bs);