欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

winform键盘全局与线程Hook

程序员文章站 2022-05-18 14:29:45
定义数据结构 /// /// 声明键盘钩子的封送结构类型 /// [StructLayout(LayoutKind.Sequential)] public class KeyboardHookStruct { public int vkCode;//表示一个 ......

定义数据结构

        /// <summary>
        /// 声明键盘钩子的封送结构类型
        /// </summary>
        [structlayout(layoutkind.sequential)]
        public class keyboardhookstruct
        {
            public int vkcode;//表示一个1到254间的虚拟键盘码
            public int scancode;//表示硬件扫描码
            public int flags;
            public int time;
            public int dwextrainfo;
        }

声明hook相关方法

        //使用windows api函数代替获取当前实例的函数,防止钩子失效
        [dllimport("kernel32.dll")]
        public static extern intptr getmodulehandle(string lpmodulename);
        //安装钩子
        [dllimport("user32.dll", charset = charset.auto, callingconvention = callingconvention.stdcall)]
        public static extern int setwindowshookex(int idhook, hookproc lpfn, intptr hinstance, int threadid);
        //下一个钩子
        [dllimport("user32.dll", charset = charset.auto, callingconvention = callingconvention.stdcall)]
        public static extern int callnexthookex(int idhook, int ncode, int32 wparam, intptr lparam);
        //卸载钩子
        [dllimport("user32.dll", charset = charset.auto, callingconvention = callingconvention.stdcall)]
        public static extern bool unhookwindowshookex(int idhook);
        // 取得当前线程编号(线程钩子需要用到)
        [dllimport("kernel32.dll")]
        static extern int getcurrentthreadid();

hook拦截方法

全局hook

        private int keyboardhookproc(int ncode, int32 wparam, intptr lparam)
        {
            if ((ncode >= 0) && (onkeydownevent != null || onkeyupevent != null || onkeypressevent != null))
            {
                keyboardhookstruct mykbhookstruct = (keyboardhookstruct)marshal.ptrtostructure(lparam, typeof(keyboardhookstruct));
 
                //引发onkeydownevent
                if (onkeydownevent != null && (wparam == wm_keydown || wparam == wm_syskeydown))
                {
                    keys keydata = (keys)mykbhookstruct.vkcode;
                    keyeventargs e = new keyeventargs(keydata);
                    onkeydownevent(this, e);
                }
            }
            return callnexthookex(hkeyboardhook, ncode, wparam, lparam);
        }

线程hook

 private int keyboardhookproc(int ncode, int32 wparam, intptr lparam)
        {
            if ((ncode >= 0) && (onkeydownevent != null || onkeyupevent != null || onkeypressevent != null))
            {
               
                //引发onkeydownevent
                if (onkeydownevent != null && ncode==0)
                {
                    keys keydata = (keys)wparam;
                    keyeventargs e = new keyeventargs(keydata);
                    onkeydownevent(this, e);
                }
            }
            return callnexthookex(hkeyboardhook, ncode, wparam, lparam);
        }

全局/线程hook参数结构区别

线程hook keyboardhookproc函数的各个参数意义如下:

ncode    消息的类型,分hc_action和hc_noremove

wparam    按键的虚拟键码 

lparam    按键的相关参数信息,包括重复时间、按键的状态(按下或弹起)等

全局hook keyboardhookproc函数的各个参数意义如下:

ncode    消息的类型,有hc_action

wparam    按键的状态(按下或弹起)wm_keydown、wm_keyup、wm_syskeydown、wm_syskeyup

lparam    指向keyboardhookstruct结构的指针,该结构包含了按键的详细信息。

添加hook

全局hook

        public void start()
        {
            if (hkeyboardhook == 0)
            {
                keyboardhookprocedure = new hookproc(keyboardhookproc);
                using (system.diagnostics.process curprocess = system.diagnostics.process.getcurrentprocess())
                using (system.diagnostics.processmodule curmodule = curprocess.mainmodule)
                    hkeyboardhook = setwindowshookex(13, keyboardhookprocedure, getmodulehandle(curmodule.modulename), 0);
 
                if (hkeyboardhook == 0)
                {
                    stop();
                    throw new exception("set globalkeyboardhook failed!");
                }
            }
        }

线程hook

   public void start()
        {
            if (hkeyboardhook == 0)
            {
                keyboardhookprocedure = new hookproc(keyboardhookproc);
                hkeyboardhook = setwindowshookex(2, keyboardhookprocedure,  intptr.zero, getcurrentthreadid());
 
                if (hkeyboardhook == 0)
                {
                    stop();
                    throw new exception("set globalkeyboardhook failed!");
                }
            }
        }

注:idhook 钩子类型,即确定钩子监听何种消息
线程钩子监听键盘消息应设为2,全局钩子监听键盘消息应设为13
线程钩子监听鼠标消息应设为7,全局钩子监听鼠标消息应设为14