如何用 VS 2013 打包 VC++ 程序?

如題,我用VS2013寫好了一個程序,在本機上運行一切正常。但是如果直接把exe文件放到另一台機器上用,則會出現:

Windows XP:不是一個正常的win32程序

Windows 7:缺少msvcp120d.dll

能否有一種方法把程序運行所需要的環境一併打包,使之可以在任何Windows計算機上使用?

ps:小問題——用VS2013寫出來的VC++程序,編譯過之後是機器代碼還是.net託管代碼?


現在,我們深入探討一下:

《如何使用VS 2013發布一個可以在Windows XP中獨立運行的可執行文件》。

這個問題是比較常見且容易造成初學者困惑的,作為曾經撞了無數次南牆的初級代碼狗終於看到了自己能夠回答的問題,那麼就讓我來簡單闡述一下造成這個問題的簡單原理極其簡單解決方法,如有錯誤紕漏敬請指正。

/*我們討論的是非託管的C++程序。*/

為了方便說明,我們新建一個簡單的控制台應用程序項目,直接如圖:

非常簡單,一個使用了C++標準庫的控制台應用程序,在裝有開發環境的本機順利執行出如下效果:

真是一個曠世奇作,我們迫不及待地就此發給XP老哥炫耀,萬萬沒想到:

裝逼不成反被XP老哥奚落:「負分滾粗!」

這裡我們遇到了題主遇到的問題之一,確實叫人納悶,不過隨便搜索一下就會有解決方法:

是的,在項目配置屬性中,將平台工具集選擇為"Visual Studio 2013 - Windows XP (v120_xp)",即可解決「無效的 Win32 應用程序」問題

但是我們還要知其所以然,為什麼?

項目默認的Visual Studio 2013(v120) 與 Visual Studio 2013 - Windows XP(v120_xp) 生成出來的可執行文件有何區別,以至於前者在XP上執行會出現那樣的錯誤?

最直覺的方法自然是比較一下兩版執行文件的區別,我們選用PE (Portable Executable:32位或64位Windows操作系統使用的可執行程序或者動態鏈接庫的文件格式)工具 Stud_PE 進行PE文件頭結構比較,很容易看到區別:

看到打紅叉的地方,就是兩個文件不同之處,其他地方几乎沒有區別。

關於PE文件結構是另外一個話題,我們暫不深入討論。

單就這兩處我們顧名思義一下就很容易明白:

MajorOSVersion ,(目標)操作系統主版本號 ,選擇默認平台工具集的文件的值是6,後者是5。

MinorOSVersion ,(目標)操作系統次版本號,前者是0,後者是1。

MajorSubsystemVersion,(目標)Win32子系統主版本號,前者是6,後者是5。

MinorSubsystemVersion,(目標)Win32子系統次版本號,前者是0,後者是1。

總結一下:一個是6.0 ,一個是5.1 。

很明顯5.1不就是XP的版本號么,6.0就是Vista唄?

我們是否可以認為,項目默認選擇的「平台工具集」生成的可執行文件是不能在6.0以下版本的Windows運行的?

試驗結果是:當我把6.0手動修改成5.1之後,這個文件立刻可以正常在XP里運行了,事實上Major/MinorOSVersion的值似乎沒有起到什麼作用,僅僅修改XxxxxSubsystemVersion的值就可以保證程序順利執行起來了。反之亦然。同時還發現:在XP中,改為5.1可以,5.2及更高就不行。

對於這個問題的認識雖然仍流於表面,但由於知識有限,我們就不再深究PE結構中的這幾個值的深層次含義了。當然如有大牛指點一二就更好了。

現在好了!我們不但解決了XP的運行問題,還大致了解了問題的根源。那麼讓我們繼續發布吧!

將新的、XP的、「5.1的」版本發給XP老哥:

我勒個去?你等等,我再編譯一個release版本…… 試試:

擦?不是說好的「Release"嗎?你等等,不就是一個dll文件嗎,我這裡有!我發給你……

我從自己的系統(Win 8.1 x64)C:Wdinwossystem32 文件夾找一個MSVCP120.DLL發過去:

是啊,這不是逗呢?拿64位的dll文件去冒充32位,能行? 重新去VS目錄里扒一個正確的32位msvcp120.dll 補上:

又來,這次叫做MSVCR120.dll ,不仔細看還真沒認出來。繼續補上:

呵呵呵呵呵,終於得以正確運行了,但是這麼狼狽的炫耀怎麼能讓人高興起來呢?

經過一番折騰,好歹知道了是因為缺少文件,那麼下次發布程序把這些瓶瓶罐罐DDLL都帶上打包不就行了嗎?沒錯,確實是這麼個道理,但總感覺很不專業的樣子。

所以一個正常的解決方案就是和其他答案中所說的那樣,讓目標機器安裝

VisualC++Redistributable Packages forVisualStudio2013 。

這個東西的作用就是:

安裝運行使用 VisualStudio2013 生成的 C++ 應用程序時所需的運行時組件。

簡單觀察安裝後系統中多出了哪些文件:

這樣一看,「運行時組件」就變得直觀和具體了。

它們都是什麼呢?我們先去VS的安裝目錄中看一下:

通過路徑很容易理解,這是有關VC的redist(再發行)的東西,我們進x86看一下:

有關CRT(運行時庫),MFC,MFCLOC(MFC的本地化文件)等等,我們看看CRT裡面:

看到了眼熟的這兩個dll了,實際上你參考前面那個XP多出文件的圖片,那些dll都能在這裡找到。

這就是 Visual C++ Redistributable 包括的東西,每個VS版本都不一樣。VS2013對應的就是120。

那管它是VS2013還是2012還是2008,對應的發行包給裝上不就完了。

沒錯。但是我們還要繼續研究一下,至少,研究一下如何讓一個可執行文件「獨立」運行在XP上。

回到項目配置,如下圖:

我們看到,運行庫這一項,包含4種選擇。

廢話不多說,我們簡單粗暴乾脆每一種都生成一個進行比較:

四種版本,分別起了對應的名稱,多線程(MT),多線程DLL(MD),多線程調試(MTd),多線程調試DLL(MDd)。

利用 Stud_PE 觀察比較它們的 函數導入表 ,發現:

1. 多線程DLL (MD)和 多線程調試DLL (MDd)

兩者都導入了2個MSVCxxxx.dll (黃箭頭所指),但細看又不同,調試版本(MDd)導入的是MSVCP120D.dll和MSVCR120D.dll,比非調試(MD)的那個都多一個字母D。很明顯這是配套給調試版的運行時庫。而我們之前安裝的發行包所部署的都是不帶D的版本,是給Release版的程序配套使用的。

順便一提MSVCP代表MicroSoft Visual C++(Plus) ,MSVCR則代表MicroSoft Visual C(沒有+)Runtime。 一個是C++運行時庫一個是C運行時庫。

2.多線程(MT) 與 多線程調試(MTd)貌似一樣,都沒有MSVCP和MSVCR函數導入,只有Kernel32.dll。同時觀察這兩個文件的體積,都比MD或MDd大了很多,這正是它們不需要導入運行時庫DLL函數的原因,因為它們把運行時庫靜態編譯到自己的文件中去了。這也代表著它們運行的時候不會再依賴外部的運行時庫DLL文件。

所以答案就在這裡,想要你的exe獨立運行在XP中:

1.將平台工具集選擇為"Visual Studio 2013 - Windows XP (v120_xp)"。

2.將運行庫選擇為 【多線程 /MT 】或【多線程調試 /MTd】。

3.當然如果使用了MFC,同理的要設置【在靜態庫中使用MFC】:

事情很簡單,大致就是這樣了。


msvcp120d 以 d 結尾,按照微軟的慣例這是個debug版本的dll。

你編譯成release版本先,debug版本的dll只有裝了開發工具的機器上才會有。

另外如果還是缺乏 msvcp120.dll ,可以先安裝下,MSVCRT 的 120版本。

Visual C++ Redistributable Packages for Visual Studio 2013

如果你用MSI打安裝包的話,可以選擇添加msvcrt支持。


1 開發面向XP的程序的話,需要改用v120_xp工具集。默認是v120,連接的CRT庫啦(不要告訴我你不用new只用VirtualAlloc)Windows SDK庫啦都不支持XP。

2 當然可以,市面上很多打包程序,不想用打包軟體的話自己把需要用的DLLzip一個包也是可以的。不過打包msvcp120d.dll給外部用戶是違反最終用戶授權協議的,這個是調試版的DLL,僅供內部測試用。正式發布的時候應該打包Release版的程序。


我注意到了一件事:

Windows 7:缺少msvcp120d.dll——你莫非給人複製的還是debug版本的exe?

把dll打包就好了,包括其它第三方庫的dll。


這個是常識啦。

在項目屬性里,選擇c++標籤頁,在代碼生成那裡,有個運行時庫,記得選第一個(默認的選擇是一定會依賴 比如某個 mscrt XX (d).dll 的 。這樣它就不會引入和你的 vs 相關的 dll 了。

還有我個人還會在第一個標籤頁哪裡,選擇靜態鏈接 atl 。(這個好像最好這麼選吧,我不確定)。

生成後,你可以用 dependency 程序打開你的 exe/dll ,check 一下它都導入了那些 dll。只要引用的都是你提供的,或者系統一定有的 dll。就沒問題了。


看了@無聊仔寫的,不明覺厲。

如果樓主有以下想法,請接著看:

1,我就是不想再設置了

2,我就是不想重新編譯了

3,我就這麼編怎麼滴吧

於是乎,樓主,在一個風高月黑的晚上,對著屏幕,苦思冥想,抽一口香煙,摸摸渣渣的鬍鬚,打開了網頁,從網上下了一個叫InstallShield的神器,本著No Zuo No Die的宗旨,樓主摸摸的看了下神器的版本,是最新版

樓主安裝了神器,顯示器瞬間閃閃發光,如有神助,一個激靈,小手一抖,打開了神器,創建了一個工程,所有內容,赤裸裸的暴露在了樓主面前:

煙鬼正傳:

1,添加需要打包的文件的時候,InstallShield會自動提醒你,是否添加文件需要的依賴【解決了樓主的問題】

2,InstallShield的強大不至於此,比如:版本控制,InstallScript腳本,各種事件,函數,滿足你的一切打包需求。

利益相關:

和InstallShield沒什麼相關,覺得好用而已。


  VS2005或者VS2008(包括VS2008 SP1)下寫的MFC程序如果在別的電腦上不能運行,那麼在編譯的時候選擇MFC靜態庫就OK了,雖然程序會大不少。

  但是如果是Win32 Application,那麼即便是使用MFC靜態庫也不解決問題了(事實上,此時根本就不能編譯通過)。其實要使Win32程序在其他電腦上能夠運行,還是很簡單的。

  首先,你需要提供工程Release文件夾下的exe文件。以及Release文件夾下的manifest文件(注意VC2005開始工程有兩個Release文件夾了)。將這兩個文件放在同一目錄下。

  然後,進入VS安裝目錄下的VC目錄,搜索「Microsoft.VC90.CRT」或者「Microsoft.VC80.CRT」,具體情況視版本而定。這裡我的是VS2008 SP1,版本是VC9。所以搜索前者。(實際路徑為C:Program FilesMicrosoft Visual Studio 9.0VC
edistx86Microsoft.VC90.CRT)。複製該文件夾到exe文件的同一目錄,把這裡得到的文件一同發布就可以運行了exe了。

  相應VS2010也存在同樣的問題,解決方案依葫蘆畫瓢。

轉自:VS2005/VS2008下Win32應用程序發布


FROM: 用VS編譯出可獨立運行的程序

使用vs2010編譯出來的EXE應用程序在別的機子上運行時會提示找不到MSVCR100.dll,這該怎麼解決呢?

一、在運行程序的計算機上安裝vc2010運行庫

說明:這種方法需要用戶自己去安裝,一般適用於大型程序,小程序不建議使用。

二、在應用程序同目錄上附帶MSVCR100.DLL文件

說明:這種方法適用於一些小項目,無需用戶另外安裝程序。

點我下載msvcr100.dll

三、在程序編譯前配置VS2010

項目-&>屬性-&>配置屬性-&>C/C++-代碼生成-&>運行庫-&>多線程 (/MT)

說明:這種方法應該對於一些程序來說最實用,僅需一個程序,放到哪都可以運行。

/MT意思就是靜態編譯VC運行庫,靜態了之後就不會再依賴MSVCR100.DLL或者MSVCR80.DLL(使用VS2005)了。

附帶說明:

MSVCR80.DLL是vs2005編譯器默認的庫

MSVCR90.DLL是vs2008

MSVCR100.DLL是vs2010的


這個問題會給太多的新手VC程序員帶來困擾,可以參考文章:VC程序如何靜態鏈接VC運行庫到單個exe-項目經驗 ,可以很好的解答這個問題,供參考。


Windows XP Targeting with C++ in Visual Studio 2012 -- 其實就是要鏈接7.1A SDK.

How to target XP with VC2012 or VC2013 and continue to use the Windows 8.x SDK 沒試過,黑科技么?


只能在xpsp3上啊,

xpsp1/xpsp2都不行


部署機器安裝一遍VS2013 redistribute package


推薦閱讀:

設計C++函數傳參時如何決定使用指針還是引用?
C++的編譯單元要知道所有的實現?
switch語句中,case的後面為什麼必須是常量?
C/C++ 中怎樣優雅的寫多判斷 if 語句?
C語言的宏定義和C++的內聯函數有什麼意義?

TAG:C | MicrosoftVisualStudio |