最近在新裝的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
關於manifest,這個文章最detailhttp://blog.csdn.net/fuzb/article/details/6730826
How to bypass the WinSxS for CRT/MFC/ATL DLLshttp://blog.kalmbachnet.de/?postid=80
Vista & Windows Side by Side Assemblieshttp://kartones.net/blogs/kartones/archive/2007/05/01/vista-windows-side-by-side-assemblies.aspx
如何:部署“安裝和部署項目”http://msdn.microsoft.com/zh-cn/library/ms235317(v=VS.90).aspx
http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/951fad2d-3e0a-4342-96a7-6aa318c90caa/