はじめに
C#アプリケーションを開発する場合、DLL形式の外部ライブラリやアセンブリを使用することが一般的です。しかし、これらのDLLが実行ファイル(EXE)と同じフォルダーになく、別の場所から参照する必要がある場合があります。
今回は、C#でEXEと異なるフォルダにあるDLLを参照するいくつかの方法について説明します。
方法
C#で、EXEと異なるフォルダに配置したDLLを参照する場合、以下のような方法があります。
- App.configにdllのパスを指定する
- AppDomain.CurrentDomain.AssemblyResolveイベントを使用してdllのパスを指定する
- SetDllDirectory関数を使用してdllのパスを指定する
- アセンブリのコードベースを使用してDLLを参照する方法
App.configにdllのパスを指定する
App.configにdllのパスを指定する方法は、App.configに以下のようにdllのパスを記述します。
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="C:\MyDlls"/>
</assemblyBinding>
</runtime>
</configuration>
上記の例では、EXEと同じフォルダに配置されている「MyDlls」フォルダにあるdllを参照しています。
この方法は、アプリケーションを起動する際にdllを探索するため、dllが見つからない場合にはdllがあるフォルダを指定することで解決することができます。
ただし、注意点として、
- App.configファイルが正しく記述されていること。
- privatePath属性で指定したフォルダが存在し、dllが存在すること。
- フォルダは、相対パスで指定する必要がある。
- .NET Framework のバージョンによっては、この方法が使用できないこと。
これらを考慮して使用することが必要です。
AssemblyResolveイベントを使用する方法
この方法は、アプリケーションで参照しているdllが見つからない場合に、独自にdllを探索し、参照することができるようにするものです。
以下に、AssemblyResolveイベントを使用してdllのパスを指定する方法の例を示します。
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string dllName = args.Name.Contains(",") ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", "");
dllName = dllName.Replace(".", "_");
if (dllName.EndsWith("_resources")) return null;
string file = @"MyDlls\" + dllName + ".dll";
return File.Exists(file) ? Assembly.LoadFile(file) : null;
}
上記の例では、アプリケーションが参照するdllが見つからない場合に、独自にdllを探索するために、AssemblyResolveイベントを使用しています。
そして、EXEと同じフォルダに配置されている「MyDlls」フォルダにあるdllを参照しています。
この方法は、dllが見つからない場合にはdllがあるフォルダを指定することで解決することができます。
ただし、注意点として、
- 指定したフォルダが存在し、dllが存在すること。
- フォルダは、相対パスで指定する必要がある。
これらを考慮して使用することが必要です。
この方法は、App.configにdllのパスを指定する方法と比較して、dllが見つからない場合にもアプリケーションがクラッシュするような事故を防ぐことができます。
ただし、この方法は、dllが見つからない場合に独自にdllを探索するため、dllが正しくない場合にアプリケーションがクラッシュする可能性があるため、dllが正しいことを確認することが重要です。
SetDllDirectory関数を使用する方法
SetDllDirectory関数を使用してdllのパスを指定する方法は、以下のようにdllのパスを指定します。
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool SetDllDirectory(string lpPathName);
....
SetDllDirectory("C:\\MyDlls");
ただし、SetDllDirectory関数は、アプリケーションのスタートアップ時に1回だけ実行することができるので、DLLを配置するフォルダを変更した場合は、アプリケーションを再起動する必要があります。
また、SetDllDirectory関数はWindows APIのため、非Windows環境では使用できない点にも注意が必要です。
💡C#などの.NET言語から、Win32 APIや、C++によって作成されたDLLを呼び出すための仕組みを、P/Invoke (Platform Invocation Services) と呼びます。
P/Invokeについては、👇の記事が詳しいです。

アセンブリのコードベースを使用してDLLを参照する方法
アセンブリのコードベースを使用するには、アセンブリに「file://」プロトコルを使用しなければならないこと、指定したDLLが実際に存在することを確認することが必要です。
以下は、アセンブリのコードベースを使用してDLLを参照する方法の例です。
[assembly: AssemblyCodeBase("file:///C:/MyDlls/MyLibrary.dll")]
上記の例では、EXEが配置されているフォルダとは異なるフォルダの「C:/MyDlls/MyLibrary.dll」にあるDLLを参照しています。
ただし、この方法は、.NET Framework 4.0以降で使用できなくなっているので、新しいプロジェクトでは使用しない方が良いでしょう。
まとめ
EXEと異なるフォルダにあるDLLを参照する方法は、簡単に実装することができますが、環境によってはうまく動作しないことがあるので、他の方法と比較して適した方法を選ぶことが重要です。