在C#中使用钩子实现Alt+F4健窗口最小化功能


[ 来源:http://www.it55.com | 作者: | 时间:2008-01-11 | 收藏 | 推荐 ] 【大 中 小】


    
  相信以前用过VB、Delphi,特别是VC的程序员应该对钩子程序都不陌生。在C#中我们同样可以使用钩子程序来实现特殊效果,比如当用户按下某个特殊键时提示,比如关闭应用程序前提示等。
  当然使用方法相对VC来说要稍微复杂一点,有的地方还不太方便,下面的例子中实现两个基本功能:
  1、按下Alt+F4时使窗口最小化
  2、关闭应用程序前提示
  
  一、加入winuser.h中的定义
  因为钩子程序一般情况下都是在vc下使用的,在c#里面并没有对应的方法、结构等的定义,我们首先需要把winuser.h中的相关定义加入自己的类
  
  
  钩子类型的枚举
   public enum HookType : int
   {
   WH_JOURNALRECORD = 0,
   WH_JOURNALPLAYBACK = 1,
   WH_KEYBOARD = 2,
   WH_GETMESSAGE = 3,
   WH_CALLWNDPROC = 4,
   WH_CBT = 5,
   WH_SYSMSGFILTER = 6,
   WH_MOUSE = 7,
   WH_HARDWARE = 8,
   WH_DEBUG = 9,
   WH_SHELL = 10,
   WH_FOREGROUNDIDLE = 11,
   WH_CALLWNDPROCRET = 12,
   WH_KEYBOARD_LL = 13,
   WH_MOUSE_LL = 14
   }具体的说明在msdn中都可以查到,主要的比如WH_KEYBOARD是监控按键事件,WH_CALLWNDPROC是在消息触发时执行
  
  虚键值的定义
   public enum VirtualKeys
   {
   VK_SHIFT = 0x10,
   VK_CONTROL = 0x11,
   VK_MENU = 0x12, //ALT
   VK_PAUSE = 0x13,
   VK_CAPITAL = 0x14
   }这个不用说明了,对应ALT、CTRL等键
  
  消息结构体
   public struct CWPSTRUCT
   {
   public IntPtr lparam;
   public IntPtr wparam;
   public int message;
   public IntPtr hwnd;
   }这个是windows内部传递过来的消息的结构
  
  二、加入自己定义的委托和事件参数
  钩子委托
   public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
   public delegate void HookEventHandler(object sender, HookEventArgs e);
  HokkProc是SetWindowsHookEx调用时的委托事件,HookEventHandler是自己的委托事件
  钩子事件参数
   public class HookEventArgs : EventArgs
   {
   public int HookCode;
   public IntPtr wParam;
   public IntPtr lParam;
   public Keys key;
   public bool bAltKey;
   public bool bCtrlKey;
   }是自己的委托事件中接受的事件参数
  
  三、实现自己的钩子类
  这一步是最重要的,要使用钩子,我们需要引用user32.dll中的相应方法:
   [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得到所按的虚键
  
  然后就可以调用这些方法来实现钩子程序,比如注册一个钩子可以调用:
   m_hook = SetWindowsHookEx(m_hooktype, m_hookproc, IntPtr.Zero, (uint)AppDomain.GetCurrentThreadId());
  其中m_hooktype就是HookType中定义的类型,m_hookproc就是实际的钩子处理程序:
  m_hookproc = new HookProc(KeyHookProcedure);
  最关键的就是KeyHookProcedure等钩子处理程序:
   protected int KeyHookProcedure(int code, IntPtr wParam, IntPtr lParam)
   {
   if (code != 0)
   {
   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) <= -127;
   eventArgs.bCtrlKey = GetKeyState(VirtualKeys.VK_CONTROL) <= -127;
   HookInvoked(this, eventArgs);
}
  
   return CallNextHookEx(m_hook, code, wParam, lParam);
   }在这个事件中可以取得消息的参数,特别是按键的值,然后通过HookInvoked委托调用事件实际的处理程序
  
  四、在应用程序中调用钩子类
  我们可以在自己的form中声明两个钩子对象
   private MyHook callProcHook = new MyHook(HookType.WH_CALLWNDPROC);
   private MyHook keyHook = new MyHook(HookType.WH_KEYBOARD);
  然后在初始化时注册钩子:
   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("程序即将关闭!");
   }
   }
   }
   }
  这样我们就可以通过钩子实现一些相对底层的应用。
  
  代码说的有点乱,我就把最主要的代码直接列在下面供大家参考:
  
  例子代码
   1using System;
   2using System.Collections.Generic;
   3using System.ComponentModel;
   4using System.Data;
   5using System.Drawing;
   6using System.Text;
   7using System.Windows.Forms;
   8using System.Runtime.InteropServices;
   9
   10namespace HookTest
   11{
   12 public partial class Form1 : Form
   13 {
   14 消息定义(WinUser.h中定义)#region 消息定义(WinUser.h中定义)
   15 private const int WM_PAINT = 0x000F;
   16 private const int WM_CLOSE = 0x0010;
   17 private const int WM_QUIT = 0x0012;
   18 private const int WM_DESTROY = 0x0002;
   19 #endregion
   20
   21 private MyHook callProcHook = new MyHook(HookType.WH_CALLWNDPROC);
   22 private MyHook keyHook = new MyHook(HookType.WH_KEYBOARD);
   23
   24 public Form1()
   25 {
   26 InitializeComponent();
   27 }
   28
   29 private void Form1_Load(object sender, EventArgs e)
   30 {
   31 keyHook.HookInvoked += new HookEventHandler(keyHook_HookInvoked);
   32 keyHook.Install();
   33
   34 callProcHook.HookInvoked += new HookEventHandler(callProcHook_HookInvoked);
   35 callProcHook.Install();
   36 }
   37
   38 private void keyHook_HookInvoked(object sender, HookEventArgs e)
   39 {
   40 if (e.key == Keys.F4 && e.bAltKey) //Alt + F4
   41 {
   42 this.WindowState = FormWindowState.Minimized;
   43 }
   44 }
   45
   46 private void callProcHook_HookInvoked(object sender, HookEventArgs e)
   47 {
   48 unsafe
   49 {
   50 CWPSTRUCT* message = (CWPSTRUCT*)e.lParam;
   51 if (message != null)
   52 {
   53 if (message->message == WM_CLOSE)
   54 {
   55 (sender as MyHook).CallNextProc = false;
   56 MessageBox.Show("程序即将关闭!");
   57 }
   58 }
   59 }
   60 }
   61
   62 }
   63
   64 消息结构体(参照WinUser.h中定义)#region 消息结构体(参照WinUser.h中定义)
   65 public struct CWPSTRUCT
   66 {
   67 public IntPtr lparam;
   68 public IntPtr wparam;
   69 public int message;
   70 public IntPtr hwnd;
   71 }
   72 #endregion
   73
   74 钩子类型的枚举#region 钩子类型的枚举
   75 public enum HookType : int
   76 {
   77 WH_JOURNALRECORD = 0,
   78 WH_JOURNALPLAYBACK = 1,
   79 WH_KEYBOARD = 2,
   80 WH_GETMESSAGE = 3,
   81 WH_CALLWNDPROC = 4,
   82 WH_CBT = 5,
   83 WH_SYSMSGFILTER = 6,
   84 WH_MOUSE = 7,
   85 WH_HARDWARE = 8,
   86 WH_DEBUG = 9,
   87 WH_SHELL = 10,
   88 WH_FOREGROUNDIDLE = 11,
   89 WH_CALLWNDPROCRET = 12,
   90 WH_KEYBOARD_LL = 13,
   91 WH_MOUSE_LL = 14
   92 }
   93 #endregion
   94
   95 虚键值的定义(参照WinUser.h中定义)#region 虚键值的定义(参照WinUser.h中定义)
   96 public enum VirtualKeys
   97 {
   98 VK_SHIFT = 0x10,
   99 VK_CONTROL = 0x11,
  100 VK_MENU = 0x12, //ALT
  101 VK_PAUSE = 0x13,
  102 VK_CAPITAL = 0x14
  103 }
  104 #endregion
  105
  106 钩子委托#region 钩子委托
  107 public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
  108 public delegate void HookEventHandler(object sender, HookEventArgs e);
  109 #endregion
  110
  111 钩子事件参数#region 钩子事件参数
  112 public class HookEventArgs : EventArgs
  113 {
  114 public int HookCode;
  115 public IntPtr wParam;
  116 public IntPtr lParam;
  117 public Keys key;
  118 public bool bAltKey;
  119 public bool bCtrlKey;
  120 }
  121 #endregion
  122
  123 钩子类#region 钩子类
  124 public class MyHook
  125 {
  126 调用Windows API#region 调用Windows API
  127 [DllImport("user32.dll")]
  128 static extern IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, uint dwThreadId);
  129
  130 [DllImport("user32.dll")]
  131 static extern bool UnhookWindowsHookEx(IntPtr hhk);
  132
  133 [DllImport("user32.dll")]
  134 static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
  135
  136 [DllImport("user32.dll")]
  137 static extern short GetKeyState(VirtualKeys nVirtKey);
  138 #endregion
  139
  140 局部变量#region 局部变量
  141 private IntPtr m_hook;
  142 private HookType m_hooktype;
  143 private HookProc m_hookproc;
  144
  145 private bool _bCallNext;
  146
  147 public bool CallNextProc
  148 {
  149 get { return _bCallNext; }
  150 set { _bCallNext = value; }
  151 }
  152
  153 #endregion
  154
  155 public event HookEventHandler HookInvoked;
  156
  157 public void Install()
  158 {
  159 m_hook = SetWindowsHookEx(m_hooktype, m_hookproc, IntPtr.Zero, (uint)AppDomain.GetCurrentThreadId());
  160 }
  161
  162 public void Uninstall()
  163 {
  164 if (m_hook != IntPtr.Zero)
  165 {
  166 UnhookWindowsHookEx(m_hook);
  167 }
  168 }
  169
  170 public MyHook(HookType HookType)
  171 {
  172 m_hooktype = HookType;
  173 if (m_hooktype == HookType.WH_KEYBOARD)
  174 {
  175 m_hookproc = new HookProc(KeyHookProcedure);
  176 }
  177 else if (m_hooktype == HookType.WH_CALLWNDPROC)
  178 {
  179 m_hookproc = new HookProc(CallProcHookProcedure);
  180 }
  181 }
  182
  183 protected int KeyHookProcedure(int code, IntPtr wParam, IntPtr lParam)
  184 {
  185 if (code != 0)
  186 {
  187 return CallNextHookEx(m_hook, code, wParam, lParam);
  188 }
  189
  190 if (HookInvoked != null)
  191 {
  192 Keys key = (Keys)wParam.ToInt32();
193 HookEventArgs eventArgs = new HookEventArgs();
  194 eventArgs.key = key;
  195 eventArgs.lParam = lParam;
  196 eventArgs.wParam = wParam;
  197 eventArgs.HookCode = code;
  198 eventArgs.bAltKey = GetKeyState(VirtualKeys.VK_MENU) <= -127;
  199 eventArgs.bCtrlKey = GetKeyState(VirtualKeys.VK_CONTROL) <= -127;
  200 HookInvoked(this, eventArgs);
  201 }
  202
  203 return CallNextHookEx(m_hook, code, wParam, lParam);
  204 }
  205
  206 protected int CallProcHookProcedure(int code, IntPtr wParam, IntPtr lParam)
  207 {
  208 try
  209 {
  210 CallNextProc = true;
  211 if (HookInvoked != null)
  212 {
  213 HookEventArgs eventArgs = new HookEventArgs();
  214 eventArgs.lParam = lParam;
  215 eventArgs.wParam = wParam;
  216 eventArgs.HookCode = code;
  217 HookInvoked(this, eventArgs);
  218 }
  219
  220 if (CallNextProc)
  221 {
  222 return CallNextHookEx(m_hook, code, wParam, lParam);
  223 }
  224 else
  225 {
  226 //return 1;
  227 return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
  228 }
  229 }
  230 catch (Exception ex)
  231 {
  232 MessageBox.Show(ex.Message);
  233 return 0;
  234 }
  235 }
  236 }
  237 #endregion
  238}
  
  以上的钩子只对当前应用程序起作用,如果想控制其他的所有程序,需要使用全局钩子。原则上全局钩子在C#中是不支持的,在http://www.codeproject.com/csharp/globalhook.asp 中的代码可以参照来实现全局钩子

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值