C#钩子内部消息拦截

来源:互联网 发布:互联网大数据营销 编辑:程序博客网 时间:2024/04/30 06:27

钩子其实就是调用一下API而已:

 

1、安装钩子:

  SetWindowsHookEx

    函数原形:HHOOK SetWindowsHookEx(

                       int       idHook,    // 钩子类型,

                       HOOKPROC  lpfn,      // 钩子函数地址

                       INSTANCE  hMod,      // 钩子所在的实例的句柄,

                       DWORD     dwThreadId // 钩子所监视的线程的线程号

                      )

    hMod: 对于线程序钩子,参数传NULL

    对于系统钩子:参数为钩子DLL的句柄

  dwThreadId:对于全局钩子,该参数为NULL

    钩子类型用WH_CALLWNDPROC=4(发送到窗口的消息。由SendMessage触发)

    返回:成功:返回SetWindowsHookEx返回所安装的钩子句柄;

          失败:NULL

 

2、回调,你要截获消息就在这里进行:

LRESULT WINAPI MyHookProc(

          int     nCode ,     // 指定是否需要处理该消息

          WPARAM  wParam,     // 包含该消息的附加消息

          LPARAM  lParam      // 包含该消息的附加消息

                        )

 

3、调用下一个钩子

LRESULT CallNextHookEx(

          HHOOK   hhk,      // 是您自己的钩子函数的句柄。用该句柄可以遍历钩子链

          int     nCode,    // 把传入的参数简单传给CallNextHookEx即可

          WPARAM  wParam,   // 把传入的参数简单传给CallNextHookEx即可

          LPARAM  lParam    // 把传入的参数简单传给CallNextHookEx即可

                      );

 

4、用完后记得卸载钩子哦,要不然你的系统会变得奇慢无比!

BOOL UnhookWindowsHookEx(

         HHOOK      hhk       // 要卸载的钩子句柄。

                      )

 

把上面这些APIC#封装一下,就可以直接用了!

给个线程钩子的例子吧(两个Form都在同一个线程中运行):

 

using System.Runtime.InteropServices;

 

public class Form1 : System.Windows.Forms.Form

{

    ...

    //定义委托(钩子函数,用于回调)

    public delegate int HookProc(int code, IntPtr wparam, ref CWPSTRUCT cwp);

 

    //安装钩子的函数

    [DllImport("User32.dll",CharSet = CharSet.Auto)]

    public static extern IntPtr SetWindowsHookEx(int type, HookProc hook, IntPtr instance, int threadID);

    //调用下一个钩子的函数

    [DllImport("User32.dll",CharSet = CharSet.Auto)]

    public static extern int CallNextHookEx(IntPtr hookHandle, int code, IntPtr wparam, ref CWPSTRUCT cwp);

    //卸载钩子

    [DllImport("User32.dll",CharSet = CharSet.Auto)]

    public static extern bool UnhookWindowsHookEx(IntPtr hookHandle);

    //获取窗体线程ID

    DllImport("User32.dll",CharSet = CharSet.Auto)]

    public static extern int GetWindowThreadProcessId(IntPtr hwnd, int ID);

 

    private HookProc hookProc;

    private IntPtr hookHandle = IntPtr.Zero;

 

    public Form1()

    {

        ....

        //挂接钩子处理方法

        this.hookProc = new HookProc(myhookproc);

    }

 

    //开始拦截

private bool StartHook()

    {

        Form2 f=new Form2();

        f.Show();//加上这个

        //安装钩子,拦截系统向Form2发出的消息

        this.hookHandle = SetWindowsHookEx(4, hookProc, IntPtr.Zero ,GetWindowThreadProcessId(f.Handle,0));

        return (this.hookHandle != 0);

    }

 

 

    //停止拦截

    private bool StopHook()

    {

        return UnhookWindowsHookEx(this.hookHandle);

    }

 

    //钩子处理函数,在这里拦截消息并做处理

    private int myhookproc(int code, IntPtr wparam, ref CWPSTRUCT cwp)

    {

        switch(code)

        {

    case 0:

    switch(cwp.message)

    {

        case 0x0000F://WM_PAINT,拦截WM_PAINT消息

                //do something

        break;

    }

            break;

        }

        return CallNextHookEx(hookHandle,code,wparam, ref cwp);

    }

   

    [StructLayout(LayoutKind.Sequential)]

    public struct CWPSTRUCT

    {

 public IntPtr lparam;

 public IntPtr wparam;

 public int message;

 public IntPtr hwnd;

    }

}

 

public class Form2 : System.Windows.Forms.Form

{

    ....

}

 

 

钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

 

关于Hook的详细介绍,在微软的MSDN中有,http://www.microsoft.com/china/community/program/originalarticles/techdoc/hook.mspx

下面是我在C#中来应用Hook

 

实现效果:

 

当用户在TextBox中输入 b 的时候,TextBox 始终显示 a

 

实现过程:

 

1、新建一个C#WindowsApplication

 

2、在Form1中,添加下面一些变量:  

 

        internal enum HookType //枚举,钩子的类型

 

        {

 

            //MsgFilter     = -1,

 

            //JournalRecord    = 0,

 

            //JournalPlayback  = 1,

 

            Keyboard         = 2,

 

            //GetMessage       = 3,

 

            //CallWndProc      = 4,

 

            //CBT              = 5,

 

            //SysMsgFilter     = 6,

 

            //Mouse            = 7,

 

            //Hardware         = 8,

 

            //Debug            = 9,

 

            //Shell           = 10,

 

            //ForegroundIdle  = 11,

 

            //CallWndProcRet  = 12,

 

            //KeyboardLL        = 13,

 

            //MouseLL           = 14,

 

        };

 

        IntPtr _nextHookPtr; //记录Hook编号

 

 

3、在Form1中引入必须的API  

 

        [DllImport("kernel32.dll")]

        static extern int GetCurrentThreadId(); //取得当前线程编号的API

 

        [DllImport("User32.dll")]

 

        internal extern static void UnhookWindowsHookEx(IntPtr handle); //取消HookAPI

 

        [DllImport("User32.dll")]

 

        internal extern static IntPtr SetWindowsHookEx(int idHook, [MarshalAs(UnmanagedType.FunctionPtr)] HookProc lpfn, IntPtr         hinstance, int threadID);  //设置HookAPI

 

        [DllImport("User32.dll")]

 

        internal extern static IntPtr CallNextHookEx(IntPtr handle, int code, IntPtr wparam, IntPtr lparam); //取得下一个HookAPI

 

4、声明一个实现的委托

 

        internal delegate IntPtr HookProc(int code, IntPtr wparam, IntPtr lparam);

 

5、添加自己的Hook处理过程 

 

        IntPtr MyHookProc(int code, IntPtr wparam, IntPtr lparam)

 

        {  

 

            if( code < 0 ) return CallNextHookEx(_nextHookPtr,code, wparam, lparam); //返回,让后面的程序处理该消息           

 

             if( wparam.ToInt32() == 98 || wparam.ToInt32() == 66 ) //如果用户输入的是 b

 

            {

 

                this.textBox1.Text = "a";

 

                 return   (IntPtr) 1; //直接返回了,该消息就处理结束了

 

            }

 

            else

 

            {

 

                return IntPtr.Zero; //返回,让后面的程序处理该消息

 

            }

 

        }

 

 6、添加加入Hook链和从Hook链中取消的函数

 

        public void SetHook()

 

        {

 

            if( _nextHookPtr != IntPtr.Zero ) //已经勾过了

 

              return;

 

            HookProc myhookProc = new HookProc(MyHookProc); //声明一个自己的Hook实现函数的委托对象

 

            _nextHookPtr = SetWindowsHookEx((int)HookType.Keyboard, myhookProc , IntPtr.Zero ,  GetCurrentThreadId()); //加到Hook链中

 

        }

 

        public void UnHook()

 

        {

 

            if( _nextHookPtr != IntPtr.Zero )

 

            {

 

                UnhookWindowsHookEx(_nextHookPtr); //Hook链中取消

 

                _nextHookPtr = IntPtr.Zero;

 

            }

 

        }

 

 7、在Form1Load事件中添加 SetHook() Form1closing 事件中添加 UnHook()

 

        private void Form1_Load(object sender, System.EventArgs e)

 

        {

 

            SetHook();

 

        }

 

        private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)

 

        {

 

            UnHook();

 

        }

 

 

 

8、运行

   

    输入 b , 发现 textbox 里面显示的是 a 了!

原创粉丝点击