[解決済み] 実行時に[DllImport]のパスを指定するにはどうしたらいいですか?
質問内容
実際、私はC++の(動作する)DLLを持っていて、それを私のC#プロジェクトにインポートしてその関数を呼び出したいと思っています。
DLLへのフルパスを指定すると、このように動作します。
string str = "C:\\Users\\userName\\AppData\\Local\\myLibFolder\\myDLL.dll";
[DllImport(str, CallingConvention = CallingConvention.Cdecl)]
public static extern int DLLFunction(int Number1, int Number2);
問題は、インストール型のプロジェクトなので、実行するコンピュータやセッションによって、ユーザーのフォルダが同じにならないことです(例:pierre, paul, jack, mum, dad, ...)。
だから、私のコードはもう少し一般的なものにしたいのです。
/*
goes right to the temp folder of the user
"C:\\Users\\userName\\AppData\\Local\\temp"
then go to parent folder
"C:\\Users\\userName\\AppData\\Local"
and finally go to the DLL's folder
"C:\\Users\\userName\\AppData\\Local\\temp\\myLibFolder"
*/
string str = Path.GetTempPath() + "..\\myLibFolder\\myDLL.dll";
[DllImport(str, CallingConvention = CallingConvention.Cdecl)]
public static extern int DLLFunction(int Number1, int Number2);
重要なのは、"DllImport" が DLL のディレクトリに対する "const string" パラメータを欲していることです。
そこで質問です:。 この場合、どうしたらいいのでしょうか?
どのように解決するのですか?
他の回答者の提案に反して、このメソッドでは
DllImport
属性は、今でも正しい方法です。
正直なところ、なぜ世界の他の人と同じように
相対
のパスが必要です。確かに、アプリケーションがインストールされるパスは人によって異なりますが、デプロイメントに関しては、基本的にこれが普遍的なルールです。そのため
DllImport
の仕組みは、このことを念頭に置いて設計されています。
実際、それは
DllImport
がそれを処理します。これは、便利なマネージド・ラッパー(P/Invokeマーシャラーは、単に
LoadLibrary
). これらのルールは、非常に詳細に列挙されています
こちら
しかし、重要なものはここに抜粋されている。
システムはDLLを検索する前に、次のことを確認します。
- 同じモジュール名のDLLがすでにメモリにロードされている場合、システムはロードされたDLLを使用します(それがどのディレクトリにあるかは関係ありません)。システムは、DLL を検索しません。
- DLLがアプリケーションを実行しているWindowsのバージョンの既知のDLLのリストにある場合、システムは既知のDLLのコピー(および既知のDLLの依存DLLがある場合は、そのコピー)を使用します。システムは、DLLを検索しません。
もし
SafeDllSearchMode
を有効にすると(デフォルト)、検索順序は次のようになります。
- アプリケーションがロードされたディレクトリ。
-
システムディレクトリです。を使用します。
GetSystemDirectory
関数を使用して、このディレクトリのパスを取得します。 - 16ビットシステムのディレクトリです。このディレクトリのパスを取得する関数はありませんが、検索されます。
-
Windowsのディレクトリです。Windowsのディレクトリです。
GetWindowsDirectory
関数を使用して、このディレクトリのパスを取得します。 - 現在のディレクトリです。
-
にリストされるディレクトリは
PATH
環境変数を使用します。これには、レジストリキーApp Pathsで指定されたアプリケーションごとのパスは含まれないことに注意してください。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のディレクトリです。Windowsのディレクトリです。
GetWindowsDirectory
関数を使用して、このディレクトリのパスを取得します。- にリストされるディレクトリは
PATH
環境変数を使用します。
つまり、DLLからインポートされた関数を初めて呼び出す前にこの関数を呼び出す限り、DLLの検索に使用されるデフォルトの検索パスを変更することができるのです。もちろん、この関数の利点は、DLLの検索に使われるデフォルトの検索パスを変更できることです。
ダイナミック
の値は、実行時に計算されるこの関数に渡されます。これは
DllImport
属性を使用する場合、相対パス (DLL の名前のみ) を使用し、新しい検索順序に依存することになります。
この関数をP/Invokeする必要があります。宣言は次のようになります。
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
関連
-
[解決済み】C#におけるtypedefの等価性
-
[解決済み】Moqを使用してメソッド呼び出しを検証する
-
[解決済み] enumを列挙するには
-
[解決済み] intをenumにキャストするにはどうすればよいですか?
-
[解決済み] 文字列の単語を反復処理するにはどうすればよいですか?
-
[解決済み] 1ビットのセット、クリア、トグルはどのように行うのですか?
-
[解決済み] なぜテンプレートはヘッダーファイルでしか実装できないのですか?
-
[解決済み] Linux上で動作するC++コードのプロファイリングを行うにはどうすればよいですか?
-
[解決済み] Pythonで定数を作成するにはどうすればよいですか?
-
[解決済み] .NETコンソールアプリケーションでアプリケーションのパスを取得するにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】「入力文字列が正しい形式ではありませんでした」エラーの解決方法は?[重複しています]。
-
[解決済み】リソースの読み込みに失敗した:ステータス500(内部サーバーエラー)のサーバーの応答)
-
[解決済み】ファイルへの読み書きの際に共有違反のIOExceptionが発生する C#
-
[解決済み】エラー「必要なフォーマルパラメータに対応する引数が与えられていない」を解決する?
-
[解決済み】 C# 条件演算子エラー 代入、call、increment、decrement、await、new object 式のみ文として使用可能です。
-
[解決済み】URLから画像をダウンロードする方法
-
[解決済み】IntPtrとは一体何なのか?
-
[解決済み】Unityでゲームオブジェクトのすべての子をループスルーして破壊する方法?
-
[解決済み] 関数を終了するには?
-
[解決済み】「namespace」なのに「type」のように使われる。