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 Find
Window
.
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_
.
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...
I integrated this with my thumbnail code and now it updates great. Thanks!
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!
I forgot to save links in 2020, so I had nothing to clear out. It was that kind of year.
Fair enough! Thanks.
Is there a list of all the macros that I should define before including
Windows.h
? I knewUNICODE
,WIN32_LEAN_AND_MEAN
andNOMINMAX
, but was not aware ofSTRICT
.STRICT is on by default these days (not sure when that changed). You now use NO_STRICT if you don’t want STRICT. See https://docs.microsoft.com/en-us/windows/win32/winprog/disabling-strict
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...