最近在新装的Win7上 编译/ 运行自己的 camera_work_simultaneously.exe 程序时,发现release 编译/运行 没有问题,但是Debug版本编译通过,run时报错:“The application was unable to start correctly(0x0000006). ....”
再查看系统的event,
把在笔记本上用VC9.0发布的SCCT.exe文件拷贝到 装有Win7的 台式机BV5上进行验证,也是出同样的问题!就是调用GigEVisionSdkD.dll时依赖的GenApi_MDd_VC80.dll又依赖与Microsoft.VC80.DebugCRT的运行时库,最后没有找到Microsoft.VC80.DebugCRT。
于是进行下列步骤:
C:\Users\BV5\Desktop\SCCT\Debug
|--scct.exe
|--opencv_calib3d231d.dll
|--opencv_core231d.dll
. .
.
|--GigEVisionSdkD.dll
|--GenApi_MDd_VC80.dll
|--GCBase_MDd_VC80.dll
(Microsoft.VC90.DebugCRT下的dll放到SCCT\下)
|--Microsoft.VC90.DebugCRT.manifest
|--msvcm90d.dll
|--msvcp90d.dll
|--msvcr90d.dll
|--GenICam\bin\Win32_i86\GenApi\Generic
|--XMLLoader_MDd_VC80.dll
|--xerces-c_2_7.dll
|--Xalan-C_1_10.dll
|--XalanMessages_1_10.dll
GigEVision的在SCCT\下的目录结构参考 “发布带GigEVision的程序 http://blog.csdn.net/jtop0/article/details/6934210”
1、在Win7上(也就是 Winsxs目录下)没有Microsoft.VC80.DebugCRT 运行时库? (的确)
虽然
2、下载到Microsoft.VC80.DebugCRT 库 版本8.0.50727.762, 并分别放到应用程序目录SCCT\下 和 SCCT\GenICam\bin\Win32_i86\GenApi\Generic下(因为running时,启动camera要调用XMLLoader_MDd_VC80.dll,这个dll 又依赖于Microsoft.VC80.DebugCRT库, 当然如果能找到msi文件的Microsoft.VC80.DebugCRT直接安装到Winsxs目录下,就可以共用了,不用再把运行时库拷到SCCT\目录下了)
.
.
|--GCBase_MDd_VC80.dll
( Microsoft.VC90.DebugCRT运行时库 )
|--Microsoft.VC90.DebugCRT.manifest
|--msvcm90d.dll
|--msvcp90d.dll
|--msvcr90d.dll
( Microsoft.VC80.DebugCRT运行时库 )
|--Microsoft.VC80.DebugCRT.manifest
|--msvcm80d.dll
|--msvcp80d.dll
|--msvcr80d.dll
|--GenICam\bin\Win32_i86\GenApi\Generic
|--XMLLoader_MDd_VC80.dll
|--xerces-c_2_7.dll
|--Xalan-C_1_10.dll
|--XalanMessages_1_10.dll
|--Microsoft.VC80.DebugCRT.manifest
|--msvcm80d.dll
|--msvcp80d.dll
|--msvcr80d.dll
并且修改Microsoft.VC80.DebugCRT.manifest把版本号改为8.0.50608.0与GCBase_MDd_VC80.dll、GenApi_MDd_VC80.dll中嵌入的manifest 版本一致
当然Microsoft.VC90.DebugCRT.manifest中的版本号,也应该改为 9.0.21022.8与嵌入scct.exe、GigEVisionSdkD.dll中的manifest要求的版本一致
3、把机器上的目录C:\Program Files\MaxxVision\GigEVision改为C:\Program Files\MaxxVision\GigEVision1 以便运行scct.exe时,避免用系统中的GigEVision库,而使用SCCT\目录下的GigEVision库以及GenApi_MDd_VC80.dll、GCBase_MDd_VC80.dll等。
4、再次运行scct.exe程序OK!
实际上这个问题根本上还是涉及到 vs2008/2005 sp1 C++ 发布程序的问题!
先参考我的前一篇blogvs2008 sp1 C++ 发布程序
现在对这个发布 作一个全方位的总结:
一、使用vs2008/vs2008开发的程序有2种部署方法:
静态链接发布:只要拥有程序的所有源代码(包括库),你就可以采用静态链接到crt 和 MFC,来发布程序,运行时 只要一个exe文件就可以了,只不文件体积太大了点。
动态链接发布:编译程序时, 采用动态链接 运行时库,即在project property---C/C++---Code Generation---Runtime Library 选 /MDd,发布的exe应用程序还要附带Runtime Library (dll) 程序才能运行(常用的方法)。
|-----------并行程序集 部署方法
|-----------私有程序集 部署方法
所谓的共享并行程序集部署方法是指程序依赖的CRT、MFC、ATL的DLL和manifest文件位于目标机器上的c:/windows/winsxs目录中,发布程序的时候只需要将程序拷贝到目标机器上就可以了;私有程序集部署方法指的是发布程序程序的时候,将所依赖的crt、mfc、atl的dll放在程序的当前目录下.
静态链接发布
动态链接发布
|----并行程序集 法 (3 种方法)
1 |-----目标机器安装了VS开发环境(vs2005 sp1/vs2008 sp1)则在机器上同时也安装了共享并行程序集,包含各个版本的dll(8.0、9.0版本,位于C:/Windows/Winsxs目录下),则不需做任何的部署,直接将需要发布的程序拷贝到目标机器上就可以了.
2 |-----安装vcredist.exe (Microsoft Visual C++ 2008 SP1 Redistributable Package (x86)
3 |-----用vs2008 的Redistibutable Merge Modules 去install 特定的VC++库,(即用vs2008新建一个Setup and Deployment 的项目包含exe需要的运行库,当install时就把相关的运行时库自动放到winsxs中去了 )
|----私有程序集法 (1 种方法 2 steps)
step1|-----拷贝C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86目录下的文件夹“Microsoft.VC90.CRT”下的4个文件到 应用程序文件夹下如:SCCT\
|--Microsoft.VC90.CRT.manifest
|--msvcm90.dll
|--msvcp90.dll
|--msvcr90.dll
step2|----- 并且修改 application.exe 和 Microsoft.VC90.CRT.manifest 中各自的manifest 描述 运行时库版本不一致问题(只在安装了vs2005 sp1/vs2008 sp1后才会出现),(有2类方法)
1|--------修改application.exe 中manifest描述的运行时库版本号 9.0.21022.8 与 实际compile 时采用的运行时库版本号(Microsoft.VC90.DebugCRT.manifest中9.0.30729.1)一致.
a|------在编译项目时定义一个符号_BIND_TO_CURRENT_VCLIBS_VERSION,该符号定义于C:/Program Files/Microsoft Visual Studio 9.0/VC/include/crtassem.h 文件中(假设VC安装在c盘),这样使得编译后的程序的manifest依赖于CRT 9.0.30729.1版本
b|------(嵌入manifest)通过外部工具修改生成的exe或dll中manifest文件(vc2008 打开application.exe 双击在RT_MANIFEST下的"1" ,或者“记事本”打开application.exe修改版本号 好像windows sdk中的mt.exe也可以做到)
c|------(未嵌入manifest)通过“记事本”打开application.exe.manifest文件修改
2|---------修改实际compile 时采用的运行时库版本号9.0.30729.1(描述在Microsoft.VC90.CRT.manifest中)为 application.exe 中manifest描述的运行时库版本号9.0.21022.8为号一致 .即:用“记事本”在step1的application.exe所在目录中把Microsoft.VC90.CRT.manifest文件描述的版本号9.0.30729.1改为9.0.21022.8。
以上为Release版本的发布方法。Debug版本的application.exe 发布 上面 |----并行程序集 法 (3种方法)的第2中方法行不通。因为vcredist.exe只安装了release版的CRT、MFC、ATL的DLL和manifest文件,没有对应的debug版本。
vc2005 sp1 版本号是: 8.0.50727.726 对应的RTM 版本号是:8.0.50608.0
二、 关于 私有程序集 法 的说明:
1、只有在从未安装过Microsoft.VC90.CRT运行时库的机器中(也就是winsxs文件夹下没有相应的Microsoft.VC90.CRT库),私有程序集法才真正起作用,也就是 application.exe文件调用 当前文件夹下(私有发布的)Microsoft.VC90.CRT 运行时库。
2、如果机器中已经安装了Microsoft.VC90.CRT(也就是winsxs文件夹下能找到),则 当运行application.exe时 首先调用 系统的(winsxs文件夹下)Microsoft.VC90.CRT运行时库,不会调用私有的Microsoft.VC90.CRT运行时库。
3、如果系统中安装的Microsoft.VC90.CRT运行时库有错误,则应用程序不能运行,回报错,也不会调用私有的Microsoft.VC90.CRT运行时库。唯一的解决方法就是 重新install 运行时库。
4、要想强制应用程序application.exe调用 当前文件夹下(私有发布的)Microsoft.VC90.CRT 运行时库,而不管系统有无运行时库,要同时去掉application.exe 和
Microsoft.VC90.CRT.manifest 中的“publicKeyToken” 属性,详见How to bypass the WinSxS for CRT/MFC/ATL DLLs:
If a DLL is installed in the WinSxS folder, the local DLLs will be ignored. So, if you want to be independed from global DLLs, a method is :just remove the “publicKeyToken” attribute from the manifests!
So an application manifest looks like:
Application.exe.manifest:
<?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.CRT"
version="8.0.50727.42" processorArchitecture="x86" />
</dependentAssembly>
</dependency>
</assembly>
You must also set the correct verion-number of the DLL! And remove the “publicKeyToken” attribute.
The manifest the for DLL looks like:
Microsoft.VC80.CRT.Manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="Microsoft.VC80.CRT"
version="8.0.50727.42" processorArchitecture="x86"></assemblyIdentity>
<file name="msvcr80.dll"></file>
<file name="msvcp80.dll"></file>
<file name="msvcm80.dll"></file>
</assembly>
Now the CRT DLLs in the WinSxS will be ignored and only the local DLLs will be loaded.
三、side-by-side assembly方法是MS 没有用注册表来进行的运行库控制,
--------仅仅在Windows XP后的版本才有这个特性
-------VC2005和VC2008采用了具有C runtime libraries 的 SxS
-------而VC2010中已经放弃这中方法,而是直接在dll文件后加一个版本号,用同名的dll 只要版本号不同,以后也视为两个dll。 如 msvcr100.v1.dll
要装载Win32本地 的运行时库到winsxs下,只有通过MSI(the Windows Installer)或第三方专用工具如InstallMate 7才可以, .不能手动加入。
参考链接:
微软的Dll管理方案及其变迁(Side-by-side assembly)http://www.cnblogs.com/zhihuichien/archive/2011/03/24/1993447.html
关于vc2005的找不到MSVCR80.dll的执行错误http://blog.csdn.net/lionzl/article/details/6015394
http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/951fad2d-3e0a-4342-96a7-6aa318c90caa/