前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >c#中使用钩子

c#中使用钩子

作者头像
冰封一夏
发布2019-09-10 18:06:14
1.1K0
发布2019-09-10 18:06:14
举报
文章被收录于专栏:c#Winform自定义控件系列

相信以前用过VB、Delphi,特别是VC的程序员应该对钩子程序都不陌生。在C#中我们同样可以使用钩子程序来实现特殊效果,比如当用户按下某个特殊键时提示,比如关闭应用程序前提示等。 当然使用方法相对VC来说要稍微复杂一点,有的地方还不太方便,下面的例子中实现两个基本功能: 1、按下Alt+F4时使窗口最小化 2、关闭应用程序前提示 不过目前只能捕获消息,不能屏蔽消息,我正在实验,也希望知道的高手能多多指教 一、加入winuser.h中的定义 因为钩子程序一般情况下都是在vc下使用的,在c#里面并没有对应的方法、结构等的定义,我们首先需要把winuser.h中的相关定义加入自己的类

代码语言:javascript
复制
钩子类型的枚举

    public enum HookType : int

    {

        WH_JOURNALRECORD = ,

        WH_JOURNALPLAYBACK = ,

        WH_KEYBOARD = ,

        WH_GETMESSAGE = ,

        WH_CALLWNDPROC = ,

        WH_CBT = ,

        WH_SYSMSGFILTER = ,

        WH_MOUSE = ,

        WH_HARDWARE = ,

        WH_DEBUG = ,

        WH_SHELL = ,

        WH_FOREGROUNDIDLE = ,

        WH_CALLWNDPROCRET = ,

        WH_KEYBOARD_LL = ,

        WH_MOUSE_LL = 

    }

具体的说明在msdn中都可以查到,主要的比如WH_KEYBOARD是监控按键事件,WH_CALLWNDPROC是在消息触发时执行

代码语言:javascript
复制
虚键值的定义

    public enum VirtualKeys

    {

        VK_SHIFT = 0x10,

        VK_CONTROL = 0x11,

        VK_MENU = 0x12,    //ALT

        VK_PAUSE = 0x13,

        VK_CAPITAL = 0x14

    }

这个不用说明了,对应ALT、CTRL等键

代码语言:javascript
复制
消息结构体

    public struct CWPSTRUCT

    {

        public IntPtr lparam;

        public IntPtr wparam;

        public int message;

        public IntPtr hwnd;

    }

这个是windows内部传递过来的消息的结构 二、加入自己定义的委托和事件参数

代码语言:javascript
复制
钩子委托

    public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

    public delegate void HookEventHandler(object sender, HookEventArgs e);

HokkProc是SetWindowsHookEx调用时的委托事件,HookEventHandler是自己的委托事件

代码语言:javascript
复制
钩子事件参数

    public class HookEventArgs : EventArgs

    {

        public int HookCode;

        public IntPtr wParam;

        public IntPtr lParam;

        public Keys key;

        public bool bAltKey;

        public bool bCtrlKey;

    }

是自己的委托事件中接受的事件参数 三、实现自己的钩子类 这一步是最重要的,要使用钩子,我们需要引用user32.dll中的相应方法:

代码语言:javascript
复制
[DllImport("user32.dll")]

        static extern IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, uint dwThreadId);



        [DllImport("user32.dll")]

        static extern bool UnhookWindowsHookEx(IntPtr hhk);



        [DllImport("user32.dll")]

        static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);



        [DllImport("user32.dll")]

        static extern short GetKeyState(VirtualKeys nVirtKey);

SetWindowsHookEx是注册一个钩子程序,UnhookWindowsHookEx是释放钩子程序,CallNextHookEx调用钩子的后续事件处理,GetKeyState得到所按的虚键 然后就可以调用这些方法来实现钩子程序,比如注册一个钩子可以调用:

代码语言:javascript
复制
m_hook = SetWindowsHookEx(m_hooktype, m_hookproc, IntPtr.Zero, (uint)AppDomain.GetCurrentThreadId());

其中m_hooktype就是HookType中定义的类型,m_hookproc就是实际的钩子处理程序:

代码语言:javascript
复制
m_hookproc = new HookProc(KeyHookProcedure);

最关键的就是KeyHookProcedure等钩子处理程序:

代码语言:javascript
复制
protected int KeyHookProcedure(int code, IntPtr wParam, IntPtr lParam)

        {

            if (code != )

            {

                return CallNextHookEx(m_hook, code, wParam, lParam);

            }



            if (HookInvoked != null)

            {

                Keys key = (Keys)wParam.ToInt32();

                HookEventArgs eventArgs = new HookEventArgs();

                eventArgs.key = key;

                eventArgs.lParam = lParam;

                eventArgs.wParam = wParam;

                eventArgs.HookCode = code;

                eventArgs.bAltKey = GetKeyState(VirtualKeys.VK_MENU) <= -;

                eventArgs.bCtrlKey = GetKeyState(VirtualKeys.VK_CONTROL) <= -;

                HookInvoked(this, eventArgs);

            }



            return CallNextHookEx(m_hook, code, wParam, lParam);

        }

在这个事件中可以取得消息的参数,特别是按键的值,然后通过HookInvoked委托调用事件实际的处理程序 四、在应用程序中调用钩子类 我们可以在自己的form中声明两个钩子对象

代码语言:javascript
复制
private MyHook callProcHook = new MyHook(HookType.WH_CALLWNDPROC);

        private MyHook keyHook = new MyHook(HookType.WH_KEYBOARD);

然后在初始化时注册钩子:

代码语言:javascript
复制
private void Form1_Load(object sender, EventArgs e)

        {

            keyHook.HookInvoked += new HookEventHandler(keyHook_HookInvoked);

            keyHook.Install();



            callProcHook.HookInvoked += new HookEventHandler(callProcHook_HookInvoked);

            callProcHook.Install();

        }

然后就是实际的钩子事件:

代码语言:javascript
复制
private void keyHook_HookInvoked(object sender, HookEventArgs e)

        {

            if (e.key == Keys.F4 && e.bAltKey) //Alt + F4

            {

                this.WindowState = FormWindowState.Minimized;

            }

        }



        private void callProcHook_HookInvoked(object sender, HookEventArgs e)

        {

            unsafe

            {

                CWPSTRUCT* message = (CWPSTRUCT*)e.lParam;

                if (message != null)

                {

                    if (message->message == WM_CLOSE)

                    {

                        (sender as MyHook).CallNextProc = false;

                        MessageBox.Show("程序即将关闭!");

                    }

                }

            }

        }

这样我们就可以通过钩子实现一些相对底层的应用。 代码说的有点乱,我就把最主要的代码直接列在下面供大家参考:

代码语言:javascript
复制
例子代码

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Runtime.InteropServices;



namespace HookTest

{

    public partial class Form1 : Form

    {

        #region 消息定义(WinUser.h中定义)

        private const int WM_PAINT = 0x000F;

        private const int WM_CLOSE = 0x0010;

        private const int WM_QUIT = 0x0012;

        private const int WM_DESTROY = 0x0002;

        #endregion



        private MyHook callProcHook = new MyHook(HookType.WH_CALLWNDPROC);

        private MyHook keyHook = new MyHook(HookType.WH_KEYBOARD);



        public Form1()

        {

            InitializeComponent();

        }



        private void Form1_Load(object sender, EventArgs e)

        {

            keyHook.HookInvoked += new HookEventHandler(keyHook_HookInvoked);

            keyHook.Install();



            callProcHook.HookInvoked += new HookEventHandler(callProcHook_HookInvoked);

            callProcHook.Install();

        }



        private void keyHook_HookInvoked(object sender, HookEventArgs e)

        {

            if (e.key == Keys.F4 && e.bAltKey) //Alt + F4

            {

                this.WindowState = FormWindowState.Minimized;

            }

        }



        private void callProcHook_HookInvoked(object sender, HookEventArgs e)

        {

            unsafe

            {

                CWPSTRUCT* message = (CWPSTRUCT*)e.lParam;

                if (message != null)

                {

                    if (message->message == WM_CLOSE)

                    {

                        (sender as MyHook).CallNextProc = false;

                        MessageBox.Show("程序即将关闭!");

                    }

                }

            }

        }



    }



    #region 消息结构体(参照WinUser.h中定义)

    public struct CWPSTRUCT

    {

        public IntPtr lparam;

        public IntPtr wparam;

        public int message;

        public IntPtr hwnd;

    }

    #endregion



    #region 钩子类型的枚举

    public enum HookType : int

    {

        WH_JOURNALRECORD = ,

        WH_JOURNALPLAYBACK = ,

        WH_KEYBOARD = ,

        WH_GETMESSAGE = ,

        WH_CALLWNDPROC = ,

        WH_CBT = ,

        WH_SYSMSGFILTER = ,

        WH_MOUSE = ,

        WH_HARDWARE = ,

        WH_DEBUG = ,

        WH_SHELL = ,

        WH_FOREGROUNDIDLE = ,

        WH_CALLWNDPROCRET = ,

        WH_KEYBOARD_LL = ,

        WH_MOUSE_LL = 

    }

    #endregion



    #region 虚键值的定义(参照WinUser.h中定义)

    public enum VirtualKeys

    {

        VK_SHIFT = 0x10,

        VK_CONTROL = 0x11,

        VK_MENU = 0x12,    //ALT

        VK_PAUSE = 0x13,

        VK_CAPITAL = 0x14

    }

    #endregion



    #region 钩子委托

    public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

    public delegate void HookEventHandler(object sender, HookEventArgs e);

    #endregion



    #region 钩子事件参数

    public class HookEventArgs : EventArgs

    {

        public int HookCode;

        public IntPtr wParam;

        public IntPtr lParam;

        public Keys key;

        public bool bAltKey;

        public bool bCtrlKey;

    }

    #endregion



    #region 钩子类

    public class MyHook

    {

        #region 调用Windows API

        [DllImport("user32.dll")]

        static extern IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, uint dwThreadId);



        [DllImport("user32.dll")]

        static extern bool UnhookWindowsHookEx(IntPtr hhk);



        [DllImport("user32.dll")]

        static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);



        [DllImport("user32.dll")]

        static extern short GetKeyState(VirtualKeys nVirtKey);

        #endregion



        #region 局部变量

        private IntPtr m_hook;

        private HookType m_hooktype;

        private HookProc m_hookproc;



        private bool _bCallNext;



        public bool CallNextProc

        {

            get { return _bCallNext; }

            set { _bCallNext = value; }

        }

    

        #endregion



        public event HookEventHandler HookInvoked;



        public void Install()

        {

            m_hook = SetWindowsHookEx(m_hooktype, m_hookproc, IntPtr.Zero, (uint)AppDomain.GetCurrentThreadId());

        }



        public void Uninstall()

        {

            if (m_hook != IntPtr.Zero)

            {

                UnhookWindowsHookEx(m_hook);

            }

        }



        public MyHook(HookType HookType)

        {

            m_hooktype = HookType;

            if (m_hooktype == HookType.WH_KEYBOARD)

            {

                m_hookproc = new HookProc(KeyHookProcedure);

            }

            else if (m_hooktype == HookType.WH_CALLWNDPROC)

            {

                m_hookproc = new HookProc(CallProcHookProcedure);

            }

        }



        protected int KeyHookProcedure(int code, IntPtr wParam, IntPtr lParam)

        {

            if (code != )

            {

                return CallNextHookEx(m_hook, code, wParam, lParam);

            }



            if (HookInvoked != null)

            {

                Keys key = (Keys)wParam.ToInt32();

                HookEventArgs eventArgs = new HookEventArgs();

                eventArgs.key = key;

                eventArgs.lParam = lParam;

                eventArgs.wParam = wParam;

                eventArgs.HookCode = code;

                eventArgs.bAltKey = GetKeyState(VirtualKeys.VK_MENU) <= -;

                eventArgs.bCtrlKey = GetKeyState(VirtualKeys.VK_CONTROL) <= -;

                HookInvoked(this, eventArgs);

            }



            return CallNextHookEx(m_hook, code, wParam, lParam);

        }



        protected int CallProcHookProcedure(int code, IntPtr wParam, IntPtr lParam)

        {

            try

            {

                CallNextProc = true;

                if (HookInvoked != null)

                {

                    HookEventArgs eventArgs = new HookEventArgs();

                    eventArgs.lParam = lParam;

                    eventArgs.wParam = wParam;

                    eventArgs.HookCode = code;

                    HookInvoked(this, eventArgs);

                }



                if (CallNextProc)

                {

                    return CallNextHookEx(m_hook, code, wParam, lParam);

                }

                else

                {

                    //return 1;

                    return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);

                }

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message);

                return ;

            }

        }

    }

    #endregion

}

以上的钩子只对当前应用程序起作用,如果想控制其他的所有程序,需要使用全局钩子。原则上全局钩子在C#中是不支持的,在http://www.codeproject.com/csharp/globalhook.asp 中的代码可以参照来实现全局钩子

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2008-05-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档