January 4th, 2021

How can I write a program that monitors another window for a change in size or position?

A few days ago, a reader bemoaned, “There’s no way to update the position/aspect ratio of live window thumbnails unless you poll.”

Today’s Little Program monitors another window for a change in its size and position, without polling. It’s basically another variation on the basic “window monitoring” pattern. This time, instead of monitoring the title, we monitor the location (which is the combination of size, position, and shape).

#define UNICODE
#define _UNICODE
#define STRICT
#include <windows.h>
#include <stdio.h>

HWND g_hwndMonitor;

void CALLBACK WinEventProc(
  HWINEVENTHOOK hook,
  DWORD event,
  HWND hwnd,
  LONG idObject,
  LONG idChild,
  DWORD idEventThread,
  DWORD time)
{
  if (hwnd == g_hwndMonitor &&
      idObject == OBJID_WINDOW &&
      idChild == CHILDID_SELF &&
      event == EVENT_OBJECT_LOCATIONCHANGE) {
    RECT rc;
    if (GetWindowRect(g_hwndMonitor, &rc)) {
        printf("window rect is (%d,%d)-(%d,%d)\n",
            rc.left, rc.top, rc.right, rc.bottom);
    }
  }
}

int __cdecl main(int, char**)
{
  g_hwndMonitor = FindWindow(L"Awesome Program", nullptr);
  DWORD processId;
  DWORD threadId = GetWindowThreadProcessId(g_hwndMonitor, &processId);
  HWINEVENTHOOK hook = SetWinEventHook(
    EVENT_OBJECT_LOCATIONCHANGE,
    EVENT_OBJECT_LOCATIONCHANGE,
    nullptr,
    WinEventProc,
    processId,
    threadId,
    WINEVENT_OUTOFCONTEXT);
  MessageBox(nullptr, L"Press OK when bored", L"Title", MB_OK);

  UnhookWinEvent(hook);
  return 0;
}

The program starts by identifying the window it wants to monitor. This is your application’s business logic, so I’ll just fake it with a FindWindow.

We get the thread and process ID for the window and use it to register a thread-specific accessibility event hook, filtered to location changes.

In the event callback, we see if the notification is for the window we are monitoring. If so, we get the window bounds and print it. The attempt to get the window bounds might fail if the window has been destroyed, so watch out for that.¹

¹ One way to track object destruction is with, yup, another accessibility hook, this time watching for EVENT_OBJECT_DESTROY.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

8 comments

Discussion is closed. Login to edit/delete existing comments.

  • Robin Krom

    For those who need something like this in .NET / C#, I wrote some "modern" abstractions for doing low level Win32 things in my open source project here: https://github.com/dapplo/Dapplo.Windows

    This has some most of the low level code implemented for you and is using reactive extensions, making this a bit more functional.

    For example, tracking the location could be done like this:
    <code>

    If you are done, dispose the observable and the registration is removed for you.
    Create...

    Read more
  • switchdesktopwithfade@hotmail.com

    I integrated this with my thumbnail code and now it updates great. Thanks!

  • Peter Cooper Jr.

    At the risk of being completely off topic, did 2020 not have an end-of-year link clearance post? It’s something I look forward to each year and I’d hate to see it go. Thanks!

    • Raymond ChenMicrosoft employee Author

      I forgot to save links in 2020, so I had nothing to clear out. It was that kind of year.

      • Peter Cooper Jr.

        Fair enough! Thanks.

  • 紅樓鍮

    Is there a list of all the macros that I should define before including Windows.h? I knew UNICODE, WIN32_LEAN_AND_MEAN and NOMINMAX, but was not aware of STRICT.

    • Ivan K

      I was reminded of a fact about C, HANDLE, and STRICT over the holidays: there is no STRICT "struct typedef" for straight HANDLEs (probably for a reason I can't spend time to think of right now). I wrote a little personal utility DLL that's about 80% Win32 calls and so decided to use straight C in MSVC 2019 out of dice roll or nostalgia or whatever. I defined STRICT before winapi includes and enabled level...

      Read more