转载 BSTR详解

来源:互联网 发布:php 数组相加 编辑:程序博客网 时间:2024/05/22 06:05

转载 BSTR详解

 BSTR详解一 - BSTR简介和内部结构

1         Why need BSTR

COM是一种跨编程语言的平台,需要提供语言无关的数据类型。多数编程语言有自己的字符串表示。

·                     C++ 字符串是以0结束的ASCIIUnicode字符数组

·                     Visual Basic字符串是一个ASCII字符数组加上表示长度的前缀。

·                     Java字符串是以0结束的Unicode字符数组。

需要定义一种通用的字符串类型,可以很容易的匹配到不同编程语言。C++中,就是BSTR

2         What is BSTR

2.1      BSTR 简介

"Basic STRing"的简称,微软在COM/OLE中定义的标准字符串数据类型。对于C++Windows头文件wtypes.h中定义如下:

typedef wchar_t WCHAR;

typedef WCHAR OLECHAR;

typedef OLECHAR __RPC_FAR *BSTR;;

2.2      BSTR实现

COM中,字符用16-bit OLECHAR表示,这样使COM可以支持各种code pages,包括Unicode。对于windows系统,可以简单理解为OLECHAR使用的就是Unicode OLECHAR串与单字节字符串很类似,是一个以null结尾的buffer。唯一的区别是每个字符占两个字节,而不是一个

 

 0 1 2 3 4 5 6 7 8 9 0 1

| H | E | L | L | O | /0|

 ^

 OLCHAR

 

 

Figure 1. Format of an OLECHAR string.

 

使用以Null结尾的简单字符串在COM component间传递不太方便。因此,标准BSTR是一个有长度前缀和null结束符的OLECHAR数组。BSTR的前4字节是一个表示字符串长度的前缀。BSTR长度域的值是字符串的字节数,并且不包括0结束符。由于是Unicode串,所以字符数是字节数的一半。这种方式的优点是允许程序员在BSTR串中间嵌入NULL字符。但是,BSTR的前四个字节表示长度,而OLECHAR数组的前四字节表示前两个字符。这种情况下,对于C++程序,如何实现BSTROLECHAR的交换?答案是COM提供了两个BSTR分配用的APISysAllocString / SysReallocString。函数返回的指针指向BSTR的第一个字符,而不是BSTR在内存的第一个字节。

 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5

0a000000 | H | E | L | L | O | /0|

         ^

         BSTR

 

Figure 2.  Format of a BSTR.

 

下面是SysAllocStringSysFreeString的伪代码。

 

BSTR SimpleSysAllocString( const OLECHAR * sz)

{

    if ( sz == NULL) return NULL;

   

    BYTE* buf = new BYTE[sizeof(INT32) + (wcslen(sz)+1)*sizeof(OLECHAR) ];

   

    if(buf == NULL)

    {

        return NULL;

    }

    else

    {

        INT32 len = wcslen(sz) * sizeof(OLECHAR);

        *((INT32*) buf) = len;

        wcscpy( (WCHAR*)(buf+sizeof(INT32)), sz);

        return (BSTR)(buf+sizeof(INT32));

    }

}

 

 

VOID SimpleSysFreeString( BSTR bstr)

{

    if(bstr != NULL)

    {

       BYTE* start = (BYTE*)bstr - sizeof(INT32);

       delete []start;

    }

}

 
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1486331

 

 BSTR详解二 - 使用时机

3         When to use BSTR

只有在你不得不用的时候。

 

使用BSTR一般有以下几种情况:

·                     COM interface接口定义,并且不希望额外提供custom marshaling库(MDIL生成或开发人员自己订制),必须使用BSTR传递字符串。使用C/C++类型的字符串在COM DLL传递字符串,表面上可以使用,但违背了COM的基本规则,并且给以后的扩展留下了隐患。例如,把一个In-process COM Object(简单说COM DLL)改成out-of-process objectCOM EXE)。理论上,客户端的代码应该不做任何改变。但如果是用了C/C++字符串,又希望只使用系统的automation mashallerOleaut32.dll),就会出错。

·                     如果可以提供custom marshaling,也推荐使用BSTR

·                     客户要求接口必须使用BSTR,和客户讨论后,不能修改。

·                     使用的外部库的接口使用BSTR

 

不使用的情况:

·                     不推荐在IDL结构体中定义BSTR成员,会给结构体的复制和释放带来麻烦。最好直接使用限定最大长度的TCHAR数组。如果确实需要传递变长字符串,BSTR应该被定义成独立的参数或者使用独立的get/set接口。

·                     尽可能缩小的BSTR及相关类型的作用域范围。类的成员变量和函数参数不使用BSTR。局部变量要尽快释放类的内部不使用BSTR。代码处理逻辑中只在接口直接相关部分使用BSTR。接收到一个BSTR时,尽量立刻变成C/C++的字符串副本进行处理。在需要传递BSTR参数前产生BSTR,用过立即释放。

 

字符串相关类型的推荐选择顺序

优先级

类型

说明

最高

stl::string/wstring

·         功能最完善,可移植性最好。

 

CString

·         如果编码规范限制使用STL的时候,推荐CString

·         VC 6的版本很不完善。.Net有明显改进,需要进一步研究。

 

C/C++ basic typeTCHAR* / char* / LPTSTR / LPCTSTR / TCHAR[]

·         在结构体中,优先使用指定最大长度的字符数组。

·         效率最好

 

CComBSTR/ _bstr_t

·         在必须使用BSTR时的优先选择。

·         ATLCOM component)工程或者工程中必须使用ATL中,优先选择CComBSTR。一般Exe/dll如果_bstr_t能满足要求,优先使用_bstr_t

·         对于VC6,使用_bstr_t一定要慎重,最好只用作简单临时变量保存调被调用函数的传入参数。因为_bstrt_t不能支持一些关键性操作,比如Detach

·         对于VC++ .Net推荐使用_bstr_t,它是C++扩展,不需要额外包含ATL的文件。

最低

BSTR

·         COM接口

 
 BSTR详解三 - BSTR使用注意事项

 

 

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语言方式的类型定义方式,这种定义方式提高了BSTRC++的应用效率,但是也带来了很多的潜在风险,它使程序员失去了利用编译器检查潜在问题的机会。

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.

 

·                     NULLBSTR的有效值。按照约定,它可以被看作含有0个字符的字符串。BSTR变量必须等于NULL,或者正确分配的BSTR指针。在改变BSTR变量的之前,必须释放原来指向的BSTR。不要把BSTR直接初始化成常量字符指针,例如,BSTR bs = L””

·                     Automationcache 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);

}

 

 

 BSTR详解四 - BSTR包容类

 

 

1.1      Programming with CComBSTR

1.1.1      概述

CComBSTRATL提供的BSTR包装类,是VC 6中提供的最完善的BSTR wrapper。就像MFC CString提供了对TCHAR的封装,CComBSTR提供了对BSTR的封装。Table 1 CComBSTR Methods列出了CComBSTR的主要方法。

 

Table 1CComBSTR Methods

      

CComBSTR Method

Description

CComBSTR

多个版本的构造函数用来创建新的BSTR。可以使用的参数包括LPCOLESTR, LPCSTR, CComBSTR

~CComBSTR, Empty

释放内部封装的BSTR.

Attach, Detach, Copy

Attach把一个已经存在BSTR加入类中。Detach把劣种的BSTR剥离,以便在超出作用域的时候,析构函数不会释放BSTRDetach用于把CComBSTR 赋给[out]参数。

Copy用于产生一个BSTR的副本。一般用于用于把CComBSTR内容赋给[out]参数。

operator BSTR, operator&

允许直接操作内部的BSTRoperator BSTR用于把CComBSTR传给BSTR输入[in]参数。operator&用于把CComBSTR传给BSTR*类型输出[out]参数。

operator=, operator+=, operator<, operator==, operator>

重载运算符,用于赋值、字符串连接、简单比较。

Append, AppendBSTR

字符串连接

Length

计算字符串长度

LoadString

利用字符串资源初始化BSTR

ToLower, ToUpper

字符串大小写转换。

WriteToStream,ReadFromStream

IStream中读/BSTR

 

 

 

下面的伪代码展示了CComBSTR的典型用法:

 HRESULT CMyObject::MyMethod(IOtherObject* pSomething)

{

    CComBSTR bstrText(L"Hello");

    bstrText += " again";                     // LPCSTR conversion

    bstrText.ToUpper();

    pSomething->Display(bstrText);            // [in] parameter

    MessageBoxW(0, bstrText, L"Test", MB_OK); // Assumes Windows NT

}

 

 

对于熟悉MFC的程序员,CComBSTR让人失望。很多CString提供的方便的特性CComBSTR都没有提供。重要的缺省列在了 Table 2  Notable CComBSTR Omissions中。简而言之,CComBSTR 没有提供完整的字符串操作。它的主要用途是把LPCTSTR转换成 BSTR,同时提供一个操作BSTR的类,使程序员可以不使用COM SysXXXXString APIs 。如果需要使用复杂的字符串操作,可以使用STL提供的wstring 类。

Table 2 Notable CComBSTR Omissions

Features Not Included in CComBSTR

Explanation

LPCSTR extraction

CComBSTR 可以把一个单字节字符串转换成BSTR,但是没有提供反向转换的功能。_bstr_t 提供了LPCTSTR operator

String manipulation (including Replace, Insert, Delete, Remove, Find, Mid, Left, Right, and so on)

CComBSTR没有提供这些方法。如果需要,可以使用STL中的wstring

Language-sensitive collation

CComBSTR 提供的字符串比较(<, >, ==)按照是byte-by-byte 方式进行的。没有提供语言相关的比较(language-specific collation)。如果需要可以使用wstring.

1.1.2      CComBSTR注意事项

 

使用CComBSTR时需要考虑的问题。

 

·                     CComBSTR初始化

CComBSTR 提供了一个长度初始化函数,CComBSTR(int nSize)。所以简单给CComBSTR初始化成NULL会发生意想不到的调用。

// CComBSTR(int nSize) is called

CComBSTR bstr1 = NULL; 

CComBSTR bstr2(NULL);

 

// CComBSTR(LPCOLESTR pSrc) is called.

CComBSTR bstr3 = static_cast< LPCOLESTR>(NULL);

CComBSTR bstr4(static_cast< LPCOLESTR>(NULL));

上面的例子中,bstr1/bstr2被初始化成长度为0BSTR,也就是说CComBSTR::m_str是有内容的。bstr3/bstr4的值被初始化成NULL,也就是说CComBSTR::m_str == 0。这样,bstr1/bstr2在被赋新的值前需要考虑是否需要释放其中的BSTR

·                     字符集转换

尽管某些CComBSTR方法可以自动把ANSI字符串转换成Unicode。所有的接口返回的都是Unicode字符串。如果需要转回 ANSI,可以使用ATLMFC转换类,或者Windows API。如果使用文字串修改CComBSTR,使用宽字节字符串。可以减少不必要的转换。例如:

// 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

CW2CT szMyString( bstrMyString );

// Display the ANSI string

MessageBox( NULL, szMyString, _T("String Test"), MB_OK );

 

// The following converts the ANSI string to Unicode

CComBSTR bstr("Test");

// The following uses a Unicode string at compile time

CComBSTR bstr(L"Test");

 

·                     变量作用域(Scope)

象所有设计完整的类一样,CComBSTR会在离开作用域的时候释放资源。如果一个函数返回一个指向CComBSTR 的指针,可能会带来问题:指针有可能指向已经被释放的内存。此时应该使用CopyDetach方法。参考下面的例子。

HRESULT CMyObject::MyMethod3(/*[out, retval]*/ BSTR* pbstr)

{

    CComBSTR bstrText(L"Hello");

    bstrText += " again";

    *pbstr = bstrText;        // No! Call Detach instead!

}

通过复制语句*pbstr = bstrText,被bstrText封装的BSTR的指针作为传出[out]参数传递。在MyMethod3 return时,bstrText离开作用域,CComBSTR destructor毁掉用SysFreeString释放这个BSTR。因此,调用者得到了一个指向已经被释放的内存的指针,可能导致意想不到的结果。因为bstrText即将超出作用域,所以必须使用CComBSTR Copy Detach*pbstr赋值。CComBSTR Copy生成字符串的一格副本,Detach简单的把BSTR移出包装类。这样,在bstrText离开作用域的时候就不会被释放。

HRESULT CMyObject::MyMethod4(/*[out, retval]*/ BSTR* pbstr)

{

    CComBSTR bstrText(L"Hello");

    bstrText += L" again";

    //*pbstr = bstrText.Copy();    // Better!

    *pbstr = bstrText.Detach();    // Much better!

}

在这个例子中,从效率考虑,最好使用Detach而不是CopyDetach 不需要产生一个额外副本的开销。当CComBSTR 必须在复制之后保持自己的内容的时候,例如CComBSTR是一个成员变量,必须使用Copy

·                     显式释放CComBSTR内容

程序员可以在CComBSTR 超出作用域范围前显示释放CComBSTR 中的字符串。一旦释放了,CComBSTR 内容就无效了。CComBSTR 提供了operator BSTR,所以代码中可以显示的释放其中的BSTR

HRESULT CMyObject::MyMethod1()

{

CComBSTR bstrText(L"This is a test");

    ::SysFreeString(bstrText);

// The string will be freed a second time

// when the CComBSTR object goes out of scope,

// which is invalid.

// CComBSTR::Empty() should be used in order to

// explicitly free the BSTR

 

}

在这段代码中,bstrText 中的BSTR被释放了。但是,bstrText 仍然没有超出作用域,看起来仍然可以使用。当bstrText 最终超出作用域的时候,SysFreeString 被第二次调用。为了防止这种意外,需要把operator BSTR 从类中删除。但这样没有办法把它用于需要BSTR类型输入[in]参数的地方,会使CComBSTR 几乎没有任何用处。

·                     外部CComBSTR用作[out]参数

把一个已经初始化好的CComBSTR 的地址传给一个函数作为[out]参数会导致内存泄漏。当把CComBSTR用于BSTR*类型的传出参数[out]时,必须首先调用Empty方法清空字符串的内容。

HRESULT CMyObject::MyMethod2(ISomething* p)

{

    CComBSTR bstrText;

    

    bstrText = L"Some assignment";     // BSTR is allocated.

    

    bstrText.Empty();                  // Must call empty before

    pSomething->GetText(&bstrText);    // using as an [out] parameter.

    if(bstrText != L"Schaller")

        bstrText += "Hello";           // Convert from LPCSTR.

}

在把CComBSTR作为[out]参数传递前,调用Empty释必须的。因为按照COM标准中的[out]参数的使用规则-被调用方法不应该在覆盖BSTR的内容前调用SysFreeString。如果你忘记调用Empty,调用前BSTR的内容占用的资源就会泄漏。

对于相同的代码,如果参数类型是[in, out],就不会有泄漏。因为函数会在复制之前,Free原有的串。

·                     CComBSTRBSTR变量赋值

在下面的代码中,CStringTest 使用CComBSTR 作为成员变量保存BSTR属性。

class CStringTest

{

    

    CComBSTR m_bstrText;

 

// IStringTest

public:

    STDMETHOD(put_Text)(/*[in]*/ BSTR newVal)

    {

        m_bstrText = newVal;

        return S_OK;

    }

    STDMETHOD(get_Text)(/*[out, retval]*/ BSTR *pVal)

    {

        *pVal = m_bstrText;    // Oops! Call m_bstrText.Copy

                               // instead.

        return S_OK;

    }

};

由于m_bstrText get_Text结束没有超出作用域,你可能认为在the *pVal = m_bstrText 赋值时,不需要调用Copy。这是不对的。按照COM规则,调用者负责释放传出[out]参数的内容。由于*pVal指向了m_bstrText 封装的BSTR,而不是一个副本,调用者和m_bstrText 析构函数都会企图删除字符串。

·                     循环中使用CComBSTR Objects

尽管CComBSTR可以分配buffer完成一些操作,例如: += operatorAppend。但是,不推荐在一个小循环内部使用CComBSTR完成字符串操作。这种情况下,CString能提供更好的性能。

// This is not an efficient way

// to use a CComBSTR object.

CComBSTR bstrMyString;

while (bstrMyString.Length()<1000)

{

   bstrMyString.Append(L"*");

}

 

1.2      _bstr_t Class

_bstr_t 是微软C++ COM扩展的一部分。_bstr_t封装了BSTR数据类型。_bstr_t通过SysAllocString and SysFreeString BSTR APIs管理资源的分配和释放。_bstr_t提供了内部引用计数来减少额外负担。

Construction

Version

 

_bstr_t

 

Constructs a _bstr_t object.

Operations

 

 

Assign

 

Copies a BSTR into the BSTR wrapped by a _bstr_t.

Attach

VC 7

Links a _bstr_t wrapper to a BSTR.

copy

 

Constructs a copy of the encapsulated BSTR.

Detach

VC 7

Returns the BSTR wrapped by a _bstr_t and detaches the BSTR from the _bstr_t.

GetAddress

VC 7

Points to the BSTR wrapped by a _bstr_t.

GetBSTR

VC 7

Points to the beginning of the BSTR wrapped by the _bstr_t.

length

 

Returns the number of characters in the _bstr_t.

Operators

 

 

operator =

 

Assigns a new value to an existing _bstr_t object.

operator +=

 

Appends characters to the end of the _bstr_t object.

operator +

 

Concatenates two strings.

operator !

 

Checks if the encapsulated BSTR is a NULL string.

operator ==, !=, <, >, <=, >=

 

Compares two _bstr_t objects.

operator wchar_t* | char*

 

Extract the pointers to the encapsulated Unicode or multibyte BSTR object.

 

 

 

 

VC6_bstr_t缺少了几个重要的方法:Attach/Detach/GetAddress/GetBSTR,所以比CComBSTR简单,使得_bstr_t的应用场合非常有限。而且,_bstr_t使用了引用计数在不同的对象间共享BSTR,内部实现比CComBSTR复杂。使用注意事项可以参考CComBSTR的类似函数。

建议只用于下面的情况:

·                     BSTR的作用域管理

解决BSTR变量超出作用域范围的自动回收。(1)构造简单的BSTR对象,对BSTR进行基本字符串操作,作为输入[in]参数传递给被调用者。

{

_bstr_t bs1(L"first ");

    bs1 += L"second ";

SetBs(bs1); // void SetBs(BSTR bs)

}

 

(2)作为BSTRwrapper,解决[out]参数BSTR的生命周期之后的回收问题。

HRESULT BetterMethod()

{

    BSTR val = NULL;

    GetBs(&val); //void GetBs(/* [out] */ BSTR*)

 

_bstr_t bsVal(val, false);

    // false is IMPORTANT. Other constructor could

          // store the BSTR, too. But you must free the

          // BSTR later.

}

 

HRESULT GoodMethod()

{

    BSTR val = NULL;

    GetBs(&val); //void GetBs(/* [out] */ BSTR*)

 

// All the function create a copy of BSTR.

// But you must free the BSTR immediately.

        _bstr_t bsVal2(val);

        _bstr_t bsVal3;

        bsVal3 = val;

        SysFreeString(val);

}

·                    使用范围

完成简单的BSTR字符串连接、比较等操作。

 

 

 BSTR详解五 - BSTR与其它字符串类型转换

1         类型转换

常用字符串件的类型转换。

 

From

To

Sample

字符串常量

BSTR

Right:

BSTR bs = ::SysAllocString(_T("Test string"));

::SysFreeString();

Wrong:

BSTR bs = _T("Test string"); //ERROR

LPWSTR /

LPCWSTR /

WCHAR* /

wchar_t

BSTR

Right:

LPCTSTR sz1 = _T("Test String");

BSTR bs = ::SysAllocString(sz1);

::SysFreeString();

 

Wrong:

LPTSTR sz1 = _T("Test String");

BSTR bs = sz1; //ERROR

BSTR

LPCWSTR /

const WCHAR * /

const wchar_t *

Right:

BSTR bs = ...; //

...

LPCTSTR sz = static_cast<LPCTSTR>bs;

...

::SysFreeString(bs);

//Never use sz after this line

 

Wrong:

BSTR bs = ...; //

...

 

LPCTSTR sz = bs;

...

::SysFreeString(bs);

//Never use sz after this line

_tcslen(sz); //ERROR

 

BSTR

LPWSTR /

WCHAR* /

wchar_t*

Right:

BSTR bs = ...; //

//...

UINT len = ::SysStringLen(bs);

 

// Do not modify the BSTR content by

// C/C++ string functions

LPTSTR sz = new TCHAR[len+1];

_tcsncpy(sz, bs, len);

::SysFreeString(bs);

 

delete []sz;

Wrong:

BSTR bs = ...; //

//...

 

// Do not modify the BSTR content by

// C/C++ string functions

LPTSTR sz = bs; //Error

 

CString

BSTR

Right:

 

CString str1 = ...;

 

BSTR bs = str1.AllocSysString();

SomeMethod(bs);

// void SomeMethod([in]BSTR)

::SysFreeString(bs);

 

CComBSTR bs1(static_cast<LPCTSTR>(str1));

SomeMethod(static_cast<BSTR> (bs1) );

 

// void SomeMethod([in] BSTR )

_bstr_t bs2( static_cast<LPCTSTR>(str1));

SomeMethod(static_cast<BSTR> (bs2) );

 

Wrong:

CString str1 = ...;

 

SomeMethod(str1.AllocSysString());

 

// No one will releasee the return BSTR of

// str1.AllocSysString()

 

BSTR

CString

Right:

 

BSTR bs = SysAllocString(_T(“Test”));

CString str1(bs);

CString str2;

Str2 = bs;

SysFreeString(bs); // Never forget this line

char* / LPSTR / LPCSTR

BSTR

Right:

Solution 1

char str[MAX_STR_LEN] = "ANSI string";

WCHAR wstr[MAX_WSTR_LEN];

// Convert ANSI to Unicode

 

MultiByteToWideChar( CP_ACP, 0, str,

        strlen(str)+1, wstr,  

     sizeof(wstr)/sizeof(wstr[0]) );

 

BSTR bs1 = ::SysAllocString(wstr);

 

CString cs = str;

BSTR bs2 = cs.AllocSysString()

 

Solution 2

char str[MAX_STR_LEN] = "ANSI string";

_bstr_t bs1(str);

CComBSTR bs2(str);

 

Wrong:

char *str = "ANSI string";

BSTR bstr1 = SysAllocString(

            (const OLECHAR*) str);

BSTR

char* / LPSTR / LPCSTR

Right:

Solution 1

char str[MAX_STR_LEN];

BSTR bs = ::SysAllocString(L"Test");

// Convert ANSI to Unicode

WideCharToMultiByte( CP_ACP, 0,

   (LPCWSTR)bs, -1,

   str, MAX_STR_LEN, NULL, NULL );

::SysFreeString(bs);

 

Solution 2

BSTR bs = ::SysAllocString(L"Test");

_bstr_t bs1(bs, false);

const char* str = static_cast <const char*> bs1;

 

Wrong:

BSTR bstr1 = SysAllocString(L”ANSI string");

char *str = (char*) bstr1;    

 

IMPORTANT: 上面所有的例子都是按照UNICODE应用程序设计的。并且不考虑BSTR中包含多个字串的情况,也就是BSTR只在结束的位置有一个0结束符。对于MBCS/ANSI程序,可以参考上面的例子。主要区别是对于现在的COM版本OLECHARwchar_t,但是TCHAR 对于UNICODE程序才是wchar_t
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 一年级孩子有逆反心里怎么办 如果一个学生会部门没人留怎么办 如果学生会部门很少人报名怎么办 职场说错话了我该怎么办? 中考通知书收到两份怎么办 高三学生英语差怎么办 论文查重百分之0怎么办 微信红包发错人了怎么办 文学社在社团活动日可以怎么办 小孩玩游戏瞎花钱怎么办 党员不配合纪检调查工作怎么办 新同事老问问题怎么办 白色衣服染红色了怎么办 左腿膝盖内侧疼怎么办 差二本线几分怎么办 吃错东西了想吐怎么办 玩游戏扣的话费怎么办 转笔实在是不会怎么办 滑板l轴承沾水了怎么办 暗影格斗3闪退怎么办 暗影格斗3文档被删怎么办 dnf手残党偷学技能学不了怎么办 打篮球没热身膝盖酸痛是怎么办 无线路由器lan口少怎么办? 电脑ip设置乱了怎么办 监控拍我我偷钱怎么办 网吧上网密码忘记了怎么办 比熊犬晚上叫怎么办 刚买的狗一直叫怎么办 酒驾罚款2年没交怎么办 法院判罚款没有钱怎么办 有人朝你吐口水怎么办 孕妇用了六神花露水怎么办 出车祸人不赔钱怎么办 交通事故对方保险不签字怎么办 肇事车主联系不上怎么办 商标被别人申请无效宣告怎么办 淘宝上传宝贝没有品牌怎么办 萌虎白卡借款2000逾期了怎么办 最里面的牙齿烂了怎么办 金龙沉底不游怎么办