C# 鼠标钩子 如何获取鼠标左右键呀 鼠标不在窗体内同时窗体不是激活的当鼠标点左/右键时 我要执行代码现在的问题就是如何捕获到 鼠标左右键? 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 用api 自己百度下win32 api 学习下 可以操作控制很多东西。 btn_MouseDown(object sender, MouseEventArgs e)事件e.Button判断是鼠标哪个键 http://www.codeproject.com/KB/cs/globalhook.aspx http://blog.csdn.net/Nocky/archive/2010/12/28/6103875.aspx时面用到了WIN32 API SetWindowsHookEx,修改一下参数设成全局的就行了,可以捕捉到鼠标消息 private void panel_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left)/ if (e.Button == MouseButtons.right)………… showModalDialog并不创建新的浏览器窗口,也不创建新的浏览器对象,而是在WebBrowser的同一个线程中创建的窗口,而showModelessDialog( )则是在新的线程中创建的窗口,所以处理方式不相同。当showModalDialog( )被调用后,浏览器线程会创建一个对话框,该对话框包含两个窗口,父窗口的类为“Internet Explorer_TridentDlgFrame”,子窗口的类为“Internet Explorer_Server”,其子窗口即为IE内核的窗口,可以通过给该窗口发送消息,进行一些自动化操作(如按键、鼠标点击等)。当子窗口创建时,父窗口会收到WM_PARENTNOTIFY消息,hwnd值即为父窗口的值,wParam的值即为Internet Explorer_Server的窗口。我们捕获窗口后就可以捕捉到IE内核窗口的句柄了。 STEP 1: 建立窗口事件的钩子函数 // 使用Windows API函数 [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SetWindowsHookEx(HookType hooktype, HookProcedureDelegate callback, IntPtr hMod, UInt32 dwThreadId); // Hook Types public enum HookType { WH_JOURNALRECORD = 0, WH_JOURNALPLAYBACK = 1, WH_KEYBOARD = 2, WH_GETMESSAGE = 3, WH_CALLWNDPROC = 4, WH_CBT = 5, WH_SYSMSGFILTER = 6, WH_MOUSE = 7, WH_HARDWARE = 8, WH_DEBUG = 9, WH_SHELL = 10, WH_FOREGROUNDIDLE = 11, WH_CALLWNDPROCRET = 12, WH_KEYBOARD_LL = 13, WH_MOUSE_LL = 14 }[StructLayout(LayoutKind.Sequential)] public struct CWPRETSTRUCT { public IntPtr lResult; public IntPtr lParam; public IntPtr wParam; public UInt32 message; public IntPtr hwnd; }; // Delegate for the EnumChildWindows method private delegate Boolean EnumerateWindowDelegate(IntPtr pHwnd, IntPtr pParam);private static Win32API.HookProcedureDelegate _WH_CALLWNDPROCRET_PROC = new Win32API.HookProcedureDelegate(WH_CALLWNDPROCRET_PROC);// 在程序开始处调用该方法 public static void Hook( ) { if (_pWH_CALLWNDPROCRET == IntPtr.Zero) { _pWH_CALLWNDPROCRET = Win32API.SetWindowsHookEx( Win32API.HookType.WH_CALLWNDPROCRET ,_WH_CALLWNDPROCRET_PROC ,IntPtr.Zero ,(uint)AppDomain.GetCurrentThreadId( )); // current thread } if (_pWH_CALLWNDPROCRET == IntPtr.Zero) throw new ApplicationException("Failed to install window hook via: SetWindowsHookEx( )"); } // 自定义的消息钩子函数,在函数中捕捉PARENTNOTIFY消息,然后再检查该消息是否窗口创建或销毁窗口 // 然后创建一个个事件WindowLife,在WebBrowser中添加该事件的处理函数即可 public delegate void WindowLifeHandler(Win32Message msg, IntPtr parent, IntPtr child); public static event WindowLifeHandler WindowLife; private static Int32 WH_CALLWNDPROCRET_PROC(Int32 iCode, IntPtr pWParam, IntPtr pLParam) { if (iCode < 0) return Win32API.CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam); Win32API.CWPRETSTRUCT cwp = (Win32API.CWPRETSTRUCT)Marshal.PtrToStructure(pLParam, typeof(Win32API.CWPRETSTRUCT)); Win32Message msg = Win32Message.WM_NULL; try { msg = (Win32Message)cwp.message; } catch { return Win32API.CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam); ; } if (msg == Win32Message.WM_PARENTNOTIFY) { if ((int)cwp.wParam == (int)Win32Message.WM_CREATE || (int)cwp.wParam == (int)Win32Message.WM_DESTROY) { System.Diagnostics.Debug.WriteLine("WM_PARENTNOTIFY hwnd=0x{0:x8} wParam={1} lParam=0x{2:x8}" ,(int)cwp.hwnd, (Win32Message)cwp.wParam,(int)cwp.lParam); if (WindowLife != null) WindowLife((Win32Message)cwp.wParam, cwp.hwnd, cwp.lParam); } } return Win32API.CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam); } STEP 2:继承WebBrowser并在派生类中添加WindowLife事件的处理函数,在派生类的构造函数中增加如下代码: public class ExWebBrowser : System.Windows.Forms.WebBrowser { public ExWebBrowser( ) { _windowLifeDelegate = new WindowsMessageHooker.WindowLifeHandler(OnWindowLife); WindowsMessageHooker.WindowLife += _windowLifeDelegate; this.Disposed += (sender, e) => { WindowsMessageHooker.WindowLife -= _windowLifeDelegate; }; private IntPtr _webPageDialogHandle = IntPtr.Zero; private static readonly string IE_WebDialogClassName = "Internet Explorer_TridentDlgFrame"; private static readonly string IE_ServerClassName = "Internet Explorer_Server"; public delegate void WebPageDialogHandler(IntPtr hwnd, string title); // 创建网页对话框时触发的事件 public event WebPageDialogHandler ShowWebDialog; // 关闭网页对话框时触发的事件 public event WebPageDialogHandler CloseWebDialog; private WindowsMessageHooker.WindowLifeHandler _windowLifeDelegate = null;private void OnWindowLife(noock.windows.Win32Message msg, IntPtr parent, IntPtr child) { StringBuilder buffer = null; string childClass = null; string parentClass = null; buffer = new StringBuilder(256); if (child != _webPageDialogHandle) { noock.windows.Win32API.GetClassName(child, buffer, buffer.Capacity); childClass = buffer.ToString( ); System.Diagnostics.Debug.WriteLine("child class:" + childClass); if (childClass != IE_ServerClassName) return; noock.windows.Win32API.GetClassName(parent, buffer, buffer.Capacity); parentClass = buffer.ToString( ); System.Diagnostics.Debug.WriteLine("parent class:" + parentClass); if (parentClass != IE_WebDialogClassName) return; } noock.windows.Win32API.GetWindowText(parent, buffer, buffer.Capacity); string title = buffer.ToString(); if (msg == noock.windows.Win32Message.WM_CREATE) { _webPageDialogHandle = child; System.Diagnostics.Debug.WriteLine(title, "showModalDialog( ) Opening:"); if (ShowWebDialog != null) { ShowWebDialog(_webPageDialogHandle, title); } } else if (msg == noock.windows.Win32Message.WM_DESTROY) { _webPageDialogHandle = IntPtr.Zero; System.Diagnostics.Debug.WriteLine(title, "showModalDialog( ) Closing:"); if (CloseWebDialog != null) { CloseWebDialog(child, title); } } } }这样就扩展了WebBrowser的事件,可以触发showModalDialog( )弹出对话框的弹出事件。 STEP3: 因为函数的钩子是使用API实现,是系统级的,所有必须在程序退出时释放钩子函数占用的资源 public static bool Hooked { get { return _pWH_CALLWNDPROCRET != IntPtr.Zero; } } public static void Unhook( ) { if ( ! Hooked) { Win32API.UnhookWindowsHookEx(_pWH_CALLWNDPROCRET); } }但是,还有一个问题,这样只能捕捉到showModalDialog( )弹出的对话框,而不能捕捉到showModelessDialog( )弹出的非模态对话框,因为钩子函数在上面的代码中只捕捉主线程的消息,而非模态对话框则是单独的线程。遗憾的是SetWindowsHookEx( )不支持面向进程的钩子函数,除了面向线程就是面向全局的,捕捉整个桌面(一般相当于整个用户)的所有消息,虽然这样做也可以捕捉到相应的事件,但显然效率是比较低的。而且,非模态对话框在实际应用中并不多见。我们还可以通过一个折衷的方法,使用API来搜索WebBrowser窗口关系树中附近的窗口,看有没有其所有者是WebBrowser父窗口的网页对话框,例如代码: public IntPtr WebPageDialogHandle { get { InvokeMethod invoker = new InvokeMethod(( ) => { if (_webPageDialogHandle != IntPtr.Zero && Win32API.IsWindow(_webPageDialogHandle)) { } else { _webPageDialogHandle = SearchWebDialog(ParentForm.Handle, Win32API.GW_HWNDPREV); if (_webPageDialogHandle == IntPtr.Zero) _webPageDialogHandle = SearchWebDialog(ParentForm.Handle, Win32API.GW_HWNDNEXT); } } ); this.Invoke(invoker); return _webPageDialogHandle; } }private IntPtr SearchWebDialog(IntPtr start, uint direction) { int processId, nextProcId; int threadId = Win32API.GetWindowThreadProcessId(ParentForm.Handle, out processId); StringBuilder sb = new StringBuilder(256); IntPtr nextWin = Win32API.GetNextWindow(ParentForm.Handle, direction); int nextTh = Win32API.GetWindowThreadProcessId(nextWin, out nextProcId); while (nextProcId == processId) { if (ParentForm.Handle == Win32API.GetParent(nextWin)) { Win32API.GetClassName(nextWin, sb, sb.Capacity); if (sb.ToString() == IE_WebDialogClassName) { _webPageDialogHandle = Win32API.FindWindowExxx(nextWin, IntPtr.Zero, IE_ServerClassName, null); return _webPageDialogHandle; } } nextWin = Win32API.GetNextWindow(nextWin, direction); nextTh = Win32API.GetWindowThreadProcessId(nextWin, out processId); } return IntPtr.Zero; }public static IntPtr FindWindowExxx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle) { IntPtr res = FindWindowEx(parentHandle, childAfter, lclassName, windowTitle); if (res != IntPtr.Zero) return res; while ( (res = FindWindowEx(parentHandle, res, null, null)) != IntPtr.Zero) { IntPtr aim = FindWindowExxx(res, IntPtr.Zero, lclassName, windowTitle); if (aim != IntPtr.Zero) return aim; } return IntPtr.Zero; } 其实窗口的句柄只是内核对象中的一个地址,同一个进程的窗口句柄一般也是连续,正如代码中所示,我们不需要搜索所有的窗口,而只需要进进程ID为边界在WebBrowser父窗口的附近搜索。非模态对话框的父窗口够本是桌面窗口,而不是WebBrowser所在的窗口,所以在SearchWebDialog函数中调用了GetParent函数,而没有使用GetAncestor,因为前者返回的不一定是父窗口,也可能是所有者,这正是非模态对话框与WebBrowser窗口的关系,浏览器窗口是模态对话框的父窗口,而只是非模态框的所有者,而不是其父窗口。 获取非模态对话框的句柄以后,就随便你对它做什么了,发送消息模拟按键、模拟鼠标点击、关闭等,都是可以的了。本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Nocky/archive/2010/12/28/6103875.aspx "','附近有语法错误,请高手指教 万分感谢 DataGrid带动另一个DataGrid C#控件实例 老问题了,报表的问题,大家帮解决下吧 C#怎么读这样的xml 数据批处理中提示"未指的错误" 如何复制Word2003中某一页的内容?十分着急! Ftp文件上传,断网后重连有延迟 关于C#字符串占位符的问题 V.net里是不是没有WinForms 三层架构的问题 问题:实例化一个类所需要的时间是否和该类的大小有关系?
事件
e.Button判断是鼠标哪个键
时面用到了WIN32 API SetWindowsHookEx,修改一下参数设成全局的就行了,可以捕捉到鼠标消息
{
if (e.Button == MouseButtons.Left)/ if (e.Button == MouseButtons.right)
……
……
STEP 1: 建立窗口事件的钩子函数
// 使用Windows API函数 [DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(HookType hooktype, HookProcedureDelegate callback, IntPtr hMod, UInt32 dwThreadId); // Hook Types
public enum HookType
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}[StructLayout(LayoutKind.Sequential)]
public struct CWPRETSTRUCT
{
public IntPtr lResult;
public IntPtr lParam;
public IntPtr wParam;
public UInt32 message;
public IntPtr hwnd;
}; // Delegate for the EnumChildWindows method
private delegate Boolean EnumerateWindowDelegate(IntPtr pHwnd, IntPtr pParam);private static Win32API.HookProcedureDelegate _WH_CALLWNDPROCRET_PROC =
new Win32API.HookProcedureDelegate(WH_CALLWNDPROCRET_PROC);// 在程序开始处调用该方法
public static void Hook( )
{
if (_pWH_CALLWNDPROCRET == IntPtr.Zero) {
_pWH_CALLWNDPROCRET = Win32API.SetWindowsHookEx(
Win32API.HookType.WH_CALLWNDPROCRET
,_WH_CALLWNDPROCRET_PROC
,IntPtr.Zero
,(uint)AppDomain.GetCurrentThreadId( )); // current thread
}
if (_pWH_CALLWNDPROCRET == IntPtr.Zero)
throw new ApplicationException("Failed to install window hook via: SetWindowsHookEx( )");
} // 自定义的消息钩子函数,在函数中捕捉PARENTNOTIFY消息,然后再检查该消息是否窗口创建或销毁窗口
// 然后创建一个个事件WindowLife,在WebBrowser中添加该事件的处理函数即可
public delegate void WindowLifeHandler(Win32Message msg, IntPtr parent, IntPtr child);
public static event WindowLifeHandler WindowLife;
private static Int32 WH_CALLWNDPROCRET_PROC(Int32 iCode, IntPtr pWParam, IntPtr pLParam)
{
if (iCode < 0)
return Win32API.CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam); Win32API.CWPRETSTRUCT cwp = (Win32API.CWPRETSTRUCT)Marshal.PtrToStructure(pLParam, typeof(Win32API.CWPRETSTRUCT));
Win32Message msg = Win32Message.WM_NULL;
try {
msg = (Win32Message)cwp.message;
} catch {
return Win32API.CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam); ;
}
if (msg == Win32Message.WM_PARENTNOTIFY) {
if ((int)cwp.wParam == (int)Win32Message.WM_CREATE || (int)cwp.wParam == (int)Win32Message.WM_DESTROY) {
System.Diagnostics.Debug.WriteLine("WM_PARENTNOTIFY hwnd=0x{0:x8} wParam={1} lParam=0x{2:x8}"
,(int)cwp.hwnd, (Win32Message)cwp.wParam,(int)cwp.lParam);
if (WindowLife != null)
WindowLife((Win32Message)cwp.wParam, cwp.hwnd, cwp.lParam);
}
}
return Win32API.CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam);
} STEP 2:继承WebBrowser并在派生类中添加WindowLife事件的处理函数,在派生类的构造函数中增加如下代码:
public class ExWebBrowser : System.Windows.Forms.WebBrowser
{
public ExWebBrowser( )
{
_windowLifeDelegate = new WindowsMessageHooker.WindowLifeHandler(OnWindowLife);
WindowsMessageHooker.WindowLife += _windowLifeDelegate;
this.Disposed += (sender, e) => {
WindowsMessageHooker.WindowLife -= _windowLifeDelegate;
}; private IntPtr _webPageDialogHandle = IntPtr.Zero;
private static readonly string IE_WebDialogClassName = "Internet Explorer_TridentDlgFrame";
private static readonly string IE_ServerClassName = "Internet Explorer_Server"; public delegate void WebPageDialogHandler(IntPtr hwnd, string title);
// 创建网页对话框时触发的事件
public event WebPageDialogHandler ShowWebDialog;
// 关闭网页对话框时触发的事件
public event WebPageDialogHandler CloseWebDialog;
private WindowsMessageHooker.WindowLifeHandler _windowLifeDelegate = null;private void OnWindowLife(noock.windows.Win32Message msg, IntPtr parent, IntPtr child)
{
StringBuilder buffer = null;
string childClass = null;
string parentClass = null; buffer = new StringBuilder(256);
if (child != _webPageDialogHandle) {
noock.windows.Win32API.GetClassName(child, buffer, buffer.Capacity);
childClass = buffer.ToString( );
System.Diagnostics.Debug.WriteLine("child class:" + childClass);
if (childClass != IE_ServerClassName)
return;
noock.windows.Win32API.GetClassName(parent, buffer, buffer.Capacity);
parentClass = buffer.ToString( );
System.Diagnostics.Debug.WriteLine("parent class:" + parentClass);
if (parentClass != IE_WebDialogClassName)
return;
} noock.windows.Win32API.GetWindowText(parent, buffer, buffer.Capacity);
string title = buffer.ToString(); if (msg == noock.windows.Win32Message.WM_CREATE) {
_webPageDialogHandle = child;
System.Diagnostics.Debug.WriteLine(title, "showModalDialog( ) Opening:");
if (ShowWebDialog != null) {
ShowWebDialog(_webPageDialogHandle, title);
}
} else if (msg == noock.windows.Win32Message.WM_DESTROY) {
_webPageDialogHandle = IntPtr.Zero;
System.Diagnostics.Debug.WriteLine(title, "showModalDialog( ) Closing:");
if (CloseWebDialog != null) {
CloseWebDialog(child, title);
}
}
}
}这样就扩展了WebBrowser的事件,可以触发showModalDialog( )弹出对话框的弹出事件。
STEP3: 因为函数的钩子是使用API实现,是系统级的,所有必须在程序退出时释放钩子函数占用的资源 public static bool Hooked
{
get { return _pWH_CALLWNDPROCRET != IntPtr.Zero; }
}
public static void Unhook( )
{
if ( ! Hooked) {
Win32API.UnhookWindowsHookEx(_pWH_CALLWNDPROCRET);
}
}但是,还有一个问题,这样只能捕捉到showModalDialog( )弹出的对话框,而不能捕捉到showModelessDialog( )弹出的非模态对话框,因为钩子函数在上面的代码中只捕捉主线程的消息,而非模态对话框则是单独的线程。遗憾的是SetWindowsHookEx( )不支持面向进程的钩子函数,除了面向线程就是面向全局的,捕捉整个桌面(一般相当于整个用户)的所有消息,虽然这样做也可以捕捉到相应的事件,但显然效率是比较低的。而且,非模态对话框在实际应用中并不多见。我们还可以通过一个折衷的方法,使用API来搜索WebBrowser窗口关系树中附近的窗口,看有没有其所有者是WebBrowser父窗口的网页对话框,例如代码:
public IntPtr WebPageDialogHandle
{
get
{
InvokeMethod invoker = new InvokeMethod(( ) =>
{
if (_webPageDialogHandle != IntPtr.Zero && Win32API.IsWindow(_webPageDialogHandle)) {
} else {
_webPageDialogHandle = SearchWebDialog(ParentForm.Handle, Win32API.GW_HWNDPREV);
if (_webPageDialogHandle == IntPtr.Zero)
_webPageDialogHandle = SearchWebDialog(ParentForm.Handle, Win32API.GW_HWNDNEXT);
}
}
);
this.Invoke(invoker);
return _webPageDialogHandle;
}
}private IntPtr SearchWebDialog(IntPtr start, uint direction)
{
int processId, nextProcId;
int threadId = Win32API.GetWindowThreadProcessId(ParentForm.Handle, out processId);
StringBuilder sb = new StringBuilder(256); IntPtr nextWin = Win32API.GetNextWindow(ParentForm.Handle, direction);
int nextTh = Win32API.GetWindowThreadProcessId(nextWin, out nextProcId);
while (nextProcId == processId) {
if (ParentForm.Handle == Win32API.GetParent(nextWin)) {
Win32API.GetClassName(nextWin, sb, sb.Capacity);
if (sb.ToString() == IE_WebDialogClassName) {
_webPageDialogHandle = Win32API.FindWindowExxx(nextWin, IntPtr.Zero, IE_ServerClassName, null);
return _webPageDialogHandle;
}
}
nextWin = Win32API.GetNextWindow(nextWin, direction);
nextTh = Win32API.GetWindowThreadProcessId(nextWin, out processId);
}
return IntPtr.Zero;
}public static IntPtr FindWindowExxx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle)
{
IntPtr res = FindWindowEx(parentHandle, childAfter, lclassName, windowTitle); if (res != IntPtr.Zero)
return res;
while ( (res = FindWindowEx(parentHandle, res, null, null)) != IntPtr.Zero) {
IntPtr aim = FindWindowExxx(res, IntPtr.Zero, lclassName, windowTitle);
if (aim != IntPtr.Zero)
return aim;
}
return IntPtr.Zero;
}
其实窗口的句柄只是内核对象中的一个地址,同一个进程的窗口句柄一般也是连续,正如代码中所示,我们不需要搜索所有的窗口,而只需要进进程ID为边界在WebBrowser父窗口的附近搜索。非模态对话框的父窗口够本是桌面窗口,而不是WebBrowser所在的窗口,所以在SearchWebDialog函数中调用了GetParent函数,而没有使用GetAncestor,因为前者返回的不一定是父窗口,也可能是所有者,这正是非模态对话框与WebBrowser窗口的关系,浏览器窗口是模态对话框的父窗口,而只是非模态框的所有者,而不是其父窗口。
获取非模态对话框的句柄以后,就随便你对它做什么了,发送消息模拟按键、模拟鼠标点击、关闭等,都是可以的了。本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Nocky/archive/2010/12/28/6103875.aspx