哪些Windows版本不支持Unicode API调用?

3
C语言的Win32 API有许多函数都有双重版本,以支持Unicode(UTF-16)字符串和旧的8位代码页字符串。API还定义了一些通用函数和类型来在一定程度上抽象出这些差异,并允许从同一代码库中编译这两个版本。
微软建议始终使用通用函数(请参见函数原型约定),以便可以编译两个版本。但是我的问题是,我们需要支持哪些版本的Windows操作系统,通过8位字符串API呢?如果是Windows 95的话,它已经不是我的首要关注点了 : )。如果通用函数只是为了支持极度陈旧的情况,似乎直接使用UTF-16调用会更容易和更清晰一些。

5
在目前阶段,泛型主要用于节省每个函数输入一个额外字符的打字工作。CreateWindowCreateWindowW 更易读、易记,而且在所有的书籍、教程和示例中都是这样。 - Igor Tandetnik
对于这些踩的原因我很好奇 - 我不知道是哪个版本引入了UTF-16调用,而且我认为这是一个合理的问题,可能对其他人有用,因为微软在他们的文档中没有解释它。 - QuadrupleA
@IgorTandetnik 对我来说更相关的一点是:输入没有 W 的版本,但不必费心测试编译是否针对 8 位 API。 - o11c
1个回答

11

我将为您解释Windows支持的三种字符串文本编码类型:

维基百科有一篇详细的文章:https://en.wikipedia.org/wiki/Unicode_in_Microsoft_Windows

  1. "ANSI" = 8位编码 - 在C语言中用char表示。尽管名称为“ANSI”,但它不是ASCII编码。不一定是特定的ANSI编码或ASCII编码,而是当前区域设置/代码页所使用的编码。
  2. "MBCS" = 多字节字符集编码 - 在C语言中用char表示(其中每个字节都是一个char)。支持的代码页列表有限,重要的是不包括UTF-8编码。请参阅此QA:Windows上MBCS和UTF-8之间的区别。MBCS已经在现代Windows中被弃用,不应在新项目中使用。
  3. "Unicode" = UTF-16(或NT3 / NT4中的UCS-2) - 在C语言中用wchar_t表示,其长度为16位。
    • 在UCS-2下,只能使用由代码点0x0000 - 0xFFFF表示的字符。不能使用超出此范围的字符。
    • 在UTF-16(Windows 2000及更高版本)中,0xFFFF之后的代码点由2个或多个wchar_t值(4个或更多字节)表示,称为代理对,这意味着字符串的二进制长度(以字节为单位)不一定与字符串的元素长度(在size_t中)成比例,后者也不一定是打印字符数。
    • 还要考虑像连字和变音符号这样的东西也会破坏编程代码经常做出的字节/元素/打印字符计数等价性假设。
    • 例如,请考虑此代码点字符串:U+0061, U+0928, U+093F, U+4E9C, U+10083
      • 在UTF-16大端字节中,这是00 61 09 28 09 3F 4E 9C D8 00 DC 83
      • 这是12个字节
      • ...这是6个wchar_t元素
      • ...但表示5个字符
      • ...由于第2个和第3个字符之间的连字,因此呈现为4个打印字符。

Windows 3.x

Windows 3.x实现了16位的Windows API,严格为8位。如果不是运行en-US版本,则使用当前默认的语言环境和代码页设置。它不支持宽字符,但可能支持某种MBCS。

Windows 3.x的“Win32 Subset”(“Win32s”)附加组件添加了一些Win32函数到Windows 3.x中,包括AW函数,但W函数被存根化并在调用时返回失败代码-与Windows 95上的“完整”Win32看到的行为相同。

Windows 95, 98, Me:

在Windows 9x(95、98、Me)上实现的Win32不支持UTF-16,仅支持“ANSI”或“MBCS”字符串。

重要提示是,与Win32s一样,在Windows 9x上也存在"宽字符"函数,但它们被存根化,调用时将返回失败代码-除了少量资源、命令行和MessageBox相关的函数之外,这些函数确实处理UCS-2字符字符串(例如MessageBoxExW)。
支持非拉丁字符集需要使用代码页和神秘的“多字节”编码选项(请记住,它们不支持UTF-8 - 除了MultiByteToWideCharWideCharToMultiByte - 可用于将UTF-8转换为UTF-16以便与Win32 API一起使用)。
在2001年,微软发布了一个名为Microsoft Layer for Unicode (MSLU)的Windows 9x插件,它将W函数从失败存根转换为代理程序,将字符串转换回8位格式,然后调用A函数,因此明确使用W函数的程序可以在Windows 9x上运行。
Windows NT从最初的NT 3.1版本(没有3.0版本)开始就使用接受wchar_t类型参数的W函数。字符串使用UCS-2(NT3、NT4)或UTF-16(NT5及更高版本)进行编码。微软产品和文档通常使用“Unicode”作为UTF-16或UCS-2的简称。Win32不支持UTF-8(除了MultiByteToWideChar和WideCharToMultiByte),因此这种模糊性仅勉强通过。
Windows CE
"Windows CE 1.0从一开始就支持UTF-16,其支持水平与Windows NT家族相当。我不知道CE何时或是否支持UCS-2而非UTF-16,或者它是否从一开始就是UTF-16。"
"简而言之:"
OS                          ANSI | MBCS | UTF-16 ("Unicode")
-----------------------------------------------------------------------------
Windows 3.x (Stock)         Yes  |   ?  | No
Windows 3.x (Win32s)        Yes  |   ?  | Stubbed, always fails (a)
Windows 95, 98, ME          Yes  | Yes  | Limited support (b) otherwise fails
Windows 95, 98, ME (MSLU)   Yes  | Yes  | Yes, runtime thunked to ANSI (c)

Windows NT 3.x, NT 4.x      Yes  | Yes  | As UCS-2 instead of UTF-16 (d)
Windows 2000 and later      Yes  | Yes  | Yes

Windows CE 1.0 and later    Yes  |   ?  | Yes (e)

(a): https://msdn.microsoft.com/zh-cn/library/cc194796.aspx (b): https://support.microsoft.com/zh-cn/kb/210341 (c): https://zh.wikipedia.org/wiki/Microsoft_Unicode_层 (d): https://zh.wikipedia.org/wiki/Unicode在Microsoft_Windows中的实现 (e): http://www.hpcfactor.com/support/windowsce/wce1.asp 结论: 只需使用“Unicode”:即使你编写针对 Windows 9x 的软件,只要使用 Unicode 层,它仍然可以运行(尽管像 Unicode 文件名和窗口标题之类的东西可能有些奇怪)。你的代码也可以移植到 Windows CE(我惊讶地看到 Windows CE 从一开始就支持 UTF-16)。

两个小点。1)确实存在处理UTF-8的API函数 - 其中两个是:MultiByteToWideCharWideCharToMultiByte。2)“Unicode代码点”和“打印字符”的对应关系相当松散 - 即使没有代理对,也有像组合变音符和连字等东西。您所称的“字符长度”指标 - 显然是Unicode代码点的数量 - 在实践中并不是很有用。另一方面,UTF-16表示中的16位单位数是有用的,至少可以用于内存分配。 - Igor Tandetnik
@IgorTandetnik 感谢您的反馈,我已经详细阐述了我的答案。 - Dai
Windows CE于1996年发布,与UTF-16在同一年发布。 - phuclv
并非所有的W函数在Win9x/ME上都会失败。有一些W函数是本地实现并且可以正常工作的,例如MessageBoxW()(请参阅Windows 95和Windows 98中的Unicode支持获取完整列表)。此外,不要忘记还有Microsoft Unicode层库,它为许多常用的W函数添加了对Win9x/ME的支持。 - Remy Lebeau
@RemyLebeau 谢谢你提供的信息,我已经修改了我的答案。 - Dai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接