.NET6 の Windows Formsから user32.dllの SetWindowsHookEx を呼び出すが ERROR_MOD_NOT_FOUND(126) エラーになる対処
動画を再生するスクリーンセイバーを作成中。
Windows Forms にElementHost(Windows FormsでWPFオブジェクトをホスティングできる)を置いて、WPFのMediaElementを配置、動画を再生させる。
そこまでは良いのだが、キーボードやマウスイベントを拾って画面を閉じたいのだが、ElementHost上のオブジェクトのイベントを拾うのが非常に難儀(そもそもできるのかもわからない)ので、グローバルフックを使用して、アプリケーション外のマウス、キーボードイベントも拾おうと思う。
いくつかサイトを検索して、以下のサイトがシンプルそうなので参考にさせていただいた。
https://myugaru.hatenadiary.org/entry/20071130/1196434749
これで、VisualStudio2022のデバッグモードでは期待通りの動きをして、よしよしと思ったのだが、発行したexeを叩くと、RROR_MOD_NOT_FOUND(126) エラーになってしまう。
int errorCode = Marshal.GetLastWin32Error();
MessageBox.Show($”{errorCode}”);
上記の部分。
2日くらい、あれやこれや試してダメ。
なんとか、以下のサイトにヒントを見つけた。
https://www.jike.in/qa/?qa=845051/
修正点は、以下ソースの「.NET 4以降ではもう動作しません。表示されるエラーコードは、126 = “指定されたモジュールが見つかりません」
直下でコメントアウトした、Marshal.GetHINSTANCE を LoadLibrary に変更。
これで期待通りに動いた。
using System; using System.Windows.Forms; using System.Runtime.InteropServices; using System.ComponentModel; namespace DsScreenSaver { public partial class ScreenSaverMainForm : Form { private System.Windows.Forms.Integration.ElementHost host; HookHandler keyboardHookDelegate; IntPtr keyboardHook; HookHandler mouseHookDelegate; IntPtr mouseHook; public ScreenSaverMainForm() { WH keyboardHookType = WH.KEYBOARD_LL; keyboardHookDelegate = new HookHandler(OnKeyboardHook); // .NET 4以降ではもう動作しません。表示されるエラーコードは、126 = "指定されたモジュールが見つかりません //IntPtr hKeyboardMod = Marshal.GetHINSTANCE( // System.Reflection.Assembly. // GetExecutingAssembly().GetModules()[0]); var hKeyboardMod = NativeMethods.LoadLibrary("user32.dll"); keyboardHook = SetWindowsHookEx(keyboardHookType, keyboardHookDelegate, hKeyboardMod, 0); if (keyboardHook == IntPtr.Zero) { int errorCode = Marshal.GetLastWin32Error(); MessageBox.Show($"{errorCode}"); throw new Win32Exception(errorCode); } WH mouseHookType = WH.MOUSE_LL; mouseHookDelegate = new HookHandler(OnMouseHook); //IntPtr hMouseMod = Marshal.GetHINSTANCE( // System.Reflection.Assembly. // GetExecutingAssembly().GetModules()[0]); var hMouseMod = NativeMethods.LoadLibrary("user32.dll"); mouseHook = SetWindowsHookEx(mouseHookType, mouseHookDelegate, hMouseMod, 0); if (mouseHook == IntPtr.Zero) { int errorCode = Marshal.GetLastWin32Error(); throw new Win32Exception(errorCode); } InitializeComponent(); } private void ScreenSaverMainForm_Loaded(object sender, EventArgs e) { host = new ElementHost(); //host.SetBounds(20, 10, 600, 300); System.Windows.Controls.MediaElement player = new System.Windows.Controls.MediaElement(); host.Dock = DockStyle.Fill; host.Child = player; this.Controls.Add(host); //自分自身のフォームを最大化 this.FormBorderStyle = FormBorderStyle.None; this.WindowState = FormWindowState.Maximized; this.BackColor = Color.Black; player.Source = new System.Uri(@"C:\Users\piroto\Desktop\movies\practice.mp4"); player.UnloadedBehavior = System.Windows.Controls.MediaState.Manual; player.Play(); } // // DELEGATE for Hook // public delegate int HookHandler( int code, WM message, IntPtr state); // // SetWindowsHookEx // [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SetWindowsHookEx( WH hookType, HookHandler hookDelegate, IntPtr module, uint threadId); // // HookType // public enum WH { KEYBOARD_LL = 13, MOUSE_LL = 14, } // // UnhookWindowsHookEx // [DllImport("user32.dll", SetLastError = true)] public static extern bool UnhookWindowsHookEx(IntPtr hook); // // CallNextHookEx // [DllImport("user32.dll")] public static extern int CallNextHookEx( IntPtr hook, int code, WM message, IntPtr state); // // Win32 Message // public enum WM { KEYDOWN = 0x0100, KEYUP = 0x0101, SYSKEYDOWN = 0x0104, SYSKEYUP = 0x0105, MOUSEMOVE = 0x0200, LBUTTONDOWN = 0x0201, LBUTTONUP = 0x0202, LBUTTONDBLCLK = 0x0203, RBUTTONDOWN = 0x0204, RBUTTONUP = 0x0205, RBUTTONDBLCLK = 0x0206, MBUTTONDOWN = 0x0207, MBUTTONUP = 0x0208, MBUTTONDBLCLK = 0x0209, MOUSEWHEEL = 0x020A, XBUTTONDOWN = 0x020B, XBUTTONUP = 0x020C, XBUTTONDBLCLK = 0x020D, MOUSEHWHEEL = 0x020E, } protected override void OnClosing(CancelEventArgs e) { base.OnClosing(e); if (keyboardHook != IntPtr.Zero) { UnhookWindowsHookEx(keyboardHook); } if (mouseHook != IntPtr.Zero) { UnhookWindowsHookEx(mouseHook); } } int OnKeyboardHook(int code, WM message, IntPtr state) { this.Close(); return CallNextHookEx(keyboardHook, code, message, state); } int OnMouseHook(int code, WM message, IntPtr state) { this.Close(); return CallNextHookEx(mouseHook, code, message, state); } static internal class NativeMethods { [DllImport("kernel32.dll")] public static extern IntPtr LoadLibrary(string dllToLoad); } } }