VC分發(fā)包版本問題來源: http://www.cnblogs.com/mixiyou/archive/2010/02/09/1663620.html 之前曾經(jīng)寫過一篇個人經(jīng)歷,是關于VC2005分發(fā)包版本不一致而引起應用程序無法正常啟動的( http://www.cnblogs.com/mixiyou/archive/2009/10/02/1575311.html )。這篇文章里只是介紹了個人在開發(fā)過程中遇到的一個非常極品的問題,但是沒有給出更多詳細的信息和解決方法。今日偶然看到一篇牛人寫的文章,順手翻譯下來,總算了了長久以來的心愿。 原文地址: http://dumian.spaces./blog/cns!B67A33A47F9F9C48!459.entry /////////////////////////////////////////////// 原文 //////////////////////////////////////////// VC redistributable security update -KB971090 mitigation problemProblem After installing KB971090 for Visual C++ 2005 SP1, the version of ATL/MFC/CRT referenced in the generated manifests is changed from 8.0.50727.762 to 8.0.50727.4053 The above change forces the application developer to rebuild all components to reference the 4053 version of the versions of ATL/MFC/CRT in the manifest, as well as making it necessary to ship a new vcredist_x86.exe and/or MSM files containing the new 4053 versions of ATL/MFC/CRT. Solution Instead of uninstalling the KB971090 update, we can force the build to use the 8.0.50727.762 version instead of the default which is 8.0.50727.4053. Microsoft provides a mechanism to specify the assembly version number to use in the manifests. Steps to take to allow your applications to reference 8.0.50727.762 instead of 8.0.50727.4053 1) Create a file named targetsxs.h with the following content and put it in a common location #ifndef __midl #define _SXS_ASSEMBLY_VERSION "8.0.50727.762" #define _CRT_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION #define _MFC_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION #define _ATL_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION #ifdef __cplusplus extern "C" { #endif __declspec(selectany) int _forceCRTManifest; __declspec(selectany) int _forceMFCManifest; __declspec(selectany) int _forceAtlDllManifest; __declspec(selectany) int _forceCRTManifestRTM; __declspec(selectany) int _forceMFCManifestRTM; __declspec(selectany) int _forceAtlDllManifestRTM; #ifdef __cplusplus } #endif #endif 2) The above file needs to be included in every project you wish to build. Accomplish this in one of two ways. The first method involves the changing of source code. The second involves changing of project settings. choose A or B which ever one is more appropriate for your situation: A) #include "targetsxs.h" near the top of every one of your stdafx.h files (using the path you saved the targetsxs.h) B) Use the force include (/FI) compile option to make sure that the above file is included in every file built. To accomplish that, add the following command line to your compiler options /FIc:\path\targetsxs.h (where c:\path is the location of the targetsxs.h you created in step 1) There are two methods to accomplish that: either directly in your project or through a compiler environment variable: Method i) Add the above to the command line section of the C/C++ project properties. Method ii) Create an environment variable named CL with the above-mentioned /FI statement Method (ii) is more convenient to use when you have dozens of projects that you do not wish to make changes to, but may conflict with other work you do on your machine. 3) For every MFC DLL project in your solution add the following line to the bottom of the stdafx.cpp file #include "..\src\mfc\dllmodul.cpp" Step three is only necessary if you have any MFC DLL projects (this step is necessary due to a bug in the handling of the assembly versions in MFC DLLs – the bug is that a reference to the latest version of the DLLs will always be included regardless of what is set in step 1) 4) Do a rebuild all of all the projects in your solution 5) Inspect manifest files (by doing a find in files for *.intermediate.manifest) to ensure that 4053 no longer appears in any of the manifests. 6) Run your app on a machine that has no 4053 components installed to WinSxS to make sure runs properly. IMPORTANT NOTE: if you have ATL controls that are affected by this security problem please ensure you have followed the directions to modify your controls to take advantage of the security updates. A simple recompile may not be enough. For more info please see the video at: http://channel9./posts/Charles/Out-of-Band-Inside-the-ATL-Security-Update/ Q&A Does referencing 762 instead of 4053 make your application less secure? No. Microsoft provides WinSxS policy redirection, so any application referencing 762 will end up loading the 4053 versions (if they’re installed). The ATL security update redistributable has been released as an update on Windows Update, so the 4053 version of ATL will be in place, and will be used even though your app still references the 762 version of ATL. *Important note: you should still ship the new version of the redistributable if at all possible, as users may have not updated using Windows Update. What are the benefits to referencing 762 instead of 4053 in your SP1 applications? 1) If you have existing applications shipped and you need to rebuild any components shipped, then new MSM or vcredist_x86.exe containing 4053 versions do not need to be shipped. You can continue to ship existing components with 762 versions. 2) If you have existing third party static libraries that reference 762, then you need not rebuild them to reference 4053. Does VC2008 SP1 security update have a similar issue? Yes, it does, if you use _BIND_TO_CURRENT_VCLIBS_VERSION in your project. It will bind to the security update version instead of the SP1 version. You can use a similar technique as described above (step 3 is not required) to get around this problem. For VC2008 SP1 the values for the current versions of the CRT/MFC/ATL have changed slightly, instead of _forceCRTManifest, you should use _forceCRTManifestCUR. The same thing applies for MFC/ATL (add the CUR). And of course, the version numbers you’re dealing with are different: SP1 9.0.30729.1 vs the new SP1+security update which is 9.0.30729.4148 ///////////////////////////////////////// 譯文 ///////////////////////////////////////// VC分發(fā)包安全更新--KB971090的修正之道 [注] KB971090的描述: http://support.microsoft.com/kb/971090/zh-cn KB971090的下載地址: http://www.microsoft.com/downloads/details.aspx?familyid=7C8729DC-06A2-4538-A90D-FF9464DC0197&displaylang=zh-cn [問題描述] 在安裝了Visual C++ 2005 SP1的KB971090安全更新后,VC生成的manifest中引用的ATL/MFC/CRT庫的版本從8.0.50727.762變成了8.0.50727.4053。 正因為上面的變動,導致了應用程序開發(fā)者必須重新編譯所有的組件使它們在manifest中指向4053版本的ATL/MFC/CRT庫,同時在發(fā)布應用程序的時候還必須部署一個新的vcredist_x86.exe(對應8.0.50727.4053版本)或者在安裝文件中內嵌包含了最新4053版本的ATL/MFC/CRG庫的MSM文件。 [解決之道] 除了卸載KB971090更新之外,我們還可以強制使用8.0.50727.762版本的庫來替換此時默認8.0.50727.4053的庫。Microsoft提供了一種在manifest文件中指定使用哪種版本編譯庫的機制。 使得你的應用程序從指向8.0.50727.4053變?yōu)橹赶?.0.50727.762的步驟如下: 1) 創(chuàng)建一個名為targetsxs.h的頭文件,填入下面的內容,保存在某個固定目錄下。 #ifndef __midl #define _SXS_ASSEMBLY_VERSION "8.0.50727.762" #define _CRT_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION #define _MFC_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION #define _ATL_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION #ifdef __cplusplus extern "C" { #endif __declspec(selectany) int _forceCRTManifest; __declspec(selectany) int _forceMFCManifest; __declspec(selectany) int _forceAtlDllManifest; __declspec(selectany) int _forceCRTManifestRTM; __declspec(selectany) int _forceMFCManifestRTM; __declspec(selectany) int _forceAtlDllManifestRTM; #ifdef __cplusplus } #endif #endif 2) 你需要在每個你希望編譯的項目中包含上面的頭文件。 可以通過兩種方法來達成這個目的。第一個方法是涉及到修改源代碼。第二個方法涉及到修改項目設置。到底選擇方法A好還是方法B好?這適合取決于你當前的應用環(huán)境: A) 在你的每一個stdafx.h頭文件的頭部包含"targetsxs.h"頭文件 (使用你保存targetsxs.h的路徑) B) 強制使用(/FI)編譯選項來保證每個文件編譯時都包含上面的頭文件(targetsxs.h)。為了達到這個目的,你可以在你的編譯器選項中添加如下的命令行 /FIc:\path\targetsxs.h (/FI:預處理指定的頭文件,與源文件中的#include有相同效果(強制包含頭文件)。c:\path是你在第一步中創(chuàng)建的targetsxs.h的保存位置) 可以使用兩個方法在編譯器選項中到達這個目的:在你的工程中直接設置或者通過編譯器環(huán)境變量來設置: 方法1: 在工程屬性c/c++ => 高級 => 強制包含 里加上c:\path\targetsxs.h 或 將上面的命令添加到C/C++工程屬性的命令行中 (在工程屬性的c/c++ => command line里加上 /FI c:\path\targetsxs.h 。就能指定使用哪個庫了) 方法2: 用上面提到的/FI語法創(chuàng)建一個名為CL的環(huán)境變量 當你有很多工程的時候,你肯定不希望一個一個地去修改它們的工程屬性,這個時候方法2就方便很多,但同時這個環(huán)境變量也可能會影響到你機器上的其他工程。 3) 對于你項目清單中的每個MFC DLL工程,你需要在stdafx.cpp文件的底部添加下面一行代碼 #include "..\src\mfc\dllmodul.cpp" 只有當你使用了MFC DLL工程的時候,這一步才是必需的(之所以是必需的是因為在MFC DLL中處理匯編代碼(assembly versions)時的一個Bug - 如果沒有包含dllmodul.cpp的話,步驟一設置的東西就不會被包含而編譯器會始終引用最新版本的DLL)。 4) 編譯你的項目清單中的所有工程。 5) 檢查manifeset文件(就是編譯器生成的那些*.intermediate.manifest文件)以確保4053不會出現(xiàn)在任何manifest文件中。 6) 在一臺沒有安裝4053版本W(wǎng)inSxS組件機器上運行你的應用程序來驗證它可以正常運行。 重要提示:如果你被ATL控件的安全性問題所影響(而必須要安裝這個更新)的話,還是請你安裝此更新以便使用更加安全的ATL控件。此時,簡單的重編譯可能并不足夠,比需要從下面的視頻中得到更多的信息: http://channel9./posts/Charles/Out-of-Band-Inside-the-ATL-Security-Update/ Q&A 1.使用762版本的組件來代替4053是否會使得你的應用程序安全性降低? 不會。微軟提供了一種WinSxS重定位策略,所以任何引用到762版本ATL的應用程序都最終會應用到4053版本(如果你安裝了它們的話)。這個ATL安全更新已經(jīng)作為Window Update的更新發(fā)布了,所以一旦你保持了與Window Update同步的更新,那么你就已經(jīng)準備好使用4053版本的ATL了,即使你的應用程序仍然引用了762版本的ATL,你最終還是會使用4053版本的ATL。 *重要提示:如果可能的話,你最好還是把最新版本的分發(fā)包隨你的應用程序一起發(fā)布,因為用戶有可能并不會使用Window Update來更新最新的組件。 2.在你的SP1應用程序中引用762版本來代替4053有什么好處么? 1) 如果你有一些應用程序已經(jīng)發(fā)布了但是必須重新編譯某些已經(jīng)發(fā)布出去的組件,那么你就不用再發(fā)布新的MSM或者包含4053版本的vcrdist_x86.exe了。你可以繼續(xù)使用762版本來發(fā)布現(xiàn)有的組件。 2) 如果你有使用引用到762版本的第三方靜態(tài)庫的話,你也不需要將它們重新編譯到4053版本。 3.VC2008 SP1安全更新是否有同樣的問題呢? 是的,如果你在你的工程中使用了_BING_TO_CURRENT_VCLIBS_VERSION,那么就會有同樣的問題。它將會綁定到最新版本的安全更新來代替原來的SP1版本。你同樣可以使用上面描述的方法(步驟3不需要)來解決這個問題。 對于VC2008 SP1,CRT/MFC/ATL的當前版本號有些許變化,你應該使用_forceCRTManifestCUR來代替_forceCRTManifest。對于MFC/ATL也必須使用同樣的設置(添加CUR)。當然,此時你所面對的版本號也是不同的:SP1是9.0.30729.1,而最新的SP1+安全更新則是9.0.30729.4148。 PS:由于個人實在無法忍受,每次編譯出來的DLL都要手動去修改其資源文件中的Manifest(使用ResHacker刪除掉有關4053版本的Manifest節(jié)點),所以今天一狠心,直接將工作機上所有關于VC2005的東東全部干掉,再重新安裝一次,雖然浪費了很多時間,但是還是這種釜底抽薪的方法最有效。 ============ WDF debug版本的.manifest文件(WDF.dll.intermediate.manifest) publicKeyToken屬性告訴加載器在Windows XP/2003/Vista系統(tǒng)研究的SxS存儲所需的DLL 清單 對于指定使用sxs文件夾下的不同版本的.dll有用的 清單可以不生成,在連接器-清單文件-生成清單,改為否(默認為是)。 也可以指定清單生成的地方(在清單工具-輸入和輸出-嵌入清單 進行設置),共有兩個地方:程序集中,獨立文件。 這個功能VC很早就有了 1.清單在exe和dll等中,默認方式。(指明了這次編譯出來的東西,需要用到的清單)。 2.清單是做為一個獨立的文件存在(*.manifest) (在xp以上系統(tǒng)上跑程序,才支持) <?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='requireAdministrator' uiAccess='false' /> </requestedPrivileges> </security> </trustInfo> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.VC90.DebugCRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /> </dependentAssembly> </dependency> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.VC90.DebugMFC' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /> </dependentAssembly> </dependency> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*' /> </dependentAssembly> </dependency> </assembly> WDF release版本的.manifest文件(WDF.dll.intermediate.manifest) <?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.30729.9463' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /> </dependentAssembly> </dependency> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.VC90.MFC' version='9.0.30729.9463' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /> </dependentAssembly> </dependency> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*' /> </dependentAssembly> </dependency> </assembly> ============ 部署VC2008應用程序 來源: http://blog.csdn.net/laiboy/article/details/5038165 http://bbs.csdn.net/topics/360008982 如果你編譯了一個VC2008的默認的CRT/MFC的應用程序,如果目標部署電腦上沒有安裝相應的VC2008的動態(tài)庫,當運行你的程序的時個,會出現(xiàn)如下錯誤信息. ------- 由于應用程序配置不正確,應用程序未能啟動。重新安裝應用程序可能會糾正這個問題。 --------- 這是因為程序使用了基于VC2008的CRT/MFC的動態(tài)庫版本. 解決這個問題,有三種方法: 1.使用靜態(tài)鏈接庫編譯(缺點,生成的exe的程序過于龐大) 2.使用 vcredist_x86.exe / vcredist_x64.exe 將VC2008的發(fā)行版的DLL安裝在你的系統(tǒng)上.(缺點,只能支持發(fā)行版,調試版程序不能支持) 3.將你的程序依賴的CRT/MFC的動態(tài)庫與你的程序一起發(fā)布(放在與你的發(fā)布程序同一目錄中) 第一種和第二種就不詳細講如何實現(xiàn)了,只要講第三種方法如何實現(xiàn).優(yōu)其是程序的開發(fā)是使用了VC2008 SP1的版本開發(fā)的程序. 在你的VC2008的安裝目錄下有兩個目錄(這個是release版本的),
debug版本是在
只要將這兩個目錄下的文件一同拷貝到發(fā)布程序的同一目錄下
這些是這個程序依賴的發(fā)行版動態(tài)庫,同理,如果是調試版的發(fā)布程序,也一樣把相應的調試動態(tài)庫拷貝到相應目錄. 程序如你意運行起來了! 注意:Microsoft.VC90.MFCLOC 是MFC的本地版本 C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/redist/Debug_NonRedist 但是,如果你安裝的是VC2008 SP1的版本的時候,問題就來了,你的程序也一樣運行不起來了! 原因就是安裝了VC2008 SP1的時候,它把"VC/redist"用新的版本文件代替了,問題不大,但是,這個程序的版本是依賴于新的manifest的文件的,當你編譯VC2008-SP1的程序的時候,它同時把RTM-version寫入程序的manifest文件中,這個是舊的RTM-version,不與新版本的VC2008-SP1的"CRT/MFC"manifest版本一致,因此程序運行的時候是拒絕導入這些新的VC2008-SP1的CRT/MFC的運態(tài)庫! 解決方法有兩種. 方法一: 最簡單的,修改Microsoft.VC90.CRT.manifest和Microsoft.VC90.MFC.manifest文件,將新的版本號改為舊的版本號,如果是依賴其它的Microsoft.VC90.*.manifest的文件,也同樣是如此修改! 如果是裝了VC2008-SP1后,它的版本號是“9.0.30729.8″ 未裝VC2008-SP1前的版本號為"9.0.21022.8" 過程如下: 將所依的動態(tài)庫的及它們的 manifest 文件拷貝到發(fā)布應用程序的同一目錄下,并修改Microsoft.VC90.*.manifest文件,將 version="9.0.30729.1"
修改為 version="9.0.21022.8" 恭喜你,你的程序運行起來了! 方法二 修改你的程序的所依賴的manifest,這樣程序會依整于新的manifest. 過程如下: 在 stdafx.h 這個文件中,增加如下宏定義: #define _BIND_TO_CURRENT_VCLIBS_VERSION 1
程序編譯后就會依賴于新的manifest,版本號為 "9.0.30729.1"無須再修改manifest文件中的version版本號了. 將所依的動態(tài)庫的及它們的 manifest 文件拷貝到發(fā)布應用程序的同一目錄下 恭喜你,程序又運行起來了! 注意:如果你是想要新的MFC-feature-pack的功能,用這種方法是最好的. 注意一點,非常重要,如果已經(jīng)安裝了vcredist_*.exe程序包,注意的是Dll會自動把引用調到系統(tǒng)目錄下的WinSxS目錄下的,即不再引用同一目錄下的動態(tài)庫! 如果是編譯時使用了(/clr)這個編譯選項去支持.net開發(fā),你必須要安裝.net framework redistributable包! 不過,在2010,編譯的程序會不再需要manifest文件! 方法三: 找windows/winsxs/目錄下對應版本的文件以及 .manifest 文件拷過去試試 |
|
|