繁体   English   中英

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

[英]How do I build a runtime version agnostic DLL in C++?

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

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

编辑:将 dll 与 static 运行时库链接起来也不起作用,因为 static 运行时(来自 dll)和动态运行时(来自坏客户端)将是混合运行时(来自 dll 应用程序)

编辑:我主要要问的是如何告诉运行时加载程序将我的 dll 与应用程序链接的任何 CRT 链接? 也许与清单有关? 更一般地说,我的问题是如何构建一个行为良好的 dll,供构建自己的应用程序的客户使用?

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

没有真正的方法可以确保您的 DLL 与多个运行时一起工作——它们之间的任何类型的变化都可能导致不兼容。 例如,object 的大小可以更改,或者其中成员的位置。 C++ 对于这种东西的空间很小。

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

如果您在 DLL 边界上暴露任何 C++ 对象,那么这是不可能的。 您可以做的(我们使用第 3 方 DLL 执行此操作)以多种配置(32 位/64 位、调试/发布、静态/动态运行时、静态/动态库)构建您的库以满足尽可能多的人。 起初设置可能有点乏味,但是一旦您设置了所有配置,只需将它们全部构建起来即可。 当然,您还需要考虑您正在构建的运行时(vc8、vc9、vc10 等),所以如果您想涵盖所有基础,您可以有很多配置。

Linking your DLL against the static runtime libs should work, except that you must be very careful about memory management (eg whoever calls your DLL can't free() or delete[] anything allocated by your DLL) and you cannot exchange standard C data结构(例如 FILE*)。 (我错过了什么吗?)

您可以通过使用 WinAPI 调用 I/O 和任何其他可能依赖运行时的方法来实现此目的。

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

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

好吧,C 运行时和 C++ 运行时之间存在巨大差异。 If you where to use msvcrt.dll, which in recent years became "knighted" as a true system DLL, you could rely on its existence on XP onwards (though for Windows 2000 you would need some redistributable for the version 6 of msvcrt.dll )。 您可以使用 msvcrt.dll 通过使用最新 WDK(Windows 驱动程序工具包)的编译器编译您的代码。 尽管这是用户模式代码,但这是编译它的可行且良好的方法。

然而,IOStreams 需要 C++ 运行时。 这使事情复杂化了很多。

编辑:将 dll 与 static 运行时库链接起来也不起作用,因为 static 运行时(来自 dll)和动态运行时(来自坏客户端)将是混合运行时(来自 dll 应用程序)

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

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

编辑:我主要要问的是如何告诉运行时加载程序将我的 dll 与应用程序链接的任何 CRT 链接? 也许与清单有关? 更一般地说,我的问题是如何构建一个行为良好的 dll,供构建自己的应用程序的客户使用?

一点都不容易。 即使您安装了所有版本的 VS,您也必须编写脚本来摆脱这种困境以选择正确的版本。

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

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

class 底座
{
上市:
虚拟 ~Base()
{
}
};

class ClassInDll:公共基础
{ public: __declspec( dllexport ) ClassInDll( int arg );
__declspec(dllexport)~ClassInDll();

私人:int _arg;
};

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

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

“delete c”语句会导致崩溃。 这与 ClassInDll 具有虚拟析构函数这一事实有关。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM