Windows 核心编程:2.1

终于开始读windows via C/C++ ,非常荣幸可以和大师Jeffrey Richter进行一次真正的心灵之旅。

2Unicode

[@more@]

终于开始读windows via C/C++ ,非常荣幸可以和大师Jeffrey Richter进行一次真正的心灵之旅。

2Unicode

随着Microsoft公司的Windows操作系统在全世界日益广泛的流行,对于软件开发人员来说,将目标瞄准国际上的各个不同市场,已经成为一个越来越重要的问题。美国的软件版本比国际版本提前6个月推向市场,这曾经是个司空见惯的现象。但是,由于各国对Windows操作系统提供了越来越多的支持,因此就更加容易为国际市场生产各种应用软件,从而缩短了软件的美国版本与国际版本推出的时间间隔。Windows操作系统始终不逾地提供各种支持,以帮助软件开发人员进行应用程序的本地化工作。应用软件可以从各种不同的函数中获得特定国家的信息,并可观察控制面板的设置,以确定用户的首选项。Windows甚至支持不同的字体,以适应应用的需要。之所以将这一章放在本书的开头,是因为考虑到Unicode是开发任何应用程序时要采用的基本步骤。本书的每一章中几乎都要讲到关于Unicode的问题,而且书中给出的所有示例应用程序都是“用Unicode实现的”。

Buffer over error which are typical when manipulating character strings have become a vector for security attacks against applications and even against OS. In previous years, Microsoft put forth a lot of internal or external efforts to raise the security bar in the Windows world. The second part of this chapter presents new function provided by Microsoft in the C run-time library. You should use these new function protect your code against buffer overruns when manipulating strings.

Highly recommend that your application always use Unicode strings and you always manipulate these strings via the new secure string function. It will also help when interoperating with the COM and .NET framework.

软件的本地化要解决的真正问题,实际上就是如何来处理不同的字符集。多年来,许多人一直将文本串作为一系列单字节字符来进行编码,并在结尾处放上一个零。对于我们来说,这已经成了习惯。当调用strlen函数时,它在以0结尾的单字节字符数组中返回字符的数目。问题是,有些文字和书写规则(比如日文中的汉字就是个典型的例子)的字符集中的符号太多了,因此单字节(它提供的符号最多不能超过2 5 6个)是根本不敷使用的。为此出现了双字节字符集(DBCS),以支持这些文字和书写规则。

在双字节字符集中,字符串中的每个字符可以包含一个字节或包含两个字节。例如,日文中的汉字,如果第一个字符在0x810 x 9 F之间,或者在0xE00xFC之间,那么就必须观察下一个字节,才能确定字符串中的这个完整的字符。使用双字节字符集,对于程序员来说简直是个很大的难题,因为有些字符只有一个字节宽,而有些字符则是两个字节宽。如果只是调用strlen函数,那么你无法真正了解字符串中究竟有多少字符,它只能告诉你到达结尾的0之前有多少个字节。ANSIC运行期库中没有配备相应的函数,使你能够对双字

节字符集进行操作。但是, Microsoft Visual C++的运行期库却包含许多函数,如_ mbslen ,它可以用来操作多字节(既包括单字节也包括双字节)字符串。为了帮助你对DBCS字符串进行操作,Windows提供了下面的一组帮助函数。前两个函数CharNext Char Prev 允许前向或逆向遍历DBCS 字符串,方法是每次一个字符。第三个函数IsDBCSLeadByte, 在字节返回到一个两字字节符的第一个字节时将返回TRUE

函数描述

PTSTR CharNextPCTSTR pszCurrentChar; 返回字符串中的下一个字符的地址;

PTSTR CharPrevPCTSTR pszStart,PCTSTR pszCurrentChar);返回字符串中的上一个字符的地址;

BOOL IsDBCSLeadByteTRUE(BYTE bTestChar) 如果该字节是DBCS字符的第一个字节,则返回TRUE;

尽管这些函数使得我们对DBCS的操作更容易,但还需要,一个更好的方法让我们来看看UnicodeUnicodeAppleXerox公司于1988年建立的一个技术标准。1991年,成立了一个集团机构负责Unicode的开发和推广应用。该集团由AppleCompaqHPIBMMicrosoftOracleSilicon Graphics, Inc.SybaseUnisysXerox等公司组成。该集团负责维护Unicode标准。Unicode的完整描述可以参阅Addison Wesley出版的《Unicode Standard》一书。Unicode提供了一种简单而又一致的表示字符串的方法。Unicode字符串中的所有字符都是

1 6位的(两个字节)。它没有专门的字节来指明下一个字节是属于同一个字符的组成部分,还是一个新字符。这意味着你只需要对指针进行递增或递减,就可以遍历字符串中的各个字符,不再需要调用CharNextCharPrevIsDBCSLeadByte之类的函数。由于Unicode用一个1 6位的值来表示每个字符,因此总共可以得到65 000个字符,这样,它就能够对世界各国的书面文字中的所有字符进行编码,远远超过了单字节字符集的256个字符的数目。目前,已经为阿拉伯文、中文拼音、西里尔字母(俄文)、希腊文、西伯莱文、日文、韩文和拉丁文(英文)字母定义了Unicode代码点。这些字符集中还包含了大量的标点符号、数学符号、技术符号、箭头、装饰标志、区分标志和其他许多字符。如果将所有这些字母和符号加在一起,总计约达35000个不同的代码点,这样,总计65,000多个代码点中,大约还有一半可供将来扩充时使用。

UTF_8

  UTF-8UNICODE的一种变长字符编码,由Ken Thompson1992年创建。现在已经标准化为RFC 3629UTF-816个字节编码UNICODE字符。如果UNICODE字符由2个字节表示,则编码成UTF-8很可能需要3个字节,而如果UNICODE字符由4个字节表示,则编码成UTF-8可能需要6个字节。用4个或6个字节去编码一个UNICODE字符可能太多了,但很少会遇到那样的UNICODE字符。

  UFT-8转换表表示如下:

  UNICODE UTF-8

  00000000 - 0000007F 0xxxxxxx

  00000080 - 000007FF 110xxxxx 10xxxxxx

  00000800 - 0000FFFF 1110xxxx 10xxxxxx 10xxxxxx

  00010000 - 001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

  00XP00 - 03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 04000000 - 7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

  实际表示ASCII字符的UNICODE字符,将会编码成1个字节,并且UTF-8表示与ASCII字符表示是一样的。所有其他的UNCODE字符转化成UTF-8将需要至少2个字节。每个字节由一个换码序列开始。第一个字节由唯一的换码序列,由n1加一位0组成。n1表示字符编码所需的字节数。

  示例

  UNICODE uCA(11001010) 编码成UTF-8将需要2个字节:

uCA -> C3 8A (11000011,10001010)

  UNICODE uF03F (1111 0000 0011 1111) 编码成UTF-8将需要3个字节:

  u F03F -> EF 80 BF

  译者注:由上分析可以看到,UNCODEUTF-8的转换就是先确定编码所需要的字节数,然后用UNICODE编码位从低位到高位依次填入上面表示为x的位上,不足的高位以0补充。以上是个人经验,如有错误,请不惜指教,谢过先:)

  UTF-8编码的优点:

  UTF-8编码可以通过屏蔽位和移位操作快速读写。字符串比较时strcmp()wcscmp()的返回结果相同,因此使排序变得更加容易。字节FFFEUTF-8编码中永远不会出现,因此他们可以用来表明UTF-16UTF-32文本(见BOM UTF-8 是字节顺序无关的。它的字节顺序在所有系统中都是一样的,因此它实际上并不需要BOM

  UTF-8编码的缺点:

你无法从UNICODE字符数判断出UTF-8文本的字节数,因为UTF-8是一种变长编码它需要用2个字节编码那些用扩展ASCII字符集只需1个字节的字符 ISO Latin-1 UNICODE的子集,但不是UTF-8的子集 8位字符的UTF-8编码会被email网关过滤,因为internet信息最初设计为7ASCII码。因此产生了UTF-7编码。 UTF-8 在它的表示中使用值100xxxxx的几率超过50% 而现存的实现如ISO 2022 4873 6429 8859系统,会把它错认为是C1 控制码。因此产生了UTF-7.5编码。

UTF-16

UTF-16Unicode的其中一个使用方式。 UTF Unicode Translation Format,即把Unicode转做某种格式的意思。它定义于ISO/IEC 10646-1的附录Q,而RFC2781也定义了相似的做法。在Unicode基本多文种平面定义的字符(无论是拉丁字母汉字或其他文字符号),一律使用2字节储存。而在辅助平面定义的字符,会以代理对(surrogate pair)的形式,以两个2字节的值来储存。UTF-16比起UTF-8,好处在于大部分字符都以固定长度的字节 (2字节) 储存,但UTF-16却无法兼容于ASCII编码。In Windows Vista, each Unicode character is encoded using UTF-16.

当开发应用程序时,当然应该考虑利用Unicode的优点。即使现在你不打算对应用程序进行本地化,开发时将Unicode放在心上,肯定可以简化将来的代码转换工作。此外, Unicode还具备下列功能:

· 可以很容易地在不同语言之间进行数据交换。

· 使你能够分配支持所有语言的单个二进制.exe文件或DLL文件。

· 提高应用程序的运行效率(本章后面还要详细介绍)。

Windows XPUnicode

Windows XP是使用Unicode从头进行开发的,用于创建窗口、显示文本、进行字符串操作等的所有核心函数都需要Unicode字符串。如果调用任何一个Windows函数并给它传递一个ANSI字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给你的应用程序。所有这些转换操作都是在你看不见的情况下发生的。当然,进行这些字符串的转换需要占用系统的时间和内存。例如,如果调用CreateWindowsEX函数,并传递类名字和窗口标题文本的非Unicode字符串,那么CreateWindowsEx必须分配内存块(在你的进程的默认堆中),将非Unicode字符串转换成Unicode字符串,并将结果存储在分配到的内存块中,然后调用Unicode版本的CreateWindowsEx函数。对于用字符串填入缓存的函数来说,系统必须首先将Unicode字符串转换成非Unicode字符串,然后你的应用程序才能处理该字符串。由于系统必须执行所有这些转换操作,因此你的应用程序需要更多的内存,并且运行的速度比较慢。通过从头开始用Unicode来开发应用程序,就能够使你的应用程序更加有效地运行。

COM的简单说明

Microsoft公司将COM16Windows转换成Win32时,公司作出了一个决定,即需要字符串的所有COM接口方法都只能接受Unicode字符串。这是个了不起的决定,因为COM通常用于使不同的组件能够互相进行通信,而Unicode则是传递字符串的最佳手段。如果你为Windows XPWindows Vista开发应用程序,并且也使用COM,那么你将会如虎添翼。在你的整个源代码中使用Unicode,将使与操作系统进行通信和与COM对象进行通信的操作变成一件轻而易举的事情。

如何编写Unicode源代码

Microsoft公司为Unicode设计了Windows API,这样,可以尽量减少对你的代码的影响。实际上,你可以编写单个源代码文件,以便使用或者不使用Unicode来对它进行编译。只需要定义两个宏(UNICODE_ UNICODE),就可以修改然后重新编译该源文件

2.8.1 C运行期库对Unicode的支持

为了利用Unicode字符串,定义了一些数据类型。标准的C头文件String . h已经作了修改,以便定义一个名字为wchar_t的数据类型,它是一个Unicode字符的数据类型:例如,如果想要创建一个缓存,用于存放最多为99个字符的Unicode字符串和一个结尾为零的字符,可以使用下面这个语句:该语句创建了一个由1001 6位值组成的数组。当然,标准的C运行期字符串函数,如strcpystrchrstrcat等,只能对ANSI字符串进行操作,不能正确地处理Unicode字符串。因此,ANSI C也拥有一组补充函数。

请注意,所有的Unicode函数均以wcs开头,wcs是宽字符串的英文缩写。若要调用Unicode函数,只需用前缀wcs来取代ANSI字符串函数的前缀str即可。注意大多数软件开发人员可能已经不记得这样一个非常重要的问题了,那就是Microsoft公司提供的C运行期库与ANSI的标准C运行期库是一致的。ANSI C规定,C运行期库支持Unicode字符和字符串。这意味着始终都可以调用C运行期函数,以便对Unicode字符和字符串进行操作,即使是在Windows 98上运行,也可以调用这些函数。换句话说, wcscatwcslenwcstok等函数都能够在Windows 98上很好地运行,这些都是必须关心的操作系统函数。

对于包含了对str函数或wcs函数进行显式调用的代码来说,无法非常容易地同时为ANSIUnicode对这些代码进行编译。本章前面说过,可以创建同时为ANSIUnicode进行编译的单个源代码文件。若要建立双重功能,必须包含TChar.h文件,而不是包含String.h文件。TChar.h文件的唯一作用是帮助创建ANSI/ Unicode通用源代码文件。它包含你应该用在源代码中的一组宏,而不应该直接调用str函数或者w c s函数。如果在编译源代码文件时定义了_ UNICODE,这些宏就会引用wcs这组函数。如果没有定义_ UNICODE,那么这些宏将引用str这组宏。

例如,在TChar.h中有一个宏称为_tcscpy。如果在包含该头文件时没有定义_ UNICODE ,那么_tcscpy就会扩展为ANSIstrcpy函数。但是如果定义了_UNICODE, _tcscpy将扩展为Unicodewcscpy函数。拥有字符串参数的所有C运行期函数都在TChar.h文件中定义了一个通用宏。如

果使用通用宏,而不是ANSI/ Unicode的特定函数名,就能够顺利地创建可以为ANSIUnicode进行编译的源代码。但是,除了使用这些宏之外,还有一些操作是必须进行的。TChar.h文件包含了另外一些宏。若要定义一个ANSI/ Unicode通用的字符串数组,请使用下面的TCHAR数据类型。如果定义了_ UNICODETCHAR将声明为下面的形式:

Typedef wchar_t TCHAR;

如果没有定义_ UNICODE,则TCHAR将声明为下面的形式:

Typedef char TCHAR;

使用该数据类型,可以像下面这样分配一个字符串:

TCHAR szString[100];

也可以创建对字符串的指针:

TCHAR *szError = “Error”

不过上面这行代码存在一个问题。按照默认设置, Microsoft公司的C + +编译器能够编译所有的字符串,就像它们是ANSI字符串,而不是Unicode字符串。因此,如果没有定义_ UNICODE,该编译器将能正确地编译这一行代码。但是,如果定义了_ UNICODE,就会产生

一个错误。若要生成一个Unicode字符串而不是ANSI字符串,必须将该代码行改写为下面的样子:

TCHAR *szError = L “Error”;

字符串(literal string)前面的大写字母L,用于告诉编译器该字符串应该作为Unicode字符串来编译。当编译器将字符串置于程序的数据部分中时,它在每个字符之间分散插入零字节。这种变更带来的问题是,现在只有当定义了_ UNICODE时,程序才能成功地进行编译。我们需要另一个宏,以便有选择地在字符串的前面加上大写字母L。这项工作由_TEXT宏来完成,_TEXT宏也在TChar.h文件中做了定义。如果定义了_ UNICODE,那么_TEXT定义为下面的形式:

#define _TEXT(x) L## x

如果没有定义_ UNICODE_TEXT将定义为:

#define _TEXT(x) x

使用该宏,可以改写上面这行代码,这样,无论是否定义了_ UNICODE宏,它都能够正确地进行编译。如下所示:

TCHAR *szError =_TEXT(“Error”;)

_TEXT宏也可以用于字符串。例如,若要检查一个字符串的第一个字符是否是大写字母J

只需编写下面的代码即可:

If (szError[0] == _TEXT(‘j’))

{}

Else

{}

2.8.2 Windows定义的Unicode数据类型

Windows头文件定义了数据类型说明:

WCHAR Unicode字符

PWSTR 指向Unicode字符串的指针

PCWSTR 指向一个恒定的Unicode字符串的指针

这些数据类型是指Unicode字符和字符串。Windows头文件也定义了ANSI/ Unicode通用数据类型PTSTRPCTSTR。这些数据类型既可以指ANSI字符串,也可以指Unicode字符串,这取决于当编译程序模块时是否定义了UNICODE宏。请注意,这里的UNICODE宏没有前置的下划线。_ UNICODE宏用于C运行期头文件,而UNICODE宏则用于Windows头文件。当编译源代码模块时,通常必须同时定义这两个宏。

2.8.3 Windows中的Unicode函数和ANSI函数

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/16916129/viewspace-1014784/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/16916129/viewspace-1014784/

Windows核心编程(第5版中文版pdf)+源代码 原书名: Windows via C/C++ 原出版社: Microsoft Press 作者: (美)Jeffrey Richter Christophe Nasarre 译者: 葛子昂 周靖 廖敏 丛书名: 微软技术丛书 出版社:清华大学出版社 ISBN:9787302184003 上架时间:2008-9-23 出版日期:2008 年9月 开本:16开 页码:770 版次:5-1 编辑推荐   权威力作 再度新鲜亮相.    名著名译 彰显经典魅力    中英联动 丰富阅读体验..    深刻剖析底层实现机理    直击Windows编程精髓... 内容简介   这是一本经典的windows核心编程指南,从第1版到第5版,引领着数十万程序员走入windows开发阵营,培养了大批精英。   作为windows开发人员的必备参考,本书是为打算理解windows的c和c++程序员精心设计的。第5版全面覆盖windows xp,windows vista和windows server 2008中的170个新增函数和 windows特性。书中还讲解了window s系统如何使用这些特性,我们开发的应用程序又如何充分使用这些特性,如何自行创建新的特性。 作译者 作者: Jeffrey Richter Jeffrey Richter是一位在全球享有盛誉的技术作家,尤其在Windows/.NET领域有着杰出的贡献。他的第一本Windows著作Windows 3: A Developer's Guide大获好评,从而声名远扬。之后, 他又推出了经典著作《Windows 高级编程指南》和《Windows核心编程》。如今这两本书早已成为Windows程序设计领域的颠峰之作,培育了几代软件开发设计人员。他的每一本新作问世,我 们都有理由相信这是一本巨著,我们想要的一切尽在其中。Jeffery 是Wintellect公司的创始人之一,也是MSDN杂志.NET专栏的特邀编辑。现在他正领导开发该公司的.NET程序设计课程,向 大众推广.NET技术。因为他自1999年开始就参与了微软.NET框架开发组的咨询工作,与这些一线人员一起经历了.NET的孕育与诞生,所以他对.NET思想的领悟、对.NET的细节熟稔,是其他任 何作家难以企及的。他是.NET著作领域中当之无愧的一面旗帜。 作者: Christophe Nasarre Christophe Nasarre是Business Objects的软件架构师和开发部门领导,该公司致力于帮助其他企业更好地专注于其主营业务,通过商业智能方案来提升决策能力和业绩。他为Addison- Wesley,APress和Microsoft Press出版的许多图书担任过技术审校,此外还是MSDN Magazine的撰稿人。 译者: 周靖
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值