鼠标HOOK

        对于win32每个进程都有自己独立的4GB空间,这个每个程序相对于其他程序都是独立的,一个程序轻易不能访问其他程序地址,一旦访问了轻则跳出出错提示,重则蓝屏,然而当你离开了当前程序,却想要跟踪一些消息,就困难重重了。幸好windws 给我们提供了钩子(hook)函数。
  钩子(hook)一般分为两个等级:全局钩子和局部钩子。全局顾名思义可以挂钩其他程序的消息,而局部则直挂钩使用钩子函数的进程。当然两种都要使用到dll,需要把dll注入到其他进程中,所以使用一定要小心,使用不当会影响其他程序的稳定性。下面先介绍一下windows的钩子函数:


安装钩子函数:
HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId);
IdHook: 钩子类型,有鼠标、键盘、巨集等等10几种
Lpfn: 挂钩的函数,用来处理拦截消息的函数。必须是全局函数
HMod: 当前进程的句柄
dwThreadId: 设置要挂接的线程ID.为NULL则为全局钩子
卸载钩子函数
BOOL UnhookWindowsHookEx(HHOOK hhk);
Hhk 要卸载的钩子句柄
还有一个函数:
LRESULT CallNextHookEx(HHOOK hhk,int nCode,WPARAM wParam, LPARAM lParam);
用于把拦截的消息继续传递下去,不然其他程序可能会得不到相应的消息,在一个按钮上点击,而程序不能执行,是很让人费解的。
基本写钩子程序主要是用上面的3个函数。下面就在vc下,一步一步写一个鼠标钩子。
首先当然是创始一个工程了(呵呵,废话),选择 MFC AppWizard(dll),下一步后,选择 MFC Extension Dll,接着创建 mousehook.h 和mousehook.cpp 文件
mousehook.h 文件内容如下,是不是很短小呢,选择MFC Extension(扩展) Dll就可以使用类,其他普通和常规dll是不能办到的,不过选择了扩展dll,这个dll就只能在 MFC 程序中使用,在vb、delphi中就不能用了:
// ____________________________________________________________________________
//
// 类: CMousehook
// 目的: 用来挂钩鼠标
// 描述: 该类会随着钩子客户端关闭而自动卸载
// ____________________________________________________________________________

#ifndef _MOUSEHOOK_ //控制头文件只包含一次
#define _MOUSEHOOK_
#define WM_MOUSE_HOOK WM_USER+110 //传递给钩子dll客户端的消息
class AFX_EXT_CLASS CMousehook:public CObject
{
public:
 CMousehook();
 //析构时自动卸载钩子
 ~CMousehook();
 //安装钩子,把客户程序窗口句柄发给dll,拦截后dll向客户程序发送消息WM_MOUSE_POS
 BOOL installhook(HWND hclientwnd);
 //卸载钩子
 BOOL uninstallhook();
 //鼠标点击次数
 int GetMouseClickCount();
 //包含鼠标位置的数组。为什么使用POINT 结构传递坐标客户端赋值不能编译成功??
 int* GetClickPosition();
};
#endif
下面是相应的实现文件:
// ==================
// INCLUDE FILES
// ==================
#include "stdafx.h"
#include
#include "mousehook.h"
// ==================
// DEFINES
// ==================
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//公共数据,用于不通进程的数据共享。不用进程都装载mousehook.dll,但都放在自己的范围,所以mousehook类成员是不能共享的,必须创建全局数据段。在不同程序之间共享这些数据,
//还需要在相应的 .def 文件中加入
SECTIONS
mymousedata READ WRITE SHARED
//把该全局数据段设置为读写共享
//全局共享数据段声明
#pragma data_seg("mymousedata")
static HINSTANCE hinst=NULL; //注入钩子的程序句柄
static HHOOK g_hook=NULL; //钩子句柄
static HWND g_hwnd=NULL; //需要处理钩子消息的客户端句柄
static int mouseclickcount=0; //鼠标点击次数
static int position[2]={0,0};//鼠标的位置信息
#pragma data_seg()

static AFX_EXTENSION_MODULE MousehookDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
 UNREFERENCED_PARAMETER(lpReserved);
 if (dwReason == DLL_PROCESS_ATTACH)
 {
 TRACE0("MOUSEHOOK.DLL Initializing!/n");
 if (!AfxInitExtensionModule(MousehookDLL, hInstance))
 return 0;
 new CDynLinkLibrary(MousehookDLL);
 }
 else if (dwReason == DLL_PROCESS_DETACH)
 {
 TRACE0("MOUSEHOOK.DLL Terminating!/n");
 AfxTermExtensionModule(MousehookDLL);
 }

 //传给SetWindowsHookEx()函数的当前程序句柄;
 hinst=hInstance;
 return 1; // ok
}
 //传递给钩子安装函数参数 lpfn ,一个要注入到各个进程的全局函数。必须声明为 extern “C”
extern "C" __declspec(dllexport) LRESULT WINAPI mouseproc(int nCode,WPARAM wParam,LPARAM lParam)
{
 //检测鼠标消息,鼠标钩子消息存放在 wParam 参数中,lParam 指向MOUSEHOOKSTRUCT //的指针,存放鼠标位置,当前窗口句柄,鼠标消息等等。
 if(wParam==WM_MOUSEMOVE||wParam==WM_LBUTTONDOWN||wParam==WM_RBUTTONDOWN)
 {
 LPMOUSEHOOKSTRUCT mousedetials=(LPMOUSEHOOKSTRUCT) lParam;
 //由于c函数不支持结构赋值,使用MOUSEHOOKSTRUCT 变量传递坐标不能成功
 position[0]=mousedetials->pt.x;
 position[1]=mousedetials->pt.y;
 if(wParam==WM_LBUTTONDOWN)
 {
 mouseclickcount++;
 }
//给钩子客户端发送消息,使客户端刷新数据,使用PostMessage,不要使用//SendMessage, SendMessage要等到函数返回才继续执行。
 PostMessage(g_hwnd,WM_MOUSE_HOOK,0,0);
 }
 //把钩子消息传递下去。
 return CallNextHookEx(g_hook,nCode,wParam,lParam);
}
CMousehook::CMousehook()
{
}
CMousehook::~CMousehook()
{
 uninstallhook();
}
BOOL CMousehook::installhook(HWND hclientwnd)
{
 BOOL bRESULT=FALSE;
 //判断是否安装了一次钩子
 if(g_hook!=NULL)
 {
 bRESULT=true;
 }
 else
 {
 //安装钩子
 g_hook=SetWindowsHookEx(WH_MOUSE,(HOOKPROC)mouseproc,hinst,0);
 if(g_hook!=NULL)
 {
 bRESULT=TRUE;
 }
 else
 {
 //安装钩子失败(可能吗???)
 bRESULT=FALSE;
 MessageBox(NULL,"挂钩失败","Failure",MB_OK);
 }
 }
 //钩子的客户端窗口句柄
 g_hwnd=hclientwnd;
 return bRESULT;
}
BOOL CMousehook::uninstallhook()
{
 BOOL bResult=false;
 if (g_hook!=NULL)
 {
 // 卸载钩子
 bResult=UnhookWindowsHookEx(g_hook);
 if (bResult)
 {
 g_hook=NULL;
 }
 }
 else
 {
 bResult=true;
 }
 return bResult;
}
int CMousehook::GetMouseClickCount()
{
 //返回鼠标点击次数
 return mouseclickcount;
}
int* CMousehook::GetClickPosition()
{
 //返回鼠标坐标
 return position;
}
现在完成的是鼠标钩子的动态链接库,经过编译后需要经应用程序的调用才能实现对当前系统下各线程间鼠标消息的拦截处理。这部分同普通动态链接库的使用没有任何区别,在将其使用LoadLibrary 加载到进程后,首先调用动态链接库的Cmousehook: :installhook函数安装好钩子,此时即可对系统下的鼠标消息实施拦截处理。经上述编程,在安装好鼠标钩子后,鼠标在移动到系统任意窗口上时,马上就会通过对鼠标消息的拦截处理而获取到当前鼠标位置。系统钩子具有相当强大的功能,通过这种技术可以对几乎所有的Windows系统消息和事件进行拦截处理。这样向QQ自动隐藏(或者可停靠)功能,都很容易实现。以及一些简单的木马,当判断鼠标当前窗口是密码窗口时,只需要向该窗口发送WM_GETTEXT即可轻松得到密码。这种技术广泛应用于各种自动监控系统对进程外消息的监控处理。本文只对鼠标钩子的一些基本原理和一般的使用方法做了简要的探讨,感兴趣的读者完全可以在本文所述代码基础之上用类似的方法实现对 诸如键盘钩子、外壳钩子等其他类型钩子的安装与使用。本文所述代码在Windows 2000下由Microsoft Visual C++ 6.0编译通过。

在WPF中,可以使用Win32 API来实现鼠标Hook。以下是一个简单的示例,可以Hook鼠标的左键和右键点击事件: 首先,需要引入以下命名空间: ```csharp using System.Runtime.InteropServices; using System.Windows.Input; ``` 然后定义以下结构体和枚举: ```csharp [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; } public enum MouseMessages { WM_LBUTTONDOWN = 0x0201, WM_LBUTTONUP = 0x0202, WM_RBUTTONDOWN = 0x0204, WM_RBUTTONUP = 0x0205 } ``` 接下来,定义以下方法: ```csharp [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetCursorPos(out POINT lpPoint); [DllImport("user32.dll")] private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("user32.dll")] private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); ``` 最后,定义以下委托和字段: ```csharp private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam); private const int WH_MOUSE_LL = 14; private const int WM_MOUSEMOVE = 0x0200; private static LowLevelMouseProc _proc = HookCallback; private static IntPtr _hookID = IntPtr.Zero; ``` 现在可以实现Hook的回调函数: ```csharp private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0 && (MouseMessages)wParam == MouseMessages.WM_LBUTTONDOWN) { // 左键点击事件 POINT point; if (GetCursorPos(out point)) { // 获取鼠标位置 var wpfPoint = new Point(point.X, point.Y); var element = Mouse.DirectlyOver as UIElement; if (element != null) { // 触发鼠标左键点击事件 element.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseLeftButtonDownEvent, Source = element, OriginalSource = element, ClickCount = 1, Timestamp = 0, MouseButtonState = MouseButtonState.Pressed, StylusDevice = null, GetPosition = p => wpfPoint, }); } } } else if (nCode >= 0 && (MouseMessages)wParam == MouseMessages.WM_RBUTTONDOWN) { // 右键点击事件 POINT point; if (GetCursorPos(out point)) { // 获取鼠标位置 var wpfPoint = new Point(point.X, point.Y); var element = Mouse.DirectlyOver as UIElement; if (element != null) { // 触发鼠标右键点击事件 element.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Right) { RoutedEvent = UIElement.MouseRightButtonDownEvent, Source = element, OriginalSource = element, ClickCount = 1, Timestamp = 0, MouseButtonState = MouseButtonState.Pressed, StylusDevice = null, GetPosition = p => wpfPoint, }); } } } return CallNextHookEx(_hookID, nCode, wParam, lParam); } ``` 最后,在需要Hook鼠标事件的地方调用以下代码即可: ```csharp _hookID = SetWindowsHookEx(WH_MOUSE_LL, _proc, IntPtr.Zero, 0); ``` 同时,在程序退出时,需要取消Hook: ```csharp UnhookWindowsHookEx(_hookID); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值