From user mode programs, one always
identifies a window by it's handle, and HWND instance. The Win32 api provides a vast number
of API's that allow you to get and set various properties of a given window, and
that is quite sufficient.
However, it's interesting to see how the system maintains this
information internally. It turns out that the internal structure kept by windows
NT for each window contains a number of interesting things, and it's even more
interesting to see how NT manipulates it internally.
For the sake of this article, I'll refer to this internal
structure maintained by NT as the WND structure. The WND structure has a layout
similar to this:
//
// internal window class representations
//
typedef struct CLASSINFO
{
DWORD unk1;
ATOM atomWindowType;
WORD unk2;
DWORD unk3;
DWORD unk4;
DWORD unk5;
DWORD unk6;
DWORD unk7;
DWORD unk8;
CLASSINFO* pSelf;
DWORD unk10;
DWORD unk11;
DWORD dwStyle;
DWORD unk13;
DWORD unk14;
DWORD dwClassBytes;
HINSTANCE hInstance;
} CLASSINFO, *PCLASSINFO;
struct WNDMENU;
//
// possible flag values for dwFlags
//
#define WF_ACTIVECAPTION (0x00000040)
#define WF_ANSI (0x00080000)
//
// All pointers that appear in this struct point to memory
// above the 2GB limit, deep into System Address Space.
// However, like the WND structures themselves, all of the
// data pointed to by them can be found in the Process
// address space by substracting from them the same amount
// we use to find this WND*
//
typedef struct WND {
HWND hWnd;
ULONG unk1;
ULONG unk2;
ULONG unk3;
WND* pSelf; // pointer to self
DWORD dwFlags;
ULONG unk6;
DWORD dwStyleEx;
DWORD dwStyle;
HINSTANCE hInstance;
ULONG unk10;
WND* pNextWnd; // pointer to "next" window
WND* pParentWnd; // pointer to parent wnd. For top-level, this points to the desktop
WND* pFirstChild; // pointer to first child window
WND* pOwnerWnd; // pointer to owner window
RECT rcWnd; // in screen coordinates
RECT rcClient; // in screen coordinates
WNDPROC* pWndProc; // for system classes, this can be > 2GB
CLASSINFO* pWndClass; // pointer to internal window class ???
ULONG unk25;
ULONG unk26;
ULONG unk27;
ULONG unk28;
union {
DWORD dwWndID; // control ID (lower 16-bits)
WNDMENU* pMenu; // pointer to internal menu representation
} id;
ULONG unk30;
ULONG unk31;
ULONG unk32;
WCHAR* pText; // pointer to window caption
DWORD dwWndBytes; // number of window bytes reserved in wlWndExtra
ULONG unk35; // for top level windows, this is pSelf again....???
ULONG unk36;
ULONG wlUserData;
ULONG wlWndExtra[1];
} WND, *PWND;
Matt Pietrek touched briefly the WND structure
in his November 199? "Under the Hood" Column in MSJ, but didn't give
out too much detail of the structure itself. However, he did
something perhaps more interesting: he told us how to the system retrieves a pointer to this
structure when needed.
As it turns out, the internal data of the windows is kept by the
kernel mode components of the Win32 subsystem, which helps protect the internal
data from wrecked user mode components. However, the kernel maps this memory
area to a read-only shared memory section maintained by USER32.DLL in the user
mode accesible address space of each process. This allows many APIs to avoid
switching into kernel mode to retrieve data, like GetWindowRect()
, which helps
improve windowing performance.
Inside USER32.DLL, the API's retrieve a WND* from an HWND by
calling the @ValidateHwnd()
function or one of its variants (like
@ValidateHwndNoRip()
), which in turn, rely on @HMValidateHandle()
.
Unfortunately, you can't call this undocumented function from your own apps, since it isn't exported by USER32.DLL.
Getting the pointer yourself is not hard with the help from a
little assembly code, but it requires that you know where USER32.DLL keeps the
window list in it's shared memory section (pointed to by _gSharedInfo
). You can calculate the
offset into this list from the HWND by extracting the lower 2 bytes
out of the HWND and multiplying it by 12.