如何在C ++中构建运行时版本无关的DLL?

时间:2011-06-01 18:29:21

标签: c++ windows dll

我的产品是一个C ++库,在Windows上,它作为dll发布。它几乎没有使用c-runtime(基本的iostream就是这样),所以我确信所有最新版本的CRT都没问题。

由于我的客户端应该使用我的dll构建他的应用程序,我不想强​​加给他任何特定的运行时版本。我希望我的dll绑定到我的客户端的应用程序正在使用的任何运行时库版本(我可以假设他将使用动态链接为他的CRT)。毕竟,这不是动态链接的全部意义吗?这可能吗?

编辑:将dll与静态运行时库链接也不起作用,因为静态运行时(来自dll)和动态运行时(来自客户端的应用程序)将会混合,这很糟糕。

编辑:我主要问的是如何告诉运行时加载器将我的dll链接到与应用程序链接的CRT?或许是清单上的东西? 更一般地说,我的问题是如何构建一个表现良好的dll,客户可以使用它来构建自己的应用程序?

编辑:感谢答案中的建议,我已将所有对std类的引用转移到我的头文件中的内联函数中,并将我的dll与静态运行时库相关联。现在它甚至可以在与不同CRT版本链接的应用程序中起作用。

8 个答案:

答案 0 :(得分:12)

没有真正的方法可以确保您的DLL与多个运行时一起工作 - 任何在它们之间发生变化的类型都可能导致不兼容。例如,对象的大小可以改变,或者成员的位置可以改变。这种事情在C ++中几乎没有空间。

您可以做的最好的事情是静态链接到运行时并确保导出的API仅限于您严格控制的类型 - 不将std::string传递给函数,不将stdlib类型作为成员传递,并且不要一个DLL中为new,另一个中为delete。不要为同一对象混合内联和导出函数(包括构造函数/析构函数),因为成员顺序和填充可能会在编译器之间发生变化。 pimpl成语可能对此有所帮助。

答案 1 :(得分:6)

如果您跨DLL边界公开任何C ++对象,那么这是不可能的。您可以做什么(我们使用第三方DLL执行此操作)是在多个配置(32位/ 64位,调试/发布,静态/动态运行时,静态/动态库)中构建库以满足尽可能多的人。首先设置可能有点繁琐,但是一旦完成所有配置设置,只需构建它们即可。当然,您还需要考虑要构建的运行时(vc8,vc9,vc10等),因此如果要覆盖所有基础,可以进行大量配置。

答案 2 :(得分:4)

将DLL与静态运行时库链接起来应该有效,除非您必须非常小心内存管理(例如,无论谁调用您的DLL都不能释放()或删除[]您的DLL分配的任何内容)并且您无法交换标准C数据结构(例如FILE *)。 (我错过了什么吗?)

答案 3 :(得分:3)

您可以通过对I / O使用WinAPI调用以及可能依赖于运行时的任何其他内容来实现此目的。

最痛苦的部分是您可能必须覆盖全局newdelete以专门使用WinAPI函数,因为它们可能在内部使用malloc / free。还有许多其他痛苦的方面,我的意见是,这不值得麻烦。 Here是一篇涵盖此主题的文章。

答案 4 :(得分:3)

如果你想以运行时中立的方式公开你的对象,那么除了COM之外,我看不到任何解决方案。

答案 5 :(得分:2)

嗯,C-runtime和C ++之间存在巨大差异 - 运行时。如果你在哪里使用msvcrt.dll,它近年来成为一个真正的系统DLL的“爵位”,你可以依赖它在XP上的存在(虽然对于Windows 2000,你需要一些可再发行的msvcrt.dll版本6 )。您可以使用最新的WDK(Windows驱动程序工具包)中的编译器编译代码来使用msvcrt.dll。即使这是用户模式代码,这也是编译它的可行且好的方法。

但是,IOStreams需要C ++ - 运行时。这使事情变得很复杂。

  

编辑:将dll链接到   静态运行时库也不起作用,   因为然后是静态运行时(来自   dll)和动态运行时(来自   客户的申请)将是   混合,这很糟糕。

好吧,如果您以这种方式混合代码,那么您的设计就会出现问题。使用其他代码的发布版本运行DLL的调试版本时会遇到类似的问题,反之亦然。

我只能建议您直接使用COM,或者 - 如果太大 - 尝试模仿COM的一些想法。最重要的一个是你有一个工厂函数,并且在这两段代码(即DLL及其调用者)之间声明(并且永远不会改变)(类)接口。工厂函数将返回类的实例,类将管理其生命周期本身(这意味着所有用于分配和释放的代码将驻留在同一实体中,即您的DLL)。然后,生命周期管理将通过addrefrelease成员函数公开。 IUnknown可能是您的这个界面的基础,而不依赖于实际COM的其他部分。

  编辑:我主要问的是怎么做   我告诉运行时加载器链接我的   dll对抗任何CRT   申请与?某物   或许显而易见?更多   一般来说,我的问题是如何建立   一个表现良好的dll,就是这样   建立他们自己的客户使用   应用

根本不容易。即使你安装了VS的所有版本,你也必须编写出你选择正确版本的困境。

答案 6 :(得分:0)

你的dll与它编译的c-runtime相关联。您的应用程序将始终使用此运行时。任何链接到您的DLL的人都使用他们的c-runtime。所以这不会有任何问题。

答案 7 :(得分:0)

如果使用C ++,除非限制自己可以暴露的内容,否则似乎无法跨越运行时边界。如前所述,std :: objects不起作用(例如std :: string)。

这是一个会导致崩溃的小例子:

班级基地
   {
   市民:
     虚〜基()
     {
     }
   };

class ClassInDll:public Base
{ 上市:    __declspec(dllexport)ClassInDll(int arg);
   __declspec(dllexport)~ClassInDll();

私人:     int _arg;
};

如果将此类编译为VS2008发布模式DLL,并在VS2008调试模式下构建.exe,请执行以下操作:

ClassInDll * c = new ClassInDll(1); 删除c;

“删除c”语句导致崩溃。 它与ClassInDll具有虚拟析构函数的事实有关。