こんにちは。
C++ にて依存関係のある自作 DLL の配置場所が実行ファイルと違う場所に配置した場合でも、
読み込む方法につきまして質問させていただければと思います。
実現したいこと
A.dll を C++ プロジェクトにて LoadLibrary でロードした際に、
B.dll が実行可能ファイル(Hoge.exe)とは別の場所にある場合でも、
読み込めるように対応したいと考えています。
Sample/ ├Bin/ │ └Hoge.exe └ DLL/Win64/ ├A.dll(B.dll に依存) └B.dll
前提
B.dll は C# で記述されているのですが、これを C++ でも使用したいため、
A のクラスでラップして DLLExport.bat で A.dll を出力しています。
環境変数への Path 設定はなるべく行わない方法で検討しています。
### 発生している問題・エラーメッセージ ``` Log EEFileLoadException System.IO.FileNotFoundException
C++ 側で A.dll 内の関数(Test)を呼び出した際に上記エラーが発生します。
ただし実行ファイルの Hoge.exe と同じ場所に B.dll を配置すると問題は発生しません。
また、ClassSub の new 文を削除した場合でも問題は発生せず関数の呼び出しも可能です。
該当のソースコード
C#
1// B.dll 2namespace SampleSub 3{ 4 public class ClassSub 5 { 6 } 7}
C#
1using SampleSub; 2 3// A.dll 4namespace SampleMain 5{ 6 public class ClassMain 7 { 8 [DllExport] 9 public static void Test() 10 { 11 // B.dll に含まれるクラスを new 12 ClassSub sub = new ClassSub(); 13 } 14 } 15}
C++
1typedef void(*FUNC)(); 2 3int main() 4{ 5 // dll を配置しているディレクトリを検索できるよう設定 6 SetDllDirectory(L"C:\\Sample\\DLL\\Win64"); 7 SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); 8 9 // A.dll をロード 10 HMODULE hModule = LoadLibrary(L"A.dll"); 11 // 関数を取得 12 FUNC func = (FUNC)GetProcAddress(hModule, "Test"); 13 func(); // ← ここで B.dll が読み込めず System.IO.FileNotFoundException となる 14}
試したこと
A.dll をロードする前に B.dll をロード(LoadLibrary)する
LoadLibraryEx("C:\Sample\DLL\Win64\A.dll", nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
SetDllDirectory を AddDllDirectory に変更
補足情報(FW/ツールのバージョンなど)
Visual Studio 2022
.Net Framework 4.8
C++(呼び出し側)
C#(DLL)
追記(Assembly.LoadFromを使用)
C#
1// A.dll 2namespace SampleMain 3{ 4 public class ClassMain 5 { 6 [DllExport] 7 public static bool Init() 8 { 9 try 10 { 11 Assembly loadedAssembly = Assembly.LoadFrom("C:\\Sample\\DLL\\Win64\\B.dll"); 12 } 13 catch (Exception ex) 14 { 15 Debug.WriteLine($"Error: {ex.Message}"); 16 return false; 17 } 18 return true; 19 } 20 21 [DllExport] 22 public static void Test() 23 { 24 ClassSub sub = new ClassSub(); 25 } 26 }
C++
1int main() 2{ 3 SetDllDirectory(L"C:\\Sample\\DLL\\Win64"); 4 SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); 5 6 HMODULE hModule = LoadLibrary(L"A.dll"); 7 FUNCInit funcInit = (FUNCInit)GetProcAddress(hModule, "Init"); 8 bool bResult = funcInit (); // ←ここでは true が返却 9 FUNCTest funcTest = (FUNCTest)GetProcAddress(hModule, "Test"); 10 funcTest (); // ← ここで EEFileLoadException 11}
追記:解決(AppDomain.CurrentDomain.AssemblyResolve + Assembly.LoadFromを使用)
C#
1// A.dll 2namespace SampleMain 3{ 4 public class ClassMain 5 { 6 [DllExport] 7 public static bool Init() 8 { 9 AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; 10 return true; 11 } 12 13 [DllExport] 14 public static void Test() 15 { 16 ClassSub sub = new ClassSub(); 17 } 18 19 private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 20 { 21 if (args.Name.StartsWith("B,")) 22 { 23 try 24 { 25 Assembly loadedAssembly = Assembly.LoadFile("C:\\Sample\\DLL\\Win64\\B.dll"); 26 return loadedAssembly; 27 } 28 catch (Exception ex) 29 { 30 Debug.WriteLine($"DLLの読み込みエラー: {ex.Message}"); 31 return null; 32 } 33 } 34 return null; 35 } 36 }
以上となります。
何卒よろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/11/13 12:32 編集
2023/11/13 12:43
2023/11/14 01:11 編集
2023/11/14 08:09