Search code examples
windowswinapimemory-alignment

`CreateWindowEx` Appears to be Returning Incorrectly Aligned Pointer Win32


I have the following code in a Win32 project written in C:

const HWND window = CreateWindowExW(...);

static_assert(alignof *window == alignof (int)); // 1. Always true

assert((uintptr_t) window % alignof (int) == 0); // 2. *FALSE* in general

assert((uintptr_t) window % alignof (short) == 0); // 3. Always true, at least in my testing

<windef.h> includes the following code, which corroborates statement 1:

typedef struct HWND__ { // NOTE: This code is abridged for simplicity
    int unused;
} *HWND;

Statements 1. and 2. are in inherent contradition. Statement 3. leads me to believe that this behavior is a holdover of the Win16 API, where sizeof (int) == 2.

Why is this happening?

Is this a bug in the Win32 API?


Solution

  • HWND might look like a pointer, but it is just a unique identifier with the same number of bits as a pointer that the Win32 Subsystem can then use for internal handle table lookups. Do not trust that typedef that's defined in the header; it is just defining a structure pointer to make sure that it's not implicitly used with other data types. (ie, if it was just uintptr_t or PVOID or an equivalent typedef, then it's difficult to differentiate a set of functions expecting the argument to be a window handle with another set of functions also using uintptr_t for something completely different like a bitmap or icon handle).

    Browsing through the source code for ReactOS (starting from the NtUserCreateWindowEx function) indicates that the returned handle is just a handle table index shifted left by one bit (likely for legacy 16-bit compatibility, as you mentioned) and added to some pre-calculated constant base value. This doesn't necessarily mean that this is what is actually being used by the official Win32 sources, but it may give you an idea about how it may be working internally (given that ReactOS attempts to implement a binary compatible operating system for both user mode and kernel mode).

    EDIT: As mentioned in the comments by user IInspectable, Raymond Chen has published two articles relating to this: How are window manager handles determined in 16-bit Windows and Windows 95? and the follow-up: How are window manager handles determined in Windows NT?