大家好,我是Ben Anderson,StDT在VisualC++图书馆团队。
在论坛和其他地方,我们从客户那里得到的最常见的问题之一是“我的应用程序需要Visual C++库(CRT、ATL、MFC、OpenMP或它们的某种组合)——我如何在客户的机器上得到它们?” 这也是我们在野外看到的事情,如果不是错误的话,至少是非常频繁的非最佳的。 MSDN中的帮助文档是正确的,但是没有一站式的解释来解释所有选项。 这篇博文将试图解释该怎么做( 如果你在寻找简短的答案,几乎总是,分发VisualC++库的正确做法是添加VisualC++可重分发MSM,或者“合并模块”,用于你的应用程序的安装库。 我已经尝试过概述基于您的部署故事可能的重新分配VisualC++库DLL的各种方法。
在大多数情况下,人们使用标准的Windows设置部署他们的应用程序。 在这些情况下,您可能会使用一些工具集(例如VisualStudio安装项目)构建一个.msi文件,然后通过工具链将其包装在一个.exe文件中。 最终用户运行此.exe文件并安装您的应用程序。 如果您还没有应用程序的安装程序,那么使用VisualStudio的安装项目(通过右键单击解决方案,单击“添加”->“新建项目…”->其他项目类型”->“安装项目”可以很容易地创建一个。 然后右键单击安装项目,单击“添加->项目输出…”,然后选择主输出。 然后可以添加“开始”菜单项并调整设置以满足需要。
为了重新分配VisualC++库,你需要做的就是包含适当的.MSM文件及其附带的策略MSM来分发你需要的库。 如果您正在创建一个安装项目作为上述解决方案的一部分,VisualStudio将尝试检测您所依赖的库,并根据需要添加MSM。 如果使用其他工具创建安装项目,或者不使用“添加项目输出”选项,则必须手动添加所需库的MSM。 这些库位于“%%ProgramFiles(x86)%%Common FilesMerge Modules”中。 例如,在我的VS 2005 SP1系统上,如果我有一个x86 MFC应用程序,我会将以下文件作为合并模块添加到我的安装项目中:
-
“C:程序文件(x86)通用文件合并模块Microsoftu VC80u CRTu x86.msm”
-
“C:程序文件(x86)通用文件合并模块Microsoftu VC80u MFCu x86.msm”
-
“C:程序文件(x86)通用文件合并模块策略u 8u 0u Microsoftu VC80u CRTu x86.msm”, 和
-
“C:程序文件(x86)公用文件合并模块策略u 8u 0u Microsoftu VC80u MFCu x86.msm”
这些文件将被安装工具使用,它们的内容将作为MSI的一部分放到用户的系统上。 它们包含将DLL和重定向策略并排安装到Windows的组件[参见脚注1] 对于您选择的库。 这些组件是ref计数的,因此每次安装使用这些MSMs的应用程序时,ref计数都会增加,每次卸载其中一个应用程序时,ref计数都会减少。 一旦ref计数为零,就会卸载dll和策略。
在某些情况下,MSM安装可能不适合您。 在一种情况下,您可能必须在用户没有管理员权限的系统上部署应用程序,因此无法运行安装程序。 你不能使用MSI安装你的应用程序可能还有其他原因,例如,用户可以直接从网络共享运行你的二进制文件。
在这些情况下,您可以执行“app local”部署,这有时称为将dll部署为“私有程序集”。 在这种情况下,您只需提供所需dll的副本,以及与应用程序中的每个.exe、.dll或.ocx文件位于同一目录中的附带清单。 要以这种方式部署,只需复制
这种方法的优点是不需要为应用程序创建安装。 这意味着您可以部署和运行,而无需用户提升到管理员权限。 用户只需将应用程序文件夹复制到系统中,或直接从当前位置运行.exe即可。 缺点是您必须将所需库的单独副本放入 每个目录 二进制文件所在的位置。 对于一个简单的应用程序来说,这可能不是一个问题,但是对于一个大型应用程序来说,它可能有许多子目录和许多工具和DLL,这是大量的文件复制。
最后,还有一个场景重新分配Visual C++库DLL。 如果您使用的是“单击一次”部署,则会出现这种情况。 在这种情况下,“Click Once”将使用名为“vcredit”的定制安装程序包_< 拱门 >.exe”来为您安装库。 不要 使用VCRedist_< 拱门 >用于任何其他目的的.exe安装程序包。
vcredit包只是通过使用 全部的 “%%ProgramFiles(x86)%%Common FilesMerge Modules”中的MSM以及MSDIA DLL(用于调试)。 然而,MSI不像MSMs中的组件那样被引用,所以如果你安装了它,你永远不能卸载它,因为你不知道除了你的应用之外还有谁在使用它。 此外,您的用户无法卸载它,因为他们不知道哪些应用程序可能正在使用它。 此外,当用户在“添加/删除程序文件”中看到条目时,可能不会意识到它是什么。 想象一个用户试图释放机器上的空间,看到他们无法识别的vcredit条目,卸载它,然后过一段时间(也许几个月),再次尝试您的应用程序。 这行不通! 您的用户可能不会连接到卸载vcredit的操作在过去的某个时间点,并将被打破没有修复,或使用您的支持中心的时间试图找出您的应用程序停止工作的原因。 更重要的是,你很可能不使用每一个Visual C++库,安装整个VCCRIST是不必要的。 另一方面,另一个应用程序使用WCKISDT重新分配VisualC++库的编写程序不完善,可能会(错误地)卸载VCCRIST在应用程序卸载时。
如果由于某种原因无法将MSM合并到安装应用程序的MSI中,那么更好的选择是使用Visual Studio或其他工具构建一个仅安装MSM的微型MSI,并且只安装您需要的MSM。 由于此MSI是您的产品所独有的,可以随意命名,因此您可以在删除应用程序时卸载它,并且您可以将其命名为这样的方式,即您的用户将其识别为应用程序的一部分,并且不会不适当地卸载它(将其命名为“MyApp Prerequisites”)。 通过使用您自己的MSI,您还可以保证使用VCRedist包的其他应用程序不会在卸载应用程序期间错误地卸载它,从而干扰您的应用程序。
再次强调,不要使用vcredit*.exe,除非您使用Click Once部署应用程序。
除了上面描述的所有分配VisualC++库DLL的方法外,还有一个用于构建应用程序的最后选项,不需要您分发DLL。 但是,此选项仅适用于纯本机代码(不受/clr支持),会使您的客户严重易受任何安全漏洞的攻击,并且如果在任何库中发现漏洞,则会给您自己增加一个很大的负担,即修补所有客户系统。 此选项是将库中的文件静态链接为.lib文件,而不是将它们动态加载为DLL。 您可以使用cl.exe命令行(vs/MD)上的/MT标志,或者通过VisualStudio在项目属性中选择适当的选项来实现这一点。 在开始使用安装程序之前,在测试机器上测试应用程序的早期调试版本时,您可能希望使用此选项[见脚注3]
然而,我想不出在任何情况下,这实际上是正确的做法,当您的产品运送到客户。 基本上,这种方法的作用是在编译时从.LIB文件中提取所需的二进制代码,使其成为.exe或.dll文件的一部分。 它增加了应用程序的大小,除了用新的.LIBs重新编译应用程序和重新分发应用程序之外,没有办法更新库。 这意味着除非你去触摸每一台安装了你的应用程序的机器,每次在Visual C++库中发现一个安全漏洞,并完全重新安装更新的二进制文件,你就会让你的客户容易受到攻击。 相反,如果使用DLL,每次在VisualC++库中发现安全漏洞时,微软将通过Windows更新将集中更新安装到WINSXS文件夹中,并且所有DLL请求将被重定向到更新版本。 这消除了你方的所有服务负担,也允许用户安装一个小的更新,这将触及他们的所有应用程序,而不是取代他们的系统上安装的每一个exe和DLL。 请不要通过静态链接到Visual C++库来构建应用程序,除非您有一个系统来更新每个客户机,并且也有非常好的理由这样做。 在这个时候,我能想到 不 在这种情况下,这将是正确的做法为航运申请。
希望本文能帮助您理解如何将VisualC++库重新分配到客户的机器上。 如果您还有其他问题,您可以在这里找到用于部署VisualC++内置应用程序的文档:
http://msdn2.microsoft.com/en-us/library/zebw5zk9(对80).aspx
如果你仍然有问题,你可以在这里发表评论(我会再检查几个星期),或者你可以在VisualC++论坛上发表你的问题:
http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=29&SiteID=1
谢谢, 本·安德森 VisualC++图书馆团队
(1)重定向策略总是将VisualC++的DLL请求重定向到最新安装的版本,即使请求DLL的应用程序使用“应用程序本地”部署将DLL丢弃为私有程序集——这样,如果出现安全问题,Windows Update可以将固定DLL放入Windows SxS,所有受影响的应用程序都将被修复。 VisualC++团队保持强大的二进制兼容性保证:针对早期版本的库构建的应用程序将与所有后续版本一起工作,只有少数例外(可利用的使用可能会被破坏,以防止客户机被黑客攻击)。
[2] 请注意,此目录中的文件没有在QFE修补程序中更新,并且此目录中的某些清单文件没有作为visualstudio2005的SP1的一部分更新。 作为一种解决方法,您可以通过键入“c:windowswinsxs>dir*VC80*”,根据版本号确定正确的目录,然后将该目录的内容复制到应用程序目录中,从而在VisualStudio开发框的WinSxS目录中找到相应的文件版本。
[3] 更好的选择是创建一个简单的安装项目并包含 全部的 Visual C++ MSMS并安装在所有目标机器上。