Detectar ventana activa cambiada usando C # sin votación

¿Cómo puede uno invocar una callback cada vez que cambia la ventana activa actual? He visto cómo se podría hacer usando CBTProc. Sin embargo, los eventos globales no son fáciles de enganchar con el código administrado. Estoy interesado en encontrar una forma que no requiera el sondeo. Prefiero un enfoque orientado a eventos.

Saludos

Cree un nuevo proyecto de formularios de Windows, agregue un cuadro de texto, multiplíquelo y configure la propiedad del Dock de la caja de texto para llenar, asígnele el nombre. Registre y pegue el siguiente código (necesitará agregar System.Runtime.InteropServices a sus usos). ..

WinEventDelegate dele = null; public Form1() { InitializeComponent(); dele = new WinEventDelegate(WinEventProc); IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT); } delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime); [DllImport("user32.dll")] static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags); private const uint WINEVENT_OUTOFCONTEXT = 0; private const uint EVENT_SYSTEM_FOREGROUND = 3; [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count); private string GetActiveWindowTitle() { const int nChars = 256; IntPtr handle = IntPtr.Zero; StringBuilder Buff = new StringBuilder(nChars); handle = GetForegroundWindow(); if (GetWindowText(handle, Buff, nChars) > 0) { return Buff.ToString(); } return null; } public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { Log.Text += GetActiveWindowTitle() + "\r\n"; } 

Sé que este hilo es viejo, pero para uso futuro: cuando ejecutas el código, notarás un locking después de un tiempo. Esto es causado por la línea en el constructor de Forma:

 public Form1() { InitializeComponent(); WinEventDelegate dele = new WinEventDelegate(WinEventProc);//< -causing ERROR IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT); } 

En lugar de lo anterior, realice la siguiente modificación:

 public Form1() { InitializeComponent(); dele = new WinEventDelegate(WinEventProc); IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT); } WinEventDelegate dele = null; 

.. funciona ahora como se esperaba!

Puede usar SetWinEventHook y escuchar el evento EVENT_SYSTEM_FOREGROUND . Use el indicador WINEVENT_OUTOFCONTEXT para evitar el problema global-hook.