疑難排解 C/C++ 隔離應用程式和並存組件
如果找不到相依的 Visual C++ 程式庫,則載入 C/C++ 應用程式可能會失敗。 您可以在轉散發 Visual C++ 檔案中找到可能的執行階段錯誤清單。 本章節內容將會描述 C/C++ 應用程式無法載入的最常見理由,並提供一些建議步驟來解決問題。
如果應用程式部署於未安裝 Visual C++ 的電腦上,而且該程式損毀時產生類似轉散發 Visual C++ 檔案中所列的錯誤訊息,您必須檢查幾件事,以了解錯誤的原因。
請依照了解 Visual C++ 應用程式的相依性中描述的步驟進行。 Dependency Walker 可針對任何特定的應用程式或 DLL 顯示大多數的相依性。 如果您看到缺少了某些 DLL,請在想要執行應用程式的電腦上安裝那些 DLL。
作業系統載入器在載入應用程式相依的組件時會用到某個資訊清單, 它可以當做資源的形式內嵌在二進位檔內,或是儲存為應用程式之本機資料夾中的外部檔案。 若要檢查資訊清單是否內嵌在二進位檔內,請在 Visual Studio 中開啟程式庫,並在此二進位檔的資源內瀏覽。 您應該可以找到一個稱為 RT_MANIFEST 的資源。 如果在二進位檔中找不到內嵌的資訊清單,請查找名稱類似 <binary_name>.<extension>.manifest 的外部檔案。
如果資訊清單不存在,您必須確保連結器會產生專案的資訊清單, 請在這個專案的 [專案屬性] 對話方塊中,檢查 [產生資訊清單] 連結器選項。
注意事項 不支援在未產生資訊清單的情況下建置 Visual C++ 專案。 任何以 Visual C++ 建置的 C/C++ 程式都必須包含資訊清單,以描述該程式和 Visual C++ 程式庫的相依性。
如果資訊清單是內嵌在二進位檔中,請確認 RT_MANIFEST 的 ID 對於這種二進位檔而言是正確的。 若是應用程式,ID 應等於 1,至於大部分的 DLL ID 應等於 2。 如果資訊清單位於外部檔案內,請以 XML 編輯器或文字編輯器將其開啟。 如需資訊清單和部署規則的詳細資訊,請參閱資訊清單。
注意事項 在 Windows XP 上,如果外部資訊清單存在於應用程式的本機資料夾中,則作業系統載入器會使用這個資訊清單,而不是內嵌在二進位檔內的資訊清單。 在 Windows Server 2003 和較新版本的 Windows 中情況卻相反,載入器會使用內嵌的資訊清單 (如果存在),而忽略外部資訊清單。
建議讓所有的 DLL 都具有內嵌於二進位檔中的資訊清單, 當透過 LoadLibrary 呼叫載入 DLL 時,會忽略外部資訊清單。 如需詳細資訊,請參閱組件資訊清單。
請檢查資訊清單中列舉的所有組件是否都正確地安裝在電腦上, 在資訊清單中,每一個組件都會依其名稱、版本號碼與處理器架構來加以指定。 如果應用程式必須依賴並存組件,請檢查這些組件是否正確地安裝在電腦上,這樣作業系統載入器才能利用組件搜尋序列中指定的步驟找到這些組件。 請牢記一點,64 位元組件不能在 32 位元處理序中載入,也不能在 32 位元作業系統上執行。
範例
假設有一個以 Visual C++ 建置的應用程式 appl.exe。 這個應用程式的資訊清單若不是內嵌於 appl.exe 中做為二進位檔資源 RT_MANIFEST (其 ID 等於 1),不然就是儲存為外部檔案 appl.exe.manifest。 資訊清單的內容看起來可能像這樣:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.xxxxx.y" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
</dependentAssembly>
</dependency>
</assembly>
對作業系統載入器而言,這個資訊清單表示 appl.exe 須依賴名稱為 Microsoft.VC90.CRT 的組件,此組件的版本為 9.0.xxxxx.y,並且是針對 32 位元 x86 處理器架構而建置。
相依的並存組件可以安裝成共用組件或私用組件, 例如,Visual Studio 2008 會將 CRT 組件當做共用並存組件來安裝。在 Windows XP 中,這個組件的位置在 %WINDIR%\WinSxS\x86_Microsoft.VC90.CRT_<版本> 目錄內;而在 Windows Vista 中,這個組件的位置則是在%WINDIR%\winsxs\x86_microsoft.vc90.crt_<版本> 目錄內。
此外,共用的 Visual C++ CRT 組件的 assembly manifest 在 Windows XP 中的安裝位置是 %WINDIR%\WinSxS\Manifests\x86_microsoft.vc90.crt_<版本>.manifest;而在 Windows Vista 中則是 %WINDIR%\winsxs\Manifests\x86_microsoft.vc90.crt_<版本>.manifest。它可識別這個組件並列出其內容 (屬於這個組件的 DLL):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright © 1981-2001 Microsoft Corporation -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<noInheritable/>
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.xxxxx.yy" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
<file name="msvcr90.dll" hash="3ca5156e8212449db6c622c3d10f37d9adb12c66" hashalg="SHA1"/>
<file name="msvcp90.dll" hash="92cf8a9bb066aea821d324ca4695c69e55b27cff" hashalg="SHA1"/>
<file name="msvcm90.dll" hash="7daa93e1195940502491c987ff372190bf199395" hashalg="SHA1"/>
</assembly>
並存組件也可以使用發行者組態檔 (也稱為原則檔) 全面將應用程式和組件從某一並存組件版本重新導向至相同組件的另一個版本。 在 Windows XP 中,您可以檢查 %WINDIR%\WinSxS\Policies\x86_policy.9.0.Microsoft.VC90.CRT_<版本>.policy 內共用 Visual C++ CRT 組件的原則;而在 Windows Vista 中的位置則是 %WINDIR%\winsxs\Manifests\x86_policy.9.0.microsoft.vc90.crt_<版本>.manifest。此組件包含類似下列的內容:
</assembly>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright © 1981-2001 Microsoft Corporation -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32-policy" name="policy.9.0.Microsoft.VC90.CRT" version="9.0.xxxxx.yy" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
<bindingRedirect oldVersion="9.0.aaaaa.bbb-9.0.ccccc.d" newVersion="9.0.xxxxx.yy"/>
</dependentAssembly>
</dependency>
</assembly>
以上的原則會指定任何應用程式或組件若需要這個組件的 9.0.aaaaa.bbb 版本,都應該改用這個組件的 9.0.xxxxx.yy 版本 (這是目前安裝在系統中的版本)。 如果原則檔中已指定應用程式的資訊清單中所提及的組件版本,載入器就會在 WinSxS 資料夾中尋找資訊清單中指定的這個組件的版本,如果沒有安裝這個版本,載入就會失敗。 此外,如果也未安裝組件版本 9.0.xxxxx.yy,則需要組件版本 9.0.aaaaa.bbb 的應用程式會載入失敗。
不過,CRT 組件還是可以在應用程式的本機資料夾中安裝成私用並存組件。 如果作業系統無法找到 CRT 或任何其他的共用組件,它就會開始尋找做為私用組件的組件。 它會依下列順序搜尋私用組件:
查看應用程式的本機資料夾,以尋找名稱為 <assemblyName>.manifest 的資訊清單檔。 在這個範例中,載入器會嘗試在與 appl.exe 所在位置相同的資料夾內尋找 Microsoft.VC90.CRT.manifest。 如果找到了資訊清單,載入器就會載入應用程式資料夾中的 CRT DLL; 如果找不到 CRT DLL,載入就會失敗。
嘗試開啟 appl.exe 的本機資料夾中的資料夾 <assemblyName>;如果它確實存在,則從這個資料夾載入資訊清單檔 <assemblyName>.manifest。 如果找到了資訊清單,載入器會載入 <assemblyName> 資料夾中的 CRT DLL; 如果找不到 CRT DLL,載入就會失敗。
如需載入器如何搜尋相依組件的詳細說明,請參閱組件搜尋序列。 如果載入器無法找到做為私用組件的相依組件,載入就會失敗,並顯示「系統無法執行指定的程式」的訊息。 若要解決這個錯誤,屬於其中一部分的相依組件和 DLL 必須以私用組件或共用組件的形式安裝在電腦上。