解决VS2005/VS2008下在子目录下部署DLL的私有程序集部署问题

采用VC++2005非托管C++代码开发,主程序名为MyApp.exe,MyPulgin.dll。MyApp.exe部署所在目录为主目录,MyPulgin.dll部署在主目录下的Plugin子目录下,如下所示:
 $Home     ---应用程序主目录
  MyApp.exe
  Plugin   ---插件部署目录(主目录下的一个子目录)
   MyPlugin.dll
程序发布要求采用XCopy方式,即将这个目录结构复制到目标机器就可以运行。

因为MyApp.exe和MyPlugin.dll依赖VS2005 CRT DLL库。所以这些库也需要随应用程序一起发布。VS2005 CRT DLL 的发布可以采用2种部署方式,即采用私有程序集方式和共享程序集方式部署。

将VS2005 CRT DLL部署为共享程序集的方式,即采用微软发布的重分发程序vcredist_x86.exe (x86是其版本,还有x64 和 IA64)将VS2005 CRT DLL安装到$Windows/WinSXS目录下。

将VS2005 CRT DLL部署为私有程序集的方式,即将VS2005 CRT DLL部署到应用程序私有目录下,这种方式无需访问系统目录,部署简单。微软官方发布了将 Visual C++ CRT DLL 部署为私有程序集的方法及步骤(http://msdn.microsoft.com/zh-cn/library/ms235291(v=VS.80).aspx)。内容如下:
1.在开发计算机上创建一个文件夹结构,让它与将在目标计算机上使用的文件夹结构一致。对于此示例,创建一个 /bin 文件夹并将 MyApp.exe 复制到其中。然后,创建一个 /bin/Plugin 文件夹并将 MyPulgin.dll 复制到其中。
2.在开发计算机上,将 Microsoft.VC80.CRT 和 Microsoft.VC80.MFC 从 %PROGDIR%/Microsoft Visual Studio 8/VC/Redist/x86 复制到 /bin 和 /bin/Plugin 中。
 3.将 /bin 文件夹复制到目标计算机。在支持基于清单的绑定的目标计算机 (Windows XP Home Edition、Windows XP Professional、Windows Server 2003) 上,没有必要做进一步的准备。在不支持类似绑定的计算机(Windows 98、Windows 98 Second Edition、Windows Millennium Edition 和 Windows 2000)上,路径中必须有 Microsoft.VC80.CRT 和 Microsoft.VC80.MFC。

微软提供的方法即在主目录和包含DLL的子目录下皆部署VS2005 CRT DLL。但这种方法存在以下问题。
其一,依赖库重复部署,造成安装包额外的空间需求
其二,DLL和EXE都是使用各自的CRT DLL,在进程中会造成多个运行时库实例。如果在DLL(Exe)中分配内存,而在Exe(DLL)中释放内存,则会造成系统崩溃。因为DLL和Exe使用的是不同的运行时库实例提供的内存管理器,在DLL中申请的内存是由Dll所使用的CRT DLL的内存管理器分配的,在Exe中释放这块内存,则会由Exe所使用的CRT DLL的内存管理器回收,结果回收的内存不是自己分配的内存,从而造成系统崩溃。

因此微软提供的方案并不适合DLL部署在子目录的需求。解题的思路是使子目录下的DLL和主目录中的Exe依赖于同一套VS2005 CRT DLL,使进程中仅存在一个运行时库实例。

考虑到vc6.0生成的应用程序依赖库只需要部署到主目录中,加载子目录中的DLL时能在已加载库中找到其依赖库。因此只要将vs2005生成的应用程序加载子目录的DLL时也能在已加载库中命中其依赖库,问题就得到解决。

vs2005与vc6.0在生成应用程序的一个不同之处在于vs2005生成的应用程序(程序集Exe或DLL)内嵌了一个manifest清单文件,该文件记录了其依赖的程序集。用vs2005打开DLL(Exe),导出RT_MANIFEST资源,得到一个xml文件,内容如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.DebugCRT" version="8.0.50608.0" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
</assembly>

该文件表示DLL依赖一个Microsoft.VC80.DebugCRT的程序集,而该程序集名称并不是DLL的文件名。进程在加载DLL时,检查有内嵌manifest,则按照manifest文件中的依赖项信息探测依赖项,具体探测方式参见微软官方说明:http://msdn.microsoft.com/zh-cn/library/aa663631.aspx#EIAA
若DLL没有内嵌manifest,则进程加载DLL时,就会按照DLL的弱依赖信息(动态库文件名---弱名称,可以通过View Dependency工具查看程序集的依赖项)加载动态库,若进程已经加载则不会再加载,从而保证Exe和Dll只加载一个运行时库实例。

让vs2005生成的程序集不产生内嵌manifest文件的方法是按照如下方法修改其工程属性:
配置属性/连接器/清单文件选项卡中,设置生成清单文件选项为否。/MANIFEST:NO

总结:
1)在主目录下部署Visual C++ CRT DLL。
2)去掉子目录下部署的程序集(DLL)的内嵌manifest。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值