1

在构建 Windows Explorer shell 扩展(当前使用 VS2010 SP1)时,您建议使用静态链接(到 CRT、C++ 运行时和其他支持库,如 ATL)还是动态链接

静态链接选项的好处之一是使部署更容易(实际上,通过这种方式,可以只部署 shell 扩展程序内 COM 服务器 DLL,而无需外部依赖于其他 C/C++ 运行时DLL)。

动态链接的情况下,如果msvcr100.dllmsvcp100.dll等 DLLWindows\System32被 shell 扩展使用,好处是如果 Microsoft 在这些 DLL 中修复了某些内容(例如安全修复),自定义 shell 扩展自动使用这些修复。
然而,坏事是那些“全局”修复也可能在依赖代码中引入错误和破坏事物。

至于VCRedist DLL 的应用程序本地部署,我不确定它在外壳扩展的情况下如何工作。应该在 shell 扩展 COM DLL 中嵌入什么样的清单来引用 shell 扩展文件夹下的 VCRedist DLL?

4

2 回答 2

2

当您有多个模块相互交互时,必须使用 CRT 的 DLL 版本通常是一个非常困难的要求。一个特别重要的方面是在所有模块中使用相同的分配器。这样在一个模块中分配的对象可以被另一个模块中的代码安全地销毁。这在 C++ 中经常出现,做一些像从函数返回 std::string 这样简单的事情是非常麻烦的。它在被调用者中创建,需要在调用者中销毁。如果跨模块边界进行函数调用并且两个模块使用不同的堆,那么灾难就会发生。

标准 C++ 对象的布局也与 CRT 实现相关联。不同版本的编译器使用不同的 std::string 实现。如果一个模块使用与另一个模块不同的实现,那么灾难就会发生,调用者根本无法正确使用被调用者创建的对象。即使像调试设置这样简单的事情也可能导致不匹配,Microsoft CRT 中的迭代器调试支持因导致不匹配而臭名昭著,它使 STL 对象更大。

然而,这些是 COM 中避免的问题。有一个强大的内存管理协议,基于 IUnknown 接口的 AddRef 和 Release 方法。这使对象的创建者始终是对象的所有者并负责销毁它。其他分配,如 BSTR 和 SAFEARRAY,必须始终从保证在进程内共享的堆中进行。CoTaskMemAlloc、CoTaskMemFree 和 IMalloc 实现了该管道。

并且它强烈地避免了对象布局问题,COM 严格只与接口一起工作。严格禁止跨互操作边界传递 C++ 对象或异常之类的操作。唯一的实现细节是调用约定,严格的 __stdcall,以及接口 v-table 布局,严格绑定到接口的 IID。更改接口需要选择一个新的 IID。

长话短说,因此您根本不需要使用 CRT 的共享版本。事实上,许多 COM 服务器都是用 /MT 编译的。使用 /MD 也很好,如果你的 COM 服务器本身是使用多个模块实现的,你只会考虑它。

于 2013-08-28T20:39:29.963 回答
2

这个问题的简短回答是“这取决于”。但这可能是你已经走了多远。

但是,它确实成为“两害相权取其轻”的选择,并且在很大程度上取决于您的扩展在做什么。如果你构建它是静态的,与非静态相比,它有多大?如果没有太大区别,那么您显然没有使用大量的 DLL 代码,这很好。

如果您发现您的扩展从几十千字节增长到几兆字节,那么您必须考虑是让客户端下载 redist-package 还是将其作为安装的一部分包含在内更好。

没有一个答案是永远正确的。这是一种妥协,您必须判断哪个对您(和您的客户)最有意义 - 易于安装,或依赖外部 DLL。

如果您将 redist DLL 与可执行文件安装在同一文件夹中,Windows 会自行找到该 DLL,因此不需要任何额外的工作。(不适用于外壳扩展)

于 2013-08-28T11:05:32.530 回答