如果无法找到依赖 Visual C++ 库,则可能无法加载 C/C++ 应用程序。本节描述了 C/C++ 应用程序加载失败的最常见的原因以及解决这些问题的建议步骤。
当无法找到依赖的 Visual C++ DLL 时,用户看到的最常见的错误信息之一是“系统无法执行指定的程序”(此信息显示在一个消息框中)。以下是一些信息,可帮助您了解产生此错误的原因。
-
按照理解 Visual C++ 应用程序的依赖项中描述的步骤操作。Dependency Walker 可显示任意特定应用程序或 DLL 的大多数依赖项。如果您发现缺少一些 DLL,请在您要试图运行应用程序的计算机上安装那些 DLL。
-
操作系统加载程序使用清单来加载应用程序所依赖的程序集。它可以作为资源嵌入二进制文件中,或作为外部文件保存在应用程序的本地文件夹中。若要检查清单是否已嵌入二进制文件中,请在 Visual Studio 中打开二进制文件,并浏览此二进制文件中的资源。应该能找到一个名为 RT_MANIFEST 的资源。如果无法找到嵌入二进制文件内的清单,请查找名称类似于 <binary_name>.<extension>.manifest 的外部文件。
-
如果不存在清单,则需要确保链接器为项目生成一个清单。需要在项目的“项目属性”对话中检查链接器选项“生成清单”。
注意 不支持在未生成清单的情况下生成 Visual C++ 项目。Visual C++ 2005 中生成的任意 C/C++ 程序都必须包括一个清单,用于描述该程序在 Visual C++ 库中的依赖项。
-
如果二进制文件中嵌入了清单,请确保对于此类型的二进制文件来说,RT_MANIFEST 的 ID 正确。对于应用程序,ID 应等于 1;对于大多数 DLL,ID 应等于 2。如果清单位于外部文件中,则使用 XML 编辑器或文本编辑器可将其打开。有关清单和部署规则的更多信息,请参见 Manifests。
注意 在 Windows XP 上,如果应用程序的本地文件夹中存在外部清单,则操作系统加载程序将使用此清单,而不使用二进制文件中嵌入的清单。在 Windows Server 2003 和 Windows 更高版本上,情况正好相反,即当存在嵌入的清单时,将忽略外部清单而使用嵌入的清单。
-
建议所有的 DLL 都应有一个嵌入二进制文件内的清单。通过 LoadLibrary 调用加载 DLL 时,将忽略外部清单。有关更多信息,请参见 Assembly manifests。
-
检查清单中列举的所有程序集是否都已正确地安装在计算机上。清单中的每个程序集都是按照程序集的名称、版本号和处理器结构指定的。如果应用程序依赖于并行程序集,请检查这些程序集是否都已正确地安装在计算机上,以便操作系统加载程序可以使用 Assembly Searching Sequence 中指定的步骤找到它们。请记住,64 位程序集不能在 32 位进程中加载,也不能在 32 位操作系统上执行。
示例
假设有一个应用程序 appl.exe,它是用 Visual C++ 2005 生成的。此应用程序的清单可作为二进制文件资源 RT_MANIFEST(ID 等于 1)嵌入 appl.exe 中,也可以存储为外部文件 appl.exe.manifest。该清单的内容可能类似于:
复制代码 | |
---|---|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50215.4631" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity> </dependentAssembly> </dependency> </assembly> |
对于操作系统加载程序,此清单表明 appl.exe 依赖于一个名为 Microsoft.VC80.CRT 程序集,该程序集的版本为 8.0.50215.4631,并且是为 32 位 x86 处理器结构生成的。
可以将依赖并行程序集作为共享程序集或私有程序集安装。例如,Visual Studio 2005 将 CRT 程序集作为可在 %WINDIR%\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50215.4631_x-ww_b7acac55 目录中找到的共享并行程序集安装。
共享 Visual C++ CRT 程序集的 assembly manifest 也安装在 %WINDIR%\WinSxS\Manifests\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50215.4631_x-ww_b7acac55.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.VC80.CRT" version="8.0.50215.4631" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/> <file name="msvcr80.dll" hash="3ca5156e8212449db6c622c3d10f37d9adb12c66" hashalg="SHA1"/> <file name="msvcp80.dll" hash="92cf8a9bb066aea821d324ca4695c69e55b27cff" hashalg="SHA1"/> <file name="msvcm80.dll" hash="7daa93e1195940502491c987ff372190bf199395" hashalg="SHA1"/> </assembly> |
并行程序集还可以使用 publisher configuration files(也称为策略文件),以便在全局上重定向应用程序和程序集,使其从使用并行程序集的一个版本变为使用该程序集的另一版本。可以在 %WINDIR%\WinSxS\Policies\x86_policy.8.0.Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_x-ww_77c24773\8.0.50215.4631.policy 中检查共享 Visual C++ CRT 程序集的策略,该文件包含类似如下的内容:
复制代码 | |
---|---|
</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.8.0.Microsoft.VC80.CRT" version="8.0.50215.4631" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/> <bindingRedirect oldVersion="8.0.41204.256" newVersion="8.0.50215.4631"/> </dependentAssembly> </dependency> </assembly> |
以上策略指定,对于需要此程序集 8.0.41204.256 版的任何应用程序或程序集,都应改用此程序集的 8.0.50215.4631 版,此版本是安装在系统上的当前版本。如果在策略文件中指定了应用程序清单中提到的程序集的版本,则加载程序将在 WinSxS 文件夹中查找清单中指定的此程序集的版本,而当未安装该版本时,加载将失败。如果也没有安装版本为 8.0.50215.4631 的程序集,则对于需要版本为 8.0.41204.256 的程序集的应用程序,加载将失败。
但是,也可以将 CRT 程序集作为私有并行程序集,安装在应用程序的本地文件夹中。如果操作系统未能找到 CRT 或作为共享程序集的任何其他程序集,它会开始将该程序集作为私有程序集来查找。它将按以下顺序搜索私有程序集:
-
在应用程序本地文件夹中查找名为 <assemblyName>.manifest 的清单文件。在此示例中,加载程序试图在 appl.exe 所在的文件夹中查找 Microsoft.VC80.CRT.manifest。如果找到该清单,加载程序将从应用程序文件夹中加载 CRT DLL。如果未找到 CRT DLL,加载将失败。
-
尝试在 appl.exe 本地文件夹中打开文件夹 <assemblyName>,如果存在此文件夹,则从中加载清单文件 <assemblyName>.manifest。如果找到该清单,加载程序将从 <assemblyName> 文件夹中加载 CRT DLL。如果未找到 CRT DLL,加载将失败。
有关加载程序如何搜索依赖程序集的更多详细说明,请参见 Assembly Searching Sequence。如果加载程序未能找到作为私有程序集的依赖程序集,则加载失败,并显示“系统无法执行指定的程序”。若要解决此错误,必须在计算机上将依赖程序集和作为依赖程序集一部分的 DLL 安装为私有程序集或共享程序集。