windows是基于消息处理的。比如用户按下了键盘,该消息首先由操作系统接收,再将其发送到当前的应用程序处理。事实上,在操作系统把消息发送到当前的应用程序前,你可以截取该消息,这就是我们通常所说的钩子程序。
说明:
SetWindowsHookEx()设置钩子函数
UnhookWindowsHookEx()取消钩子函数
CallNextHookEx()把消息传递给下一个钩子,如果是最后一个钩子,则把消息返回给操作系统
截取键盘消息实例:
1 vs新建一个项目WindowsMessageHook,类型为Class Library,把KeyboardHook.cs加入工程,编译后,生成WindowsMessageHook.dll
KeyboardHook.cs代码
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using
System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;
namespace WindowsMessageHook
{
public delegate IntPtr HookProc( int code, IntPtr wparam, IntPtr lparam);
public enum HookType // 枚举,钩子的类型 WindowsMessageHook
{
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
}
[StructLayout(LayoutKind.Sequential)]
public class KeyboardHookStruct
{
public int vkCode; // 表示一个在1到254间的虚似键盘码
public int scanCode; // 表示硬件扫描码
public int flags;
public int time;
public int dwExtraInfo;
}
public class KeyboardHook
{
private const int WM_KEYDOWN = 0x100 ;
private const int WM_KEYUP = 0x101 ;
private IntPtr nextHookPtr; // 记录Hook编号
private HookProc hookProc;
[DllImport( " User32.dll " )]
public static extern void UnhookWindowsHookEx(IntPtr handle);
[DllImport( " User32.dll " )]
public static extern IntPtr SetWindowsHookEx( int idHook, [MarshalAs(UnmanagedType.FunctionPtr)] HookProc lpfn, IntPtr hinstance, int threadID);
[DllImport( " User32.dll " )]
public static extern IntPtr CallNextHookEx(IntPtr handle, int code, IntPtr wparam, IntPtr lparam);
public KeyboardHook()
{
nextHookPtr = IntPtr.Zero;
}
public void SetKeyboardHook()
{
if (nextHookPtr != IntPtr.Zero)
return ;
hookProc = new HookProc(KeyboardhookProc); // 键盘事件消息处理函数
nextHookPtr = SetWindowsHookEx(( int )HookType.KeyboardLL,
hookProc,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[ 0 ]),
0 );
}
public void UnKeyboardHook()
{
if (nextHookPtr != IntPtr.Zero)
{
UnhookWindowsHookEx(nextHookPtr); // 从Hook链中取消
nextHookPtr = IntPtr.Zero;
}
}
private IntPtr KeyboardhookProc( int code, IntPtr wparam, IntPtr lparam)
{
if (code >= 0 )
{
KeyboardHookStruct myKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lparam, typeof (KeyboardHookStruct));
switch (wparam.ToInt32())
{
case WM_KEYDOWN:
Console.Write( string .Format( " WM_KEYDOWN:{0} " , Convert.ToChar(myKeyboardHookStruct.vkCode)));
break ;
case WM_KEYUP:
Console.Write( string .Format( " WM_KEYUP:{0:0} " , Convert.ToChar(myKeyboardHookStruct.vkCode)));
break ;
default :
break ;
}
}
return CallNextHookEx(nextHookPtr, code, wparam, lparam); // 返回,让后面的程序处理该消息
}
}
}
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;
namespace WindowsMessageHook
{
public delegate IntPtr HookProc( int code, IntPtr wparam, IntPtr lparam);
public enum HookType // 枚举,钩子的类型 WindowsMessageHook
{
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
}
[StructLayout(LayoutKind.Sequential)]
public class KeyboardHookStruct
{
public int vkCode; // 表示一个在1到254间的虚似键盘码
public int scanCode; // 表示硬件扫描码
public int flags;
public int time;
public int dwExtraInfo;
}
public class KeyboardHook
{
private const int WM_KEYDOWN = 0x100 ;
private const int WM_KEYUP = 0x101 ;
private IntPtr nextHookPtr; // 记录Hook编号
private HookProc hookProc;
[DllImport( " User32.dll " )]
public static extern void UnhookWindowsHookEx(IntPtr handle);
[DllImport( " User32.dll " )]
public static extern IntPtr SetWindowsHookEx( int idHook, [MarshalAs(UnmanagedType.FunctionPtr)] HookProc lpfn, IntPtr hinstance, int threadID);
[DllImport( " User32.dll " )]
public static extern IntPtr CallNextHookEx(IntPtr handle, int code, IntPtr wparam, IntPtr lparam);
public KeyboardHook()
{
nextHookPtr = IntPtr.Zero;
}
public void SetKeyboardHook()
{
if (nextHookPtr != IntPtr.Zero)
return ;
hookProc = new HookProc(KeyboardhookProc); // 键盘事件消息处理函数
nextHookPtr = SetWindowsHookEx(( int )HookType.KeyboardLL,
hookProc,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[ 0 ]),
0 );
}
public void UnKeyboardHook()
{
if (nextHookPtr != IntPtr.Zero)
{
UnhookWindowsHookEx(nextHookPtr); // 从Hook链中取消
nextHookPtr = IntPtr.Zero;
}
}
private IntPtr KeyboardhookProc( int code, IntPtr wparam, IntPtr lparam)
{
if (code >= 0 )
{
KeyboardHookStruct myKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lparam, typeof (KeyboardHookStruct));
switch (wparam.ToInt32())
{
case WM_KEYDOWN:
Console.Write( string .Format( " WM_KEYDOWN:{0} " , Convert.ToChar(myKeyboardHookStruct.vkCode)));
break ;
case WM_KEYUP:
Console.Write( string .Format( " WM_KEYUP:{0:0} " , Convert.ToChar(myKeyboardHookStruct.vkCode)));
break ;
default :
break ;
}
}
return CallNextHookEx(nextHookPtr, code, wparam, lparam); // 返回,让后面的程序处理该消息
}
}
}
2 创建一个winform程序,测试上面的dll。
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
//
声明
private KeyboardHook keyhook = new KeyboardHook();
private void Form1_Load( object sender, EventArgs e)
{
// 设置hook
keyhook.SetKeyboardHook();
}
private void Form1_FormClosed( object sender, FormClosedEventArgs e)
{
// 关闭hook
keyhook.UnKeyboardHook();
}
private KeyboardHook keyhook = new KeyboardHook();
private void Form1_Load( object sender, EventArgs e)
{
// 设置hook
keyhook.SetKeyboardHook();
}
private void Form1_FormClosed( object sender, FormClosedEventArgs e)
{
// 关闭hook
keyhook.UnKeyboardHook();
}
编译运行,在vs的output窗口中可以看到hook程序截获的键盘消息。