Hook钩子程序
好久没写了,经历了考试周,现在又解放了。这2天有事,还是没有写,今晚简单整理下,写了个钩子程序玩玩~
记得最早是人人某主页君写的一个钩子程序,作为愚人节礼物发到主页上的。当时觉得好神奇啊~最近在看1200例的书,第二卷一开始就说到了钩子程序,所以迫不及待的敲一遍,改一下,完成了基本功能~屏蔽所有的鼠标左键~哈哈~捉弄人的这是。。。。。。
******************************************分割线***************************************
在钩子程序中,需要用到几个windows api函数。
// 声明钩子函数
[DllImport( " user32.dll " , CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true )]
public static extern int SetWindowsHookEx(Int32 HookType, HOOKPROCEDURE methodAddress, IntPtr handler, Int32 dwThreadId);
// 释放钩子函数
[DllImport( " user32.dll " , CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true )]
public static extern bool UnhookWindowsHookEx(IntPtr idHook);
对于第一个函数,四个参数,分别指,钩子类型,消息处理函数地址,句柄(这个不太理解),线程ID
对于第二个函数,只需要指出钩子的句柄就可以了。
******************************************分割线***************************************
首先,建立一个基本的MouseHook类
class MouseHook
{
public bool StartHook()
{
IntPtr InstallHook = IntPtr.Zero;
if ( this .mouseHandler == IntPtr.Zero)
{
this .m_MouseHookProcedure = new HOOKPROCEDURE(MouseHookProcedure);
// 安装钩子函数
this .mouseHandler = (IntPtr)SetWindowsHookEx(WH_MOUSE_LL, this .m_MouseHookProcedure, InstallHook, 0 );
if ( this .mouseHandler == IntPtr.Zero)
{
this .UnInstallHook();
return false ;
}
}
return true ;
}
public bool UnInstallHook()
{
bool Result = true ;
if ( this .mouseHandler != IntPtr.Zero)
{
Result = (UnhookWindowsHookEx( this .mouseHandler) && Result);
this .mouseHandler = IntPtr.Zero;
}
return Result;
}
public IntPtr mouseHandler = IntPtr.Zero;
public event MouseEventHandler MouseDown;
public static int flag = 0 ;
// 声明钩子函数
[DllImport( " user32.dll " , CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true )]
public static extern int SetWindowsHookEx(Int32 HookType, HOOKPROCEDURE methodAddress, IntPtr handler, Int32 dwThreadId);
// 释放钩子函数
[DllImport( " user32.dll " , CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true )]
public static extern bool UnhookWindowsHookEx(IntPtr idHook);
// 声明钩子函数地址
public delegate int HOOKPROCEDURE( int nCode, Int32 wParam, IntPtr IParam);
private HOOKPROCEDURE m_MouseHookProcedure;
// 定义使用户可以控制类或结构的数据字段的物理布局
[StructLayout(LayoutKind.Sequential)]
protected class MouseHookStruct
{
public POINT pt;
public int mouseData;
public int flags;
public int time;
public int dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
protected class POINT
{
public int x;
public int y;
}
// 自定义的消息处理函数
private int MouseHookProcedure( int nCode, Int32 wParam, IntPtr IParam)
{
if (nCode >= 0 && MouseDown != null ) // 判断是否处理该消息以及是否有鼠标按键被按下
{
// 定义一个结构体实例
MouseHookStruct mouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(IParam, typeof (MouseHookStruct));
MouseButtons button = GetButton(wParam); // 获鼠标的按键类型
short mouseDelta = 0 ; // 定义一个表示滑轮转动次数的变量
switch (wParam)
{
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_LBUTTONUP:
button = MouseButtons.Left;
flag = 1 ;
break ;
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
case WM_RBUTTONUP:
button = MouseButtons.Right;flag= 0 ;
break ;
case WM_MOUSEWHEEL: flag = 0 ;
mouseDelta = ( short )((mouseHookStruct.mouseData >> 16 ) & 0xffff );
break ;
case WM_MOUSEMOVE: flag = 0 ; break ;
}
int clickCount = 0 ;
// 判断传递消息 表示的鼠标单击次数
if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK)
clickCount = 2 ;
else
clickCount = 1 ;
if (flag != 1 )
{
// 定义一个为鼠标事件提供数据的实例
System.Windows.Forms.MouseEventArgs e = new System.Windows.Forms.MouseEventArgs(button, clickCount, mouseHookStruct.pt.x, mouseHookStruct.pt.y, mouseDelta);
MouseDown( this , e);
}
}
return flag;
}
private MouseButtons GetButton(Int32 wParam)
{
switch (wParam)
{
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_LBUTTONUP:
return MouseButtons.Left;
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
case WM_RBUTTONUP:
return MouseButtons.Right;
case WM_MBUTTONDBLCLK:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
return MouseButtons.Middle;
default :
return MouseButtons.None;
}
}
public const int WH_MOUSE_LL = 14 ;
public const int WM_MOUSEMOVE = 0x200 ;
public const int WM_LBUTTONDOWN = 0x201 ;
public const int WM_RBUTTONDOWN = 0x204 ;
public const int WM_MBUTTONDOWN = 0x207 ;
public const int WM_LBUTTONUP = 0x202 ;
public const int WM_RBUTTONUP = 0x205 ;
public const int WM_MBUTTONUP = 0x208 ;
public const int WM_LBUTTONDBLCLK = 0x203 ;
public const int WM_RBUTTONDBLCLK = 0x206 ;
public const int WM_MBUTTONDBLCLK = 0x209 ;
public const int WM_MOUSEWHEEL = 0x020A ;
}
在整个类中,主要通过 StartHook 和 UnInstallHook 来控制钩子的开启和关闭。
在挂载钩子的时候,函数调用四个参数分别为: ( IntPtr )SetWindowsHookEx(WH_MOUSE_LL, this.m_MouseHookProcedure, InstallHook, 0);
WH_MOUSE_LL是一个const常量,指示钩子的类型,这里表示, 此挂钩只能在Windows NT中被安装,用来对底层的鼠标输入事件进行监视。
当然还有其余的值,不同的值代表不同的效果。
第二个参数表示处理函数,第三个,这里给的值为0,同样,第四个线程ID也为0。线程ID填0表示,监测所有的消息,也就导致,就算我不是在当前winform下操作,也会被监测到~(其实这就是我想要的效果~尤记当年某主页君发的钩子程序)
在这个地方,有一个疑问吧,第三个参数,不知道该如何写。按照书上的写法,总是无法安装钩子,但是将其值改为Zero后就可以了。。。。
*****************************分割线*************************
写完了hook类,接下来添加winform的代码:
MouseHook mouseHook = new MouseHook();
[DllImport( " user32.dll " , SetLastError = true )]
public static extern bool RegisterHotKey(IntPtr Hwnd, int Id, KeyModifiers keyModifiers, Keys key);
[DllImport( " user32.dll " , SetLastError = true )]
public static extern bool UnregisterHotKey(IntPtr Hwnd, int Id);
[Flags()]
public enum KeyModifiers
{
None = 0 ,
Alt = 1 ,
Control = 2 ,
}
void Mouse_Down( object sender, MouseEventArgs e)
{ AddMouseValueEvent(e.Button.ToString()); }
public void AddMouseValueEvent( string MouseValue)
{ }
private void button1_Click( object sender, EventArgs e)
{
label1.Text = " F10解除钩子~ " ;
mouseHook.StartHook();
mouseHook.MouseDown += new MouseEventHandler(Mouse_Down);
}
private void Form1_Load( object sender, EventArgs e)
{
Clipboard.Clear();
RegisterHotKey(Handle, 100 , 0 , Keys.F10);
}
private void Form1_FormClosing( object sender, FormClosingEventArgs e)
{
UnregisterHotKey(Handle, 100 );
}
protected override void WndProc( ref Message m)
{
const int WM_Key = 0x312 ;
switch (m.Msg)
{
case WM_Key:
mouseHook.UnInstallHook();
label1.Text = " 好玩不~? " ;
break ;
}
base .WndProc( ref m);
}
这里的Mouse_Down和AddMouseValueEvent仅仅做消息传递的功能。
而,由于点击开始后,鼠标左键被我屏蔽了(mouseHook类中的消息处理,如果是鼠标左边,不进行MouseDown的消息传递)。所以,再添加一个系统热键F10进行解除屏蔽。这里使用了WndProc的重载,来过滤消息。
*******************************分割线************************
这样的钩子程序,不好给图演示效果。说一下这些代码的效果吧。当单机button之后,鼠标左键就再也没用了。就如同坏掉了一样。。。。右键和滑轮还是好的,可以使用。就算右键激活了其余的窗体,而不在HookLTest窗体下,鼠标左键一样没有效果~最后,只能按F10解除。
但是,发觉这个代码还是可能存在问题。我经常性的运行后,资源管理器都有问题,最后都得重启资源管理器。不知道这个是由什么导致的。望知道的可以指点下。。。。
然后,对于那个WH_MOUSE_LL。其实,还有别的值,不同的值对应不同的效果,看个人的需要吧。
嘿嘿,Hook是捉弄人的好神器啊~
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did47044