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使用新的而不是缓存的信息。

posted on 2020-03-06 13:56  活着的虫子  阅读(1165)  评论(0编辑  收藏  举报

导航