最終更新日 2024-09-25

C#で作成した「中間アセンブリdll」の配置フォルダの追加

概要

秀丸用の自作.dllを作成した場合、通常は「秀丸本体のhidemaru.exe」と「自分で作成した.dll」とは、
「異なるディレクトリ」へと配置するのが普通です。
通常はおそらく、「起動のきっかけとなるマクロファイル(.mac)」と同じフォルダに自作のdllを配置したいと思うことでしょう。

そして、hm.NETは、「起動した際のマクロファイル(.mac)と同じフォルダ」を中間アセンブリの検索対象に追加しています。

これらはどのように実現されているのでしょうか?
また、さらに「自分自身で配置場所を独自に追加」したい場合には、どのようにすればいいのか紹介します。

アセンブリの解決

自作のdllに、以下のような「AssemblyResolve」とも呼べるプログラムを、追加することで、「アセンブリが読み込めなかったら、ここにあるこのdllで代用してください」と パスを指定してアセンブリを読み込ませることができます。

DllAssemblyResolver.cs
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;

internal class DllAssemblyResolver
{
    public DllAssemblyResolver()
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    }

    ~DllAssemblyResolver()
    {
        AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
    }

    // アセンブリdllの読み込みに失敗した時、このメソッドが実行される。
    // ようするに「dllがみつからなかったので、この場所のこのファイルを探してください」といった形で返すメソッドである。
    private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        try
        {
            var requestingAssembly = args.RequestingAssembly;
            var requestedAssembly = new AssemblyName(args.Name);
            System.Diagnostics.Trace.WriteLine($"CurrentDomain_AssemblyResolve:{args.Name}"); // デバッグモニター表示用

            // このdll自体を置いているフォルダに読み込み対象のアセンブリがあるかもしれない。
            String self_full_path = Assembly.GetExecutingAssembly().Location;
            String self_dir = Path.GetDirectoryName(self_full_path);

            // このフルパスを整形することで、違うフォルダ、あるいはサブフォルダに配置してあるdllをアセンブリとして読み込ませることが出来る。
            var targetfullpath = self_dir + $@"\{requestedAssembly.Name}.dll";

            if (File.Exists(targetfullpath))
            {
                return Assembly.LoadFile(targetfullpath);
            }

            // そのようなフルパスが指定されている場合(フルパスを指定した書き方)
            targetfullpath = requestedAssembly.Name;
            if (File.Exists(targetfullpath))
            {
                return Assembly.LoadFile(targetfullpath);
            }
        }
        catch (Exception ex)
        {
            return null;
        }
        return null;
    }
}

秀丸マクロから最初に呼ぶ予定の「メソッドを含むクラス」の「静的コンストラクタ」に以下のようなものを記述することです。
ポイントは秀丸マクロから最初に呼ぶ予定の「メソッドを含むクラス」の「静的コンストラクタ」に書くことです。

MyTest.cs
using System;
using System.Runtime.InteropServices;
using HtmlAgilityPack; // nuget などを経由して自分で参照を追加すること。

namespace MyTestNameSpace {

    public class MyTestClass
    {
        static DllAssemblyResolver dasmr; 
        // 秀丸から最初に呼ぶメソッドが含まれているクラスの「静的コンストラクタ(static付きのコンストラクタ)」
        // でアセンブリリゾルバーオブジェクトを生成する。
        static MyTestClass() {
            dasmr = new DllAssemblyResolver();
            System.Diagnostics.Trace.WriteLine("MyTestClass 静的コンストラクタ実行");
        }

        // 秀丸から最初に呼ぶメソッド
        static IntPtr abc(IntPtr a)
        {
            // HttmlAgiliyPack を実際に利用する記述
            var doc = new HtmlAgilityPack.HtmlDocument();
            System.Diagnostics.Trace.WriteLine(doc.ToString());

            int b = (int)a + 3;
            return (IntPtr)b;
        }
    }
}