2

I have some code that will take a screenshot of the active window. My boss would like the code I have to run each time the active window changes. Example:

  • Open up calculator - Screenshot is taken
  • Switch focus to notepad - Screenshot is taken
  • Switch focus to Chrome - Screenshot is taken

The first thought that came to my mind was to store the handle of the current active window's handle in a variable and then continually check to see if the current active window's handle is the same as the value in the variable. Is there a way to subscribe to the events happening in my computer and have it tell me whenever the active window changes?

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
Clint
  • 33
  • 5
  • I hope your boss isn't going to use this code to monitor his employees! If so, I'm glad I don't work there! :P Besides, I think there are already commercial applications available that do this. – Chris Dunaway Sep 16 '13 at 16:04
  • I am doing a work term at a network security research group. From what I can tell this will actually be used to study malware. As for there already being commercial applications available to do this - I would imagine there is. The reason I am doing it myself is that once I am finished developing this it will be added to a program that my boss is working on himself. – Clint Sep 16 '13 at 18:42

1 Answers1

4

Please look at following methods available in Win32 API,

    SetWinEventHook()
    UnhookWinEvent()

This will help you to detect the window changed events.

Sample code

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

class NameChangeTracker
{
    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);

    [DllImport("user32.dll")]
    static extern bool UnhookWinEvent(IntPtr hWinEventHook);

    const uint EVENT_OBJECT_NAMECHANGE = 0x800C;
    const uint WINEVENT_OUTOFCONTEXT = 0;

    // Need to ensure delegate is not collected while we're using it,
    // storing it in a class field is simplest way to do this.
    static WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc);

    public static void Main()
    {
        // Listen for name change changes across all processes/threads on current desktop...
        IntPtr hhook = SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, IntPtr.Zero,
                procDelegate, 0, 0, WINEVENT_OUTOFCONTEXT);

        // MessageBox provides the necessary mesage loop that SetWinEventHook requires.
        // In real-world code, use a regular message loop (GetMessage/TranslateMessage/
        // DispatchMessage etc or equivalent.)
        MessageBox.Show("Tracking name changes on HWNDs, close message box to exit.");

        UnhookWinEvent(hhook);
    }

    static void WinEventProc(IntPtr hWinEventHook, uint eventType,
        IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
    {
        // filter out non-HWND namechanges... (eg. items within a listbox)
        if(idObject != 0 || idChild != 0)
        {
            return;
        }
        Console.WriteLine("Text of hwnd changed {0:x8}", hwnd.ToInt32()); 
    }
}
Rajesh Subramanian
  • 6,400
  • 5
  • 29
  • 42