NSISで、C#で書かれた自作のDLLを使う

NSISでインストーラ&アンインストーラを作っていて、インストール時に一緒にインストールしたAdobe AIRアプリケーションを、アンインストール時に同時にアンインストールしたいという要件。

Adobe AIRアプリケーションのアンインストールは、手動ならWindowsのコントロールパネルからできるので、ここの情報をレジストリから引っ張り出して実行すればOK。この辺は良くある手段。

で、レジストリからアンインストールに必要なプログラムの実行パス情報を持ってこようとしたら、Adobe AIRでは、Uninstall以下のサブキーの名前が毎回変わるので、検索する必要があることが発覚。

NSISにはレジストリの特定のキーを読む機能はあっても、キーを検索する機能はないので、DLLで拡張を作成。さっくり適当にC#でレジストリを検索して文字列を返すDLLを作成してみた。

ちなみにアンインストール情報はHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall以下にあります。

ということで、必要な動作はUninstall以下のサブキーを全部開いてDisplayNameが目的の名前と一致するサブキーを探すこと。ソースは以下。

SearchUninstall.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace SearchUninstall
{
    public class SearchUninstall
    {
        public static string Find(string name)
        {
            string keyPath = "";

            // レジストリからの読み取り
            Microsoft.Win32.RegistryKey regkey =
                Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", false);
            // キーが存在しないときは null が返される
            if (regkey == null) return null;

            // 文字列を読み込む
            // 読み込む値が存在しないときは null が返される
            string stringValue = (string)regkey.GetValue("string");

            // sub以下のすべてのキー名を取得
            string[] keyNames = regkey.GetSubKeyNames();
            foreach (string k in keyNames)
            {
                string tmp_keyPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" + k;
                Microsoft.Win32.RegistryKey regkey2 =
                    Microsoft.Win32.Registry.LocalMachine.OpenSubKey(tmp_keyPath, false);
                try
                {
                    string displayName = (string)regkey2.GetValue("DisplayName");
                    if (displayName == name)
                    {
                        keyPath = tmp_keyPath;
                        break;
                    }
                }
                catch (Exception e)
                {
                    ;
                }
                finally
                {
                    regkey2.Close();
                }
            }

            //閉じる
            regkey.Close();

            return keyPath;
        }
    }
}

で、出来上がったDLLをNSISに読み込ませようとしても、どうにも動かない。

Dependency walkerで他のDLLと見比べてみると、C#で作られたDLLはエントリポイントが見えない。

そう言えばそんな話もあったような。

参考:WINAMP.COM | Forums – How can I use a C# DLL in NSIS

NSISからでは.NETのDLLが読めないらしい。ということで、見つけたのが以下。.NETのDLLを使えるようにするプラグイン。

Call .NET DLL methods plug-in – NSIS

CLR.zipをダウンロードしてきて、NSISをインストールしたフォルダのPluginsフォルダに入れておけばOK。

先に作ったSearchUninstall.dllはnsiファイルと同じ場所に入れておく。

で、nsiファイルは以下の感じ。Uninstall部分の必要部分を抜粋。

; アンインストーラ
Section "Uninstall"
  ; アンインストールで使用するプラグインの準備
  InitPluginsDir
  SetOutPath $PLUGINSDIR
  File "SearchUninstall.dll"

  ; AIRアプリケーションのアンインストーラを探す
  CLR::Call /NOUNLOAD "SearchUninstall.dll" "SearchUninstall.SearchUninstall" "Find" 1 "HogeHogeAir"
  pop $0
  CLR::Destroy

  ReadRegStr $4 HKLM $0 "UninstallString"

  ; AIRアプリケーションのアンインストーラをPassiveモード(自動処理)で実行する
  ExecWait "$4 /passive"

  ; 後片付け
  Delete "$PLUGINSDIR\SearchUninstall.dll"
SectionEnd

これで、アンインストール時にAdobe AIRアプリケーションのアンインストーラも勝手に起動して削除できる。

CLR超便利。プラグインを作るのが相当楽に。


新しく会社作りました!

コメント / トラックバック 1 件

  1. […] NSISで、C#で書かれた自作のDLLを使う : blog.loadlimit – digital matter – […]

コメントをどうぞ