CLR 运行时版本和错误0x80131700和0x80113101B
COM可见的.Net对象由标准COM调用实例化,例如CoCreateInstance。COM在注册表或激活上下文中找到CLSID,加载并调用mscoree.dll,该dll继续激活CLR和创建对象的过程。在此过程中,可能会出现错误0x80131700“未能加载运行时”或0x8013101b“此程序集是由比当前加载的运行时更新的运行时生成的,无法加载”。
这两条消息都是运行时版本不匹配的结果。0x80131700并不一定意味着任何损坏,它只是意味着无法加载运行时。可能是因为未安装,或者未安装所需的版本。0x8013101b表示加载了运行时,但结果与继续处理所需的版本不匹配。
让我们考虑Manifest Maker附带的Visual Studio示例。这里的本机主机程序是cmdEXE.exe,.Net对象是在clrDLL.dll中实现的。在本例中,我们重建了项目,而没有在DLL中嵌入CLR清单。因此,我们在子文件夹clrDLL\clrDLL.DLL中有clrDLL.manifest文件和DLL。当我们现在执行“cmdEXE.exe clr”时,程序使用CoCreateInstance实例化clr对象:
clrDLL::IClrSampleClassPtr scp; HRESULT hr = scp.CreateInstance(__uuidof(clrDLL::ClrSampleClass), nullptr, CLSCTX_INPROC_SERVER); if (S_OK != hr) { wprintf(L"\nCLR class instantiation failed, hresult = 0x%08X\n", hr); return hr; }
clrDLL.manifest 包含下面的条目 :
<clrClass name="clrDLL.ClrSampleClass" clsid="{A1B62C33-E218-469D-81C4-10D4F2C608F7}" progid="clrDLL.ClrSampleClass" threadingModel="Both"/>
事件的顺序如下:
- 我们运行“cmdEXE.exe clr”
- CSRSS创建进程,查找应用程序清单并创建包含clrDLL.manifest的激活上下文。
- 程序调用COM来创建对象。
- COM在激活上下文中找到CLSID,注意这是<clrClass>,加载并调用mscoree.dll。
- mscoree.dll加载实际的.Net运行时并初始化它。
- 运行时(当前为mscoreei.dll)从system和cmdEXE.exe.config读取配置
- 运行时创建请求的对象。
流程监视器日志摘录:
1:38:32.0379228 PM csrss.exe 500 ReadFile C:\Projects\Examples.2\vs2015\_Debug-Win32\clrDLL.Manifest
1:38:32.0913937 PM cmdEXE.exe 3320 Load Image C:\Windows\SysWOW64\mscoree.dll
1:38:32.0980055 PM cmdEXE.exe 3320 Load Image C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscoreei.dll
1:38:32.1078790 PM cmdEXE.exe 3320 CreateFile C:\Projects\Examples.2\vs2015\_Debug-Win32\cmdEXE.exe.config
从上面可以看出,虽然mscoree决定加载哪个版本的.Net运行时,但它没有cmdEXE.exe.config的内容。这意味着此文件无助于解决任何运行时版本问题。处理此文件时,运行时已加载。
如果如上所示编写<clrClass>,mscoree将决定(在Windows 7/8/8.1上)该类需要.Net 2.0,并尝试加载此版本的运行时。如果此计算机没有.Net 2.0,调用将失败,并出现错误0x80131700,在Windows 8上,将显示一个对话框,其中包含安装.Net 2.0的选项:
如果runtime is 2.0可用并已加载,但DLL是用4.0构建的,则会出现错误0x8013101b。因此无法成功实例化如上所示定义的.Net类。必须修改<clrClass>条目以包含“runtimeVersion”属性:
<clrClass name="clrDLL.ClrSampleClass" clsid="{A1B62C33-E218-469D-81C4-10D4F2C608F7}" progid="clrDLL.ClrSampleClass" runtimeVersion="v4.0.30319" threadingModel="Both"/>
注意“runtimeVersion”与supportedRuntime不同。Net期望“supportedRuntime”包含“v4.0”,而“runtime version”必须包含实际的、完整的运行时版本。这意味着要选择.Net 4.0运行时,必须指定runtimeVersion=“v4.0.30319”。在编写本文时,存在以下运行时版本:
- v1.0.3705
- v1.1.4322
- v2.0.50727
- v4.0.30319
另外.Net似乎接受“v3.0”和“v3.5”作为版本2.0的别名。确定实际版本号的一种快速方法是查看C:\ Windows\Microsoft.NET\Framework和C:\ Windows\Microsoft.NET\Framework64文件夹中的子文件夹名称。找到已安装版本的最终方法是运行以下代码:
ICLRMetaHost *pMetaHost; HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (void **)&pMetaHost); IEnumUnknown* pEnum = 0; if (S_OK == pMetaHost->EnumerateInstalledRuntimes(&pEnum)) { ULONG celt = 0; ICLRRuntimeInfo *pRuntime; while (S_OK == pEnum->Next(1, (IUnknown**)&pRuntime, &celt)) { WCHAR version[256] = { 0 }; DWORD chars = _countof(version); if (S_OK == pRuntime->GetVersionString(version, &chars)) wprintf(L"Found: %s\n", version); pRuntime->Release(); } pEnum->Release(); }
清单生成器使用此技术填充“项目选项”对话框中的“CLR版本”属性页。健全性检查:Windows正在缓存每个程序的清单信息。如果您正在尝试清单,则必须更改每个参与文件(包括可执行文件)的时间戳,以使Windows使用新的而不是缓存的信息。