Detect Active Window Changed Using C# Without Polling

Detect active window changed using C# without polling

Create a new windows forms project, add a textbox, make it multiline, and set the textbox Dock property to fill, name it Log and paste in the following code (you'll need to add System.Runtime.InteropServices to your usings)...

    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";
}

Detect active window changed using C# with a console application

It can be changed to run as a console application with a few changes. Here is a working code.

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

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
dele = new WinEventDelegate(WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
Application.Run(); //<----
}

static WinEventDelegate dele = null; //STATIC

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 static string GetActiveWindowTitle() //STATIC
{
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 static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) //STATIC
{
Console.WriteLine(GetActiveWindowTitle());
}
}
}

Catch active window switch (also in same application, for example Chrome tabs)

However I have noticed that it does not react in case Google Chrome is
opened and I am switching between Tabs.

Switching between tabs cause focus changes, so you can use EVENT_OBJECT_FOCUS (in addition) to cover this situation.

Is there Windows system event on active window changed?

Yes, you can use SetWinEventHook function.

hEvent = SetWinEventHook(EVENT_SYSTEM_FOREGROUND , 
EVENT_SYSTEM_FOREGROUND , NULL,
WinEventProcCallback, 0, 0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);

.......

VOID CALLBACK WinEventProcCallback ( HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
/* your code here */
}

Get active window without global hooks or polling GetActiveWindow?

I have never found a clean way to get notified. I use GetForegroundWindow with a timer. :(

c# - Get current window title

Can you stick it in a loop on another thread. Have two variables: previousWindow and currentWindow. Keep comparing them, when they change - you update your log file.

Determine when a third-party application becomes active

Thanks spender for the links. I've been able to use the information in those questions to create a reusable component that returns a Process object for the active window and triggers an event when it changes.

The code for this is available here: https://github.com/DanStevens/ActiveWindowWatcher/blob/master/ActiveWindowWatcher.cs



Related Topics



Leave a reply



Submit