Shell扩展:C / C ++运行时DLL的静态链接与动态链接

时间:2013-08-28 10:48:24

标签: c++ winapi com crt shell-extensions

在构建Windows资源管理器外壳扩展(当前使用的是VS2010 SP1)时,是否建议静态链接(到CRT,C ++运行时和其他支持库,如ATL) )或动态链接

静态链接选项的一个好处是使部署更容易(事实上,通过这种方式,可以只部署shell扩展-proc COM服务器DLL,没有对其他C / C ++运行时DLL的外部依赖性。)

如果是动态链接,如果msvcr100.dllmsvcp100.dllWindows\System32中的DLL由shell扩展使用,那么好处是如果Microsoft修复了这些DLL中的某些内容(例如安全修复程序),自定义外壳扩展会自动修复 。 然而,糟糕的是,那些“全局”修复程序也可能在依赖代码中引入错误和中断事物。

对于VCRedist DLL的 app-local 部署,我不确定在shell扩展的情况下它是如何工作的。应该在shell扩展COM DLL中嵌入什么样的清单来引用shell扩展文件夹下的VCRedist DLL?

2 个答案:

答案 0 :(得分:2)

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

然而,它确实成为“两个邪恶中较小的一个”的选择,并且在很大程度上取决于你的扩展正在做什么。如果你构建它静态,与非静态相比有多大?如果没有太大的区别,那么你显然没有使用大量的DLL代码,这很好。

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

没有一个答案总是正确的。这是一个折衷方案,您必须判断哪个对您(以及您的客户)最有意义 - 易于安装或依赖外部DLL。

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

答案 1 :(得分: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服务器本身是使用多个模块实现的,那么您只考虑它。