他のいくつかの回答による提案とは異なり、DllImport
属性を使用することは依然として正しいアプローチです。
正直なところ、世界中の人と同じようにできない理由を理解できず、DLLへの相対パスを指定します。はい、アプリケーションがインストールされるパスはユーザーのコンピューターによって異なりますが、それは基本的に、展開に関しては一般的なルールです。DllImport
メカニズムはこれを念頭において設計されています。
実際には、それDllImport
を処理することすらありません。便利なマネージラッパー(P / Invokeマーシャラーがを呼び出すだけLoadLibrary
)を使用しているかどうかに関係なく、それはWin32 DLLのネイティブの読み込み規則です。これらのルールはここで詳しく列挙されていますが、重要なルールはここで抜粋されています。
システムはDLLを検索する前に、以下をチェックします。
- 同じモジュール名のDLLがすでにメモリに読み込まれている場合、システムは、どのディレクトリにあるかに関係なく、読み込まれたDLLを使用します。システムはDLLを検索しません。
- DLLが、アプリケーションが実行されているWindowsのバージョンの既知のDLLのリストにある場合、システムは既知のDLL(および既知のDLLの依存DLL)のコピーを使用します。システムはDLLを検索しません。
もし SafeDllSearchMode
(デフォルト)有効になって次のように、検索順序は次のとおりです。
- アプリケーションのロード元のディレクトリ。
- システムディレクトリ。
GetSystemDirectory
関数を使用して、このディレクトリのパスを取得します。
- 16ビットのシステムディレクトリ。このディレクトリのパスを取得する機能はありませんが、検索されます。
- Windowsディレクトリ。使用
GetWindowsDirectory
関数を、このディレクトリのパスを取得します。
- 現在のディレクトリ。
PATH
環境変数にリストされているディレクトリー。これには、App Pathsレジストリキーで指定されたアプリケーションごとのパスは含まれないことに注意してください。DLL検索パスを計算する場合、App Pathsキーは使用されません。
したがって、DLLにシステムDLLと同じ名前を付けない限り(どのような状況でも明らかにすべきではないことですが)、デフォルトの検索順序は、アプリケーションのロード元のディレクトリから検索を開始します。インストール中にDLLをそこに配置すると、DLLが見つかります。相対パスだけを使用すれば、複雑な問題はすべてなくなります。
書くだけ:
[DllImport("MyAppDll.dll")] // relative path; just give the DLL's name
static extern bool MyGreatFunction(int myFirstParam, int mySecondParam);
ただし、それが何らかの理由で機能せず、アプリケーションにDLLの別のディレクトリを検索させる必要がある場合は、SetDllDirectory
関数を使用してデフォルトの検索パスを変更できます。
ドキュメントに従って:
を呼び出した後SetDllDirectory
の標準DLL検索パスは次のとおりです。
- アプリケーションのロード元のディレクトリ。
lpPathName
パラメータで指定されたディレクトリ。
- システムディレクトリ。
GetSystemDirectory
関数を使用して、このディレクトリのパスを取得します。
- 16ビットのシステムディレクトリ。このディレクトリのパスを取得する機能はありませんが、検索されます。
- Windowsディレクトリ。
GetWindowsDirectory
関数を使用して、このディレクトリのパスを取得します。
PATH
環境変数にリストされているディレクトリー。
したがって、DLLからインポートされた関数を初めて呼び出す前にこの関数を呼び出す限り、DLLの検索に使用されるデフォルトの検索パスを変更できます。もちろん、利点は、実行時に計算される動的な値をこの関数に渡すことができることです。これはDllImport
属性では不可能であるため、相対パス(DLLの名前のみ)を引き続き使用し、新しい検索順序に基づいて検索します。
この関数をP / Invokeする必要があります。宣言は次のようになります。
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);