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 集名称提供一种查询机制,可以清楚地检测某个 API 在任何给定设备上是否可用。

  • 某些 Win32 API 实现存在于不同 Windows 设备上具有不同名称的 DLL 中。 在检测 API 可用性和延迟加载 API 时,使用 API 集名称而不是 DLL 名称,无论 API 实际实现在哪里,都可以为实现提供正确的路径。

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

API 集和 dll 是一回事吗?

不是 - API 集名称是物理 .dll 文件的虚拟别名。 这是一种实现隐藏技术,作为调用者,你不必确切地知道哪个模块托管信息。

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

那么,为什么 API 集的名称中具有 .dll? 原因在于 DLL 加载程序的实现方式。 加载程序是操作系统的一部分,用于加载 DLL 和/或解析对 DLL 的引用。 在前端,加载程序要求传递给 LoadLibrary 的任何字符串都以“.dll”终止。 但在前端之后,加载程序可以去掉后缀,并使用结果字符串查询 API 集数据库。

LoadLibrary(和延迟加载)成功地使用 API 集名称(其中带有“.dll”);但在电脑上的任何地方不一定有该名称的实际文件。

链接伞型库

为了更轻松地将代码限制为核心 OS 中支持的 Win32 API,我们提供了一系列伞型库。 例如,名为 OneCore.lib 的伞型库为所有 Windows 设备通用的 Win32 API 子集提供导出。

有关更多详细信息,请参阅 Windows 伞型库

API 集协定名称

API 集合由一个强协定名称标识,该名称遵循库加载程序识别的这些标准约定。

  • 名称必须以字符串 api-ext- 开头。
    • api- 开头的名称表示保证在所有 Windows 版本上都存在的 API。
    • ext- 开头的名称表示并非所有 Windows 版本都存在的 API。
  • 名称必须以序列 l<n>-<n>-<n> 结尾,其中 n 由十进制数字组成。
  • 名称的正文可以是字母数字字符,也可以是短划线 (-)。
  • 此名称不区分大小写。

以下是 API 集协定名称的一些示例:

  • api-ms-win-core-ums-l1-1-0
  • ext-ms-win-com-ole32-l1-1-5
  • ext-ms-win-ntuser-window-l1-1-0
  • ext-ms-win-ntuser-window-l1-1-1

可以在加载程序操作的上下文中使用 API 集名称,如 LoadLibraryP/Invoke,而不是 DLL 模块名称,以确保无论 API 在当前设备上实际实现的位置如何,都可以正确地路由到实现。 但是,执行此操作时,必须将字符串 .dll 附加在约定名称的末尾。 这是加载程序正常运行的要求,实际上不被视为协定名称的一部分。 尽管在这种情况下,协定名称看起来与 DLL 名称相似,但它们与 DLL 模块名称有根本不同,并且不会直接引用磁盘上的文件。

除了在加载程序操作中追加字符串 .dll 外,API 集协定名称应被视为与特定协定版本相对应的不可变标识符。

标识 Win32 API 的 API 集

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

本节内容