0%

解决 Windows Rx034

以前没有遇上这个错误,这次遇上这个错误是装vim的YouCompleteMe插件后出现,因此很容易想到是装插件引起的这个错误,错误提示Runtime Error 如下图:

error

先放狗搜一下,微软的对R6034的解释如下:

1
2
3
4
5
An application has made an attempt to load the C runtime library without using
a manifest. This is an unsupported way to load Visual C++ DLLs. You need to
modify your application to build with a manifest. For more information, see the
"Visual C++ Libraries as Shared Side-by-Side Assemblies" topic in the product
documentation.

微软的链接中也提到了解决的方法

1
2
3
4
5
6
Rebuild your application to include a manifest. Building an application with
Visual Studio automatically puts the manifest into the resulting .exe or .dll
file. If you are building at the command line, use the mt.exe tool to add the
manifest as a resource. Use resource ID 1 if you build an .exe, and resource
ID 2 if you build a .dll. For more information, see How to: Embed a Manifest
Inside a C/C++ Application.

大概的意思是需要使用manifest.xml来指定需要加载的DLL。上网又翻看了几个链接发现这个错误的成因比较复杂,主要原因是加载mscvr*.dll 出现了问题。不管怎样还是先看看是否使用了 manifest。从微软的解决办法可以知道,manifest很有可能在资源文件里。

还是先看看manifest的作用,在msdn网站搜索相关内容,根据《Understanding Manifest Generation for C/C++ Programs》中的内容,manfest.xml可以是一个外部的XML文件也可以是嵌入在程序的资源文件中。manifest.xml用于管理程序在运行时需要的共享程序集的名字和版本。如果程序只依赖 VisualC++ 的程序集(CRT,MFC,ATL等),manifest会被链接器自动生成。Manifest的Sxs指定了其依赖的清单名称,版本,资源,和其他组件。Sxs是Windows XP引入的新技术,vs 2005 开始使用,全名叫Side by Side assembly,主要还是为了解决兼容性问题,这样同一个系统可以存在不同版本的同名文件而互相不影响各自的运行。

sxs

现在需要定位gvim.exe加载哪个DLL引起了R6034错误,使用Process Explorer发现是加载ycm_client_support.pyd导致。删除YouCompleteMe插件后错误消失。

先看看ycm_client_support.pyd是否使用了manifest.xml, 使用神器TC, F3一下,可以查看manifest的情况。

manifest.xml

发现其实ycm_client_support.pyd已经使用了manifest,但是仍然出现R6034错误。上网搜索了一番(见文末的参考链接),发现这就是非常著名的DLL Hell了,维基百科中专门记录了这个问题。 http://en.wikipedia.org/wiki/Dll_hell

不论如何应该就是DLL加载时出错了,可以使用Process Explorer 工具来查看出问题的进程,看看在进程空间内具体是什么情况。

p-e

哈哈,发现了一些情况,msvcr90.dll在gvim进程空间里有两个!再看看这两个DLL的位置。

p-e1

p-e2

删除掉不在C:\WINDOWS\WinSxS\目录里的msvcr90.dll,问题得以解决。由于这个错误是因为加载ycm_client_support.pyd引起的,再看看ycm_client_support.pyd的情况,拿出TC直接F3一下,又发现了一些有用的信息。ycm_client_support.pyd加载的是cmake目录下的msvcr90.dll, 正常情况下因该使用 C:\Windows\winsxs 目录下的msvcr90.dll

tc1

tc2

查看一下系统环境变量:

1
2
3
4
5
6
7
8
9
10
D:\Program Files\Microsoft Visual Studio 9.0\VC> set | findstr Path

Path=D:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE;D:\Program Files\M
icrosoft Visual Studio 9.0\VC\BIN;D:\Program Files\Microsoft Visual Studio 9.0\C
ommon7\Tools;c:\Windows\Microsoft.NET\Framework\v3.5;c:\Windows\Microsoft.NET\Fr
amework\v2.0.50727;D:\Program Files\Microsoft Visual Studio 9.0\VC\VCPackages;C:
\Program Files\\Microsoft SDKs\Windows\v6.0A\bin;C:\Windows\system32;C:\Windows;
d:\Program Files\CMake 2.8\bin;d:\Program Files\LLVM 3.4.svn\bin;d:\Program File
s\Git\cmd;d:\Python27;D:\Program Files\IDM Computer Solutions\UltraEdit\
PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\

引错误的原因是Windows程序加载DLL是会先加载PATH变量中的DLL文件,后面会加载manifest指定的WinSxS目录的文件,这样就加载了两次,引起了错误。

这个问题涉及 Windows加载DLL文件的顺序,Windows定位 DLL文件的顺序和一个注册表键值相关,这个键值是:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode

SafeDllSearchMode的值为1,开启SafeDllSearchMode,
SafeDllSearchMode的值为0,禁用SafeDllSearchMode。

Windows系统默认开启SafeDllSearchMode (Windows XP SP2 后),MSDN文章《Dynamic-Link Library Search Order》中指出,在SafeDllSearchMode开启的情况下,Windows定位DLL文件的顺序为:

  1. The directory from which the application loaded.
  2. The system directory. ( GetSystemDirectory )
  3. The 16-bit system directory.
  4. The Windows directory. (GetWindowsDirectory )
  5. The current directory.
  6. The directories that are listed in the PATH environment variable.

在SafeDllSearchMode关闭的情况下,Windows定位DLL文件的顺序为:

  1. The directory from which the application loaded.
  2. The current directory.
  3. The system directory. (GetSystemDirectory )
  4. The 16-bit system directory.
  5. The Windows directory. ( GetWindowsDirectory)
  6. The directories that are listed in the PATH environment variable.

另外,《Dynamic-Link Library Search Order》中指出使用manifest可以指定加载DLL的路径,但实际的情况是有可能加载多个DLL导致进程崩溃。

Desktop applications can control the location from which a DLL is loaded by specifying a full path, using DLL redirection, or by using a manifest. If none of these methods are used, the system searches for the DLL at load time as described in this section.

参考资料

[1]《Windows via C/C++ Fifth Edition》
[2] Side-by-side Assemblies http://msdn.microsoft.com/en-us/library/aa376307.aspx
[3] DLL Hell http://en.wikipedia.org/wiki/Dll_hell
[4] C Run-Time Error R6034 http://msdn.microsoft.com/en-us/library/ms235560(v=vs.90).aspx
[5] Understanding Manifest Generation for C/C++ Programs http://msdn.microsoft.com/en-us/library/ms235542.aspx
[6] Search Path Used by Windows to Locate a DLL http://msdn.microsoft.com/en-us/library/7d83bc18.aspx
[7] Dynamic-Link Library Search Order http://msdn.microsoft.com/en-us/library/windows/desktop/ms682586(v=vs.85).aspx
[8] https://bitbucket.org/Haroogan/vim-youcompleteme-for-windows/src/7dca764c2ee0?at=master
[9] https://github.com/Valloric/YouCompleteMe/wiki/Windows-Installation-Guide
[10] http://www.davidlenihan.com/2007/07/winsxs.html