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
Background Color of a Listbox Item (Windows Forms)
Why Does Enumerable.All Return True for an Empty Sequence
Automapper Convert from Multiple Sources
Linq to SQL Using Group by and Count(Distinct)
Why Does (Int)(Object)10M Throw "Specified Cast Is Not Valid" Exception
What Is the Impact of Thread.Sleep(1) in C#
Cancelling a Pending Task Synchronously on the UI Thread
Select Parsed Int, If String Was Parseable to Int
Best Way to Access Com Objects from C#
Why Is Array.Length an Int, and Not an Uint
How to Split a String by Strings and Include the Delimiters Using .Net
Cannot Access a Disposed Object in ASP.NET Core When Injecting Dbcontext
X509Certificate Constructor Exception
.Net Xml Serialization - Storing Reference Instead of Object Copy