我使用Loadlibrary
和Getprocaddress
来链接一些WinApis以进行运行时链接。它按预期正常工作。
但是对于一些Apis我只使用-ldllname
作为编译器选项。相同的选项会为某些API提供链接器错误,并且需要加载dll。
这有什么特别的区别,那就是某些特定的API需要运行时链接,其他API将与-ldllname
选项一起使用?如何区分这类API?
更新:我观察到的是支持UNICODE和ANSI的API,即: 以“W”和“A”为后缀的API将通过静态解析 连接自己?我对么?如果我错了,请纠正我!
为什么某些API需要运行时链接,而其他API则需要使用Static解析 链接自己(-l选项)?有什么理由吗?
答案 0 :(得分:1)
这基本上就是你所描述的。我会在这里跳过非Windows,但它基本上是相似的。)
所以,有两种不同的情况:
编译时间(静态)链接:代码包括所有函数,类等的声明,但没有实体。您必须在编译时提供正确的库文件(例如通过-ldllname
):
void sayHello(void); // the declaration might be a bit more complicated, e.g. adding a calling convention or dllimport/dllexport, etc.
运行时(动态)链接:代码包括基本上加载库和检索地址的最小函数体(通过您命名的函数):
HMODULE lib = LoadLibrary("hello.dll"); // loading happening somewhere once
void sayHello(void) {
myfnproc call = GetProcAddress(lib, "sayHello");
call(); // actual call
}
FreeLibrary(lib); // unloading happening somewhere else
虽然运行时方法更复杂,但它有一个很大的优点:您可以处理丢失的库。例如。如果用户缺少某些库,您可以告诉他在哪里下载(甚至自己下载),并且可以轻松替换链接代码(例如插件功能)。使用静态链接你运气不好:如果缺少依赖项,程序将无法运行。
答案 1 :(得分:1)
我使用了Loadlibrary
这将是对DLL进行隐式依赖的示例。 LoadLibrary是由kernel ap.dll(Windows api DLL)导出的函数。它实际上存在两个版本,LoadLibraryA和LoadLibraryW。分别是非Unicode和Unicode版本的函数。您将获得其中一个,具体取决于编译时是否具有UNICODE宏#defined。
这与动态链接导出和GetProcAddress完全相反,您必须告诉链接器您的程序依赖于带有-l
选项的kernel32。并且在运行时,DLL会在您自己的代码开始运行之前自动加载。
对操作系统DLL具有隐式依赖是很正常的。并且不可避免地,你永远不能动态地链接kernel32.dll,这将是一个鸡与蛋的问题。