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

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

前の記事

XCode実機デバッグ証明書エラー