当前位置: 代码迷 >> 综合 >> BSTR,_bstr_t ,CComBSTR
  详细解决方案

BSTR,_bstr_t ,CComBSTR

热度:45   发布时间:2023-10-31 05:49:53.0

BSTR

BSTR(Basic string or binary string)是COM 、Automatic、Interop 使用的string数据类型。在从脚本访问的所有接口中使用BSTR。

 BSTR被定义为OLECHAR*类型,查看OLECHAR类型的声明,可以发现它其实是一个wchar_t类型,也就是说一个BSTR字符串其实是一个UNICODE字符串

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

·                     C++ 字符串是以 0 结束的 ASCII 或 Unicode 字符数组

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

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

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

//头文件 wtypes.h 
typedef WCHAR OLECHAR;
typedef OLECHAR* BSTR;
typedef BSTR* LPBSTR;

BSTR是一个复合性的数据类型,其包含长度前缀(length prefix),字符串数据(Data string),和结尾标志(Terminator)。

长度前缀:4字节的整数,描述字符串数据的长度。出现在字符串数据的第一个字符之前。

字符串数据:Unicode编码的字符串,可包含多个嵌入的空字符。

结尾标志:空的WCHAR

一个BSTR是一个指针,其指向string数据的第一个字符,而非长度前缀。

BSTR由COM内存分配函数分配,所以能被函数直接返回,不用考虑内存的分配问题

//BSTR->char*
#include <comutil.h>
#include <stdio.h>#pragma comment(lib, "comsuppw.lib")int main() {BSTR bstrText = ::SysAllocString(L"Test");//声明BSTRwprintf_s(L"BSTR text: %s\n", bstrText);char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);printf_s("char * text: %s\n", lpszText2);SysFreeString(bstrText);delete[] lpszText2;
}
//char* ->BSTR:
#include <comutil.h>
#include <stdio.h>#pragma comment(lib, "comsuppw.lib")
#pragma comment(lib, "kernel32.lib")int main() {char* lpszText = "Test";printf_s("char * text: %s\n", lpszText);BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);wprintf_s(L"BSTR text: %s\n", bstrText);SysFreeString(bstrText);
}

 COM中一共提供了两个类来对BSTR进行封装,一个是编译器提供的COM支持类:_bstr_t,另一个则是ATL库提供的包裹类:CComBSTR。

_bstr_t

Header: 

Lib: comsuppw.lib or comsuppwd.lib 

_bstr_t 是微软 C++ COM 扩展的一部分。 _bstr_t 封装了 BSTR 数据类型。 _bstr_t 通过 SysAllocString and SysFreeString 等 BSTR APIs 管理资源的分配和释放

_bstr_t提供的封装层次较低,它仅提供简单的字符串构造、连接以及比较操作,在某种意义上,它更像是一个万能转换头,提供char*、wchar_t*类型到BSTR类型之间的转换。

关于_bstr_t,需要注意的有三点:

一是,它内部采用引用计数来管理字符串数组的生命周期;

二是,它在构造或操作的过程是有可能抛出异常的;

三是,它内部使用SysAllocString和SysFreeString来分配和释放内存,在调用Detach操作之后,_bstr_t内“包裹”的BSTR字符串就会脱离出来,脱离出来的BSTR字符串,是需要手动调用SysFreeString来释放内存的,否则会造成内存泄露问题

CComBSTR

Header: atlbase.h

CComBSTR 是 ATL 提供的 BSTR 包装类,建议使用CComBSTR。

CComBSTR Method

Description

CComBSTR

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

~CComBSTR, Empty

释放内部封装的 BSTR.

Attach, Detach, Copy

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

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

operator BSTR, operator&

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

operator=, operator+=, operator

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

Append, AppendBSTR

字符串连接

Length

计算字符串长度

LoadString

利用字符串资源初始化 BSTR 。

ToLower, ToUpper

字符串大小写转换。

WriteToStream,ReadFromStream

从 IStream 中读 / 写 BSTR 。

在使用CComPtr时的注意事项如下:

1、转换问题:虽然一些 CComBSTR 方法自动将 ANSI 字符串参数转换为 Unicode,但这些方法总是返回 Unicode 格式的字符串。若要将输出字符串转换回 ANSI,请使用 ATL 转换类。另外,如果使用字符串来修改 CComBSTR 对象,请使用宽字符字符串。这会减少不必要的转换。

2、范围问题:与任何功能完善的类一样,CComBSTR 在超出范围时将释放其资源。如果函数返回指向 CComBSTR 字符串的指针,这会引起问题,因为指针将引用已经释放的内存。在这种情况下,请使用 Copy 方法。

3、显式释放 CComBSTR 对象:在对象超出范围之前,可以手动调用SysFreeString显式释放包含在 CComBSTR 对象中的字符串。如果字符串被释放,则 CComBSTR 对象无效。

4、在循环中使用 CComBSTR 对象:在CComBSTR 类分配缓冲区来执行某些运算时,如 += 运算符或 Append 方法,建议不要在紧密型循环内执行字符串操作。在这种情况下,CString可以提供更好的性能;

5、将已初始化的 CComBSTR 的地址作为 [out] 参数传递到函数会导致内存泄漏。若要避免泄漏,请在作为 [out] 参数传递地址之前,对现有的 CComBSTR 对象调用 Empty 方法。请注意,如果函数的参数是 [in, out],则同样的代码将不会导致泄漏。