C头文件如何导入win32api函数?
Posted
技术标签:
【中文标题】C头文件如何导入win32api函数?【英文标题】:How C header files import win32api functions? 【发布时间】:2020-05-04 18:16:09 【问题描述】:简短的问题。
当我这样做时:
#include <windows.h>
CreateProcess(..)
头文件如何知道将我连接到正确的dll?
在这些头文件中是否有一个字典将每个win32api函数映射到相关的dll?
【问题讨论】:
【参考方案1】:标头仅包含 API 函数的声明,而不是它们的定义。通过链接适当的库可以找到定义。
例如,将以下内容复制到.c
文件中:
#include <Windows.h>
int main()
MessageBoxW(NULL, L"Hello World", L"", MB_OK);
return 0;
尝试在 Visual Studio 命令提示符上使用命令 cl example.c
编译它。您将看到错误消息:
example.obj : error LNK2019: unresolved external symbol __imp__MessageBoxW@16 referenced in function _main
注意编译本身实际上是成功的;抱怨缺少函数定义的是链接器。
如果您改为使用cl example.c /link user32.lib
编译它,链接器将找到MessageBox
的定义。你也可以link example.obj user32.lib
。
所以,回答您的问题:头文件不需要知道函数在哪些 DLL 中,因为项目需要提供适当的库引用。幸运的是,Windows API 函数的 MSDN 文档会告诉您该函数在哪个 DLL 中以及要链接哪个库。
【讨论】:
你在这里真的让我大开眼界。为什么在 gcc 中不是这样? cl.exe不能自动链接吗?另一个问题,据我了解,为了使用某个dll的功能,您需要相应的头文件,该头文件将包含所有函数签名和相关结构? @TrigosinDarom 默认情况下编译器/实现可能会隐式链接某些库,因此 GCC 可能不需要您指定 MSVC 确实需要的附加库,反之亦然。访问 DLL 的导出函数取决于您用于链接到 DLL 的方法。有关详细信息,请参阅this article on MSDN。 @TrigosinDarom 不同的 DLL 实现不同的功能,并提供单独的导入库文件来查找这些功能。您真的希望链接器了解系统上的每个 lib 文件吗?不,所以你必须告诉它你真正感兴趣的是哪个 lib 文件。因此,要静态地使用给定的 DLL 函数,您需要它的声明(头文件)和它的定义(lib 文件)。如果您要在运行时使用GetProcAddress()
动态导入 DLL 函数,那就完全不同了(不需要 lib 文件)。【参考方案2】:
简答:头文件不知道实现这些功能的 DLL。
通常,您会将这些 DLL 指定给链接器。
或者,您可以使用#pragma comment(lib, “XXX”)
为您执行此操作。
【讨论】:
如果你真的以某种方式指定.dll
(/DELAYLOAD
) 你需要GetModuleHandle
GetProcAddress
【参考方案3】:
头文件不知道也不关心函数的位置。头文件只是简单地声明函数。当您在代码中调用函数时,编译器只是在目标文件中发出引用,指出正在调用的函数。
编译器完成后,链接器将所有目标文件放在一起并更新函数引用以指向实际实现,无论它们是否位于 DLL 中。所以你必须为链接器而不是编译器提供必要的信息,它需要知道哪些目标文件和 DLL 导入文件来查看函数的位置。
大多数通用编译器/链接器工具链的项目生成文件通常会包含一组默认的 DLL 导入文件,供链接器查看,例如 kernel32.lib
(可以从中解析 CreateProcess(A|W)
)、user32.lib
等.
【讨论】:
【参考方案4】:为了静态链接到 DLL(是的,静态链接),您链接到声明要导入的函数的 .lib 库。
VS 编译器支持#pragma,它告诉链接器使用特定的.lib 文件(使用特定的路径解析规则)。这样的#pragma 存在于 Windows 头文件中。
现在在加载时,系统使用特定的路径解析规则查找在 .lib 文件中命名的 DLL 文件,并将导入的原型与 DLL 导出的函数进行匹配。
因此,将函数映射到 DLL 的字典实际上是由每个 DLL 的头文件引用的 .lib 文件组成的。
【讨论】:
以上是关于C头文件如何导入win32api函数?的主要内容,如果未能解决你的问题,请参考以下文章