1.9K Views
December 17, 23
スライド概要
.NETラボ 2023/12 勉強会資料
今更聞けないNative DLLを 環境に合わせて 動的にロードするには? とっちゃん(高萩 俊行) Microsoft MVP for Developer Technologies Since 2005/10https://github.com/Tocchann/AssemblyResolveSamples .NETラボ 勉強会 2022年12月
はじめに 前回セッションでは AssembyResolve イベントを利用して プラットフォーム依存アセンブリ(Managed DLL)を動 作環境に応じて動的に選択してロードする段取りを 紹介しました。 今回は AssemblyResolve イベントでは 対応できない Native DLL を対象に 動作環境に応じて動的にロードする段取りを 紹介したいと思います。 .NETラボ 勉強会 2022年12月
アジェンダ • • • • • • • プロジェクト構成 Native DLL の特性 別名DLL同名エクスポート関数を呼び出す簡単な方法 同名DLL同名エクスポート関数を呼び出す場合 動的ロードの方法 デモ まとめ .NETラボ 勉強会 2022年12月
プロジェクト構成 前回の構成 Project Name Language Type Target Framework Platform ConsoleAppCore C# exe .NET 6.0 Any CPU CppCliDllCore C++/CLI dll .NET 6.0 x86, x64, ARM32, ARM64 CsDllCore C# dll .NET 6.0 x86, x64, ARM32, ARM64 ConsoleAppNetfx C# exe .NET Framework 4.8.1 Any CPU CppCliDll C++/CLI dll .NET Framework 4.8.1 x86, x64, ARM64 CsDll C# dll .NET Framework 4.8.1 x86, x64, ARM64 AssemblyResolveLoader C# dll .NET Standard 2.0 Any CPU .NETラボ 勉強会 2022年12月
プロジェクト構成 今回追加分 Project Name Language Type Target Framework Platform ConsoleAppCore C# exe .NET 6.0 Any CPU CppCliDllCore C++/CLI dll .NET 6.0 x86, x64, ARM32, ARM64 CsDllCore C# dll .NET 6.0 x86, x64, ARM32, ARM64 CppNativeDLL C++ dll Native DLL x86, x64 CppDll(別名出力) C++ dll Native DLL x86, x64 ConsoleAppNetfx C# exe .NET Framework 4.8.1 Any CPU CppCliDll C++/CLI dll .NET Framework 4.8.1 x86, x64, ARM64 CsDll C# dll .NET Framework 4.8.1 x86, x64, ARM64 CppNativeDLL C++ dll Native DLL x86, x64 CppDll(別名出力) C++ dll Native DLL x86, x64 AssemblyResolveLoader C# dll .NET Standard 2.0 Any CPU .NETラボ 勉強会 2022年12月
プロジェクト構成 今回の構成 Project Name Language Type Target Framework Platform ConsoleAppCore C# exe .NET 6.0 Any CPU CppCliDllCore C++/CLI dll .NET 6.0 x86, x64, ARM32, ARM64 CsDllCore C# dll .NET 6.0 x86, x64, ARM32, ARM64 CppNativeDLL C++ dll Native DLL x86, x64 CppDll(別名出力) C++ dll Native DLL x86, x64 ConsoleAppNetfx C# exe .NET Framework 4.8.1 Any CPU CppCliDll C++/CLI dll .NET Framework 4.8.1 x86, x64, ARM64 CsDll C# dll .NET Framework 4.8.1 x86, x64, ARM64 CppNativeDLL C++ dll Native DLL x86, x64 CppDll(別名出力) C++ dll Native DLL x86, x64 AssemblyResolveLoader C# dll .NET Standard 2.0 Any CPU .NETラボ 勉強会 2022年12月
Native DLL の特性 • ロードされたDLLの管理は名前で行われる • ロード済みのDLLをロードした場合、カウンタをアップす る • LoadLibrary のロードパスは決まっている – SetDllDirectory で変更が可能 • P/Invokeで使える名前は一つだけ – 別DLLでも同名メソッドは定義できない(別名定義が必要) .NETラボ 勉強会 2022年12月
別名DLL同名エクスポート関数を呼び出す簡単な方法
• P/Invoke で別名定義
• ラッパーメソッドを用意して条件分岐する
EXTERN_C int APIENTRY GetMaxValue( int left, int right )
public static int GetMaxValue( int left, int right )
{
switch( RuntimeInformation.ProcessArchitecture )
{
case Architecture.X86: return GetMaxValue32( left, right );
case Architecture.X64: return GetMaxValue64( left, right );
default: throw new PlatformNotSupportedException();
}
}
[DllImport( "CppDll32.dll", CallingConvention=CallingConvention.Winapi, EntryPoint="GetMaxValue" )]
private extern static int GetMaxValue32( int left, int right );
[DllImport( "CppDll64.dll", CallingConvention=CallingConvention.Winapi, EntryPoint="GetMaxValue" )]
private extern static int GetMaxValue64( int left, int right );
.NETラボ 勉強会 2022年12月
同名DLL同名エクスポート関数を呼び出す場合 • P/Invoke による分岐定義はできない – P/Invoke 上の記述は同じになるため • exeと同じフォルダには同名DLLは一つしか置けない • 何らかの実行時処理が必要 .NETラボ 勉強会 2022年12月
動的ロードの方法 • SetDllDirectory を使ってロードパスを設定する – スタティックコンストラクタなどでセットアップ • LoadLibary を使って事前にロードする – DLLの特性を利用した方法 • Marshal.GetDelegateForFunctionPointer する – P/Invoke の内部実装に相当する処理 – GetProcAddress で EndPoint を自力解決 • NativeLibrary.SetDllImportResolver を利用 – .NET Core(3.0以上) のみ。 .NET Framework にはない .NETラボ 勉強会 2022年12月
デモ 実際にいろんなパターンでの Native DLL の関数コールを行ってみましょう .NETラボ 勉強会 2022年12月
まとめ • 動的処理だからとCOMにする必要はない • 適材適所はNativeDLLのロードにも当てはまる • .NET Core の場合は NativeLibrary を使おう! – Windows 以外でも利用可能 • もちろんパス名設定などは異なる! .NETラボ 勉強会 2022年12月