Bootstrap その後

「Bootstrapperはもう終わり」と思っていたのですが、WiX Bootstrapperは気持ちの悪い終わり方をしたし、どうしてもこのまま終了にするのが嫌なので、結局やるところまでやることにしました。

まず、マイクロソフトがインストールの方法として、最近はClickOnceを推奨しているので、ClickOnceがどんなものか使ってみることにしました。

簡単なサンプルを作り、ClickOnceの長短をまとめた記事を読んでみました。短所は、細かい指示ができそうにないということで、今後は、改良されてインストール手段のメインになるかもしれませんが、「今は、よしわかった」でClickOnceは終わりにします。

WiX以外のBootoStrapperがあるという情報を得たので、探し出し使ってみました。AutoItです。これを使っていて、はたとわかったことは、「要するに、ターゲットコンピュータに、私の場合Accessがインストールされているかどうか調べて、なければ、所定のURLから用意したAccessRuntimeをダウンロードし、インストールすればいいのだから、このプログラムをVBでもC#でもいいから、自作すればいいだけだ」ということです。

ごく当たり前のことなのに、難しく考えていました。

C#はあまり経験ないので、この際C#で書いてみました。

ターゲットコンピュータのOSのバージョン、32/64ビット版の確認、さらに、Accessがインストールされているかレジストリーをしらべ、なければRunTimeをダウンロード、インストール、それが済んだら自分のセットアップソフト(MyApp.msi)をダウンロードしインストールします。

正味200行もないと思います。

難しいことはありませんが、注意すべき点がいくつかあります。

1. RunTimeの存在を調べるとき、32ビットOSと64ビットOSで調べる場所が異なる点です。

調べるAccessは2つあります。
Access2010でもいいし、Access2013でもいいです。

Access2010のProgIDは[Access.Application.14]、Access2013のProgIDはAccess.Application.15です。

これらがインストールされているかどうかは、レジストリーのLOCAL_MACHINESOFTWAREClassesを探します。

これだけでいいと思いますが、更に念のためここで得られたCLSIDからインストールの状況を調べました。

このとき、32ビットOSではSOFTWAREClassesCLSID、64ビットOSではSOFTWAREWOW6432NodeClassesCLSIDを調べる必要があります。

2. ファイルのダウンロードが完了後に、そのインストールを始めなければいけません。ダウンロードが完了していないのに、インストールを始めては当然いけません。

ダウンロードにはWebClientクラスを使います。
WebClient.DownloadFileメソッドは同期をとっていると思うのですが、作業の終了を確認しないとエラーがでます。

WebClient.IsBusyの間は、次の処理に移行しないようにしました。
これでOKでした。

また、MyAppのインストールの前に、AccessRuntimeのインストール作業を終了しておかなければいけません。

これはProcessを使い、Process.WaitForExit()で同期をとればOKです。
次にコードの一部を示します。

System.Diagnostics.Process p = System.Diagnostics.Process.Start(AccessRuntime);
p.WaitForExit();

	
        private bool AccessRuntimeInstall()
        {
            bool res = false;
            int osbit = System.Environment.Is64BitProcess ? 64 : 32;

            RegistryKey BaseKey = null;
            RegistryKey Key = null;

            // Access.Application.14    Access2010
            BaseKey = Registry.LocalMachine;
            Key = BaseKey.OpenSubKey("SOFTWARE\Classes\Access.Application.14\CLSID");

            bool SearchKeyRes = SearchKey(BaseKey, Key, osbit);
            if (SearchKeyRes == false)         {
                // Access.Application.15    Access2013
                Key = BaseKey.OpenSubKey("SOFTWARE\Classes\Access.Application.15\CLSID");
                SearchKeyRes = SearchKey(BaseKey, Key, osbit);
            }
            
            if (SearchKeyRes == true)   {
                res = true;
                return res;
            }  else {
                String Access = "AccessRunTime.exe";
                try {
                    WebClient client = new WebClient();

                    if (osbit == 32)  {
                        client.DownloadFile("http://www.aa.bb/cc/AccessRuntime_x86_ja-jp.exe", Access);
                    }   else  {
                        client.DownloadFile("http://www.aa.bb/cc/AccessRuntime_x64_ja-jp.exe", Access);
                    }

                    while (client.IsBusy == true)                {
                        System.Threading.Thread.Sleep(1000);
                    }

                    Using (System.Diagnostics.Process p = System.Diagnostics.Process.Start(Access)) {
			p.WaitForExit();
		    }
		    res = true;
                } catch (Exception ex)  {
                    Console.WriteLine(ex.Message);
                    res = false;
                }  finally  {
                    System.IO.File.Delete(Access);
                }
            }
            return res;
        }

        private bool SearchKey(RegistryKey BaseKey, RegistryKey Key, int osbit)
        {
            RegistryKey CLSKey;
            if (Key != null)           {
                String CLSID = (String)Key.GetValue("");
                if (osbit == 32)       {
                    CLSKey = BaseKey.OpenSubKey("SOFTWARE\Classes\CLSID\" + CLSID);
                }   else     {
                    // HKEY_LOCAL_MACHINESoftwareWOW6432NodeClassesCLSID    で  CLSID をキーとして を探す
                    CLSKey = BaseKey.OpenSubKey("SOFTWARE\WOW6432Node\Classes\CLSID\" + CLSID);
                }
                if (CLSKey != null) { return true; }
            }
            return false;
        }
    }

error: コピーできません !!