CBTProc 回调不起作用,setEventHookEx

CBTProc callback not working, setEventHookEx

我这里有一些代码针对 windows 事件挂钩,以便在触发时写入日志文件。我在 powershell 中 运行 这个。我已成功使用此代码记录 mouse/keyboard 事件,但是当我使用 WH_CBT 5 使用 CBTProc 回调时,我没有收到任何事件。即使使用 WH_MOUSE_LL 14 的鼠标目标也能正常工作...有人可以解释为什么吗?我是不是漏掉了什么……或者由于某种原因不可能?

https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx

Add-Type -TypeDefinition @"
using System;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyLogger {

  public static class Program {
    private const int HOOK_CODE = 5;
    private const int CALLBACK_CODE = 9;
    private const string logPath = @"c:\MyTest.txt";

    private const string logFileName = "log.txt";

    private static StreamWriter logFile;

    private static HookProc hookProc = HookCallback;
    private static IntPtr hookId = IntPtr.Zero;

    public static void Main() {

      logFile = File.AppendText(logPath);
      logFile.AutoFlush = true;

      hookId = SetHook(hookProc);
      Application.Run();
      UnhookWindowsHookEx(hookId);
    }

    private static IntPtr SetHook(HookProc hookProc) {
      IntPtr moduleHandle = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
      return SetWindowsHookEx(HOOK_CODE, hookProc, moduleHandle, 0);
    }

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

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
      logFile.WriteLine("gg");


      return CallNextHookEx(hookId, nCode, wParam, lParam);
    }

    [DllImport("user32.dll")]
    private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll")]
    private static extern bool UnhookWindowsHookEx(IntPtr hhk);

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

    [DllImport("kernel32.dll")]
    private static extern IntPtr GetModuleHandle(string lpModuleName);
  }
}
"@ -ReferencedAssemblies System.Windows.Forms

[MyLogger.Program]::Main();

修改代码

Add-Type -TypeDefinition @"
using System;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyLogger {

  public static class Program {

    private const int WINEVENT_OUTOFCONTEXT = 0;
    private const int EVENT_OBJECT_FOCUS = 0x8005;

    private const string logPath = @"c:\MyTest.txt";

    private const string logFileName = "log.txt";

    private static StreamWriter logFile;

    private static HookProc hookProc = HookCallback;
    private static IntPtr hookId = IntPtr.Zero;

    public static void Main() {

      logFile = File.AppendText(logPath);
      logFile.AutoFlush = true;

      hookId = SetHook(hookProc);
      Application.Run();

    }

    private static IntPtr SetHook(HookProc hookProc) {

      return SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, null, hookProc, 0, 0, WINEVENT_OUTOFCONTEXT);
    }

    private delegate IntPtr HookProc(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime);

    private static IntPtr HookCallback(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime) {
      logFile.WriteLine("gg");



    }
    internal enum SetWinEventHookFlags
      {
          WINEVENT_INCONTEXT = 4,
          WINEVENT_OUTOFCONTEXT = 0,
          WINEVENT_SKIPOWNPROCESS = 2,
          WINEVENT_SKIPOWNTHREAD = 1
      } 

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr SetWinEventHook(int eventMin, int eventMax, IntPtr hmodWinEventProc, HookProc lpfnWinEventProc, int idProcess, int idThread, int dwflags);
    private static extern int UnhookWinEvent(IntPtr hWinEventHook);


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

    [DllImport("kernel32.dll")]
    private static extern IntPtr GetModuleHandle(string lpModuleName);
  }
}
"@ -ReferencedAssemblies System.Windows.Forms

[MyLogger.Program]::Main();

与WH_MOUSE_LL不同,WH_CBT的回调必须在被hook的进程中;因此回调必须在 DLL 中。

此代码记录具有焦点的 HWND。

Add-Type -TypeDefinition @"
using System;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyLogger {
    public static class Program {
        private const int WINEVENT_OUTOFCONTEXT = 0;
        private const int EVENT_OBJECT_FOCUS = 0x8005;
        private const int WM_GETTEXT = 0x000D;

        private const string logPath = @"c:\Temp\MyTest.txt";

        private static StreamWriter logFile;

        private static HookProc hookProc = HookCallback;
        private static IntPtr hookId = IntPtr.Zero;

        public static void Main() {
            logFile = File.AppendText(logPath);
            logFile.AutoFlush = true;

            hookId = SetHook(hookProc);
            Application.Run();
        }

        private static IntPtr SetHook(HookProc hookProc) {
            return SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, IntPtr.Zero, hookProc, 0, 0, WINEVENT_OUTOFCONTEXT);
        }

        private delegate void HookProc(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime);

        private static void HookCallback(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime) {
            logFile.WriteLine(string.Format("{0}", hWnd));
        }
        internal enum SetWinEventHookFlags
        {
            WINEVENT_INCONTEXT = 4,
            WINEVENT_OUTOFCONTEXT = 0,
            WINEVENT_SKIPOWNPROCESS = 2,
            WINEVENT_SKIPOWNTHREAD = 1
        } 

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr SetWinEventHook(int eventMin, int eventMax, IntPtr hmodWinEventProc, HookProc lpfnWinEventProc, int idProcess, int idThread, int dwflags);

        [DllImport("user32.dll")]
        private static extern bool UnhookWinEvent(IntPtr hWinEventHook);
    }
}
"@ -ReferencedAssemblies System.Windows.Forms

[MyLogger.Program]::Main();

传递给HookCallbackhWnd可以是子window(像列表控件或树控件等),不一定是最外层的应用window 就像您对 WH_CBT 的期望一样。

如果您需要最外层的应用程序 window,您可以简单地执行以下操作:

HWND hwnd = hWndPassedToHookCallback;
HWND hwndApp;
do
{
    hwndApp = hwnd;
    hwnd = GetParent(hwnd)
} while(hwnd);

// hwndApp now is the outermost application window