Chapter 6

VB-的代码是ANSI还是Unicode?

正如我在第1章"入门指南,"中老早就暗示过,Visual Basic是ANSI还是Unicode这个问题,这的确是一个难题。可以给出的唯一的可能答案只有是与否,或更准确地说,这个答案取决于这个问题的含意。也许,更深入地钻研到历史中,会有助于给出这个问题足够的含意,"取决于"这个答案至少让人感到有些许的满意。

ANSI = ~Unicode = MBCS

我已经论述了一个重要的定义:我在这里提到Unicode时,用的是微软的UCS - 2/UTF - 16的概念。 我没有论述的另一个定义是非Unicode字符串。虽然这些通常被称为多字节(它包含其他所有的代码页,包括将使用两个字节和将使用1 - 5字节的UTF - 8的DBCS代码页等等),许多人也把它们称为" ANSI。" 这主要是历史上的原因,但这个误用的术语有一个现代的基础:所有多字节的Windows APIs都有一个" A "后缀," A "代表ANSI。例如FindWindow API,它会把字符串认为是窗口类,标题,或两者。FindWindowA API存在于所有Win32操作系统中,接受可由默认系统代码页表示的字符串 。FindWindowW API只存在于Windows NT和Windows 2000上,并接受Unicode字符串 。

我个人则喜欢称" A " APIs为~ Unicode APIs (意思是"非Unicode " APIs ),但这个代字号字符不是标识符中有效的那个字符。这很令人迷惑!至少可以说。

我将在本章末和第7章将要论述Unicode和非Unicode APIs的使用和名称的问题,"理解Codepage 阻挡层,"和第8章," 处理VB 表单和格式。"

微软产品和Unicode简史

下列并不是完全着眼于Unicode的主题,或Unicode目前匹配字符的ISO - 10646标准。它意味着给定一个历史条件,帮助说明Visual Basic及其他微软产品与Unicode[ md ]有关的地方,以及希望它们开发的方向。从哪儿开始?好,首先……

16位Windows ( Windows 3.0 , 3.1 ,和 3.1x )

Windows是由美国微软公司开发。当时,Unicode还不是一个为人所知的术语,因此,没有16位的Windows操作系统说Unicode并不奇怪。微软公司的一些有远见的人,他们瞄准了国际市场,特别是日本市场。这确实使微软公司开始考虑代码页1252以外的代码页,并考虑日本及其他亚洲的代码页。对全球化和本地化的费用也不了解,但日本市场的需求是非常明白清楚的,足以使微软公司投入到本地化的目的中。

然而,现阶段的本地化还是很简单的,涉及的美国开发人员"把他们围墙上的代码丢给"日本开发人员,然后让他们对所需的产品进行更改并测试那些更改。可惜的是,那些开发人员和测试人员同他们的原始相关开发人员一样犯有许多多的错误,而且,产品的这些版本不是可以处理所有语言的超集,而是经常中断处理在原版工作的数据子集。

这样,就存在着本地化,但是全球化相对来说仍是未知的。因为每个地区只支持它自己的版本,交叉代码页的互操作性并不是必要条件,所以,这对任何人来说都不是大问题。

16位世界的COM

由于几乎相同的原因,COM并不能真正地理解Unicode。实际上,Component Object Model(部件对象模型)根本没有真正地体现语言/地区的重要性。 它是在同样的假设条件下工作,也就是,假设它足以在当前系统的默认代码页内工作。

16位世界的Visual Basic

Visual Basic的早期版本是在与其他16位应用程序相同的规定下工作。但是,到Visual Basic 3.0出现的时候,一般处理软件的最佳方法,很明显,是必须降低费用,提高需要在其他国家销售的产品质量。然而,Visual Basic始终是基于它安装的平台,且没有基础支持,房子在这样的条件下是建造不起来的。因此,VB 3.0就维持原状,而人们却在展望Windows新技术,即Windows NT。

Windows NT

David Cutler的第二个操作系统(第一个操作系统是用于数字的)的建立是充满希望的,对我们来说,重要的是Windows NT对Unicode的完全支持。整个操作系统完全是认真地去写的,Unicode核心和Unicode支持是该操作系统的最重要的方法。因为内存和硬盘空间在这样的条件下,大多数人只看到了一个时期内比实际问题大两倍的情况,但Cutler先生确实看到了未来。他选择的"Unicode "是UCS - 2,这个ISO - 16046包含的世界标准,该标准规定每个字符基于两个字节。美国英语地区还有在第一个127个字符的"位置"优势,但它不再优越于所占空间较少的亚洲语言。

同时,真实性逐渐产生,很显然,没有人能够转移到不支持做事的"老方法"的平台上。所以,为了向后兼容,ANSI将被支持,而且使所有现有的应用程序都能持续工作(主要)。目前所有带字符串的Win32 APIs都有两个版本:用于多字节字符系统的 " A "版本,比如英语,荷兰语,日语,和使用Unicode的" W "版本。在编译时,通过选择是否用Unicode标志编译,你会选择哪个APIs集,例如,决定是否把GetWindowLong调入你的C/C++代码将被称为GetWindowLongA或GetWindowLongW。你总能够明确地选择调用这个或那个,但希望你别这样。理论上,总有一天,你可以很容易地只是轻击一下开关,就处于Unicode状态!

他们为什么要这样做?首先,有遍及全世界的EXE的明显力量(Windows NT还没有,因为,在核心可以被认为是明白这个程度上说,它自己的许多核心应用程序仍不象核心应用程序[ md ])。其次,任何时侯直接处理Unicode,你的所有操作都会更快,因为ANSI和Unicode之间不需要额外的翻译。人们很快就会了解到,SDK的文档要求是精确的,额外地调用MultiByteToWideCharWideCharToMultiByte函数会减慢应用程序。

毫无疑问,MultiByteToWideCharWideCharToMultiByte的其中一个隐藏特征是,必须有代码页表参与Unicode和任何代码页之间字符串的转化,反之亦然。支持世界的一种给定语言(大多数应用程序内部确未使用Unicode)也意味着支持代码页。

Windows 95

Windows 95是在稍有不同的原则下出现的:在许多方面,它是一个原始的16位Win 3.x代码库的端口(正如大部分的应用程序是,甚至是基于Windows NT的 )。最初它的意图是完全支持与Windows NT相同的Win32 API,虽然在大多数情况下,API函数的" W "版本只是返回一个ERROR_CALL_NOT_IMPLEMENTED或E_NOTIMPL的错误。在Windows 95/98下用来支持Unicode和ANSI的Win32 API调用的极限数参见表6.1。表6.1 [ em]所有平台下支持Unicode的Win32 API调用

表6.1 支持所有平台下Unicode 的Win32 API 调用 Platforms

API 调用

它要做的

EnumResourceLanguages

列举给定模块中指定资源名/类型支持的语言

EnumResourceNames

列举给定模块中指定类型的所有资源

EnumResourceTypes

列举给定模块中所有资源类型

ExtTextOut

写出一字符串到一指定位置,选择性地启用在TextOut支持以外的参数

FindResource

查找指定名字和标题的资源

FindResourceEx

查找指定名字和标题的资源,允许被指定的语言

GetCharWidth

恢复指定字符的宽度

GetCommandLine

恢复当前过程的命令行字符串

GetTextExtentPoint

计算给定文字串的宽度和高度(用于向后兼容,推荐用GetTextExtentPoint32 )

GetTextExtentPoint32

计算给定文字串的宽度和高度

lstrlen

返回空结束字符串的长度

MessageBox

建立,显示和操作消息框。

MessageBoxEx

建立,显示和操作消息框,允许用户指定预定义按钮的语言

MultiByteToWideChar

把多字节字符串转换为Unicode字符串,给定进行转换的代码页

TextOut

写字符串到一指定位置

WideCharToMultiByte

把Unicode字符串转换为多字节字符串,给定进行转换的代码页

无疑,写Unicode应用程序用于Windows 95或98,给定这样的工具稀疏集,这是具挑战性的。但是,首先,概念是,你以后将只编译成一个Unicode应用程序用于Windows NT,而且用它来工作;Windows 95/98上Unicode需要支持应用程序只有以后才清楚。

所有这些,唯一例外的是32位COM。

32位世界中的COM

COM用两个操作系统进行了一个有趣的中断操作:它支持Unicode,而ANSI则被冷落。在某程度上,你不能说Unicode [ md ],即使它仅意味着支持MultiByteToWideChar和WideCharToMultiByte调用来转换它[ md ],你这样就不能对COM说。由于需要Unicode的32位Windows外壳的如此多的基本功能性,每个应用程序在Unicode中都必须至少做一点工作。32位COM( OLESTRs和BSTRs )的字符串始终是Unicode。 当然,通过处理转换函数和使用系统默认代码页( CP_ACP ),(唯一保证始终被支持的代码页)大多数应用程序都最低程度地支持它。

Windows 98

只有核心操作系统添加一些API调用到支持Unicode和ANSI的列表( 参见表6.2 )。

表6.2 用于添加Unicode支持的Windows 98 Win32 API调用

API调用

它要做的

lstrcat

追加一个字符串到另一个字符串

lstrcpy

复制一个字符串到缓冲器

但是,添加了许多新的界面,比如新的外壳扩展和集成浏览增强。这些都是COM界面,而且只支持Unicode。

Windows Millennium Edition (Windows千禧版)(Windows Me )

Windows Me并没有添加太多东西到等式。根据Microsoft,它是Win9x代码库的最后版本,但是,公平地说,该公司自从Windows 95的OSR2发布后已说过这些。 我提到的有关Windows 95和98适用于Windows Me的基本问题。

在Millennium加入Unicode支持的两个APIs集都是与Input Method Manager ( IMM ) API和Geographical Information Management ( Geo ) API有关的集(我将在第8章中进一步论述)。Geo被用于许多Windows Me组件,它们把地区信息映射到地理位置。

数据存储引擎

引擎本身(不论是SQL Server,Jet,FoxPro还是其他)起初都远离Unicode世界的,首选区域世界,在这里,单一代码页是所需的一切。虽然在很多情况下,Jet和SQL Server都可以进行它们自己的字符串规范化(关于该主题的更多信息参看第12章),它只用于性能原因,不支持相同文件中多代码页的概念。两个产品都是默认代码页的操作系统概念外的一个步。 你可以明确地选择使用任何OS支持的单一代码页,但仍被限于单一代码页。

然而,Jet和SQL Server的最新版本确是作为一种本地格式支持Unicode:在Jet中,一切都被移动到Unicode;在SQL Server中,你可以在ANSI和Unicode之间选择。其他引擎(比如FoxPro )在数据库引擎级上没有本地的Unicode支持。

数据存取法

不同于引擎本身,大多数数据存取法( ADO,OLE DB,DAO和RDO )都是只支持Unicode的COM组件。如果基础引擎不工作,而数据层必须说Unicode时,那么,数据层该做什么?简单地说,它们转换到和从Unicode转换(用默认系统代码页,或在FoxPro,Jet和SQL Server的情况下)它们选择的代码页。显然,这里有许多空间用于转换错误。

通过数据引擎移动到Unicode不仅没有了通常的转换错误(如果一切都保持在一种格式,则不会有什么错误转换!),而且也因为没有那么多的转换调用而提高了性能!第12章中有更多的关于这个区域为什么和在哪儿仍存在问题的信息。

Microsoft Office

受欢迎的Visual Basic的作者Bruce McKinney曾声称,"总有一天会有Unicode数据文件格式,但它可能不会发生在你的有生之年"这是怎样的错误!在Office的第一个三个32位版本上,所有主要的应用程序( Word,Excel,Access和PowerPoint )都移动到Unicode文件格式和Unicode可执行文件。甚至在文本文件中(它通常以ANSI格式保存),假定文件的代码页未被创建。

要给一个特殊例子,这本书是通过出版商使用Word 2000,来写,编辑和设计的。为什么?因为在很多情况下,我想支持多语言文本。我不想要出版商使用QuarkXpress,这个在出版界受欢迎的程序,因为它和我在其他程序中描述的一样有同样的限制。在我写的文章中(Quark , Inc.公司,毫无疑问是许多出版商的标准),我讨论这样程序包的限制已经好几年了,但是,对于这本书,重要的是能够均衡处理所有语言。通过移动到Word 2000,我能够包含有印地语文本比如 "आप यहाँ पर क्यों आना चाहते हैं?" 或泰语文本比如 "ทำไมคุณถึงต้องเข้ามาชมเว็บไซต์นี้?" 而每个文本不需要使用特殊的屏幕快照。关于这点,"用Satellite DLLs处理本地化资源。",我将在第10章中进一步论述。

因为好奇,用多种语言翻译先前的印地语和泰语文本见于表6.3 (也许是你需要的东西!)这些翻译用于许多在trigeminal.com网站上使用的地区。

表6.3 看,妈妈,不是位图!用各方式说相同的短语(炫耀我的出版商的能力!)

语言

短语

Hindi

आप यहाँ पर क्यों आना चाहते हैं?

Thai

ทำไมคุณถึงต้องเข้ามาชมเว็บไซต์นี้?

Bulgarian

или защо Ви трябва да идвате тук?

English

That is, why would you want to be here?

Simplified Chinese

即你来这儿的目的?

Traditional Chinese

即你為什麼要來這裡?

Turkish

örneğin; Neden bu sitede olmayı isteyeceginiz gibi?

German

d.h. warum lohnt es sich, hier zu sein?

French

i.e., pour quelles raisons dé sirez-vous explorer ce site?

Greek

δηλαδή, γιατί θέλετε να είστε εδώ;

Hebrew

כלוםר למה בכלל תרצה להיות כאן?

Dutch

d.w.z., waarom wilt u hier zijn?

Japanese

すなわち、あなたに必要なもの

Swedish

m.a.o. vad gör du här?

Portuguese

porque é que tu queres estar aqui?

Russian

возможно это то, что Вам надо

Spanish

ejemplo, ¿Porqué deseas estar aquí?

Italian

in altre parole, perché potreste voler visitare queste pagine?

Romanian

cu alte cuvinte, de ce sunteti aici?

Tamil

ஏன்நீ இஙுகு வரவேண்டு?

Windows 2000

Windows 2000,已知的,同时正在开发中的被称为NT5,不过是延续了NT3.1,3.51和4.0的传统。它从Windows 98获得崭新的外壳,并发布许多可用性意见。但是,从全球化观点上看,它更接近于遍及全世界的EXE模型:不再有仅用于专用语言的错误确定!支持MUI (多语言用户界面)证明了Windows 2000是一个世界性的操作系统。

可惜的是,某些应用程序大多数是著名的网络信息服务器,仍不离开ANSI,但这些应用程序无疑地已注意到了他们发展的方向:Unicode。

Windows CE

尚有另一个用于最小操作系统的模型:Windows CE是最接近于COM,它只支持API级的Unicode。然而,因为仅有有限的应用程序,它们仍支持纯Unicode,而且在较小的代码页转换表装置上只有极少量的空间,Windows CE应用程序在他们使用的代码页方面仍受限制。但是无疑,这是迈向正确方向的一步。

32位世界的Visual Basic

终于,根据这本书,这将是最重要的RAD工具:Visual Basic的32位版本!围绕着VB的Unicode支持存在着许多问题: