第二章 Unicode
Windows 中的Unicode
Windows头文件定义了几种关于Unicode的数据类型:
WCHAR Unicode字符
PWSTR 指向Unicode字符串的指针
PCWSTR 指向一个恒定的Unicode字符串的指针
同时Windows头文件也定业了ANSI/Unicode的通用数据类型,PTSTR和PCTSTR,这类数据指向那一种字符,取决于当编译程序模块时是否定义了UNICODE宏。这里这个宏UNICODE没有下划线前缀,带前缀的宏_UNICODE用于C运行期头文件。当编译源代码模块时,通常必须同时定义这两个宏。
Windows中的函数CreatWindowsEx有两个版本,一个是接受Unicode字符串的,为CreatWindowsExW;一个接受ANSI字符串的,为CreatWindowsExA。我们在代码中,通常只包括了对CreatWindowsEx的调用,而不是直接调用这两者,因为在WinUser.h文件中,CreatWindowsEx实际上是定义为一个宏。故编译源代码模块时,调用的是哪CreatWindowsEx版本,取决于你是否已作了UNICODE的定义。
若要创建供其它开发人员使用的DLL,DLL中最好提供两个输出函数,一个ANSI版本,一个Unicode版本,在ANSI版本中,只需要分配内存,执行必要的字符串转换,然后调用该函数的Unicode版本即可。
Windows的一些老函数存在一个大问题,它们不接受Unicode字符串。这时候应该避免使用这些函数。所有新的和未过时的函数在Windows2000中都同时拥有ANSI和Unicode两个版本。
Windows字符串函数
Windows提供了一组范围很广的字符串操作函数,它们是操作系统的一个组成部分,常常被大型应用程序所使用。由于这些函数使用得比较多,故在你的应用程序运行时,它们可能被装进RAM,所以调用它们而不是使用C运行期库,会有助于稍稍提高你的运行性能。要使用经典的操作系统函数样式中的操作字符串的函数,必须加上ShlWApi.h头文件。这些字符串函数,既有ANSI版,也有Unicode版本,因此,当创建应用程序时,如果定义了Unicode,那么它们会自动扩展为宽字符版本。
成为符合ANSI和Unicode的应用程序
要使你的应用程序符合Unicode,应该遵循下面一些基本原则:
1.将文本串视为字符数组,而不是chars数组或字节数组。
2.将通用数据类型(如TCHAR和PTSTR)用于文本字符和字符串。
3.将显式数据类型(如BYTE和PBYTE)用于字节、字节指针和数据缓存。
4.将TEXT宏用于原义字符和字符串。
5.执行全局性替换(例如用PTSTR替换PSTR)。
6.修改字符串运算问题。例如函数通常希望你在字符中传递一个缓存的大小,而不是字节。这意味着你不应该传递sizeof(szBuffer) ,而应该传递(sizeof(szBuffer)/sizeof(TCHAR )。另外,如果需要为字符串分配一个内存块,并且拥有该字符串中的字符数目,那么请记住要按字节来分配内存。这就是说,应该调用malloc(nCharacters *sizeof(TCHAR)), 而不是调用
malloc(nCharacters)。在上面所说的所有原则中,这是最难记住的一条原则,如果操作错误,编译器将不发出任何警告。
Windwos提供了如下一组对Unicode字符串进行操作的函数:
lstrcat 将一个字符串置于另一个字符串的结尾处
lstrcmp 对两个字符串进行区分大小写的比较
lstrcmpi 对两个字符串进行不区分大小写的比较
lstrcpy 将一个字符串拷贝到内存中的另外一个位置
lstrlen 返回字符串的长度
这些函数都是作为宏来实现的,即是说它们可作为Unicode/ANSI的通用版本,会根据是否定义了UNICODE而自动扩展。
Windows提供了两个函数,以便转换Unicode字符串的大小写字母:
PTSTR CharLower(PTSTR pszString);
PTSTR CharUpper(PTSTR pszString);
既可以转换单个字符,也可以转换以0结尾的整个字符串。若要转换整个字符串,只需要传递字符串的地址即可。若要转换单个字符,则必须像下面这样传递各个字符:
TCHAR cLowerCaseChar = CharLower(PTSTR) szString[0];
将单个字符转换成一个PTSTR,便可调用该函数,将一个值传递给它,在这个值中,较低的16位包含了该字符,较高的16位包含0。当该函数看到较高位是0时,该函数就知道你想要转换单个字符,而不是整个字符串。返回的值是个32位值,较低的16位中是已经转换的字符。
当资源编译器对你的所有资源进行编译时,输出文件是资源的二进制文件。资源(字符串表、对话框模板和菜单等)中的字符串值总是写Unicode字符串。
Windows用IsTextUnicode函数来区分所打开文本是ANSI字符还Unicode字符。
DWORD IsTextUnicode(CONST PVOID pvBuffer , int cb , PINT pResult);
文本文件存在的问题是,它们的内容没有严格和明确的规则,因此很难确定该文件是包含ANSI字符还是Unicode字符。IsTextUnicode使用一系列统计方法和定性方法,以便猜测缓存的内容。由于这不是一种确切的科学方法,因此IsTextUnicode有可能返回不正确的结果。
2004年11月11日