Net实现钩⼦函数(Hook)以及通过SendMessage实现⾃动点击
按钮和给⽂本框赋值
1.实现钩⼦函数
钩⼦(Hook)的实现需要三个主要的函数和⼀个委托
[DllImport(\"user32.dll\
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);//设置系统钩⼦[DllImport(\"user32.dll\private static extern bool UnhookWindowsHookEx(int idHook);//卸载系统钩⼦
[DllImport(\"user32.dll\
public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);//调⽤下⼀个钩⼦函数public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);//⽤于处理Hook住的消息
当我们在执⾏⼀个操作的时候,⾸先不是由我们的窗体获得消息,⽽是系统获得,然后系统再把消息发送到对应的窗体,Hook就是在窗体获取到信息之前抓住信息,然后对信息进⾏处理,然后可以传递给船体继续执⾏,或者就不传递给窗体
当在HookProc处理消息的时候,如果return 1,那么消息就会被截断,不会再传递到⽬标窗⼝,如果return的是CallNextHookEx那么就会继续调⽤下⼀个钩⼦,如果下⾯没有钩⼦了,那么消息就会被传递到⽬标窗体进⾏处理SetWindowsHookEx第⼀个参数是需要勾住的消息类型,总共14种消息类型,如下public const int WH_JOURNALRECORD = 0;
public const int constWH_JOURNALPLAYBACK = 1;public const int WH_KEYBOARD = 2;public const int WH_GETMESSAGE = 3;public const int WH_CALLWNDPROC = 4;public const int WH_CBT = 5;
public const int WH_SYSMSGFILTER = 6;public const int WH_MOUSE = 7;
public const int WH_HARDWARE = 8;public const int WH_DEBUG = 9;public const int WH_SHELL = 10;
public const int WH_FOREGROUNDIDLE = 11;public const int WH_CALLWNDPROCRET = 12;public const int WH_KEYBOARD_LL = 13;public const int WH_MOUSE_LL = 14;
第⼆个参数就是HookProc委托,⽤于对钩住的消息进⾏处理,
第三个参数是需要钩住的实例的句柄,最后⼀个是钩住的线程,如果是0则是全局钩住返回值为抓住的钩⼦的ID
UnhookWindowsHookEx卸载掉钩⼦,参数为上⾯返回的ID 辅助函数
[DllImport(\"kernel32.dll\")]
public static extern IntPtr GetModuleHandle(string name);//根据模块名称获取到对应的句柄[DllImport(\"user32.dll\
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);//查询⼀个窗体[DllImport(\"User32.dll\
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);//获取窗体中的所有⼦窗体(⽂本框,按钮等,都属于窗体)
[DllImport(\"user32.dll\")]
public static extern int EnumChildWindows(IntPtr hWndParent, CallBack lpfn, int lParam);//枚举窗体中的所有⼦窗体public delegate bool CallBack(IntPtr hwnd, int lParam);
此委托是EnumChildWindows的回调函数,⽤于遍历的时候对窗⼝进⾏处理
根据Module的名字获取到对应的句柄SetWindowsHookEx的第三个参数可以使⽤这个函数来获得。下⾯是⼀个⽰例程序,设置⼀个全局钩⼦,作⽤是,如果输⼊的字符是⼩写字母,则直接转换为⼤写字母。1.1 HookProc的⽅法实现
private int MessageHandle(int nCode, Int32 wParam, IntPtr lParam) {
if (0x100 == wParam || 0x101 == wParam) //如果按键为按下状态,如果没有这句判断,则内部代码会执⾏两遍,⼀遍是KeyDown⼀遍是KeyUp {
KBDLLHOOKSTRUCT ks = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT)); //将所有的⼩写字母直接加1
if (ks.vkCode >= 65 && ks.vkCode <= 90) {
string cUpper = Convert.ToChar(ks.vkCode).ToString().ToUpper(); SendMessage(txtHandle, 0x0c, IntPtr.Zero, cUpper); } }
return CallNextHookEx(result, nCode, 0, lParam); }
1.2 KBDLLHOOKSTRUCT结构体(这个结构体因为不同的钩⼦内容会不⼀样)public struct KBDLLHOOKSTRUCT {
public int vkCode; public int scanCode; public int flags; public int time;
public IntPtr dwExtraInfo; }
1.3设置钩⼦和卸载钩⼦(两个按钮的事件)
private void btnInstallHook_Click(object sender, EventArgs e) {
HookProc hProc = new HookProc(MessageHandle);
IntPtr cInstance = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName); result = SetWindowsHookEx(HookHelper.WH_KEYBOARD_LL, hProc, cInstance, 0);
}
private void btnUnhook_Click(object sender, EventArgs e) {
UnhookWindowsHookEx(result); }
辅助⽅法:为了获取到窗体中的⽂本框的句柄//枚举窗体中的⼦窗体的回调函数
private bool EnumWindow(IntPtr hwnd, int lParam) {
StringBuilder sb=new StringBuilder(); GetWindowText(hwnd, sb, 10); if (sb.ToString() == \"HookTest\") {
txtHandle = hwnd; }
return true; }
2.SendMessage的使⽤
可以使⽤SendMessage模拟给发送⼀条系统消息[DllImport(\"user32.dll\
private static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport(\"User32.dll\
private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);//发送消息,此重载⽅法可以直接给⽂本框赋值
下⾯是⼀个⾃动点击按钮和⾃动给⽂本框赋值的⽰例
private void btnTest_Click(object sender, EventArgs e) {
#region ⾃动点击按钮
//IntPtr cProcess = FindWindow(null, \"测试Hook\");
//winHandle = FindWindowEx(cProcess, IntPtr.Zero, null, \"点击显⽰界⾯\");
////SendMessage(winHandle, 0xf5, 0, 0);//0xf5 BM_CLICK 按钮单击对应的消息--经过测试,直接使⽤0xf5⽆法实现点击按钮的功能 ////测试结果发现,如果想要实现单击按钮的功能,必须先按下⿏标左键,再抬起⿏标左键
//SendMessage(winHandle, 0x201, IntPtr.Zero, IntPtr.Zero);//0x201 WM_LBUTTONDOWN 按下⿏标左键对应的消息 //SendMessage(winHandle, 0x202, IntPtr.Zero, IntPtr.Zero);//0x201 WM_LBUTTONUP 抬起⿏标左键对应的消息
#endregion
#region ⾃动输⼊⽂本
//IntPtr cProcess = FindWindow(null, \"Test.txt - 记事本\"); //winHandle = FindWindowEx(cProcess, IntPtr.Zero, null, \"\");
//IntPtr cProcess = FindWindow(null, \"测试Hook\");
//winHandle = FindWindowEx(cProcess, IntPtr.Zero, null, null);
////winHandle = new IntPtr(0xE10F2);//这种⽅式是先通过Spy++找到控件的句柄,然后再使⽤这个句柄进⾏数据交互(此⽅法每次重启窗体,对应的句柄都会发⽣变化)
//SendMessage(txtHandle, 0x0c, IntPtr.Zero, \"ABCDEFGHIJKLMN\");//0x0c wm_settext 给窗体设置⽂本 #endregion }
源代码:https://files.cnblogs.com/files/ckym/HookTest.rar