VS2008生成的程序無法在其它電腦上運行,提示系統無法執行指定的程序


經過一番查找,最給力的參考是


http://www.cnblogs.com/visoeclipse/archive/2010/02/27/1674866.html


-----------------------以下為轉載--------------------------------------------------------------


首先感謝這位幾仁兄的幾篇博客:


  http://hi.baidu.com/fairysky/blog/item/130dda13db7b050a5aaf53be.html


  http://hi.baidu.com/fairysky/blog/item/e7a8366dbaa735f3431694c8.html


  http://www.cppblog.com/lf426/archive/2008/04/12/46885.aspx



時間緣由:


有時間再來整理:有點凌亂,不好意思。



感謝的XCyber回復:


  為什么這么折騰呢?
  這樣看來,微軟發明manifest是錯誤的,因為大家都為運行庫煩惱,真的還不如VC6,這可能嗎?
其實很簡單,打開你的vs,創建一個Setup and Development下的Setup
Project項目,然后添加Merge Module,選擇你需要的運行庫,最后就是Build,生成的文件與你的程序一起發布就行了;




參考資料


1、VS2005解決"應用程序配置不正確,程序無法啟動"問題


2、VS2005安裝文件
"由於應用程序配置不正確,應用程序未能啟動"


3、Microsoft
Visual C++ 2008發布程序的部署問題


4VC編寫的程序不能在其他機器上運行的解決方案


新增(先看看上面的4個鏈接之后,遇到問題之后再看下面的幾個鏈接)


5關於vs2008
sp1 C++生成的 manifest中運行庫版本號的問題

(
推薦1)


6、在VC++2008的項目中,如何顯示地指定要使用的C++庫的版本? (推薦2)


7、VC9 SP1
generates manifests with the wrong version number


ps:有人認為這是一個bug,並匯報到ms網站上,但“推薦1”認為這不是一個bug


8、VC Runtime
Binding...
(ms的官方blog對這個問題的解釋)


關於VC運行時綁定(上面鏈接的中文翻譯)


9、部署
(C++)
推薦,比較難看懂


關於鏈接9下幾個比較有用的鏈接:


程序集搜索順序英文,主要講的是CRT、MFC等的DLL和manifest文件的部署方式


選擇部署方法


使用
Program Files\Microsoft Visual
Studio 8\VC\Redist目錄中提供的文件將特定
Visual
C++程序集作為應用程序的私有程序集安裝。允許沒有管理員權限的用戶安裝應用程序或可以通過共享運行應用程序時,建議使用這種方法。有關示例,請參見
如何:使用
XCopy進行部署
。(摘自:選擇部署方法



總結如下:


使用vs2008/vs2008開發的程序有2種部署方法:共享並行程序集和私有程序集部署方法


所謂的共享並行程序集部署方法是指程序依賴的CRTMFCATLDLL和manifest文件位於目標機器上的c:\windows\winsxs目錄中,發布程序的時候只需要將程序拷貝到目標機器上就可以了私有程序集部署方法指的是發布程序程序的時候,將所依賴的crt、mfc、atl的dll放在程序的當前目錄下



對於release版程序


比較的簡單的方法采用共享程序集的方式來部署,安裝vcredist.exeMicrosoft Visual C++ 2008 SP1
Redistributable Package (x86
)


也可以采用下面debug程序的私有程序集的部署方法



對於debug版本程序


若目標機器安裝了VS開發環境(vs2005 sp1/vs2008 sp1),則在機器上同時也安裝了共享並行程序集,包含各個版本的dll(8.0、9.0版本,位於C:\Windows\Winsxs目錄下),則不需做任何的部署,直接將需要發布的程序拷貝到目標機器上就可以了,這和release版程序的發布方式是一樣的



在沒有安裝VS開發環境(安裝了vs2005 sp1/vs2008
sp1)的機器上,只能采用私有程序集的方式來部署
(因為vcredist.exe只安裝了release版的CRT、MFC、ATL的DLL和manifest文件,沒有對應的debug版本)


已知的2種方法:(針對vs2008
sp1
,安裝了sp1之后,在系統上會存在兩個版本的CRT、MFC、ATL的DLL:9.0.21022.89.0.30729.1


1、使當前程序的manifest文件中依賴項的版本與vc安裝目錄下的redist目錄下的dll的版本一致,均為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版本(同樣的,對於MFC也應該定義一個類似的符號,大家可以自己在VC的include目錄下搜索“9.0.30729.1”或“9.0.21022.8”,就可以找到對應的定義該符號的頭文件)


b、通過外部工具修改生成的exe或dll中manifest文件(好像windows
sdk中的mt.exe可以做到,不過關於這個工具的資料十分的少)


2、將VC安裝目錄下的redist目錄下(C:\Program Files\Microsoft Visual
Studio 9.0\VC\redist)

Microsoft.VC90.CRT拷貝到要發布的程序的當前目錄下,修改Microsoft.VC90.CRT目錄中的
Microsoft.VC90.CRT.manifest文件中的版本號,改成9.0.21022.8,這樣使得程序誤以為該目錄下的vc的dll版本是
9.0.21022.8(實質上仍然是9.0.30729.1版本)



說明:


1、鏈接4
的說法是錯誤的,根據我自己的實驗,如果采用私有程序集的部署方法,必須保證manifest文件中的版本號都是相等的,不存在要發布的程序的manifest文件中的版本號大於等於依賴項(CRT、MFC、ATL的dll)的版本號的說法


2、采用共享並行程序集部署方式發布的程序,會自動根據所謂的“policy”(位於C:\WINDOWS\WinSxS\Policies目錄下)進行跳轉(由低版本號向高版本號跳轉);例如程序中的manifest的版本號為9.0.21022.8而實際上程序是用vc2008 sp1編譯的(版本號為9.0.30729.1,在程序實際執行的時候,會根據


x86_policy.9.0.Microsoft.VC90.DebugCRT_1fc8b3b9a1e18e3b_x-ww_037be232目錄下的9.0.30729.1.policy文件可以用記事本打開該文件中的內容選擇9.0.30729.1版本的debugCRT




我個人推薦的閱讀順序:①
先看前面的4個鏈接,大致有點印象,知道什么是manifest、如何查看manifest文件的內容(能力強的話,也可以自己編寫manifest文件)、在vc中如何查看編譯過程中生成的manifest文件內容、知道
C:\WINDOWS\WinSxS\目錄是干什么的、知道vcredist.exe這個程序;
② 再嘗試着看看鏈接7、8、9,這些鏈接的文章內容十分的晦澀,有的還是英文的,需要有點耐心看; ③
最后仔細的看看鏈
接5、6,並多多試驗(特別推薦鏈接5,這個鏈接中的內容十分的詳細)



 




vc2005/vc2008采用了新的程序部署技術(manifest清單文件),manifest清單文件實際上類似於我們常用的makefile文件,它定義了程序運行的依賴關系(程序運行所需要的dll庫的名稱、版本等)。


程序運行,首先根據manifest清單文件(這個文件可以嵌入到exe或dll中,或者單獨生成外部文件,可以通過vc2005/vc2008的編譯選項控制:工程“屬性”->“配置屬性”->“清單工具”->“輸入輸出”->“嵌入清單文件”,選擇“是”或“否”來控制)來查找程序運行需要的dll庫的名稱、版本等,如果所在的系統中沒有程序運行所需要的dll庫和相應的manifest清單文件,則彈出“應用程序配置不正確,程序無法啟動”對話框。




外要注意,由於vc2005/vc2008與.net集成,導致出現一個新的概念:在.net中,將exe、dll都看成“程序集
(assemble)”,每個程序集(assemble)都附帶有一個manifest清單文件,因此使得vc2005/vc2008的CRT(C
運行時庫)、MFC、ATL等dll庫都附帶有一個manifest清單文件。



根結底是由於老版本的系統沒有我們開發的程序運行所需要的基本運行時庫(2k、xp系統只有vc6的一些dll庫,而沒有vc2005、vc2008所需
要的dll庫以及相應的manifest清單文件,而在vista系統或者即將到來的windows
7系統上則包含有vc2005、vc2008的dll庫和manifest清單文件)


ps:上面的那段話說的有點幼稚和簡單了,這里涉及到很多的問題:程序的升級更新、vs的補丁、庫的版本問題等等,不是簡單的拷貝、粘貼就能解決的。。。





舉個例子:(在XP SP3系統下)


 


使用vc2008 express sp1版(沒有mfc、atl),新建一個“HelloWorld”的“win32控制台應用程序”工程,在release下編譯,此時默認的編譯選項:(在這里我們只關注與我們的問題相關的幾個選項)


1、工程“屬性”->“配置屬性”->“c/c++”->“代碼生成”->“運行庫”


默認選項為/MD(release)、/MDd(debug),對這幾個編譯選項不清楚的可以參見:
VC運行庫版本不同導致鏈接.LIB靜態庫時發生重復定義問題的一個案例分析和總結


2、工程“屬性”->“配置屬性”->“清單工具”->“輸入輸出”->“嵌入清單文件”


默認選項為“是”(表示將manifest清單文件嵌入到程序中);當然,我們也可以選擇“否”,從而單獨生成一個manifest清單文件,不過這會增加不必要的依賴項,因此不建議選擇“否”。


編譯->鏈接之后在“ HelloWorld
”工程的release或debug目錄下,我們能夠看到一個HelloWorld.exe.intermediate.manifest清單文件(
根據編譯選項,見上,vc2008將manifest清單文件嵌入到了exe程序中,HelloWorld.exe.intermediate.manifest清單文件是一個臨時文件,但它的內容與嵌入到exe程序的manifest文件是一樣的),用文本編輯器打開該文件(用“記事本”也行,不過格式太亂,看不清楚內容,推薦使用vim或其它的文本編輯器查看),大致內容如下:


ps:在網上看到另外的一個方法,用記事本打開exe或dll程序,查看嵌入到exe或dll中的manifest清單文件,方法:“打開記事本,然后將exe或dll拖入到記事本中,當然了,肯定會出現大段的亂碼,沒關系,直接往后看,就能發現類似於下面的內容的部分


XML語言: HelloWorld.exe.intermediate.manifest


01 <?xml version='1.0'
encoding='UTF-8' standalone='yes'?>

02 <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
03 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
04      <security>
05       
<requestedPrivileges>

06          <requestedExecutionLevel
level=
'asInvoker' uiAccess='false' />
07       
</requestedPrivileges>

08      </security>
09 </trustInfo>
10 <dependency>
11     
<dependentAssembly>

12        <assemblyIdentity
type=
'win32' name='Microsoft.VC90.CRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
13     
</dependentAssembly>

14 </dependency>
15 </assembly>


我們重點查看紅色部分,這說明編譯后的exe程序依賴於vc90(也即vc2008)的CRT(C運行時庫),版本9.0.210022.8(這是由於使用/MD選項,程序動態的依賴於CRT,如果使用/MT選項,則會將CRT靜態鏈接到程序中,當然,這會使程序的尺寸急劇的增長,大概有10倍的大小差距)


當exe程序執行時,它會根據嵌入的manifest文件查找相應的依賴項,在這個HelloWorld.exe程序中,它依賴於vc90
CRT
,因此它會在“C:\WINDOWS\WinSxS”和“當前目錄”下查找相應的dll庫以及manifest文件,(這里指的是xp系統,不考慮vista系統,具體的參見:程序集搜索順序)


在我的機器上有2個版本的vc90 CRT(由於安裝了vc2008 express sp1)


vc90
CRT的dll庫位於
9.0.21022.8版本)“C:\WINDOWS\WinSxS\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375”


相應的manifest文件則位於“C:\WINDOWS\WinSxS\Manifests\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375.manifest”


vc90
CRT的dll庫位於
9.0.30729版本)“C:\WINDOWS\WinSxS\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_6f74963e”


相應的manifest文件則位於“C:\WINDOWS\WinSxS\Manifests\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_6f74963e.manifest”


在這里我們就有一個疑問了,我們的開發環境是vc2008
express sp1,那么我們的程序鏈接的CRT版本應該是
9.0.30729版本的啊?這個不是我瞎說的,大家可以用dependency
walker
來查看程序實際鏈接的DLL版本),為什么在manifest文件中依賴的CRT卻是9.0.21022.8版本的?
這里就涉及到一個新的名詞“policy ",操作系統會根據C:\WINDOWS\WinSxS\Policies
\x86_policy.9.0.Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_x-ww_b7353f75
\9.0.30729.1.policy文件的內容,進行dll版本的跳轉(
重點看深藍斜體字部分)從而選擇了9.0.30729版本vc90 CRT
(這個所謂的“policy跳轉”是道聽途說來的,具體的英文資料藏在microsoft的什么地方我就不得而知了。里面夾帶了一些我自己的主觀猜測,不然的話,沒有辦法解釋manifest版本號9.0.21022.8是,而實際鏈接的dll的版本號卻是9.0.30729




XML語言: 9.0.30729.1.policy

01 <?xml
version="1.0" encoding="UTF-8" standalone="yes"?>

02 <!-- Copyright
(c) Microsoft Corporation. All rights reserved. -->

03 <assembly xmlns= "urn:schemas-microsoft-com:asm.v1"
manifestVersion= "1.0" >
04    
<assemblyIdentity type= "win32-policy" name= "policy.9.0.Microsoft.VC90.CRT" version= "9.0.30729.1" processorArchitecture= "x86" publicKeyToken= "1fc8b3b9a1e18e3b" />
05
    <dependency>
06         <dependentAssembly>
07             <assemblyIdentity type= "win32" name= "Microsoft.VC90.CRT" processorArchitecture= "x86" publicKeyToken= "1fc8b3b9a1e18e3b" />
08             <bindingRedirect oldVersion="9.0.20718.0-9.0.21022.8" newVersion="9.0.30729.1"/>
09
            <bindingRedirect oldVersion="9.0.30201.0-9.0.30729.1" newVersion="9.0.30729.1"/>

10         </dependentAssembly>
11     </dependency>
12 </assembly>



如果我們將這個HelloWorld.exe拷貝到其它的機器上(沒有安裝vc2008 sp1Microsoft
Visual C++ 2008 SP1
Redistributable
Package (x86)
),則程序因為沒能找到vc90
CRT
,而不能運行,彈出“應用程序配置不正確,程序無法啟動”對話框。


根據參考資料的文章中的內容,對於release版程序,有一個簡單的辦法就是安裝vcredist_x86.exe”,文件大小4M左右,自動安裝在“C:\WINDOWS\WinSxS目錄下,包含了CRT、MFC、ATL等庫的dll和manifest清單文件;整個安裝時間不到1分鍾。


如果機器上安裝了vc2005/vc2008,則會自動的安裝vcredist_x86.exe程序,安裝后在“控制面板”->“添加刪除程序”中有一項“Microsoft Visual
c++ 2008 Redistributable - x86 9.0.3.729
”(我安裝的是Microsoft Visual C++ 2008 SP1
Redistributable Package (x86) 版
本)


注意:要根據編譯器版本以及vc2005/vc2008是否安裝了sp1補丁進行選擇對應的vcredist.exe版本




上述的解決辦法我稱之為共享程序集部署方法,同樣的我們也可以采用私有程序集的部署方式來發布程序



Helloworld例子的私有程序集的部署方法:(針對release版本,仍然是采用上面的例子


,采用參考資料中提到的第2中私有程序集部署方法:將Microsoft.VC90.CRT目錄下的manifest文件的版本號修改為9.0.21022.8


1、將編譯后的程序拷貝到一個目錄下,假定為d:\helloworld


2、將vc安裝目錄下的redist\x86目錄下的Microsoft.VC90.CRT目錄拷貝到d:\helloworld(假定vs安裝在C:\Program
Files\Microsoft Visual Studio 9.0,則vc安裝目錄為C:\Program Files\Microsoft Visual
Studio 9.0\VC)


3、將Microsoft.VC90.CRT目錄下的manifest文件的版本號修改為9.0.21022.8用記事本打開修改


最終發布程序的目錄結構


D:\helloworld


     
|--helloworld.exe


     
|--Microsoft.VC90.CRT


                    
|--Microsoft.VC90.CRT.manifest


                   
|--msvcm90.dll


                    
|--msvcp90.dll


                   
|--msvcr90.dll


這個時候,程序的manifest文件(已經內嵌到exe中了)依賴的vc90
CRT的版本號和
Microsoft.VC90.CRT.manifest文件的版本號對應一致,都是9.0.21022.8但是要注意的是,我們的helloworld程序實際上依賴的vc90
CRT版本是
9.0.30729版本這里只是采用了一種欺騙的方法,因為我們編譯時鏈接的CRT的版本是9.0.30729版本)



例子是針對release版,對於debug版本必須要采用私有程序的部署方法,這是拷貝的目錄就不是release版的Microsoft.VC90.CRT了,而是Microsoft.VC90.DebugCRT,方法同release版的是一樣的




Microsoft Visual C++ 2008 發布程序的部署問題 生成Microsoft.VC90.CRT文件目錄結構:


VC2005和VC2008編譯出來的程序放到別人的電腦上為什么有可能無法運行呢?
       
這個問題無數人在問,但是很遺憾,沒有人給出完整的解釋和完美的解決方案。其實我也只有一台電腦,而且裝了VC了,這個問題必須要台沒有裝這類軟件的電腦
才容易去分析。感謝那些為了測試我小程序的朋友,是你們一次次在如此惡劣的網絡速度下收取我一次次修改的dll包和部署文件,才讓這個問題的完美解決方案
浮出水面。這里就把我的經驗給大家分享吧。

1:Microsoft Visual C++ 2008 Express
Edition可以發布軟件嗎?

        能!
       
很多人說,因為是Express版,不是Studio,所以只是用來練習語言的,不能發布軟件——錯!
        除了沒有MFC和ATL,基本上跟
.net 版本是一樣的。發布出來的,是完整的可執行文件。

2:VC 2008 (2005)
發布出來的程序必須附帶上他們特定的dll文件嗎?

        不一定。
       
如果目標系統是個經常升級的系統,微軟已經為其打上了所需要的dll文件補丁了,不需要在軟件包里面附加特定的dll文件。特別在Vista系統中,你更是不需要VC8和VC9的dll文件。但是在一些老版本的系統中,這些文件就是必須的。

3:VC2008和VC2005特定的dll文件是哪些?

VC8:
msvcm80.dll, msvcp80.dll, msvcr80.dll
VC9: msvcm90.dll, msvcp90.dll,
msvcr90.dll

4:如何部署文件?

首先,請選擇release版本;在生成可執行文件(exe文件)的時候,會得到相應的部署文件(manifest文件)。
比如,得到a.exe文件,就會同時生成a.exe.intermediate.manifest文件。請將這2個文件放在同一文件夾下。
然后,你需要VC8和VC9的部署文件:Microsoft.VC80.CRT.manifest和Microsoft.VC90.CRT.manifest。
請到你的VC安裝目錄下尋找,比如:
C:\Program
Files\Microsoft Visual Studio
9.0\VC\redist\x86\Microsoft.VC90.CRT
我這里也把2個部署文件直接貼出來,沒裝的直接用就是了:
Microsoft.VC80.CRT.manifest


<? xml version="1.0" encoding="UTF-8" standalone="yes" ?>
< assembly xmlns ="urn:schemas-microsoft-com:asm.v1" manifestVersion ="1.0" >
< noInheritable ></ noInheritable >
< assemblyIdentity type ="win32" name ="Microsoft.VC80.CRT" version ="8.0.50727.762" processorArchitecture ="x86" publicKeyToken ="1fc8b3b9a1e18e3b" ></ assemblyIdentity >
< file name ="msvcr80.dll" /> < file name ="msvcp80.dll" /> < file name ="msvcm80.dll" />
</ assembly >
Microsoft.VC90.CRT.manifest

<? xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!-- Copyright (c) Microsoft Corporation.  All rights reserved. -->
< assembly xmlns ="urn:schemas-microsoft-com:asm.v1" manifestVersion ="1.0" >
   
< noInheritable />
   
< assemblyIdentity
       
type ="win32"
        name
="Microsoft.VC90.CRT"
        version
="9.0.21022.8"
        processorArchitecture
="x86"
        publicKeyToken
="1fc8b3b9a1e18e3b"
   
/>
   
< file name ="msvcr90.dll" /> < file name ="msvcp90.dll" /> < file name ="msvcm90.dll" />
</ assembly >
然后將VC8的3個dll以及這個manifest裝到一個文件夾里,並將文件夾命名為Microsoft.VC80.CRT。
同樣將VC9的3個dll以及這個manifest裝到一個文件夾里,並將文件夾命名為Microsoft.VC90.CRT。
將這2個文件夾放到與exe文件(及其部署文件)所在目錄下就OK了。
至於為什么VC9編譯的程序要用VC8的dll,大家可以看看我例程部署文件:

<? xml version='1.0' encoding='UTF-8' standalone='yes' ?>
< assembly xmlns ='urn:schemas-microsoft-com:asm.v1' manifestVersion ='1.0'>
 
<trustInfo xmlns ="urn:schemas-microsoft-com:asm.v3" >
   
< security >
     
< requestedPrivileges >
       
< requestedExecutionLevel level ='asInvoker' uiAccess ='false' />
     
</ requestedPrivileges >
   
</ security >
 
</ trustInfo >
 
< dependency >
   
< dependentAssembly >
     
< assemblyIdentity type ='win32' name ='Microsoft.VC90.CRT' version ='9.0.21022.8' processorArchitecture ='x86' publicKeyToken ='1fc8b3b9a1e18e3b' />
   
</ dependentAssembly >
 
</ dependency >
 
< dependency >
   
< dependentAssembly >
     
< assemblyIdentity type ='win32' name ='Microsoft.VC80.CRT' version ='8.0.50727.762' processorArchitecture ='x86' publicKeyToken ='1fc8b3b9a1e18e3b' />
   
</ dependentAssembly >
 
</ dependency >
</ assembly >
VC
2008生成出來就需要VC90和VC80的CRT,我們能有什么脾氣呢……
也就是說,還別管你exe文件多大,要保證正常運行,我們需要首先拷貝這8個文件……
MinGW(gcc)編譯的就沒這些麻煩。所以,我現在都是用兩個編譯器編譯兩個exe以供發布了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM