- 获取鼠标位置处窗口句柄,需要使用到Win32Api函数WindowFromPoint,用来根据坐标获取窗口句柄,C#引用如下:只要能够获取鼠标的位置,然后调用该函数就可以得到窗口句柄。
[DllImport("user32.dll", EntryPoint = "WindowFromPoint")]//指定坐标处窗体句柄
public static extern int WindowFromPoint( int xPoint,int yPoint);
- 获取鼠标位置,需要使用鼠标钩子,本文使用已经设计好的鼠标钩子类,关于该类的详细信息见参考资料。
//添加新建类Win32Api,该类封装Api函数,代码如下:
public class Win32Api
{
[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;
}
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
//安装钩子
[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, IntPtr wParam, IntPtr lParam);
}
public class MouseHook
{
private Point point;
private Point Point
{
get { return point; }
set
{
if (point != value)
{
point = value;
if (MouseMoveEvent != null)
{
var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0);
MouseMoveEvent(this, e);
}
}
}
}
private int hHook;
public const int WH_MOUSE_LL = 14;
public Win32Api.HookProc hProc;
public MouseHook() { this.Point = new Point(); }
public int SetHook()
{
hProc = new Win32Api.HookProc(MouseHookProc);
hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0);
return hHook;
}
public void UnHook()
{
Win32Api.UnhookWindowsHookEx(hHook);
}
private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct));
if (nCode < 0)
{
return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
}
else
{
this.Point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y);
return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
}
}
//委托+事件(把钩到的消息封装为事件,由调用者处理)
public delegate void MouseMoveHandler(object sender, MouseEventArgs e);
public event MouseMoveHandler MouseMoveEvent;
}
- 引用Win32Api和MouseHook鼠标钩子类,详见参考资料。
//在Form1中添加代码,如下:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
MouseHook mh;
private void Form1_Load(object sender, EventArgs e)
{
//安装鼠标钩子
mh = new MouseHook();
mh.SetHook();
mh.MouseMoveEvent += mh_MouseMoveEvent;
}
void mh_MouseMoveEvent(object sender, MouseEventArgs e)
{ //当前鼠标位置
int x = e.Location.X;
int y = e.Location.Y;
lb_p.Text = string.Format("({0},{1})", x, y);
int hwnd = Win32Api.WindowFromPoint(x, y);//获取指定坐标处窗口的句柄
lb_h.Text = hwnd.ToString();
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
mh.UnHook();
}
}
注意:
- 使用钩子之前,必须创建钩子,使用函数SetWindowsHookEx,函数原型如下:
HHOOK WINAPI SetWindowsHookEx(
__in int idHook, \\钩子类型
__in HOOKPROC lpfn, \\回调函数地址
__in HINSTANCE hMod, \\实例句柄,钩子所在的实例的句柄
__in DWORD dwThreadId); \\线程ID,钩子所监视的线程的线程ID
)
函数说明:
1、钩子的类型:分两种,全局钩子和局部钩子。全局钩子可以抓取其他进程的消息,分为抓取其他进程中某一特定线程的消息和抓取所有进程的消息两种。而局部钩子只抓取当前进程的消息。
2、 回调函数。当抓取到消息时,操作系统将自动调用该函数处理消息。在C#中要使用委托。
3、实例句柄,对于线程序钩子,参数传NULL;对于系统钩子:参数为钩子DLL的句柄。
4、线程ID:对于全局钩子,该参数为NULL。 -
钩子函数是回调函数。当钩子捕获到指定的消息后,系统将会自动调用该函数进行处理。注意:钩子函数应当“短小精悍”,不能占用太多的时间,最好是只用来捕获和传递消息,对消息的处理应放在其他地方。函数原型如下:LRESULT WINAPI MyHookProc( int nCode , // 指定是否需要处理该消息 WPARAM wParam, // 附加消息wParam
LPARAM lParam // 附加消息lParam
)
注意:在C#中应当使用委托,而且应带在钩子函数的结尾调用CallNextHookEx函数处理下一条消息,函数原型如下:
LRESULT CallNextHookEx( HHOOK hhk, // 钩子句柄 int nCode, // nCode WPARAM wParam, // 附加消息wParam
LPARAM lParam // 附加消息lParam
) -
使用完钩子后一定要卸载钩子,否则可能会导致BUG,甚至导致死机。使用函数UnhookWin_
dowsHookEx()卸载钩子即可。函数原形如下:
BOOL UnhookWindowsHookEx(
HHOOK hhk // 要卸载的钩子句柄。 )