The internal WND structure

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.



