C#におけるDLLの動的ロードと実行

C#で外部DLL(ダイナミックリンクライブラリ)を動的にロードして、その中のメソッドを実行する方法について説明します。主にSystem.Reflection名前空間を利用する方法と、DllImport属性を利用する方法があります。

方法1: ReflectionによるDLLのロードとメソッド実行

この方法は、実行時にDLLファイルのパスを指定し、Assembly.LoadFileメソッドでDLLをロードします。その後、Type.GetTypeでクラスを取得し、Activator.CreateInstanceでインスタンスを生成します。最後に、Type.GetMethodでメソッドを取得し、MethodInfo.Invokeでメソッドを実行します。

using System;
using System.Reflection;

public class DynamicDllLoader
{
    public static void Main(string[] args)
    {
        // DLLファイルのフルパスを指定します。
        string dllFilePath = @"C:\path\to\your\library.dll"; 
        
        try
        {
            // DLLアセンブリをロードします。
            Assembly loadedAssembly = Assembly.LoadFile(dllFilePath);

            // ロードしたアセンブリから特定の型(クラス)を取得します。
            // "YourNamespace.YourClass" は、DLL内のクラスの完全修飾名に置き換えてください。
            Type targetType = loadedAssembly.GetType("YourNamespace.YourClass");

            if (targetType != null)
            {
                // 型のインスタンスを生成します。
                object instance = Activator.CreateInstance(targetType);

                // 実行したいメソッドを取得します。
                // "YourMethod" は、DLL内のメソッド名に置き換えてください。
                MethodInfo methodToExecute = targetType.GetMethod("YourMethod");

                if (methodToExecute != null)
                {
                    // メソッドを実行します。引数がない場合はnullを指定します。
                    methodToExecute.Invoke(instance, null); 
                    Console.WriteLine("DLL内のメソッドが正常に実行されました。");
                }
                else
                {
                    Console.WriteLine("指定されたメソッドが見つかりませんでした。");
                }
            }
            else
            {
                Console.WriteLine("指定された型が見つかりませんでした。");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"DLLのロードまたは実行中にエラーが発生しました: {ex.Message}");
        }
    }
}

方法2: DllImport属性によるネイティブDLLのロード

DllImport属性は、主にアンマネージコード(C++などで作成されたDLL)をC#から呼び出す際に使用されます。この属性を使用すると、DLLのロードパスが固定されるか、システムパス(環境変数PATHなど)から検索されることになります。

DLLのパスを動的に設定したい場合、環境変数PATHを一時的に変更する方法があります。

using System;
using System.Runtime.InteropServices;
using System.Diagnostics;

public class NativeDllCaller
{
    // 外部DLLの関数をインポートするための宣言
    // "****.dll" は実際のDLL名に置き換えてください。
    [DllImport("****.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int CallExternalFunction(int inputCode);

    public static void Main(string[] args)
    {
        // DLLが存在する可能性のあるディレクトリパスを取得または設定します。
        string specificDllDirectory = @"C:\Program Files\YourApp\Bin"; // DLLが存在するディレクトリパスを設定

        // 環境変数PATHにDLLディレクトリを追加します。
        string currentPath = Environment.GetEnvironmentVariable("PATH");
        if (currentPath != null)
        {
            // パスの末尾にセミコロンがない場合に追加し、DLLディレクトリを追加します。
            string newPath = currentPath.TrimEnd(';') + ";" + specificDllDirectory;
            Environment.SetEnvironmentVariable("PATH", newPath);

            try
            {
                // DLL内の関数を呼び出します。
                int result = CallExternalFunction(123); // 例として引数123を渡す
                Console.WriteLine($"外部関数からの結果: {result}");
            }
            catch (DllNotFoundException)
            {
                Console.WriteLine("DLLが見つかりませんでした。パスが正しく設定されているか確認してください。");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"関数の呼び出し中にエラーが発生しました: {ex.Message}");
            }
            finally
            {
                // 必要であれば、元のPATH環境変数を復元します。
                // Environment.SetEnvironmentVariable("PATH", currentPath);
            }
        }
        else
        {
            Trace.TraceError("PATH環境変数が取得できませんでした。");
        }
    }
}

実行例

ここでは、簡単なC#クラスライブラリ(ZWH.dll)を作成し、それを別のコンソールアプリケーションから動的にロードしてメソッドを実行する例を示します。

1. DLLプロジェクト (ZWH.dll)

以下のコードでZWH.dllを作成します。

using System;

namespace ZWH
{
    public class Class1
    {
        public void DisplayMessage() 
        {
            Console.WriteLine("Hello from ZWH.dll!");
        }
    }
}

2. メインアプリケーションプロジェクト

以下のコードで、作成したZWH.dllをロードしてDisplayMessageメソッドを実行します。

using System;
using System.Reflection;

namespace MainApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // ZWH.dllへのパスを指定します。
            // 実行ファイルと同じディレクトリにある場合は、ファイル名だけでロードできます。
            // 例: string dllPath = "ZWH.dll";
            // 特定のパスを指定する場合:
            string dllPath = @"E:\path\to\your\project\ZWH\bin\Debug\ZWH.dll"; 

            try
            {
                // DLLアセンブリをロードします。
                Assembly assembly = Assembly.LoadFrom(dllPath);

                // ZWH.Class1 型を取得します。
                Type type = assembly.GetType("ZWH.Class1");

                if (type != null)
                {
                    // ZWH.Class1 のインスタンスを作成します。
                    object obj = Activator.CreateInstance(type);

                    // DisplayMessage メソッドを取得します。
                    MethodInfo method = type.GetMethod("DisplayMessage");

                    if (method != null)
                    {
                        // DisplayMessage メソッドを呼び出します。
                        method.Invoke(obj, null); 
                    }
                    else
                    {
                        Console.WriteLine("メソッド 'DisplayMessage' が見つかりません。");
                    }
                }
                else
                {
                    Console.WriteLine("型 'ZWH.Class1' が見つかりません。");
                }
            }
            catch (System.IO.FileNotFoundException)
            {
                Console.WriteLine($"DLLファイルが見つかりません: {dllPath}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"エラーが発生しました: {ex.Message}");
            }

            Console.WriteLine("プログラムを終了するには何かキーを押してください...");
            Console.ReadKey();
        }
    }
}

実行結果

上記MainAppを実行すると、コンソールに以下のように表示されます。

Hello from ZWH.dll!
プログラムを終了するには何かキーを押してください...

タグ: C# DLL Reflection Assembly.LoadFile Assembly.LoadFrom

8月2日 23:50 投稿