July 16th, 2026
intriguing1 reaction

Speculating on how the buggy control panel extension truncated a value that it had right in front of it

Last time, we found that a crash in a control panel extension was caused by pointer truncation. The code had a perfectly good 64-bit pointer in its hand, but somehow lost its mind and opted to throw away the top 32 bits.

How could something like this happen?

My guess is that this code started out as perfectly good 32-bit code:

HWND hwndButton = GetDlgItem(hdlg, ID_BUTTON);
SetWindowLong(hwndButton, GWL_WNDPROC, (LONG)g_originalWndProc);

And then they recompiled it as 64-bit code and got an error.

error C2065: 'GWL_WNDPROC': undeclared identifier

They then went back to the documentation and saw that for 64-bit Windows, GWL_WNDPROC was renamed to GWLP_WNDPROC.

So they fixed it by changing GWL_WNDPROC to GWLP_WNDPROC.

HWND hwndButton = GetDlgItem(hdlg, ID_BUTTON);
SetWindowLong(hwndButton, GWL_WNDPROC, (LONG)g_originalWndProc);

However, the point of renaming the value was not to annoy you. The point of renaming the value was to call your attention to places where pointer truncation is likely to occur. In this case, it’s the final parameter, the original 64-bit window procedure. The build break is telling you that you are probably passing a 32-bit value as something that should be 64-bit. In this case, because it was being cast to (LONG). You are expected to upgrade the GWL_WNDPROC to GWLP_WNDPROC and at the same time upgrade the cast from (LONG) to (LONG_PTR).

HWND hwndButton = GetDlgItem(hdlg, ID_BUTTON);
SetWindowLong(hwndButton, GWL_WNDPROC, (LONG_PTR)g_originalWndProc);

Now, this was likely an oversight rather than a systemic failure, because they did manage to subclass the window properly:

WNDPROC g_originalWndProc;

HWND hwndButton = GetDlgItem(hdlg, ID_BUTTON);
g_originalWndProc = (WNDPROC)SetWindowLong(hwndButton, GWLP_WNDPROC,
    (LONG_PTR)subclassWndProc);

They merely missed a spot. Perhaps the developer got distracted after fixing the symbol name and forgot to come back and fix the pointer.

Next time, we’ll look at why this bug has remained unfixed for so long.

Topics

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.

2 comments

Sort by :
  • Tom Lint 5 hours ago

    Is this a truly ancient application? Otherwise, they really should have been using SetWindowLongPTR from the get-go. They’re setting a pointer. Even if this wasn’t targeting 64-bit code, semantically, SetWindowLongPtr would be the only correct function to use (and, conversely, GetWindowLongPtr for retrieving the old WNDPROC), irrespective of whether SetWindowLongPtr is an alias or not. Something something RTFM

    • Antonio Rodríguez 4 hours ago · Edited

      The fact that they have converted the code from 32 to 64 bits tells us that it probably dates from when 32 bits was the most frequent option, or the only one available. The first x64 version of Windows widely used was Windows 7 (from 2009), and the very first one for consumer devices was Windows XP x64 Edition (from 2005). Your guess is as good as mine, but I'd bet that the code is, at the very least, 15-20 years old, perhaps much more. Maybe SetWindowLongPtr already existed, or maybe not; but even if it did, in code from...

      Read more