我正在用C语言编写一个可以通过模块/共享对象/ DLL在运行时扩展的应用程序。这些模块可以使用现有程序的API,但也可以提供新功能以便在以后加载的模块中使用,因此模块可能相互依赖。
我目前在Linux下的方法是让每个模块定义一个depends()函数,该函数返回它所依赖的其他模块名称的列表。这样,我可以为自己编译和链接每个模块,使用dlopen()和RTLD_LAZY
加载模块,首先解析其依赖关系,然后使用RTLD_GLOBAL
完全加载它。这工作得很好,完全符合我的要求。它还允许我用不同的版本替换模块,而无需根据它重新编译所有其他模块。
将此端口移植到Windows时会出现实际问题。首先,我没有找到任何方法来链接DLL而没有提供它的所有依赖项的导出符号表。有没有我忽略过的?
其次,来自Windows API的LoadLibraryEx似乎无法执行任何延迟加载,因为它不是让我处理依赖项,而是继续并在它返回之前加载所有引用的DLL本身。由于我想在将来实际加载模块之前执行版本检查,这根本不是我想要的。有没有办法绕过这种行为?
第三个奇怪的是,如果不重新编译所有其他模块,我就无法替换DLL。它实际上有时会起作用,但通常会发生野外事件或程序段错误。
甚至可以在Windows上编写类似的模块化应用程序吗?任何建议或不同的方法都非常感谢!
更新:只是为了说明我的模块如何在Linux上使用彼此的功能(我也希望在Windows上使用它):每个模块只返回另一个模块的名称想在所描述的depends()函数中调用函数并包含它的头,然后直接在代码中调用使用过的函数而不进行任何包装。这是有效的,因为Linux不要求您在链接时为共享对象解析所有符号。
答案 0 :(得分:4)
您可以手动导出所有功能(使用__declspec(dllexport)
)并使用GetProcAddress
加载它们。在这种情况下,您需要知道每个函数的签名,并且您仅限于C函数,但这将起作用。如果您编译这两个模块,您的C函数也可以返回C ++类,稍后将详细介绍。使用GetProcAddress
& LoadLibrary
使模块完全独立。基本上,你手动进行链接,但据我所知,这是你在Linux上做的,对吧?
LoadLibary
仅加载库所依赖的库,因此请确保它们不相互依赖加载。要么它们真的是独立的,要么它们不是,如果处理得当,更改一个库不会强制重新编译另一个(因为你没有将它们链接在一起)。
一个好主意是使用类似COM的东西,因此让每个库返回一个接口,而不是单个函数。这样,您可以简单地加载整个DLL并将它们轻松链接在一起(传递DLL - >传递对象)。查找XPCOM和COM,实际上很容易做到。