在 Windows 应用中使用 UTF-8 代码页

使用 UTF-8 字符编码在 Web 应用和其他基于 *nix 的平台(Unix、Linux 和变体)之间实现最佳兼容性,最大程度地减少本地化 bug,并减少测试开销。

UTF-8 是国际化的通用代码页,可以编码整个 Unicode 字符集。 它在 Web 上广泛使用,并且是基于 *nix 的平台的默认代码页。

将进程代码页设置为 UTF-8

从 Windows 版本 1903(2019 年 5 月更新)起,可以使用打包应用的 appxmanifest 中的 ActiveCodePage 属性,或使用未打包应用的合成清单来强制进程使用 UTF-8 作为进程代码页。

注意

GDI 目前不支持为每个进程设置 ActiveCodePage 属性。 相反,GDI 默认为活动系统代码页。 若要将应用配置为通过 GDI 呈现 UTF-8 文本,请转到 Windows“设置”>“时间和语言”>“语言和区域”>“管理语言设置”>“更改系统区域设置”,然后选中“Beta:使用 Unicode UTF-8 获得全球语言支持”。 然后重新启动电脑,使更改生效。

你可以声明 ActiveCodePage 属性,并以早期 Windows 版本为目标或在这些版本上运行,但必须和往常一样处理旧代码页检测和转换。 使用最小目标版本 Windows 1903 版,进程代码页将始终为 UTF-8,因此可以避免使用旧代码页检测和转换。

注意

一个编码字符采用 1 到 4 个字节。 UTF-8 编码支持较长的字节序列(最多 6 个字节),但 Unicode 6.0 的最大码位 (U+10FFFF) 只需要 4 个字节。

示例

打包应用的 Appx 清单:

<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
         ...
         xmlns:uap7="http://schemas.microsoft.com/appx/manifest/uap/windows10/7"
         xmlns:uap8="http://schemas.microsoft.com/appx/manifest/uap/windows10/8"
         ...
         IgnorableNamespaces="... uap7 uap8 ...">

  <Applications>
    <Application ...>
      <uap7:Properties>
        <uap8:ActiveCodePage>UTF-8</uap8:ActiveCodePage>
      </uap7:Properties>
    </Application>
  </Applications>
</Package>

未打包 Win32 应用的合成清单:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity type="win32" name="..." version="6.0.0.0"/>
  <application>
    <windowsSettings>
      <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
    </windowsSettings>
  </application>
</assembly>

注意

使用 mt.exe -manifest <MANIFEST> -outputresource:<EXE>;#1 从命令行向现有可执行文件添加清单。

-A 与 -W API

Win32 API 通常同时支持 -A 和 -W 变体。

-A 变体识别系统上配置的 ANSI 代码页并支持 char*,而 -W 变体在 UTF-16 中运行并支持 WCHAR

到目前为止,Windows 一直强调“Unicode”-W 变体,而不是 -A API。 但是,最近发布的版本使用了 ANSI 代码页和 -A API 作为将 UTF-8 支持引入应用的一种方法。 如果 ANSI 代码页配置了 UTF-8,则 -A API 通常在 UTF-8 中运行。 此模型的优点是,支持使用 -A API 生成的现有代码,而无需进行任何代码更改。

代码页转换

由于 Windows 在 UTF-16 (WCHAR) 中以本机方式运行,因此你可能需要将 UTF-8 数据转换为 UTF-16(反之亦然),以便与 Windows API 进行互操作。

MultiByteToWideCharWideCharToMultiByte 使你可以在 UTF-8 和 UTF-16 (WCHAR)(以及其他代码页)之间进行转换。 如果旧版 Win32 API 只能理解 WCHAR,这将特别有用。 这些函数允许你将 UTF-8 输入转换为 WCHAR,以传递到 -W API,然后在必要时将结果转换回来。

使用这些函数时,请使用 dwFlags0MB_ERR_INVALID_CHARS,并将 CodePage 设置为 CP_UTF8,否则会出现 ERROR_INVALID_FLAGS

注意

仅当在 Windows 版本 1903(2019 年 5 月更新)或更高版本上运行,且上述“ActiveCodePage”属性设置为“UTF-8”时,CP_ACP 才等于 CP_UTF8。 否则,它采用旧的系统代码页。 建议显式使用 CP_UTF8