2012-07-23 18 views
24

Tengo el siguiente código que obtuve de algún lugar para capturar eventos del mouse. Lo modifiqué e hice un controlador de eventos para poder suscribirme. Los eventos del mouse se capturan correctamente. Pero nunca dispara el controlador de eventos. ¿Alguien puede descubrir qué está mal con el código?Controlador global de eventos del mouse

public static class MouseHook 

{ 
    public static event EventHandler MouseAction = delegate { }; 

    public static void Start() 
    { 
     _hookID = SetHook(_proc); 


    } 
    public static void stop() 
    { 
     UnhookWindowsHookEx(_hookID); 
    } 

    private static LowLevelMouseProc _proc = HookCallback; 
    private static IntPtr _hookID = IntPtr.Zero; 

    private static IntPtr SetHook(LowLevelMouseProc proc) 
    { 
     using (Process curProcess = Process.GetCurrentProcess()) 
     using (ProcessModule curModule = curProcess.MainModule) 
     { 
      return SetWindowsHookEx(WH_MOUSE_LL, proc, 
       GetModuleHandle(curModule.ModuleName), 0); 
     } 
    } 

    private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam); 

    private static IntPtr HookCallback(
     int nCode, IntPtr wParam, IntPtr lParam) 
    { 
     if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam) 
     { 
      MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); 
      MouseAction(null,new EventArgs()); 
     } 
     return CallNextHookEx(_hookID, nCode, wParam, lParam); 
    } 

    private const int WH_MOUSE_LL = 14; 

    private enum MouseMessages 
    { 
     WM_LBUTTONDOWN = 0x0201, 
     WM_LBUTTONUP = 0x0202, 
     WM_MOUSEMOVE = 0x0200, 
     WM_MOUSEWHEEL = 0x020A, 
     WM_RBUTTONDOWN = 0x0204, 
     WM_RBUTTONUP = 0x0205 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct POINT 
    { 
     public int x; 
     public int y; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct MSLLHOOKSTRUCT 
    { 
     public POINT pt; 
     public uint mouseData; 
     public uint flags; 
     public uint time; 
     public IntPtr dwExtraInfo; 
    } 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr SetWindowsHookEx(int idHook, 
     LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool UnhookWindowsHookEx(IntPtr hhk); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, 
     IntPtr wParam, IntPtr lParam); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr GetModuleHandle(string lpModuleName); 


} 

Me suscribo a esto como este.

MouseHook.Start(); 
    MouseHook.MouseAction += new EventHandler(Event); 

Función que recibe el evento.

private void Event(object sender, EventArgs e) { Console.WriteLine("Left mouse click!"); } 

Actualización: que armó el código de trabajo en un open source nuget package for user action hooks.

+1

Esto no puede funcionar en una aplicación de modo consola, su programa debe bombear un bucle de mensajes. Application.Run() es obligatorio. –

+0

De hecho, uso el código anterior dentro de mi aplicación WPF. Llamo a la clase MouseHook desde el método Onstartup de App.cs. – justcoding124

+0

Para todas las sensaciones de que esto hace que el mouse se arrastre, ejecútelo en un proceso elevado separado y use hilos separados para manejar eventos. – justcoding124

Respuesta

20
 return SetWindowsHookEx(WH_MOUSE_LL, proc, 
      GetModuleHandle(curModule.ModuleName), 0); 

Este código fallará cuando se ejecuta en .NET 4 en una versión de Windows antes que Windows 8. CLR ya no simula los controladores de módulos no administrados para los ensamblados administrados. No puede detectar esta falla en su código porque le falta la comprobación de errores requerida. Ambos en GetModuleHandle y SetWindowsHookEx. Nunca omita la comprobación de errores cuando pinvoke, el winapi no arroja excepciones. Compruebe si devuelven IntPtr.Zero y simplemente lanzan una excepción Win32Exception cuando lo hagan.

La solución es simple, SetWindowsHookEx() requiere un identificador de módulo válido pero no lo usa cuando configura un gancho de mouse de bajo nivel. Entonces, cualquier manejador servirá, puede pasar el manejador de user32.dll, siempre cargado en una aplicación .NET. Solución:

IntPtr hook = SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle("user32"), 0); 
    if (hook == IntPtr.Zero) throw new System.ComponentModel.Win32Exception(); 
    return hook; 
+0

Gracias. Pero modifiqué el código con la corrección. Solía ​​mostrar las coordenadas cuando uso Console.WriteLine (hookStruct.pt.x + "," + hookStruct.pt .y) dentro de la función HookCallback. Ahora no funciona. – justcoding124

+0

Erm, espera, esto comenzó con "no funciona". ¿En realidad estaba funcionando? ¿Al menos puedes documentar la versión de .NET y Windows que estás usando? ver excepciones de la primera oportunidad en la ventana de resultados? –

+0

Sí, estaba dando las coordenadas del mouse cuando estaba trabajando ayer. En realidad, verifiqué si el evento se desencadena utilizando el seguimiento de la ruta de depuración. Sí, pero Console.WriteLine (" algo ") no muestra ningún resultado. Creo que el console.writeline no está funcionando correctamente. Strange – justcoding124

8

He copiado el código en un simple formulario de ventanas y su trabajo a medida que se describe lo que debería. ¿Cómo lo estás usando exactamente? ¿Dónde estás comenzando y adjuntando el evento?

Y por el amor completo este es el código que terminó con - partió de una forma simple plantilla de C#

using System; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 

      MouseHook.Start(); 
      MouseHook.MouseAction += new EventHandler(Event); 
     } 

     private void Event(object sender, EventArgs e) { Console.WriteLine("Left mouse click!"); } 
    } 

    public static class MouseHook 
    { 
     public static event EventHandler MouseAction = delegate { }; 

     public static void Start() 
     { 
      _hookID = SetHook(_proc); 


     } 
     public static void stop() 
     { 
      UnhookWindowsHookEx(_hookID); 
     } 

     private static LowLevelMouseProc _proc = HookCallback; 
     private static IntPtr _hookID = IntPtr.Zero; 

     private static IntPtr SetHook(LowLevelMouseProc proc) 
     { 
      using (Process curProcess = Process.GetCurrentProcess()) 
      using (ProcessModule curModule = curProcess.MainModule) 
      { 
       return SetWindowsHookEx(WH_MOUSE_LL, proc, 
        GetModuleHandle(curModule.ModuleName), 0); 
      } 
     } 

     private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam); 

     private static IntPtr HookCallback(
      int nCode, IntPtr wParam, IntPtr lParam) 
     { 
      if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam) 
      { 
       MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); 
       MouseAction(null, new EventArgs()); 
      } 
      return CallNextHookEx(_hookID, nCode, wParam, lParam); 
     } 

     private const int WH_MOUSE_LL = 14; 

     private enum MouseMessages 
     { 
      WM_LBUTTONDOWN = 0x0201, 
      WM_LBUTTONUP = 0x0202, 
      WM_MOUSEMOVE = 0x0200, 
      WM_MOUSEWHEEL = 0x020A, 
      WM_RBUTTONDOWN = 0x0204, 
      WM_RBUTTONUP = 0x0205 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct POINT 
     { 
      public int x; 
      public int y; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct MSLLHOOKSTRUCT 
     { 
      public POINT pt; 
      public uint mouseData; 
      public uint flags; 
      public uint time; 
      public IntPtr dwExtraInfo; 
     } 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern IntPtr SetWindowsHookEx(int idHook, 
      LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     private static extern bool UnhookWindowsHookEx(IntPtr hhk); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, 
      IntPtr wParam, IntPtr lParam); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern IntPtr GetModuleHandle(string lpModuleName); 


    } 
} 
+0

Si quiero saber las coordenadas de MouseClicks, ¿qué debo hacer? –

+0

Funciona para todos los eventos de botón de mouse, excepto el quinto botón. En realidad, los botones 4 y 5 devuelven el mismo código. – Masum

+0

Acabo de hacer esto. public static int x = 0; // va en Program.cs y MyConsoleApp.Program.x = hookStruct.pt.x; // encontrado en HookCallback –

Cuestiones relacionadas