COM中的字符串(一)

CComBSTR(1)



繁杂的字符串

字符串是一个文本类型数据(字符)的数组,我们要处理一个字符串需要考虑这么几点:

第一, 字符类型。不同的操作系统,或者统一操作系统内会有不同的字符类型比如说,, char, unsigned char, wchar类型。

第二, 和字符集不同。如UNICODE, SBCS(ANSI), MBCS, DBCS等不同的字符集。而且统一字符集下会有不同代码页(CODE PAGE)。

第三, 如何决定字符串长度。如有的语言把字符串中的NUL作为字符串结尾,而另外一些则在字符串首位标定该字符串的长度。

第四, 字符串相关的资源管理问题。由于长度一般不同,所以经常会为字符串动态分配内。而这些内存的收回由于所有权不同而不同,不同的语言处理方式也不一样。

所有这些不同会使得字符串的处理也不尽相同。

Windows平台内本身就有好几种字符集,相应用不同的字符类型来表示。

n UNICODE wchar, wchar*

16位的多语言字符集。

n MBCS/DBCS unsigned char, unsigned char*

混合长度的字符集。有的字符用一个字节表示,而有些字符用几个字节表示。VC中他们是等效的。

n ANSI(SBCS) char, char*

面对这么做纷繁复杂的情况,我们比较头疼。希望我们在程序内部用一种统一的字符集进行编码。同时,为了让软件发布在不同操作系统下,我们最好能在编译的时候来决定具体使用哪一种编码。

根据这一要求Microsoft定义了一种统一的数据类型TCHAR/_TCHAR来编写统一的代码。我们在编码的时候统一使用这种数据类型,然后在编译的时候来更具编译选项来确定目标代码所用的字符集。为此,Microsoft在C运行库里添加了tchar.h以支持TCHAR及其处理函数。WIN32环境内的Microsoft在winnt.h中也定义了TCHAR及其处理函数。同时,有相应的一整套TCHAR字符串处理函数。

另外对于每个需要字符串的win32 API都有两个版本xxxxA和xxxxW,他们会通过编译宏来进行切换。

使用方法:

确认是否包含了WINNT.H。一般Wizard生成的文件中都已经包含了该文件;

在程序内严格使用TCHAR/LPTSTR/LPCTSTR来表示字符/字符串;

每个文字或者字符串都要用宏_TEXT/__TEXT/_T/__T包起来;

处理字符串的时候用_tcsXXX(同strXXX, wcsXXX相对应)函数集。

使用两个预处理符号进行编译_UNICODE/UNICODE, _MBCS来确定TCHAR和内在字符类型之间的映射。UNICODE: TCHAR->wchar, _MBCS: TCHAR->char

如果编译时定义了_MBCS符号,则所有的TCHAR字符被映射成char字符,并且预处理器会去掉所有的_T和_TEXT宏的变种,不改变字符或字符串(分别创建一个MBCS字符或字符串)

若编译时未定义任何与处理器符号,则所有的TCHAR字符会被映射成char字符,并且预处理器会去掉所有的_T和_TEXT宏的变种,不改变字符或字符串(分别创建一个ANSI字符或字符串)

COM字符串类型

COM是一个语言中立硬件结构中立的模型。因此,它需要一个语言中立、硬件结构中立的文本数据类型。由于不同的平台使用的字符类型不同,所以很难有一种类型能使和COM的需要。所以COM就定义了一种文本数据类型——OLECHAR。在大多数平台上,包括WIN32平台都把OLECHAR解释成wchar,而在一些16位操作系统下,如win95, Macintonsh OS, OLECHAR会被解释成CHAR。

当我们使用C/C++定义接口的方法传递字符串的时候或者从接口接受一个字符串的时候,经常会用OLECHAR*,在构建一个OLECHAR*的时候需要用宏OLESTR()把字符串包起来。但是如果我们使用其它语言定义的接口时,字符串经常是BSTR类型。

对于BSTR,他实际上就是OLECHAR*,不过他还有一些特殊的含义

n BSTR指向的数组的前缀是该字符串的长度。

n 字符数组是以NUL字符作为结尾。

n 纪录的长度是字节为单位,而不是字符,并且不包括NUL终止符。

n 字符数组内部可以包含嵌入的NUL字符。

n 他必须用SysAllocString和SysFreeString函数来分配和释放。

n NULL BSTR意味着一个空字符串。

n 复制BSTR意味着制作字符串的一个拷贝,不是简单的复制指针。

注意:BSTR的前缀是BSTR指向数组的前边四个字节。这段内存会被::SysStringxxxx管理。所以如果把BSTR当作OLECHAR*有时是可以用的,因为他们指向一个字符串数组。但是,OLECHAR*会以NUL为结尾,会把内嵌NUL的BSTR截断。反过来,我们不能把OLECHAR*看作BSTR,虽然他们都指向一个字符数组,但是他前边的四个字节的内容是无效的,也就是BSTR的长度无效。这个时候让::SysStringxxxx来管理他的话会出问题。

字符串的转换

即使我们在程序内部都进行了统一编码。但是,如果涉及到对第三方程序的应用,不可避免的要引起字符处理的混乱。我们希望能够把这些涉外的字符串和程序内部的字符串进行转换。这样可以维护程序的一致性。

ATL提供了一系列的转换宏,在必要的时候他可以在前边提到的字符类型之间进行转换。这些宏的命名使用“<源类型缩写>2<目标类型缩写>”的形式。具体缩写如下所示:

T TCHAR类型指针——LPTSTR

W Unicode wchar类型指针——LPWSTR

A MBCS/ANSI char类型指针——LPSTR

OLE COM OLECHAR类型的指针——LPOLESTR

BSTR COM BSTR类型字符串。

C C/C++中的const修饰符

在宏转换的时候,不可避免的要产生一些临时变量(如字符串长度),这些变量会在栈上分配。如果我们在一个循环内进行这些转换,就会有很多临时变量产生而不能得到及时的释放。所以我们定义一个宏USES_CONVERSION(只需要一次)来纪录这些临时变量,从而大大节约了内存。



辅助函数

当我们在编写一个WIN32的组件时执行了一个操作——复制OLECHAR字符串。由于在WIN32系统上OLECHAR实际上是wchar所以,在WINNT上是通过lstrcpyW来实现的。但是如果把这个组件放在win95上,由于他没有实现lstrcpyW,所以程序调用就会出问题。同样涉及到OLECHAR字符串的长度获取以及字符便利等等。在这里ATL提供了

OLECHAR* ocscpy (LPOLESTR dest, LPCOLESTR src);

size_t ocslen(LPOLESTR s);

LPOLESTR CharNextO(LPCOLESTR lp);

三个函数,使得这些操作在NT和95下都能正确运行。

心得

对于COM内部统一使用TCHAR/LPTSTR来说是很容易理解的。需要明确的一点就是TCHAR的映射问题。我们建立组件的时候应根据特定的操作系统来使用最优的字符串处理方法。对于WIN NT我们一般选用UNICODE编译选项,但是编译结果却不能在WIN9X下正确运行(WIN9X不支持UNICODE)。所以在不涉及到OLECHAR的情况下为了使的构建出来的组件即能在NT下运行也能在WIN9X下运行我们一般选用_MBCS编译选项。

但是,如果涉及到了OLECHAR,问题就比较复杂了。因为在一般情况OLECHAR都当作wchar,如果我们无法回避对OLECHAR*的直接操作,就必须使用上边提到的一些辅助函数。如果这些辅助函数不够用,从而使用了wchar的相应函数,那么在win9x下就会出现运行错误。

以上说的都是win32平台上的应用。如果这个组件要在16位操作系统下运行,那么就需要注意OLECHAR的映射。由于在16位操作系统下一个OLECHAR就是一个char,所以在WIN32平台下如果没有添加_OLE2ANSI选项,编译出来的组件(有涉及到OLECHAR的接口)就根本不能用,反过来,在16操作系统下编译出来的组件也不能在32位操作系统下运行。这些问题是的我们发布一个“万能”组建变得很困难。所以,还是根据不同的目标操作系统进行编译、发布。这样反而利用了这些操作系统的优点。 还有一个问题就是OLECHAR*,和BSTR的关系了。我们前边也介绍了他们的区别和联系。我想组件是一个语言中立的结构,所以尽量能让他不被一种语言限定。而OLECHAR*作为字符串只能C/C++的语言环境下使用,限制了组件的应用范围。故而还是尽量使用BSTR进行字符串的操作。

转自:http://zhikangs.spaces.live.com/blog/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值