.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);
}
}
}

