DLL 引用与 DLL 隐式链接

DLL reference vs DLL Implicit Linking

我最近刚刚了解到如何通过隐式链接或显式链接将可执行文件链接到 DLL;但是,它让我对项目(或 DLL)引用感到困惑。

既然可以将隐式链接添加为 Visual Studio 中的引用,为什么还要使用隐式链接?隐式链接要求您通过在头文件中标记 __declspec(dllimport) 来导出函数,以便使用它。另一方面,如果您添加一个项目库作为引用,您可以只使用 #include "header.h" 并使用 DLL 中的函数。 this feature 有什么意义?

您发布的 link 中关于隐式链接的重要段落是:

[...] where the operating system loads the DLL at the same time as the executable that uses it.

所以您的 dll 必须存在才能启动应用程序,无论您是否使用它。假设您有一个使用 dlls 作为其插件系统的可扩展应用程序,您需要事先知道将会有哪些插件,并且需要它们的所有库。

或者你只是显式检查任何插件dlls并在运行时导入它们。

显式链接的更多示例:

  • 基于当前系统的实现选择
  • 根据用户输入选择实现
  • 如果预期的 dll 不存在(无 DirectX,使用 OpenGL),则采用故障保护机制
  • ...

另请查看 this thread about implicit vs explicit linking

关于术语的一些说明:

  • '#include',包含由编译器在编译时发生,不需要完全定义 类 和函数。这意味着如果您缺少一个库,您的编译器将不会抛出错误
  • 链接发生在编译之后,由链接器完成。此处链接器检查是否定义了所有函数和 类(符号)。
  • 加载库(隐式或显式)发生在运行时。上面已经提到了详细信息。

你有点糊涂了

  • 隐式链接:需要 .lib 文件,其中指定了所有导出的符号。这是将 lib 和 dll 文件放入搜索路径(工作目录或您必须在链接器选项中指定的自定义路径)中的常用方法。当可执行文件调用函数或引用该 dll 中的任何符号时,它将加载 dll。

  • 显式链接:在某些情况下,您必须在运行时加载 dll。在这种情况下,可执行文件需要使用 loadlibrary 或类似的 API 从特定路径加载库。

在你的情况下,你应该选择第一个选项。

Why use implicit linking when you can add it as a reference in Visual Studio?

Visual studio 确实隐含 linking 在引擎盖下,当你引用它时,据我所知。我认为您对这两种方式有点困惑。让我清楚地单独解释一下:

隐式链接:

在这里,您有一组翻译单元,它们被编译到一个共享库中(.dll on windows)。一个 .lib 文件随之生成。 .lib 文件包含函数指针声明,这些函数的定义位于 .dll 中。当您 link 那个 .lib 文件时,应用程序将自动查看其路径中的 .dll。如果找到,它将加载它。加载 .dll 后,您可以使用 .dll 中的任何函数,就像您 link 使用 .lib 一样。请注意,标记为“__declspec(dllexport)”的函数将被“导出”。

那么隐式链接有什么用呢?

  • 多个应用程序可以加载一个 .dll,如果您有在应用程序之间共享的相同代码,您可以在 .dll.
  • 中添加该代码
  • 它使 .dll 的使用更容易,但它是有代价的,与显式链接不同,您不能“重新加载”它。

显式链接:

在这种情况下,即使您生成 .lib,也不会 link。相反,您使用 Win32API(或您的 OS 的 API)加载共享库。在 windows 上,您使用 LoadLibrary("Path/To/The/DLLFile.dll")。这给你一个 HMODULE 对象。然后你用函数GetProcAdress(sHMODULE, "Function Name")手动检索函数指针。最后,您调用 FreeLibrary(sHMODULE). 来卸载库。请注意,这发生在运行时。在这种情况下,您也必须使用“__declspec(dllexport)”标记您的函数。

那么显式链接有什么用呢?

  • 在支持 C++ 脚本的游戏引擎中(如 Unreal),它们使用显式 linking 来 热重载 脚本代码。
  • 如果你想在你的应用程序中有一个插件系统