Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CBTProc callback not working, setEventHookEx

I have some code here that is targeting windows event hooks in order to write to a log file when triggered. I am running this in powershell. I have successfully used this code to log mouse/keyboard events however when I use WH_CBT 5 using the CBTProc callback I receive no events. Even when using a mouse target of WH_MOUSE_LL 14 works just fine... can someone explain why? Have I missed something... or is it not possible for some reason?

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

Modded code

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();
like image 481
elev8ed Avatar asked Oct 26 '25 21:10

elev8ed


1 Answers

This code logs the HWND that has the focus.

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

The hWnd passed to HookCallback can be a child window (like a list control or tree control, etc.), it is not always the outermost application window like you might be expecting from WH_CBT.

If you need the outermost application window, you can simply do something like:

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

// hwndApp now is the outermost application window
like image 51
David Ching Avatar answered Oct 29 '25 12:10

David Ching



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!