Windows API 集合

重要

本主题中的信息适用于所有版本的 Windows 10 及更高版本。 我们在这里将这些版本称为“Windows”,并在必要时指出任何例外情况。

所有版本的 Windows 都共享称为核心 OS 的操作系统 (OS) 组件(在某些上下文中,此通用基础也称为 OneCore)。 在核心 OS 组件中,Win32 API 组织为称为 API 集的功能组。

API 集的目的是在实现给定 Win32 API 的主机 DLL 与 API 所属的功能协定之间提供体系结构分隔。 API 集在实现和协定之间提供的分离为开发人员提供了许多工程优势。 具体而言,在代码中使用 API 集可以提高与 Windows 设备的兼容性。

API 集合专门适用于以下场景:

  • 尽管电脑上支持 Win32 API 的完整广度,但其他Windows设备(如 HoloLens、XBOX 和其他设备)仅提供了 Win32 API 的子集。 API 集名称为你提供了一个稳定的查询依据,因此你的应用可以在运行时判断当前设备上某项功能是否可用。 查询本身由 IsApiSetImplemented 函数执行。

  • 某些 Win32 API 实现存在于不同 Windows 设备上具有不同名称的 DLL 中。 在检测 API 可用性和对 API 进行延迟加载时,使用 API 集名称而不是 DLL 名称,可以确保无论 API 实际在哪里实现,都能正确定位到其实现。

有关详细信息,请参阅 API 集加载程序操作和检测 API 集可用性。

API 集和 DLL 是否相同?

否 - API 集名称标识 协定,而不是文件。 在运行时,加载程序通过当前设备上的 API 集架构方案解析该契约,并将该引用路由到承载该实现的 DLL。 这是一种实现隐藏技术,作为调用者,你不必确切地知道哪个模块托管信息。

该技术允许在不同 Windows 版本和版次上重构模块(拆分、合并、重命名等)。 你的应用程序仍然能够链接,并且在运行时仍会路由到正确的代码。

那么,为什么 API 集的名称中具有 .dll? 原因在于 DLL 加载程序的实现方式。 加载器是操作系统中负责加载 DLL 和/或解析对 DLL 的引用的部分,它通过导入表中按文件名写法拼写的模块名来确定要加载的内容。 API 集名称遵循相同的命名约定,以便它们能够放在同一位置。

加载程序可识别以 api- 或 ext- 开头的名称,并将其路由到 API 集运行时;它是加载程序的一个扩展,通过架构解析协定。 从那一点起,该名称由 API 集命名规则(而不是文件名)分析,因此 .dll 后缀不是正在解析的协定名称的一部分。

可以将 API 集名称传递给 LoadLibrary,或将其用作延迟加载目标。 当当前设备上的架构将协定映射到可用主机时,该操作会成功;电脑上的任何位置都不一定存在具有该名称的实际文件。 如果当前设备上未映射该契约,则直接调用 LoadLibrary 会失败。 延迟加载的引用表现不同:进程仍然会加载,而缺失会在稍后调用 API 时才显现出来。

无论哪种方式,成功的链接或加载本身都不是证明实现存在的证据。 若要确定这一点,请参阅 “检测 API 集可用性”。

链接伞型库

为了更轻松地将代码限制为核心 OS 中支持的 Win32 API,我们提供了一系列伞型库。 使用伞式库可以链接单个库,而不是为调用的每个 API 标识单个导入库。

有关更多详细信息,并选择与目标匹配的伞库,请参阅Windows伞库。

API 集协定名称

API 集通过协定名称进行标识,该名称遵循库加载器可识别的约定。

所有合约名称均遵循以下命名约定:

  • 名称以字符串 api 或 ext-开头。
  • 名称的正文可以是字母数字字符,也可以是短划线 (-)。 波浪号(~)仅作为组名称前的分隔符显示。
  • 此名称不区分大小写。

两种形式的协定名称正在使用中,你可能会遇到任一形式。

带版本号的协定名称以序列l<n<->n<->n>结尾,其中n由十进制数字组成,例如ext-ms-win-core-samplefeature-l1-1-0。 末尾的数字用于标识该契约的某个特定版本,而这种形式的名称应被视为该版本的不可变标识符。

协定别名不带有任何版本,例如api-win-core-samplefeature。 它标识协定本身,而不是它的一个版本。 当协定将其单独可用的功能组织到命名组中时,通过将组名称追加到协定别名(用波形符分隔)来寻址组。 api-win-core-samplefeature~AdvancedOperations

samplefeature此处使用的名称是虚构Windows组件的说明名称。

api- 和 ext- 前缀

前缀是命名约定。 它最初旨在区分存在于每个符合条件的版本中的契约(api-)与可能不存在的契约(ext-)。 这种区别未一致应用,并且合同的角色可能会随时间而变化,而无需重命名合同。

加载程序没有为前缀分配任何意义;它按相同的规则解析 api 和ext- 名称。 不要从前缀推断可用性。 请改为查询它 - 请参阅 “检测 API 集可用性”。

使用合同名称

两类不同的操作都接受一个契约名称。

加载器操作(例如 LoadLibrary 或 P/Invoke)会在通常填写 DLL 模块名称的位置使用协定名称。 追加 .dll 项在该上下文中是常规的,但它不是 API 集名称解析所必需的,不是协定名称的一部分。 使用协定名称而不是物理 DLL 模块名称,以确保无论该 API 在当前设备上的何处实际实现,都能正确路由到相应的实现。 磁盘上不需要有具有该协定名称的文件。

可用性查询示例 通常省略 .dll 后缀,并使用与 API 的寻址方式匹配的表单:

API 接口面 查询表单 Example
命名组 <contract>~<group> api-win-core-samplefeature~AdvancedOperations
默认组 不带 ~Default 的协定别名 api-win-core-samplefeature
版本化契约 完整的带版本号的契约名称 ext-ms-win-core-samplefeature-l1-1-0

组名称不能与带版本号的协定名称结合使用。

标识 Win32 API 的 API 集

若要确定特定 Win32 API 是否属于 API 集,请查看 API 参考文档中的要求表。 如果 API 属于 API 集,则文章中的要求表列出了 API 集名称和首次引入 API 集的 Windows 版本。 有关属于 API 集的 API 的示例,请参阅以下文章:

如果 API 的标头提供 Is<APIName>Present 帮助程序函数,在测试可用性时首选该帮助程序。 它已包含承载 API 的 API 集或组的正确名称。 有关详细信息,请参阅 检测 API 集可用性。

本节内容