我正在使用C编写一个应用程序,可以通过模块/共享对象/DLL在运行时进行扩展。这些模块可以使用现有程序的API,但也可以提供新功能供后续加载的模块使用,因此模块之间可能存在依赖关系。
我目前在Linux下的方法是让每个模块都定义一个depends()函数,该函数返回其所依赖的其他模块的名称列表。这样,我可以为每个模块单独编译和链接,在使用dlopen()和RTLD_LAZY加载模块时首先解决其依赖关系,然后使用RTLD_GLOBAL完全加载它。这很好地实现了我的要求。它还允许我用不同版本的模块替换一个模块,而无需重新编译所有依赖它的其他模块。
当我要将其移植到Windows时,实际问题就出现了。首先,我没有找到任何Link DLL的方式,而不必提供其所有依赖项的导出符号表。我有忽略的方法吗?
第二个问题,来自Windows API的LoadLibraryEx似乎无法执行任何延迟加载,因为它不是让我处理依赖项,而是在返回之前先加载所有引用的DLL。由于我希望在实际加载模块之前进行版本检查,这根本不是我想要的。有没有任何方法来规避这种行为?
第三个奇怪的事情是,我不能替换一个DLL而无需重新编译所有依赖它的其他模块。有时确实可以工作,但通常会发生各种问题或程序segfault。
在Windows上是否可能编写类似的模块化应用程序?非常感谢您的任何建议或不同的方法!
更新:只是为了说明我的模块如何在Linux上使用彼此的函数(我也希望在Windows上拥有):每个模块只返回它想从中调用函数的另一个模块的名称,并包含其头文件,然后在代码中直接调用使用的函数,没有任何封装。这可以工作,因为Linux对于共享对象不需要在链接时解析所有符号。
我目前在Linux下的方法是让每个模块都定义一个depends()函数,该函数返回其所依赖的其他模块的名称列表。这样,我可以为每个模块单独编译和链接,在使用dlopen()和RTLD_LAZY加载模块时首先解决其依赖关系,然后使用RTLD_GLOBAL完全加载它。这很好地实现了我的要求。它还允许我用不同版本的模块替换一个模块,而无需重新编译所有依赖它的其他模块。
当我要将其移植到Windows时,实际问题就出现了。首先,我没有找到任何Link DLL的方式,而不必提供其所有依赖项的导出符号表。我有忽略的方法吗?
第二个问题,来自Windows API的LoadLibraryEx似乎无法执行任何延迟加载,因为它不是让我处理依赖项,而是在返回之前先加载所有引用的DLL。由于我希望在实际加载模块之前进行版本检查,这根本不是我想要的。有没有任何方法来规避这种行为?
第三个奇怪的事情是,我不能替换一个DLL而无需重新编译所有依赖它的其他模块。有时确实可以工作,但通常会发生各种问题或程序segfault。
在Windows上是否可能编写类似的模块化应用程序?非常感谢您的任何建议或不同的方法!
更新:只是为了说明我的模块如何在Linux上使用彼此的函数(我也希望在Windows上拥有):每个模块只返回它想从中调用函数的另一个模块的名称,并包含其头文件,然后在代码中直接调用使用的函数,没有任何封装。这可以工作,因为Linux对于共享对象不需要在链接时解析所有符号。
GetProcAddress
的建议已经有所帮助了。我刚刚尝试了一下,通过这种方式调用 DLL 中的函数可以在没有链接的情况下工作。但这意味着我不能像在 Linux 中那样让一个模块包含它依赖的模块的头文件,对吧?在调用父模块中的任何内容之前,我必须先使用GetProcAddress
收集所有需要的函数指针。感谢你提供 COM 的提示,我会去看看的。 - smf68GetInterface
的地址,并在该模块指针上工作。 - Anteru