创build一个Windows钩子来检测菜单点击

我想附加到一个单独的应用程序(例如Microsoft Excel),并检测某个菜单项何时被点击(或新版本中的function区命令,无论)。

我以为我可以使用user32.dllRegisterWindowMessage来做到这一点,但我不知道要拦截哪些消息。 理想情况下,我想概括一下,并检测如下内容:

 "menu item XXX was clicked in the app YYY" 

我发现这个CodeProject文章显示如何注册事件的钩子,如控件的创build,应用程序的启动/停止等,但我找不到如何获得button点击或菜单点击的例子。

这甚至有可能吗? 我在正确的轨道上,还是我需要采取不同的方法?

Solutions Collecting From Web of "创build一个Windows钩子来检测菜单点击"

好吧,所以我无法抗拒这里的挑战:)写了一个小程序,做你想做的。

它是如何工作的SetWindowsHookEx让你放置一个全局的鼠标钩子。 现在 ,你得到XY ,然后使用WindowFromPoint来获取目标窗口的hWnd 。 从这里你可以做任何你喜欢的事情,就我而言,我发了一个WM_GETTEXT来获得它的头衔。

这是程序看起来像实现的东西。 一旦您单击Begin ,它将全局查找右键单击事件,并将它们添加到列表框。 注意 :它需要是一个窗口窗体应用程序,挂钩将无法与控制台应用程序。

在这里输入图像说明

用法(只需创建一个默认的WinForms项目并将其更改为此):

  public partial class MainForm : Form { public MainForm() { InitializeComponent(); } RMouselistner _native; private void button1_Click(object sender, EventArgs e) {//start _native = new RMouselistner(); _native.RButtonClicked += new EventHandler<SysMouseEventInfo>(_native_RButtonClicked); } private void button2_Click(object sender, EventArgs e) {//stop _native.Close(); } void _native_RButtonClicked(object sender, SysMouseEventInfo e) { listBox1.Items.Add(e.WindowTitle); } } 

实现(这是一个代码;))

 public class SysMouseEventInfo : EventArgs { public string WindowTitle { get; set; } } public class RMouselistner { public RMouselistner() { this.CallBack += new HookProc(MouseEvents); //modulee mod = Assembly.GetExecutingAssembly().Getmodulees()[0]; //IntPtr hMod = Marshal.GetHINSTANCE(mod); using (Process process = Process.GetCurrentProcess()) using (Processmodulee module = process.Mainmodulee) { IntPtr hmodulee = GetmoduleeHandle(module.moduleeName); _hook = SetWindowsHookEx(WH_MOUSE_LL, this.CallBack, hmodulee, 0); //if (_hook != IntPtr.Zero) //{ // Console.WriteLine("Started"); //} } } int WH_MOUSE_LL = 14; int HC_ACTION = 0; HookProc CallBack = null; IntPtr _hook = IntPtr.Zero; public event EventHandler<SysMouseEventInfo> RButtonClicked; int MouseEvents(int code, IntPtr wParam, IntPtr lParam) { //Console.WriteLine("Called"); if (code < 0) return CallNextHookEx(_hook, code, wParam, lParam); if (code == this.HC_ACTION) { // Left button pressed somewhere if (wParam.ToInt32() == (uint)WM.WM_RBUTTONDOWN) { MSLLHOOKSTRUCT ms = new MSLLHOOKSTRUCT(); ms = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); IntPtr win = WindowFromPoint(ms.pt); string title = GetWindowTextRaw(win); if (RButtonClicked != null) { RButtonClicked(this, new SysMouseEventInfo { WindowTitle = title }); } } } return CallNextHookEx(_hook, code, wParam, lParam); } public void Close() { if (_hook != IntPtr.Zero) { UnhookWindowsHookEx(_hook); } } public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam); [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)] public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId); [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); [System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] public static extern IntPtr GetmoduleeHandle(string lpmoduleeName); [DllImport("user32.dll")] static extern IntPtr WindowFromPoint(int xPoint, int yPoint); [DllImport("user32.dll")] static extern IntPtr WindowFromPoint(POINT Point); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [Out] StringBuilder lParam); public static string GetWindowTextRaw(IntPtr hwnd) { // Allocate correct string length first //int length = (int)SendMessage(hwnd, (int)WM.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero); StringBuilder sb = new StringBuilder(65535);//THIS COULD BE BAD. Maybe you shoudl get the length SendMessage(hwnd, (int)WM.WM_GETTEXT, (IntPtr)sb.Capacity, sb); return sb.ToString(); } } [StructLayout(LayoutKind.Sequential)] public struct MSLLHOOKSTRUCT { public POINT pt; public int mouseData; public int flags; public int time; public UIntPtr dwExtraInfo; } enum WM : uint {//all windows messages here WM_RBUTTONDOWN = 0x0204, WM_GETTEXT = 0x000D, WM_GETTEXTLENGTH = 0x000E } [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; public POINT(int x, int y) { this.X = x; this.Y = y; } }