Windows API是什么?它是如何工作的?

4

看起来我们可以通过包含所需的头文件来自由使用Windows API。然而,我无法理解这是如何可能的,因为头文件没有函数定义,只有声明,这应该被认为是一个错误,因为它缺少实现细节。编译器是如何定位实现细节并将其映射到内存中的?


1
Windows已经内置了所有的功能,并为其提供了API。其中包括连接到该功能的库。头文件仅提供这些函数的定义。实现是由Windows通过DLLs提供的。找一本解释这些基础知识的教程或书可能是个好主意。 - Ken White
@KenWhite 你的意思是说DLL会自动被考虑进去,以至于在链接过程中编译器可以得到所有需要的东西?为了让这有意义,头文件必须确保编译器知道需要哪个DLL。这是如何实现的呢? - user3647351
1
不,我的意思是头文件提供了声明,导入库的包含提供了与内置DLL功能的链接。再次强调,找一个教程可能是个好主意。使用DLL和导入库是使用Windows API的基本信息,并且可以在许多地方找到相关资料。 - Ken White
2个回答

6
Windows API是在安装Windows时安装的DLL中实现的。这些DLL位于系统目录中,名称类似于User32.dll、Kernel32.dll等。
正如您正确指出的那样,与您的编译器一起提供的Windows API头文件仅包含声明。当您的C程序调用其中一个函数(或任何其他在头文件中标识但未实际编译到项目中的函数)时,编译器在生成的对象文件中放置了一条记录,大致上表示“我需要调用一个名为GetWindowRect(或任何你所调用的函数名称)的函数”。
连接器是实际解析名称的工具。如果查看连接器选项,您会发现它链接了一些库,如User32.lib、Kernel32.lib等。这些库包含编译的函数,它们只是一些小小的存根代码——导致相应的DLL被加载,然后调用DLL中的函数。
这比那稍微复杂一点,但这是大体的想法。简单来说:
1. 您包括Windows API头文件。 2. 您的代码调用了其中一个或多个在这些头文件中声明的Windows API函数。 3. 编译器为链接器解析这些API函数调用做了一个注记。 4. 链接器通过在链接器命令行指定的库中找到存根函数来解析这些调用。 5. 在运行时,对其中一个函数的调用导致相应的DLL被加载,然后控制权分支到DLL中的函数。

我有一个关于你的回答的问题。你说在.lib中编译的代码会导致DLL被加载。然而,我不知道为什么需要DLL。理论上,我认为库足以提供实现细节,不是吗?是否有任何理由将二进制代码包装两次? - user3647351
1
@user3647351:Windows API函数的实现细节包含在DLL中。.lib文件中的函数提供了您编译代码和位于DLL中的已编译代码之间的桥梁。 - Jim Mischel
DLL被用于实现可以在多个进程中重复使用,且更新只需安装一次。@导入.lib文件中没有函数。它们包含对实际DLL函数的引用。链接器将这些引用放入最终可执行文件的IMPORTS表中。当可执行文件在运行时加载到内存中时,操作系统加载程序会使用实际DLL函数的地址来修补IMPORTS表。当您的代码调用静态链接的Win32 API函数时,它会直接跳转到DLL函数。 - Remy Lebeau
1
阅读《Win32可移植可执行文件格式深入探究,第1部分》和《第2部分》。 - Remy Lebeau
1
请注意,有两种.lib文件;一种是桥接您的应用程序和DLL的文件,另一种是包含实际代码的静态库。许多库(包括C运行时库)都提供这两种类型,并且您可以选择使用哪种类型。Windows API不提供静态库,因为使用静态库意味着您不仅需要为每个新版本的Windows重新构建应用程序,还需要在Microsoft发布Windows更新时进行重建。 - Harry Johnston

2

它与任何其他库(例如C的stdlib)的工作方式相同-您的程序只需要“知道”函数的原型(因此也知道底层符号名称)。编译后进行链接-这是缺失的符号(函数定义)与正确库“链接”的时候。


然而,当使用Windows API时,我们从未明确编译支持头文件中的函数声明所需的源文件。我的意思是,即使我们没有适当的源文件,链接为什么会起作用? - user3647351
1
根据您使用的链接器,如果您不必添加任何特殊参数并且“它只是工作”,那么链接器会自动为您链接某些.lib文件。 - Kelm

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