はじめてのデフォルトCLRホストその4

タイトルと内容があっていないので、変更しました。(^^;

前回、何気なく

互換性のあるアップグレード(.NET1.0 -> 1.1など)の場合は

と書きましたが、互換性のあるアップグレードとは何を指しているのでしょうか? Breaking Changes in .NET Framework 2.0とか見ると、互換性があるとは言えないだろーとか思いたくなりますが、実は単純な方法で判断されています。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\Policy\Upgrades

レジストリキーの値を見ると、

1.1.4322 REG_SZ 1.0.3705-1.1.4322

のような登録があります。例えば、1.1.4322なら1.0.3705〜1.1.4322で互換があることを示しているのです。

では、ロードするCLRのバージョンの決定ですが、

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

class Program {
    static void Main(string args) {
        if (args.Length < 1)
            return;

        Version ver = new Version (args[0]);

        RegistryKey keyNet = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\.NETFramework");
        if (keyNet == null)
            return;
        
        string root = (string)keyNet.GetValue("InstallRoot");
        string path = String.Format(@"{0}v{1}", root, ver);
        string engine = Path.Combine(path, "mscorwks.dll");
        if (File.Exists(engine)) {
            // 一致するバージョンのCLRがインストールされていたら、それを使う
            Console.WriteLine ("version {0} is installed.", ver);
            return;
        }
        else {
            Console.WriteLine ("version {0} is not installed.", ver);
        }

        // 一致するバージョンのCLRがインストールされていなければ、
        // 互換性のあるバージョンの中で一番バージョンが高いものを採用する
        RegistryKey keyUpgrades = null;
        keyUpgrades = keyNet.OpenSubKey("Policy").OpenSubKey("Upgrades");
        if (keyUpgrades == null) {
            return;
        }

        List<Version> list = new List<Version> ();
        foreach (string key in keyUpgrades.GetValueNames ()) {
            string  ss = keyUpgrades.GetValue (key).ToString ().Split ('-');
            Version v = new Version (key);
            Version from = new Version (ss [0]);
            Version to = new Version (ss [1]);
            if (from <= ver && ver <= to)
                list.Add (v);
        }

        if (list.Count > 0) {
            list.Sort ();
            list.Reverse ();
            foreach (Version v in list) 
                Console.WriteLine ("version {0} of the CLR is compatible with {1}", v.ToString ().PadRight(9), ver);
            Console.WriteLine ("use version {0}.", list[0]);
        }
    }
}

/* upgrades.exe 1.0.3705
version 1.0.3705 is not installed.
version 2.0.50727 of the CLR is compatible with 1.0.3705
version 1.1.4322  of the CLR is compatible with 1.0.3705
use version 2.0.50727.
 */

こんな感じです。ただし、アプリケーション構成ファイル(.config)が存在しないことが前提です。

勿論、CLRホスティングを使えば、ロードするバージョンを最新ではなく互換性のある中で一番バージョンが近いものを使うとか出来ます。しかし、アプリケーション構成ファイルのタグにバージョンを列挙すれば、その優先順位でロードしてくれるので、わざわざ自分でホストを書くまでもありません。

なかなかCLRホスティングの出番がありませんねぇ。(^^;