银河

SKYIV STUDIO

  博客园 :: 首页 :: 博问 :: 闪存 :: :: :: 订阅 订阅 :: 管理 ::
  268 随笔 :: 2 文章 :: 2604 评论 :: 48 引用

公告

我写了一个 C# 程序来检测 .NET Framework CLR 版本。

在 Ubuntu 操作系统中的运行结果:

ben@ben-m4000t:~/work$ ./ClrInfo.exe
      OS Version: Unix 2.6.31.16
     CLR Version: 2.0.50727.1433  ( Mono 2.4.2.3 )
Default Encoding: System.Text.UTF8Encoding

Available Frameworks:
  Mono 1.0 Profile
  Mono 2.0 Profile

在 Windows Vista 操作系统中的运行结果:

E:\CS\ClrInfo> ClrInfo.exe
      OS Version: Microsoft Windows NT 6.0.6002 Service Pack 2
     CLR Version: 2.0.50727.4200  ( Net 2.0.50727.4200 )
Default Encoding: System.Text.DBCSCodePageEncoding

Available Frameworks:
  Net 2.0.50727

注意,这个程序检测的是 .NET Framework CLR 版本,而不是 .NET Framework 版本。实际上这个 Windows Vista 操作系统中安装了 .NET Framework 的以下版本:

  • 2.0.50727.4016
  • 3.0.30729.4037
  • 3.5.30729.01

而三个版本的 .NET Framework 的 CLR 版本都是 2.0.50727。

在 Windows Server 2003 操作系统中的运行结果:

E:\CS\ClrInfo> ClrInfo.exe
      OS Version: Microsoft Windows NT 5.2.3790 Service Pack 2
     CLR Version: 2.0.50727.3603  ( Net 2.0.50727.3603 )
Default Encoding: System.Text.DBCSCodePageEncoding

Available Frameworks:
  Net 1.1.4322
  Net 2.0.50727
  Net 4.0.21006

另外,Microsoft Windows SDK 中的 ClrVer.exe 的运行结果:

E:\CS\ClrInfo> ClrVer.exe
Versions installed on the machine:
v1.1.4322
v2.0.50727
v4.0.21006

我们来看看源程序吧。下面是 ClrInfo.cs:

using System;
using System.Text;

namespace Skyiv
{
  public class ClrInfo
  {
    static void Main()
    {
      Console.WriteLine("      OS Version: {0}", Environment.OSVersion);
      Console.WriteLine("     CLR Version: {0}  ( {1} )", Environment.Version, RuntimeFramework.CurrentFramework);
      Console.WriteLine("Default Encoding: {0}", Encoding.Default);
      Console.WriteLine();
      Console.WriteLine("Available Frameworks:");
      foreach (var frame in RuntimeFramework.AvailableFrameworks) Console.WriteLine("  " + frame);
    }
  }
}

下面是 RuntimeFramework.cs (该程序是从 NUnit 的源程序中的同名文件改写而来的):

using System;
using System.Reflection;
using System.Collections.Generic;
using Microsoft.Win32;

namespace Skyiv
{
  public enum RuntimeType
  {
    Any,   // Any supported runtime framework
    Net,   // Microsoft .NET Framework
    NetCF, // Microsoft .NET Compact Framework
    SSCLI, // Microsoft Shared Source CLI
    Mono,  // Mono
  }

  // See http://nunit.org, this class from NUnit Project's RuntimeFramework.cs
  // RuntimeFramework represents a particular version of a common language runtime implementation.
  [Serializable]
  public sealed class RuntimeFramework
  {
    public RuntimeType Runtime { get; private set; }
    public Version Version { get; private set; }
    public string DisplayName { get; private set; }
    static RuntimeFramework currentFramework;

    public static RuntimeFramework CurrentFramework
    {
      get
      {
        if (currentFramework == null)
        {
          var monoRuntimeType = Type.GetType("Mono.Runtime", false);
          var runtime = monoRuntimeType != null ? RuntimeType.Mono : RuntimeType.Net;
          currentFramework = new RuntimeFramework(runtime, Environment.Version);
          if (monoRuntimeType != null)
          {
            var method = monoRuntimeType.GetMethod("GetDisplayName", BindingFlags.Static |
              BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.ExactBinding);
            if (method != null) currentFramework.DisplayName = (string)method.Invoke(null, new object[0]);
          }
        }
        return currentFramework;
      }
    }

    public static RuntimeFramework[] AvailableFrameworks
    {
      get
      {
        var frameworks = new List<RuntimeFramework>();
        foreach (var framework in GetAvailableFrameworks(RuntimeType.Net)) frameworks.Add(framework);
        foreach (var framework in GetAvailableFrameworks(RuntimeType.Mono)) frameworks.Add(framework);
        return frameworks.ToArray();
      }
    }

    public static bool IsMonoInstalled()
    {
      if (CurrentFramework.Runtime == RuntimeType.Mono) return true;
      // Don't know how to do this on linux yet, but it's not a problem since we are only supporting Mono on Linux
      if (Environment.OSVersion.Platform != PlatformID.Win32NT) return false;
      var key = Registry.LocalMachine.OpenSubKey(@"Software\Novell\Mono");
      if (key == null) return false;
      var version = key.GetValue("DefaultCLR") as string;
      if (string.IsNullOrEmpty(version)) return false;
      return key.OpenSubKey(version) != null;
    }

    // Returns an array of all available frameworks of a given type, for example, all mono or all .NET frameworks.
    public static RuntimeFramework[] GetAvailableFrameworks(RuntimeType rt)
    {
      var frameworks = new List<RuntimeFramework>();
      if (rt == RuntimeType.Net && Environment.OSVersion.Platform != PlatformID.Unix)
      {
        var key = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\.NETFramework\policy");
        if (key != null)
          foreach (var name in key.GetSubKeyNames())
            if (name.StartsWith("v"))
              foreach (var build in key.OpenSubKey(name).GetValueNames())
                frameworks.Add(new RuntimeFramework(rt, new Version(name.Substring(1) + "." + build)));
      }
      else if (rt == RuntimeType.Mono && IsMonoInstalled())
      {
        var framework = new RuntimeFramework(rt, new Version(1, 1, 4322));
        framework.DisplayName = "Mono 1.0 Profile";
        frameworks.Add(framework);
        framework = new RuntimeFramework(rt, new Version(2, 0, 50727));
        framework.DisplayName = "Mono 2.0 Profile";
        frameworks.Add(framework);
      }
      return frameworks.ToArray();
    }

    public RuntimeFramework(RuntimeType runtime, Version version)
    {
      Runtime = runtime;
      Version = version;
      DisplayName = runtime.ToString() + " " + version.ToString();
    }

    public override string ToString()
    {
      return DisplayName;
    }
  }
}

RuntimeFramework 类的 CurrentFramework 属性中,如果发现当前环境是 mono 的话,就通过反射调用 Mono.Runtime 类的静态方法 GetDisplayName 来设置 DisplayName 属性。

RuntimeFramework 类的静态方法 GetAvailableFrameworks 中,如果发现当前操作系统不是 Unix 的话,就通过遍历注册表的 Software\Microsoft\.NETFramework\policy 项来检测 .NET Framework CLR 版本。

下面是 makefile (关于 makefile,可以参见:GUN make 中文手册):

CSC = csc
SRC1 = ClrInfo.cs RuntimeFramework.cs

ClrInfo.exe: $(SRC1)
	$(CSC) -out:$@ $(SRC1)

在 Linux 操作系统下可以用 make 命令编译。在 Windows 操作系统下可以用 nmake 命令编译。

注意,Mono 的 C# 编译器是 gmcs,但是她有个别名叫 csc ,如下所示:

ben@ben-m4000t:~$ ls -l /usr/bin/csc /usr/bin/gmcs
lrwxrwxrwx 1 root root  4 2009-11-01 18:53 /usr/bin/csc -> gmcs
-rwxr-xr-x 1 root root 75 2009-09-23 23:04 /usr/bin/gmcs
ben@ben-m4000t:~$ cat /usr/bin/gmcs
#!/bin/sh
exec /usr/bin/mono $MONO_OPTIONS /usr/lib/mono/2.0/gmcs.exe "$@"
ben@ben-m4000t:~$ gmcs --version
Mono C# compiler version 2.4.2.3
ben@ben-m4000t:~$ csc --version
Mono C# compiler version 2.4.2.3

最后,完整的源程序可以到 http://bitbucket.org/ben.skyiv/clrinfo/downloads/ 页面下载。

也可以使用 hg clone http://bitbucket.org/ben.skyiv/clrinfo/ 命令下载。

关于 hg ,请参阅 Mercurial 备忘录

posted on 2009-12-13 00:14 银河 阅读(...) 评论(...) 编辑 收藏