2012-07-23 3 views
24

마우스 이벤트를 캡쳐하기 위해 다음과 같은 코드를 가지고 있습니다. 이벤트 핸들러를 수정하여 구독 할 수 있도록했습니다. 마우스 이벤트가 올바르게 캡쳐됩니다. 하지만 결코 이벤트 처리기를 실행하지 않습니다. 아무도 코드를 잘못 이해할 수 있습니까?전체 마우스 이벤트 핸들러

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); 


} 

나는 이렇게 신청합니다.

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

이벤트 수신 기능.

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

업데이트 : 나는 당신이해야 설명한대로 그냥 간단한 창 형태로 코드와 작업을 복사 된 open source nuget package for user action hooks.

+1

콘솔 모드 앱에서는 작동하지 않습니다. 프로그램에서 메시지 루프를 가동해야합니다. Application.Run()이 필요합니다. –

+0

실제로 WPF 응용 프로그램에서 위 코드를 사용합니다. App.cs의 Onstartup 메서드에서 MouseHook 클래스를 호출합니다. – justcoding124

+0

이로 인해 마우스가 끌리는 모든 느낌에 대해 별도의 상승 된 프로세스에서 실행하고 별도의 스레드를 사용하여 이벤트를 처리하십시오. – justcoding124

답변

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

실패하는 간단한 C# 양식 서식 파일에서 시작 CLR은 더 이상 관리되는 어셈블리에 대한 관리되지 않는 모듈 핸들을 시뮬레이트하지 않습니다. 필요한 오류 검사가 누락되어 코드에서이 오류를 감지 할 수 없습니다. GetModuleHandle 및 SetWindowsHookEx에서 둘 다. pinvoke 때 오류 검사를 건너 뛰지 마십시오. winapi는 예외를 발생시키지 않습니다. 그들이 IntPtr.Zero를 반환하는지 확인하고 단순히 Win32Exception을 던집니다.

수정 사항은 간단하지만 SetWindowsHookEx()에는 유효한 모듈 핸들이 필요하지만 저수준 마우스 훅을 설정할 때 실제로 사용하지는 않습니다. 그래서 어떤 핸들이든, 당신은 user32.dll에 대한 핸들을 전달할 수 있습니다. 항상 .NET 어플리케이션에로드됩니다. 수정 :

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

고마워.하지만 수정 코드를 수정했습니다. Console.WriteLine (hookStruct.pt.x + ","+ hookStruct.pt 사용하면 좌표를 표시하는 데 사용되는 .y) HookCallback 함수 안에서. – justcoding124

+0

음, 잠깐, 이건 "작동하지 않아"시작 했어. 실제로 작동 했어? 적어도 사용중인 .NET 및 Windows의 버전을 문서화 할 수 있습니까? 출력 창에서 첫 번째 예외가 발생합니까? –

+0

예, 어제 작업 할 때 마우스 좌표를 지정했습니다. 실제로 디버그 경로 추적을 사용하여 이벤트가 발생했는지 확인했습니다. 예, 그렇습니다! Console.WriteLine (" 뭔가 ") 출력을 표시하지 않습니다. console.writeline 제대로 작동하지 않는 것 같아요. 이상한 – justcoding124

8

에 함께 작업 코드를 넣습니다. 어떻게 정확히 사용하고 있습니까? 이벤트 시작 및 첨부는 어디에서합니까?

그리고 완전성을 위해

이 내가 함께 결국 코드는이 - 당신이 Windows 버전에 .NET 4를 실행할 때이 코드는

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

mouseClicks의 좌표를 알고 싶다면 어떻게해야합니까? –

+0

다섯 번째 단추를 제외한 모든 마우스 단추 이벤트에 사용됩니다. 실제로 4 번째와 5 번째 버튼은 같은 코드를 반환합니다. – Masum

+0

방금 ​​했어요. 공공 정적 int 엑스 = 0; // Program.cs 및 MyConsoleApp.Program.x = hookStruct.pt.x; // HookCallback에서 찾았습니다 –