【问题标题】:Dynamic modules with DLLs on WindowsWindows 上带有 DLL 的动态模块
【发布时间】:2010-11-13 23:56:02
【问题描述】:

我正在用 C 语言编写一个应用程序,它可以在运行时通过模块/共享对象/DLL 进行扩展。这些模块可能使用现有程序的 API,但也可能提供新功能供以后加载的模块使用,因此模块之间可能存在依赖关系。

我目前在 Linux 下的方法是让每个模块定义一个 depends() 函数,该函数返回它所依赖的其他模块名称的列表。这样,我可以自己编译和链接每个模块,使用 dlopen() 和 RTLD_LAZY 加载模块,首先解决其依赖关系,然后使用 RTLD_GLOBAL 完全加载它。这工作得很好,完全符合我的要求。它还允许我用不同的版本替换一个模块,而无需重新编译所有其他模块。

将其移植到 Windows 时会出现实际问题。首先,我还没有找到任何方法来链接 DLL,而无需为其提供所有依赖项的导出符号表。有没有我忽略的?

其次,来自 Windows API 的 LoadLibraryEx 似乎无法执行任何延迟加载,因为它没有让我处理依赖项,而是继续并在返回之前自行加载所有引用的 DLL。由于我想在将来实际加载模块之前执行版本检查,这根本不是我想要的。有没有办法规避这种行为?

第三件奇怪的事情是,如果不重新编译依赖于它的所有其他模块,我就无法替换 DLL。它有时确实有效,但通常会发生一些疯狂的事情或程序段错误。

甚至可以在 Windows 上编写像这样的模块化应用程序吗?任何建议或不同的方法都非常感谢!

更新: 只是为了澄清一下我的模块如何在 Linux 上使用彼此的功能(我也希望在 Windows 上也有):每个模块只返回它的另一个模块的名称想从所描述的depends()函数中调用函数并包含它的头文件,然后直接在代码中调用使用的函数而不进行任何包装。这是可行的,因为 Linux 不要求您在链接时为共享对象解析所有符号。

【问题讨论】:

    标签: c windows dll module lazy-loading


    【解决方案1】:

    您可以手动导出所有函数(使用__declspec(dllexport))并使用GetProcAddress 加载它们。在这种情况下,您需要知道每个函数的签名,并且您仅限于 C 函数,但这会起作用。如果您编译这两个模块,您的 C 函数也可以返回 C++ 类,稍后会详细介绍。使用GetProcAddress & LoadLibrary 使模块完全独立。基本上,您手动进行链接,但据我了解,这就是您在 Linux 上所做的,对吧?

    LoadLibary 仅加载库所依赖的库,因此请确保它们不加载相互依赖。它们要么是真正独立的,要么不是,如果处理得当,更改一个库不会强制重新编译另一个库(因为您没有将它们链接在一起)。

    一个好主意是使用 COM 之类的东西,因此让您的每个库都返回一个接口,而不是单个函数。这样,您可以简单地加载整个 DLL 并将它们轻松链接在一起(传递 DLL -> 传递对象)。查一下XPCOM和COM,其实很容易做到的。

    【讨论】:

    • 好的,您对GetProcAddress 的建议已经有点帮助了。我只是尝试了一下,然后从 DLL 调用一个函数,这种方式可以在没有链接的情况下工作。但这意味着我不能像在 Linux 中那样让一个模块包含它所依赖的那个模块的头文件,对吧?在从父模块调用任何内容之前,我必须首先使用GetProcAddress 以某种方式收集所有需要的函数指针。也感谢 COM 的提示,我会看看。
    • 是的,但正如我所说,只需将一个模块的所有函数分组到一个类中,然后调用它。这要容易得多,而且还减少了导出符号的数量。它不是真正的 COM,因为您不涉及继承,它只是基于类似的想法。您的客户使用该接口,但不知道其背后的实际实现。
    • 有趣的话题。因此,如果模块的开发人员必须具备有关 WinAPI 和/或 COM 的知识,就没有办法做到这一点? :-(
    • 当然有,你可以做类似 COM 的事情,而不用实际使用 COM。正如我所说,在最简单的情况下,您有类似 struct Interface { your methods here ... }; 之类的东西,并且您的模块由 extern "C" Interface* GetInterface(); -- 所以你只得到GetInterface 的地址,然后处理那个模块指针。
    • 啊好吧,我把这个用“接口”误解了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-02
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 2016-02-09
    • 1970-01-01
    • 2020-11-09
    相关资源
    最近更新 更多