【问题标题】:Is there a common way for C# and unmanaged native C++ to determine installed CLR versions?C# 和非托管本机 C++ 是否有通用方法来确定已安装的 CLR 版本?
【发布时间】:2012-04-03 05:51:08
【问题描述】:

正如标题所说:在 C# 中,尤其是非托管原生 C++ 中是否有一种通用方法来确定已安装的 CLR 版本?这意味着不仅仅是检查框架是否按照this KB article 安装。我想通过使用 CLR 接口来做到这一点,就像 here 对 CLR1、CLR1.1 和 CLR2 所做的那样。通过这种方式,我可以确保它们确实已安装。但这不适用于 CLR4。有什么想法吗?

我的目标是创建可用 CLR 版本的枚举,例如 Clrver(不管进程列表功能)。

【问题讨论】:

  • 我必须这样做的地方 我一直使用注册表方法,您引入的任何库都可能会做同样的事情。如果有更好的方法来做到这一点,那就太好了,但我认为没有。
  • 我认为你是对的。问题是,在这种情况下,所有版本都必须是众所周知的,这也是 beta 版本的原因。但就像我发布的代码示例一样,有时可能还需要考虑 beta 版本。而且我认为必须有一种方法,因为 VS2008 的 CLRVER 在安装 .NET4 而不是 VS2010(以及新版本的 CLRVER)时也可以工作。因此,必须有一种方法可以在不完全了解它们的情况下检测所有已安装的 CLR 版本。

标签: c# c++ .net clr clr-hosting


【解决方案1】:

“通用方式”与否,但dotNetInstaller at Codeplex 在本机、非托管 C++ 代码中执行此操作。
既然是开源的,那就看看他们是怎么做的吧。

此外,您可以使用 ICLRMetaHost::EnumerateInstalledRuntimes Method 检测 .NET v4+ 和 GetRequestedRuntimeInfoInfo(与 clrver.cpp 的做法非常相似)检测 .NET v1 - v2。 所以你必须打两个电话,但这应该涵盖它。

【讨论】:

  • 我查看了源代码。但如果我是对的,它似乎使用了上面提到的众所周知的方法。它会查找已安装的 .NET-Frameworks,但不会显式查找已安装的 CLR-Versions。
  • 好的,添加了 EnumerateInstalledRuntimes
  • 方法 EnumerateInstalledRuntimes 仅在 .NET Framework 4.0 之后可用。
  • “所以你必须进行两次调用,但这应该涵盖它。” >> 实际上,由于 1.0 之间的差异,clrver.cpp 进行了更多的调用和检查, 1.1 和 2.0。我不确定这是否也能找到所有 beta 版本(不确定 OP 是否想要)。我建议更新 clrver.cpp 并创建自己的“一次调用函数”,虽然不理想,但它会起作用(不幸的是,最新的、功能更强大的 clrver 版本只能以二进制形式提供......)。跨度>
  • 更多:clrver 检测 1.0、1.1 和任何 2.x-3.5 版本中的最新版本(知道 3.5 实际上报告为更高的 2.x 版本)。它没有找到List Of Version Numbers 的版本号。奇怪的是,GetRequestedRuntimeInfo 没有找到它所说的“最新版本”,它找到了最新的 2.x。文档对它应该返回的内容含糊不清。
【解决方案2】:

在阅读 Jeffrey Richters 的书 Applied Microsoft® .NET Framework Programming 时,我发现了一些关于该主题的有趣提示。关于主题加载公共语言运行时(第 41 页),他提到要检查注册表路径(和子项)HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\policy 以检查已安装的运行时。因此,我发现了一个有趣的KB article 针对该主题。此外,在运行时如何解析类型引用部分(第 132 页)中,他提到 mscorlib.dll 与 CLR 版本相关联。所以我认为应该可以根据这个文件及其版本检查找到的注册表项,以确保找到的密钥是安装的 CLR 版本。

在下文中,您将在代码中找到我对此的结论。 :) 我认为 Clrver 做了类似的事情。而且我认为这个解决方案也应该适用于原生 C++ 应用程序,因为我的以下代码是 C# 并且只是使用非常基本的框架函数。

List<string> installedRuntimes = new List<string>();

Regex rxVersion = new Regex(@"^[v](\d{1,5})([\.](\d{1,5})){0,3}$");
Regex rxVersionPart = new Regex(@"^\d{1,5}$");            

try
{
    string installPath = Convert.ToString(Registry.GetKey("HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework").GetValue("InstallRoot"));
    string[] shortVersions = Registry.GetKey("HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework/Policy", false).GetSubKeyNames();
    foreach (string shortVersion in shortVersions)
        if (rxVersion.IsMatch(shortVersion))
        {
            string[] versionExtensions = Registry.GetKey("HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework/Policy/" + shortVersion, false).GetValueNames();
            foreach (string versionExtension in versionExtensions)
                if (rxVersionPart.IsMatch(versionExtension))
                {
                    string fullVersion = shortVersion + "." + versionExtension;
                    if (rxVersion.IsMatch(fullVersion))
                    {
                        string clrPath = installPath + fullVersion + "\\mscorlib.dll";
                        if (File.Exists(clrPath) && FileVersionInfo.GetVersionInfo(clrPath).FileVersion.StartsWith(fullVersion.Substring(1))) installedRuntimes.Add(fullVersion);
                    }
                }
        }
}
catch { } // May fails while getting a specific registry key, if Microsoft changes the naming rules.

(不要搞砸Registry.GetKey(...) - 它只是 .NET 注册表功能的一个包装器,以简化我习惯使用注册表的方式。)最后你应该有 CLR 版本字符串在列表 installedRuntimes 中,正如 Clrver 列出的那样。

【讨论】:

  • 好问题!如您所见,此代码依赖于命名规则,这些规则可能会在未来的 CLR/.NET 版本中发生变化。所以代码仍然可以运行,但是 CLR 在注册表中的命名和位置已经改变。在这种情况下,像GetKey(和子方法)这样的方法调用将失败。结果将是一个空的版本列表。但目前这段代码应该可以在没有 try catch 块的情况下工作。
  • 当目标机器没有安装任何 CLR 版本时 您的托管代码应用程序如何在应用程序代码有机会运行之前检测到已安装的 CLR。我认为您需要在 C++ 等非托管平台中重写代码
  • 关于这段代码的使用,你是对的,没有安装任何 CLR 就不可能运行它。上面的代码用于展示规则,Clrver 是如何工作的,并且可以很容易地被任何其他语言和/或运行时环境采用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-16
  • 2010-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多