Managed C ++ - Importing various DLLs based on a config file
I am currently writing an application that will serve a similar purpose for multiple clients, but needs to adapt to how it will handle the data it transfers. In essence, this will serve the same purpose, but transfer data in completely different ways.
So, I decided to do this: -Run the shared engine library, which will support the common functions of all methods and provide a default interface, ensuring that different engines will respond the same way. -Write a specific engine for each way of working ... each one compiles into its own .dll.
So my project will eventually have many libraries, some of which are like this: project_engine_base.dll project_engine_way1.dll project_engine_way2.dll
Now there will be an engine section in the config file that we use for custom settings so we can decide which engine to use:
[ENGINE]
Way1
So somewhere in the code we want to do:
If (this->M_ENGINE == "Way1")
//load dll for way1
Else If (this->M_ENGINE == "Way2")
//load dll for way2
Else
//no engines selected...tell user to modify settings and restart application
Question ... How do I import my dlls this way? Is it possible? If not, can I get some suggestions on how to achieve a similar way of working?
I know that I could just import all the DLLs right at the start and just choose which engine to use, but the idea was that I didn't want to import too many engines for anything or unnecessary resources, I want to ship all of these DLL to our clients. One client will use one engine, another will use another. Some of our clients will be using more than one, perhaps because of this, so I wanted to exteriorize this and let our users use a config file to switch the engine.
Any ideas?
EDIT: Just figured out that while each of my engines will present the same interface, if they are loaded dynamically at runtime and not all references in the project, my project will not compile. So I have no choice but to include them in my project, right?
This also means that they all have to be sent to my clients. The settings in the config will only be dictated by the class I would use to initialize my engine member.
OR
I could compile each of these engines with the same name. Import only one dll to my main project and this particular engine will be used all the time. This would render my clients unable to use our application for several of their clients. Unless they want to manually switch DLLs. Ugh
Any suggestions?
EDIT # 2: At this point, seeing my options, I could also make one big dll containing the base engine as well as all the children and my config for the user to select. Instead of linking to multiple DLLs and shipping them all. Just one huge and only one ship / link. I don't like this too much because it means delivering one big dll to all my clients, not just one or two small ones that satisfy the needs. This is still the best solution I have come up with.
I am still looking for the best suggestions or answers to my original question. Thanks.
a source to share
The solution I came up with is the following:
Engine_Base^ engine_for_app;
Assembly^ SampleAssembly;
Type^ engineType;
if (this->M_ENGINE == "A")
{
SampleAssembly = Assembly::LoadFrom("path\\Engine_A.dll");
engineType = SampleAssembly->GetType("Engine_A");
engine_for_app = static_cast<Engine_Base^>(Activator::CreateInstance(engineType, param1, param2));
}
else
{
SampleAssembly = Assembly::LoadFrom("path\\Engine_B.dll");
engineType = SampleAssembly->GetType("Engine_B");
engine_for_app = static_cast<Engine_Base^>(Activator::CreateInstance(engineType, param1, param2, param3, param4));
}
I used Daniel's answer and the comments that were made on his answer. After some more research, I came across the LoadFrom method.
a source to share
Use separate DLLs for each engine and use LoadLibrary in your main project to load a specific engine based on configuration.
You have your engine interface in some kind of general header file from which all engines will be inferred and that interface will also be used in your main project.
It might look like this:
// this should be an abstract class
class engine {
public:
virtual void func1() = 0;
virtual void func2() = 0;
...
};
Each individual implementation of the mechanism exports a function from a DLL, something like this:
// might aswell use auto_ptr here
engine* getEngine() { return new EngineImplementationNumberOne(); }
Now in your main project, just load the DLL you are interested in using LoadLibrary and then the GetProcAddress getEngine function.
string dllname;
if (this->M_ENGINE == "Way1")
dllname = "dllname1.dll";
else if (this->M_ENGINE == "Way2")
dllname = "dllname2.dll";
else
throw configuration_error();
HMODULE h = LoadLibraryA(dllname.c_str());
typedef engine* (*TCreateEngine)();
TCreateEngine func = (TCreateEngine)GetProcAddress(h, "getEngine");
engine* e = func();
The name of the exported function is likely to be garbled, so you can use DEF or extern "C" files in your DLLs, also remember to check for errors.
a source to share