3

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

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

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

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

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

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

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

4

1 回答 1

4

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

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

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

于 2009-07-25T12:30:00.530 回答