Reputation: 1008
I'm writing an application in C that can be extended at runtime by means of modules / shared objects / DLLs. Those modules may use the API of the existing program but may also provide new functions for use in later loaded modules, so there is the possibility for modules to have dependencies on each other.
My current approach under Linux is to have every module define a depends() function that returns a list of other module names it depends on. That way, I can compile and link every module for itself, load a module with dlopen() and RTLD_LAZY
, resolve its dependencies first and then fully load it with RTLD_GLOBAL
. This works just fine and does exactly what I want. It also allows me to replace a module with a different version without recompiling all other modules depending on it.
The actual problem arises when porting this to Windows. First, I haven't found any way to link a DLL without already providing it with the export symbol tables of all its dependencies. Is there one I've overlooked?
Second, LoadLibraryEx from the Windows API doesn't seem to be able to perform any lazy loading because instead of letting me handle dependencies, it goes ahead and loads all referenced DLLs itself before it even returns. Since I'd like to perform version checking as well before actually loading modules in the future, this it not at all what I want. Is there any way to circumvent this behaviour?
The third odd thing is that I cannot replace a DLL without recompiling all other modules depending on it. It actually does work sometimes, but usually wild things start to happen or the program segfaults.
Is it even possible to write a modular application like that on Windows? Any suggestions or different approaches are highly appreciated!
Update: Just to provide some clarification on how my modules use each others functions on Linux (which I would like to have on Windows as well): Every module just returns the name of another module it would like to call functions from in the described depends() function and includes its header, then calls the used functions directly in the code without any wrapping. This works because Linux does not require you to have all symbols resolved at link time for shared objects.
Upvotes: 3
Views: 635
Reputation: 19384
You can export all functions manually (using __declspec(dllexport)
) and load them using GetProcAddress
. In this case you need to know the signature of each function, and you're limited to C functions only, but this is going to work. If you compile both modules, your C functions can also return C++ classes, more on this later. Using GetProcAddress
& LoadLibrary
makes modules totally independent. Basically, you do the linking manually, but as I understand, this is what you do on Linux, right?
LoadLibary
only loads the libraries a library is dependent on, so make sure they don't load depend on each other. Either they are really independent, or they aren't, if done properly, changing one library will not force a recompile of the other (as you don't link them together).
A good idea is to use something like COM, so make each of your libraries return an interface, instead of individual functions. That way, you can simply load a whole DLL and also link them easily together (passing a DLL -> passing an object). Look up XPCOM and COM, it's actually very easy to do.
Upvotes: 4