See the question and my original answer on StackOverflow

Here is some code based on UI automation events. It gives window opened, closed, and focused events.

C#

[STAThread]
public static void Main(string[] args)
{
    Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, (sender, e) =>
    {
        var element = (AutomationElement)sender;
        var name = element.Current.Name;
        Console.WriteLine("open: " + name + " hwnd:" + element.Current.NativeWindowHandle);
        Automation.AddAutomationEventHandler(WindowPattern.WindowClosedEvent, element, TreeScope.Element, (s, e2) =>
        {
            Console.WriteLine("close: " + name + " hwnd:" + element.Current.NativeWindowHandle);
        });
    });

    Automation.AddAutomationFocusChangedEventHandler((sender, e) =>
    {
        var element = (AutomationElement)sender;
        var name = element.Current.Name;
        Console.WriteLine("focused: " + name + " hwnd:" + element.Current.NativeWindowHandle);
    });
    Console.ReadLine();
    Automation.RemoveAllEventHandlers();
}

C++ equivalent:

#include <windows.h>
#include <stdio.h>
#include <uiautomation.h>

// some useful macros
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)

#define MYTRACE wprintf
#define CHECKHR(expr) {hr=(expr);if(FAILED(hr)){ MYTRACE(L"HR FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }  
#define CHECKWIN32(expr) {if(!(expr)){hr = HRESULT_FROM_WIN32(GetLastError()); MYTRACE(L"WIN32 FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }  
#define CHECKARG(expr) {if(!(expr)){ MYTRACE(L"ARG FAILED line:%u file:%s\n", __LINE__, __WFILE__); hr = E_INVALIDARG; goto cleanup; } }  
#define CHECKMEM(expr) {if(!(expr)){ MYTRACE(L"MEM FAILED line:%u file:%s\n", __LINE__, __WFILE__); hr = E_OUTOFMEMORY; goto cleanup; } } 
#define CORELEASE(expr) {if(expr){ expr->Release(); expr = NULL; } } 
#define HR HRESULT hr=S_OK;

class EventHandler :
  public IUIAutomationEventHandler,
  public IUIAutomationFocusChangedEventHandler
{
private:
  LONG _ref;
  IUIAutomation* _automation;
  HWND _hwnd;
  IUIAutomationElement* _sender;

public:
  EventHandler(IUIAutomation* automation, IUIAutomationElement* sender, HWND hwnd) :
    _ref(1),
    _automation(automation),
    _sender(sender),
    _hwnd(hwnd)
  {
    if (sender)
    {
      sender->AddRef();
    }
  }

  ~EventHandler()
  {
    CORELEASE(_sender);
  }

  // IUnknown
  ULONG STDMETHODCALLTYPE AddRef() { ULONG ret = InterlockedIncrement(&_ref); return ret; }
  ULONG STDMETHODCALLTYPE Release() { ULONG ret = InterlockedDecrement(&_ref); if (!ret) { delete this; return 0; } return ret; }
  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppInterface)
  {
    if (riid == __uuidof(IUnknown))
    {
      *ppInterface = (IUIAutomationEventHandler*)this;
    }
    else if (riid == __uuidof(IUIAutomationEventHandler))
    {
      *ppInterface = (IUIAutomationEventHandler*)this;
    }
    else if (riid == __uuidof(IUIAutomationFocusChangedEventHandler))
    {
      *ppInterface = (IUIAutomationFocusChangedEventHandler*)this;
    }
    else
    {
      *ppInterface = NULL;
      return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
  }

  // IUIAutomationFocusChangedEventHandler
  HRESULT STDMETHODCALLTYPE HandleFocusChangedEvent(IUIAutomationElement* sender)
  {
    HWND hwnd = NULL;
    sender->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd);
    wprintf(L"Window focused hwnd:%p'\n", hwnd);
    return S_OK;
  }

  // IUIAutomationEventHandler
  HRESULT STDMETHODCALLTYPE HandleAutomationEvent(IUIAutomationElement* sender, EVENTID eventID)
  {
    HR;
    HWND hwnd = NULL;
    EventHandler* windowHandler;

    switch (eventID)
    {
    case UIA_Window_WindowOpenedEventId:
      sender->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd);
      wprintf(L"Window opened hwnd:%p\n", hwnd);

      // register for close on this window
      // we build a new handler, this is the only way to remember the hwnd (the close event doesn't have anything)
      windowHandler = new EventHandler(_automation, sender, hwnd); // implicit addref
      CHECKMEM(windowHandler);
      CHECKHR(_automation->AddAutomationEventHandler(UIA_Window_WindowClosedEventId, sender, TreeScope_Element, NULL, windowHandler));
      break;

    case UIA_Window_WindowClosedEventId:
      wprintf(L"Window closed hwnd:%p\n", _hwnd);
      CHECKHR(_automation->RemoveAutomationEventHandler(UIA_Window_WindowClosedEventId, _sender, this));
      Release(); // we release our own reference, 'this' we be deleted sometime when all COM references are gone. don't do 'delete this'!
      break;
    }

  cleanup:
    return hr;
  }
};

int main()
{
  HR;
  IUIAutomationElement* root = NULL;
  EventHandler* handler = NULL;
  IUIAutomation* automation = NULL;

  CoInitializeEx(NULL, COINIT_MULTITHREADED);
  CHECKHR(CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), (void**)&automation));

  CHECKHR(automation->GetRootElement(&root));

  handler = new EventHandler(automation, NULL, NULL);
  CHECKMEM(handler);

  CHECKHR(automation->AddAutomationEventHandler(UIA_Window_WindowOpenedEventId, root, TreeScope_Subtree, NULL, handler));
  CHECKHR(automation->AddFocusChangedEventHandler(NULL, handler));

  wprintf(L"Press any key to stop listening for events.\n");
  getchar();

cleanup:
  if (automation != NULL)
  {
    automation->RemoveAllEventHandlers();
    CORELEASE(automation);
  }

  CORELEASE(handler);
  CORELEASE(root);
  CoUninitialize();
  return hr;
}