托管C ++ - 根据配置文件导入不同的DLL

时间:2009-05-14 18:11:20

标签: c++ visual-c++ dll dllimport

我目前正在编写一个应用程序,它将为多个客户端提供类似的用途,但需要调整它如何处理它所提供的数据。从本质上讲,它将起到同样的作用,但是以完全不同的方式分发数据。

所以我决定这样做: - 制作通用引擎库,它将保留所有方式的通用功能,并提供默认接口,确保不同的引擎以相同的方式响应。 - 为每种功能方式写一个特定的引擎......每一个都编译成自己的.dll。

所以我的项目最终会出现一堆库,其中一些看起来像这样: project_engine_base.dll project_engine_way1.dll project_engine_way2.dll

现在在我们用于用户首选项的配置文件中,会有一个引擎部分,以便我们决定使用哪个引擎:

[ENGINE]
Way1

因此我们希望在代码中的某处:

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

问题是......我将如何以这种方式导入我的dll?它甚至可能吗?如果没有,我可以获得一些关于如何实现类似功能的建议吗?

我知道我可以在开始时直接导入所有dll并选择使用哪个引擎,但我的想法是我不想导入太多引擎,浪费资源而且我们没有'我想要把所有这些dll都运送给我们的客户。一个客户将使用一个引擎另一个将使用不同的引擎。我们的一些客户可能会使用多个,因此我想要将其外部化并允许我们的用户使用配置文件进行引擎切换。

有什么想法吗?

编辑: 刚刚意识到,即使我的每个引擎在运行时动态加载并且不是项目中所有引用都会呈现相同的接口,我的项目也无法编译。所以我没有选择,只能将它们全部包含在我的项目中,不是吗?

这也意味着他们都必须运送给我的客户。配置中的设置只会指定我用来初始化引擎成员的类。

OR

我可以将每个引擎编译成相同的名称。只在我的主项目中导入一个dll,并且将始终使用该特定引擎。这将使我的客户无法将我们的应用程序用于他们自己的多个客户端。除非他们愿意手动切换dll。

有什么建议吗?

编辑#2:编辑#2: 在这一点上看到我的选择,我也可以写一个包含基本引擎的大dll以及所有孩子和我的配置让用户选择。而不是引用多个dll并将它们全部发送出去。只有一个巨大的,只有一个船只/参考。我不太喜欢这个,因为它意味着向我的所有客户发送一个大的dll而不是只有一两个适合那里的小客户。这仍然是我提出的最好的解决方案。

我仍在寻找更好的建议或原始问题的答案。 感谢。

2 个答案:

答案 0 :(得分:2)

为每个引擎使用单独的DLL,并在主项目中使用LoadLibrary根据配置加载特定引擎。

将您的引擎接口放在一个所有引擎都可以派生的公共头文件中,此接口也将在您的主项目中使用。

可能看起来像这样:

// this should be an abstract class
class engine {
public:
     virtual void func1() = 0;
     virtual void func2() = 0;
...
};

在每个不同的引擎实现中从DLL导出一个函数,如下所示:

// might aswell use auto_ptr here
engine* getEngine() { return new EngineImplementationNumberOne(); }

现在在您的主项目中,只需使用LoadLibrary加载您感兴趣的DLL,然后使用getProcAddress加载getEngine函数。

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();

导出函数的名称可能会被破坏,因此您可以在DLL中使用DEF文件或extern“C”,也不要忘记检查错误。

答案 1 :(得分:0)

我找到的解决方案如下:

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));
}

我使用了丹尼尔的答案以及他对答案的评论。经过一些额外的研究后,我遇到了LoadFrom方法。