三、Windows键盘消息和字符集—Unicode怎么样?
我在第二章谈到过Windows NT支持的Unicode有助于为国际市场程序写作。让我们编译一下定义了UNICODE标识符的KEYVIEW1,并在不同版本的Windows NT下执行(在本书附带的光盘中,Unicode版的KEYVIEW1位于DEBUG目录中)。
如果程序编译时定义了UNICODE标识符,则「KeyView1」窗口类别就用RegisterClassW函数注册,而不是RegisterClassA函数。这意味着任何带有字符或文字数据的消息传递给WndProc时都将使用16位字符而不是8位字符。特别是WM_CHAR消息,将传递16位字符代码而不是8位字符代码。
请在美国英语版的Windows NT下执行Unicode版的KEYVIEW1。这里假定您已经安装了至少三种我们试验过的键盘布局-即德语、希腊语和俄语。
使用美国英语版的Windows NT,并安装了英语或者德语的键盘布局,Unicode版的KEYVIEW1在工作时将与非Unicode版相同。它将接收相同的字符代码(所有0xFF或者更低的值),并显示同样正确的字符。这是因为最初的256个Unicode字符与Windows中使用的ANSI字符集相同。
现在切换到希腊键盘布局,并键入『abcde』。WM_CHAR消息将含有Unicode字符代码0x03B1、 0x03B2、0x03C8、 0x03B4和0x03B5。注意,我们先看到的字符代码值比0xFF高。这些Unicode字符代码与希腊字母、、、d和相对应。不过,所有这五个字符都显示为方块!这是因为SYSTEM_FIXED_FONT只含有256个字符。
现在切换到俄语键盘布局,并键入『abcde』。KEYVIEW1显示WM_CHAR消息和Unicode字符代码0x0444、0x0438、0x0441、0x0432和0x0443,这些字符对应于斯拉夫字母φ、и、с、в和у。不过,所有这五个字母也显示为实心方块。
简言之,非Unicode版的KEYVIEW1显示错误字符的地方,Unicode版的KEYVIEW1就显示实心方块,以表示目前的字体没有那种特殊字符。虽然我不愿说Unicode版的KEYVIEW1是非Unicode版的改进,但事实确实如此。非Unicode版显示错误字符,而Unicode版不会这样。
Unicode和非Unicode版KEYVIEW1的不同之处主要在两个方面。
首先,WM_CHAR消息伴随一个16位字符代码,而不是8位字符代码。在非Unicode版本的KEYVIEW1中,8位字符代码的含义取决于目前活动的键盘布局。如果来自德语键盘,则0xE1代码表示á,如果来自希腊语键盘则代表,如果来自俄语键盘则代表。在Unicode版本程序中,16位字符代码的含义很明确:a字符是0x00E1,字符是0x03B1,而字符是0x0431。
第二,Unicode的TextOutW函数显示的字符依据16位字符代码,而不是非Unicode的TextOutA函数的8位字符代码。因为这些16位字符代码含义明确,GDI可以确定目前在设备内容中选择的字体是否可显示每个字符。
在美国英语版Windows NT下执行Unicode版的KEYVIEW1多少让人感到有些迷惑,因为它所显示的就好像GDI只显示了0x0000到0x00FF之间的字符代码,而没有显示高于0x00FF的代码。也就是说,只是在字符代码和系统字体中256个字符之间简单的一对一映射。
然而,如果安装了希腊或者俄语版的Windows NT,您将发现情况就大不一样了。例如,如果安装了希腊版的Windows NT,则美国英语、德语、希腊语和俄语键盘将会产生与美国英语版Windows NT同样的Unicode字符代码。不过,希腊版的Windows NT将不显示德语重音字符或者俄语字符,因为这些字符并不在希腊系统字体中。同样,俄语版的Windows NT也不显示德语重音字符或者希腊字符,因为这些字符也不在俄语系统字体中。
其中,Unicode版的KEYVIEW1的区别在日语版Windows NT下更具戏剧性。您从IME输入日文字符,这些字符可以正确显示。唯一的问题是格式:因为日文字符通常看起来非常复杂,它们的显示宽度是其它字符的两倍。