Microsoft 游戏开发工具包中的 UTF-8 支持

本话题概述了 Microsoft 游戏开发工具包(GDK)中的 UTF-8 支持。

概述

UTF-8 是用于国际化的通用代码页,它通过使用 1–4 字节变量宽度编码来支持所有 Unicode 代码点。 它在网上广泛使用,一些竞争性平台(如基于 Unix 的系统)默认情况下在 UTF-8 下运行。 通过在 UTF-8 下运行,你只需最小的工作量和测试负担,就可确保国际方案的最大兼容性和数据互换。

Windows 本身在 UTF-16(或 WCHAR)下运行,它需要使用 MultiByteToWideCharWideCharToMultiByte 进行代码页转换。 这是 Windows 在编写针对多个平台的代码时的特有负担。 更大的挑战在于 Windows 的 ANSI 代码页概念,它在不同地区和不同用户配置中是不同的,错误地依赖它时可导致严重的不一致行为。

Microsoft 游戏开发工具包 (GDK) 和 Windows 正在努力推动支持 UTF-8 的工作,以消除 Windows 在针对多个平台和网站以及与它们互换时的代码转换问题。 这还将减少应用和游戏中的国际化问题,并且简化调试它们所需的测试矩阵。

-A 与 -W API

Win32 API 通常提供 -A 和 -W 变体。 -A 变体采用在系统上配置的 ANSI 代码页,用于处理 char*。 -W 变体在 UTF-16 下运行,用于处理 WCHAR

现在,-A API 已过时,因为 Windows 用了数十年时间来推广“Unicode”-W 变体。 不过,在最近的版本中,Windows 使用了 ANSI 代码页和 -A API,以便在新版 SKU 中引入 UTF-8 支持。 如果将 ANSI 代码页配置为 UTF-8,-A API 将在 UTF-8 下运行。 此模型的优势是支持使用 -A API 生成的现有代码,无需进行任何代码更改。

对于 Microsoft 游戏开发工具包 (GDK),UTF-8 是主机上默认的唯一的 ANSI 代码页。 主机上的 -A API 始终在 UTF-8 下运行,并且它是推荐调用的一组 API,用于实现最大程度的可移植性。 还提供 -W API 以实现源代码与现有 Windows 代码的兼容(可能来自被前推的游戏的现有 Windows 电脑版本)。

主机代码页

UTF-8 是主机上默认的唯一代码页,因此建议使用 -A API 来充分利用这一点。

Windows 电脑代码页

为了兼容,Windows 电脑上的默认 ANSI 代码页仍采用旧版(因区域和用户配置而异)。 这会增加面向 Windows 电脑和主机的用户的负担,他们必须考虑代码页转换以及调试时所需的测试矩阵问题。

为了缓解此问题,Windows 引入了一种强制进程选择 UTF-8 作为进程代码页的方式(无论系统代码页是什么)。 这可以通过使用 appxmanifest(针对打包的应用)或 fusion manifest(针对设置了 ActiveCodePage 属性的非打包应用)来实现。 有关详细信息,请参阅以下代码示例。

注意

此功能仅适用于 Windows 19H1 或更高版本的内部版本。 你可以声明此属性,并面向/运行早期的 Windows 内部版本。 但必须按以往处理旧版代码页的检测和转换。 目标版本为 19H1 或更高版本时,进程代码页将始终为 UTF-8。

appxmanifest(已打包)

<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="https://schemas.microsoft.com/appx/manifest/foundation/windows10"
         ...
         xmlns:uap7="https://schemas.microsoft.com/appx/manifest/uap/windows10/7"
         xmlns:uap8="https://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 manifest(未打包)

<?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="https://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
    </windowsSettings>
  </application>
</assembly>

Note: You can add a manifest to an existing executable via the command line with mt.exe -manifest <MANIFEST> -outputresource:<EXE>;#1

MultiByteToWideChar/WideCharToMultiByte

使用 MultiByteToWideCharWideCharToMultiByte 函数可以在 UTF-8 和 UTF-16 (WCHAR)(以及其他代码页)之间转换。 如果旧版 Win32 API 只能理解 WCHAR,这将特别有用。 使用这些函数可以将 UTF-8 输入转换为 WCHAR 以传入 -W API,然后根据需要将任何结果转换回去。

在 Microsoft 游戏开发工具包 (GDK) 中使用这些函数时,根据文档将 CodePage CP_UTF8dwFlags(为 0 或 MB_ERR_INVALID_CHARS)一起使用。 否则你将收到错误 ERROR_INVALID_FLAGS

注意

在主机上, CP_ACP 始终与 CP_UTF8相同。 如果显式切换到 CP_UTF8 不易实现,可以继续使用现有代码。 在 Windows 电脑上,仅当在 19H1+ 上运行且将上述 ActiveCodePage 属性设置为 UTF-8 时,CP_ACP 才等于 CP_UTF8。 否则,它采用旧的系统代码页。 今后,最佳做法是显式使用 CP_UTF8

高级 UTF-8 的 ICU 和全球化支持

ICU 是 Unicode 库的国际组件。 它是开源、跨平台的国际化库,该库通过 C/C++ 接口支持高级 UTF-8 操作(例如排序规则、规范化和词汇切分)。

自版本 64.1 起,此库已针对 Microsoft 游戏开发工具包 (GDK) 进行了更新。 要使用它,请生成该库(请参阅自述文件中的 #HowToBuild),然后使用你的游戏将该库打包(请参阅自述文件中的 #HowToPackage)。

注意

自述文件不直接在 GitHub 上呈现。 如果你通过将存储库在本地克隆来生成,可以在本地查看它。

支持早期版本的 Windows

如果您针对的 Windows 版本低于 19H1(包括 Windows 7),则必须处理旧代码页检测和转换问题。

我们正在探索提供一个静态帮助程序库,该库提供 Win32 API 的 -Utf8 变体,无需执行代码页检测和转换。 这将提供面向主机和 Windows 电脑(向下涵盖到 Windows 7)的通用编程面。

另请参阅

系统