应用程序有自己的截获方式,那么操作系统呢,也有自己的截获方式,那就是使用钩子技术。(这里以windows系统为例)
钩子工作原理:
windows应用是通过windows消息机制去做驱动的,那么什么是消息机制呢,就是你电脑中所有的操作,都可以被操作系统捕获,然后操作系统把捕获的消息推送到消息队列。然后对应的应用程序去从消息队列中获得响应。
那么钩子是用来干嘛的呢?
如上图:
应用程序的所有IO操作,我们操作系统是可以捕获到的。钩子作用就是,再操作系统准备把数据推送到消息队列的时候,进行截断。然后处理想处理的东西。
安装全局鼠标钩子
自己在C#中定义一个类,用来做钩子操作。
/// <summary>
/// 装载钩子
/// </summary>
/// <param name="idHook">钩子类型(比如 鼠标 键盘 等)</param>
/// <param name="lpfn">钩子函数(截获后想如何操作) </param>
/// <param name="hInstance">模块ID(当前模块实例ID 也可理解为进程ID NULL表示当前应用程序自己)</param>
/// <param name="threadId">线程id</param>
/// <returns></returns>
//装置钩子的函数
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
因为SetWindowsHookEx
为非托管函数,所以需要DllImport
进行dll引用和extern
进行标识。
解释SetWindowsHookEx
函数:
它就相当于创建钩子的入口,需要创建什么样的钩子,对应传值就可以呢。
SetWindowsHookEx微软地址
那么具体如何装载了:看代码。
static int hMouseHook = 0; //鼠标钩子句柄
//鼠标常量
public const int WH_MOUSE_LL = 14; //mouse hook constant
//钩子处理函数
public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
HookProc MouseHookProcedure; //声明鼠标钩子事件类型.
public void Start()
{
//安装鼠标钩子
if (hMouseHook == 0)
{
//生成一个HookProc的实例.
MouseHookProcedure = new HookProc(MouseHookProc);
using (System.Diagnostics.Process curProcess = System.Diagnostics.Process.GetCurrentProcess())
using (System.Diagnostics.ProcessModule curModule = curProcess.MainModule)
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, GetModuleHandle(curModule.ModuleName), 0);
//如果装置失败停止钩子
if (hMouseHook == 0)
{
Stop();
throw new Exception("SetWindowsHookEx failed.");
}
}
}
注释:
1.WH_MOUSE_LL
为装载类型,比如它表示的是装载的监视鼠标的钩子。也可以装载其他类型,比如键盘等,具体其他类型可以去官方查找。官网
2.MouseHookProcedure
为钩子会的的函数,也就是你需要操作的业务逻辑。
3.hMouseHook
作用是接收钩子函数操作后的值。如果函数成功,则返回值是挂钩过程的句柄。如果函数失败,则返回值为 NULL
。hMouseHook
将会作为CallNextHookEx
函数的第一个值。CallNextHookEx
作用就是将截断的操作续上。
MouseHookProc函数代码:
private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
**看到这了给你些福利:C#接单交流群452760896**
//如果正常运行并且用户要监听鼠标的消息
if ((nCode >= 0) && (OnMouseActivity != null))
{
MouseButtons button = MouseButtons.None;
int clickCount = 0;
switch (wParam)
{
case WM_LBUTTONDOWN:
button = MouseButtons.Left;
clickCount = 1;
break;
case WM_LBUTTONUP:
button = MouseButtons.Left;
clickCount = 1;
//从回调函数中得到鼠标的信息
MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, 0);
//发送ctrl+c
SendCtrl_C(0);
OnMouseActivity(this, e);
//释放
SendCtrl_C(2);
break;
case WM_LBUTTONDBLCLK:
button = MouseButtons.Left;
clickCount = 2;
break;
case WM_RBUTTONDOWN:
button = MouseButtons.Right;
clickCount = 1;
break;
case WM_RBUTTONUP:
button = MouseButtons.Right;
clickCount = 1;
break;
case WM_RBUTTONDBLCLK:
button = MouseButtons.Right;
clickCount = 2;
break;
}
}
//将挂钩信息传递到当前挂钩链中的下一个挂钩过程。 挂钩过程可以在处理挂钩信息之前或之后调用此函数。
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
注释:
1.如果MouseHookProc
不返回CallNextHookEx
而返回1 那么你注册的是什么类型钩子,什么就会失效(屏蔽)。
UnhookWindowsHookEx卸载钩子
public void Stop()
{
bool retMouse = true;
if (hMouseHook != 0)
{
retMouse = UnhookWindowsHookEx(hMouseHook);
hMouseHook = 0;
}
//如果卸下钩子失败
if (!(retMouse)) throw new Exception("UnhookWindowsHookEx failed.");
}
下面给出鼠标钩子类的所有代码:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace Translate
{
/// <summary>
/// 监控鼠标钩子
/// </summary>
public class MouseHook
{
private const int WM_MOUSEMOVE = 0x200;
private const int WM_LBUTTONDOWN = 0x201;
private const int WM_RBUTTONDOWN = 0x204;
private const int WM_MBUTTONDOWN = 0x207;
private const int WM_LBUTTONUP = 0x202;
private const int WM_RBUTTONUP = 0x205;
private const int WM_MBUTTONUP = 0x208;
private const int WM_LBUTTONDBLCLK = 0x203;
private const int WM_RBUTTONDBLCLK = 0x206;
private const int WM_MBUTTONDBLCLK = 0x209;
//全局的事件
public event MouseEventHandler OnMouseActivity;
static int hMouseHook = 0; //鼠标钩子句柄
//鼠标常量
public const int WH_MOUSE_LL = 14; //mouse hook constant
HookProc MouseHookProcedure; //声明鼠标钩子事件类型.
//声明一个Point的封送类型
[StructLayout(LayoutKind.Sequential)]
public class POINT
{
public int x;
public int y;
}
//声明鼠标钩子的封送结构类型
[StructLayout(LayoutKind.Sequential)]
public class MouseHookStruct
{
public POINT pt;
public int hWnd;
public int wHitTestCode;
public int dwExtraInfo;
}
[DllImport("user32.dll")]
public static extern void keybd_event(int bVk, byte bScan, int dwFlags, int dwExtraInfo); //用于发送鼠标热键操作
/// <summary>
/// 获取模块名
/// </summary>
/// <param name="lpModuleName"></param>
/// <returns></returns>
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
/// <summary>
/// 装载钩子
/// </summary>
/// <param name="idHook">钩子类型(比如 鼠标 键盘 等)</param>
/// <param name="lpfn">钩子函数(截获后想如何操作)</param>
/// <param name="hInstance">模块ID(当前模块实例ID 也可理解为进程ID NULL表示当前应用程序自己) Null表示当前进行</param>
/// <param name="threadId">线程id 设为0 表示全局 局部的请获取当前的线程 </param>
/// <returns></returns>
//装置钩子的函数
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
//卸下钩子的函数
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
//下一个钩挂的函数
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
//钩子处理函数
/// <summary>
///
/// </summary>
/// <param name="nCode">如何处理当前消息(有几种状态值)</param>
/// <param name="wParam">(指定消息是否由当前进程发送。如果消息是由当前进程发送的,则它不是零;否则为NULL)附加消息</param>
/// <param name="lParam">截获下来的附加信息(指向包含消息详细信息的CWPRETSTRUCT结构的指针)</param>
/// <returns></returns>
public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
/// <summary>
/// 墨认的构造函数构造当前类的实例.
/// </summary>
public MouseHook()
{
}
//析构函数.
~MouseHook()
{
Stop();
}
public void Start()
{
//安装鼠标钩子
if (hMouseHook == 0)
{
//生成一个HookProc的实例.
MouseHookProcedure = new HookProc(MouseHookProc);
//获取当前进程
using (System.Diagnostics.Process curProcess = System.Diagnostics.Process.GetCurrentProcess())
//获取当前进程的模块
using (System.Diagnostics.ProcessModule curModule = curProcess.MainModule)
//配置全局钩子 全局钩子模块必须动态获取
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, GetModuleHandle(curModule.ModuleName), 0);
//如果装置失败停止钩子
if (hMouseHook == 0)
{
Stop();
throw new Exception("SetWindowsHookEx failed.");
}
}
}
public void Stop()
{
bool retMouse = true;
if (hMouseHook != 0)
{
retMouse = UnhookWindowsHookEx(hMouseHook);
hMouseHook = 0;
}
//如果卸下钩子失败
if (!(retMouse)) throw new Exception("UnhookWindowsHookEx failed.");
}
private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
//如果正常运行并且用户要监听鼠标的消息
if ((nCode >= 0) && (OnMouseActivity != null))
{
MouseButtons button = MouseButtons.None;
int clickCount = 0;
switch (wParam)
{
case WM_LBUTTONDOWN:
button = MouseButtons.Left;
clickCount = 1;
break;
case WM_LBUTTONUP:
button = MouseButtons.Left;
clickCount = 1;
//从回调函数中得到鼠标的信息
MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, 0);
//发送ctrl+c
SendCtrl_C(0);
OnMouseActivity(this, e);
//释放
SendCtrl_C(2);
break;
case WM_LBUTTONDBLCLK:
button = MouseButtons.Left;
clickCount = 2;
break;
case WM_RBUTTONDOWN:
button = MouseButtons.Right;
clickCount = 1;
break;
case WM_RBUTTONUP:
button = MouseButtons.Right;
clickCount = 1;
break;
case WM_RBUTTONDBLCLK:
button = MouseButtons.Right;
clickCount = 2;
break;
}
}
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
/// <summary>
/// 发送 和 释放
/// </summary>
/// <param name="dwFlags"> //这里为整数类型 0为按下,2为释放</param>
private void SendCtrl_C(int dwFlags)
{
keybd_event(Convert.ToInt32(System.Windows.Forms.Keys.ControlKey), 0, dwFlags, 0);
keybd_event(Convert.ToInt32(System.Windows.Forms.Keys.C), 0, dwFlags, 0);
}
}
}