THREADINFO

The THREADINFO (formally tagTHREADINFO) is the most of what WIN32K.SYS keeps about a thread. A portion at its start is reproduced as a W32THREAD (formally _W32THREAD), apparently as an unnamed member. It is not clear what governs the separation.

No thread is born with a THREADINFO and many execute to their end without ever having one—and not just for being system threads that execute no user-mode code at all. To get a THREADINFO a thread must try to use at least some of the extensive but optional GUI functionality that Windows is known and loved for. When a thread calls a system service that is not yet defined for the thread, the kernel attempts to convert the thread to a GUI thread. This gets the thread connected with WIN32K.SYS in kernel mode and its support for USER32.DLL and GDI32.DLL, among others, in user mode—and gives the thread an additional service descriptor table so that those DLLs can communicate with WIN32K. Though the distribution of the work involved in this conversion varies between versions, the mechanism is essentially unchanged since version 3.51 prepared for the introduction of WIN32K in version 4.0.

Documentation Status

Neither the W32THREAD nor the THREADINFO is documented, but structural details of the W32THREAD—more or less equivalent to having a C-language definition—are disclosed as type information in the public symbol files for WIN32K.SYS starting with Windows XP. The larger THREADINFO is apparently more secret. Though symbol files for Windows 8 and higher name the THREADINFO in the C++ decorations of internal routines, type information for the structure is present in symbol files for Windows 7 only—not before and not since.

For some versions before Windows XP, Microsoft’s names for some, and even all, members of both structures are known with varying confidence from the output of one or another debugger command as implemented in the USEREXTS.DLL or USERKDX.DLL debugger extensions which Microsoft published with one or another Device Driver Kit (DDK). Nobody would sensibly count this as documentation. It does show, however, that Microsoft understood for a while that knowledge of the THREADINFO may help programmers in the depths of debugging what they’re doing with Windows!

Access

The THREADINFO has long been a kernel-mode structure allocated from per-session paged pool, but although it is not accessible from user mode its address is readily available to user-mode software, even with low integrity, even as late as Windows 10, through all sorts of techniques from all sorts of places.

Most direct and obvious is that in each TEB for a GUI thread, the Win32ThreadInfo member, reliably at offset 0x40 since version 3.51, is formally a pointer to void but what it actually holds is the kernel-mode address of the THREADINFO. Less direct but ubiquitous is that the table of handles to user objects is in shared memory such that any user-mode process that can find the SHAREDINFO structure and knows that the aheList member addresses an array of HANDLEENTRY structures can get THREADINFO addresses by the bucketload because in each HANDLEENTRY for a user object that can be owned by a thread (as can a window, for instance) the pOwner member is the address of the owning thread’s THREADINFO.

These kernel-mode addresses’ presence in user-mode memory—despite increasing effort by Microsoft to eliminate such leakage in general—is perhaps a relic from the earliest Windows versions. Before version 4.0, the THREADINFO was a user-mode structure. Much of the work that is since done in kernel mode by WIN32K.SYS was instead done in user mode by WINSRV.DLL in the CSRSS.EXE process. Especially notable in the present context is a continuous history of a routine named xxxCreateThreadInfo now in WIN32K but with the same name in WINSRV version 3.51 and with an even earlier existence in version 3.10 as plain CreateThreadInfo.

Kernel Mode

In kernel mode, each KTHREAD has a Win32Thread member whose value is returned by the exported function PsGetThreadWin32Thread in version 5.1 and higher. Starting with version 5.2 from Windows Server 2003 SP1, the kernel also exports a PsGetCurrentThreadWin32Thread which, of course, reads this member specifically from the current thread’s KTHREAD. The contemporaneous elaboration PsGetCurrentThreadWin32ThreadAndEnterCriticalRegion does the same but also puts the thread into a critical region (as if to have called KeEnterCriticalRegion) and indirectly returns the thread’s process ID. None of these functions are documented, but all three are declared in the NTOSP.H that was disclosed in some editions of the Windows Driver Kit (WDK) for Windows 10.

The Win32Thread in the KTHREAD also is formally a pointer to void. Historically, what it actually points to, if it points to anything, is the THREADINFO. In version 10.0, however, it points to a W32THREADNONPAGED that is in session-global non-paged pool and whose pW32Thread is in turn a pointer to the THREADINFO (which, remember, is in per-session paged pool).

Layout

Not only is the THREADINFO highly variable between versions but in the one version for which publicly available symbol files have type information not just for the W32THREAD but for the THREADINFO too, reconciling the information against the matching executable shows immediately that the THREADINFO as described in the symbol files is not the full story. The memory block the THREADINFO is created in is larger than is declared for the structure, yet the additional space is accessed as if for members of a larger structure. It could be that the THREADINFO is itself a reduction from an even more secret structure, but close inspection shows something more interesting: the THREADINFO as described by type information in the symbol file for WIN32K is not the THREADINFO that the matching WIN32K executable actually uses. Even the following table just of changing sizes is therefore not just more than usually complex but more than usually uncertain.

Version W32THREAD THREADINFO Remarks
Size (x86) Size (x64) SIze (x86) Size (x64)
3.10     0x026C    
3.51     0x01F8    
early 4.0 (before Windows NT 4.0 SP3) 0x38   0x0148    
late 4.0 (Windows NT 4.0 SP3 and higher) 0x38   0x0150    
5.0 0x1C   0x013C    
5.1 0x28   0x014C    
5.2 0x28 0x60 0x0150 0x0278  
6.0 0x28 0x60 0x0164 0x0298  
6.1 0xB4 0x0150 0x0220 0x03D0 symbol files have 0x0208 and 0x03A8 for THREADINFO size
6.2 0xC0 0x0168 0x0278 0x0468  
6.3 0xC0 0x0168 0x0298 0x0490  
10.0 0xC4 0x0170 0x02D0 0x04E0  

That the THREADINFO shrinks by nearly half before it starts the continuing growth that would ordinarily be expected is because three relatively large structures that are later built on the stack or in dynamically allocated memory started out in the THREADINFO itself.

W32THREAD

For versions 5.1 and higher, offsets, types and Microsoft’s names for the first part of the THREADINFO are known from type information in public symbol files. For versions 4.0 and 5.0, offsets and Microsoft’s names are known with good confidence from the output of the debugger’s !dso command as supported by the USEREXTS.DLL and USERKDX.DLL debugger extensions for these versions.

Memory for the THREADINFO is allocated by the kernel in version 4.0, the required size having been communicated by WIN32K as an argument to the undocumented (and highly variable) PsEstablishWin32Callouts function. The first 0x20 bytes of the THREADINFO get copied from the kernel’s service descriptor table. The remainder is zero-initialised, to be completed by WIN32K. It is not known how service descriptor table entries are represented in Microsoft’s definitions. Version 5.0 redistributed the work, such that the THREADINFO is instead created by WIN32K and the service descriptor tables stay with the kernel.

Offset (x86) Offset (x64) Definition Versions Remarks
0x00 (4.0)  
<unknown-type> ServiceDescriptorTable [2];
4.0 only  
0x20 (4.0);
0x00
0x00
ETHREAD *Thread;
4.0 only  
ETHREAD *pEThread;
5.0 and higher  
0x24 (4.0)  
CLIENT_ID RealClientId;
4.0 only  
0x2C (4.0)  
PVOID GdiCachedProcessHandle;
4.0 only  
0x04 0x08
ULONG RefCount;
5.0 and higher  
0x08 0x10
TL *ptlW32;
5.0 and higher  
0x30 (4.0);
0x0C
0x18
PVOID pgdiDcattr;
4.0 and higher  
0x34 (4.0);
0x10
0x20
PVOID pgdiBrushAttr;
4.0 and higher last W32THREAD member in 4.0
0x14 0x28
PVOID pUMPDObjs;
5.0 to 6.1  
LIST_ENTRY UMPDOBJList;
10.0  
0x18 (5.0 to 6.3);
0x1C
0x30 (5.1 to 6.3);
0x38
PVOID pUMPDHeap;
5.0 and higher last W32THREAD member in 5.0
0x1C (5.1)  
ULONG dwEngAcquireCount;
5.1 only  
0x20 (5.1)  
PVOID pSemTable;
5.1 only  
0x1C (6.2 to 6.3) 0x38 (6.2 to 6.3)
PVOID DxThread;
6.2 to 6.3 next at 0x28 and 0x50
0x24 (5.1);
0x1C (5.2 to 6.1);
0x20 (6.2 to 6.3)
0x38 (5.2 to 6.1);
0x40 (6.2 to 6.3)
PVOID pUMPDObj;
5.2 to 6.3 last W32THREAD member in 5.1
0x24 (6.2 to 6.3);
0x20
0x40 (5.2 to 6.1);
0x48 (6.2 to 6.3);
0x40
PVOID pProxyPort;
late 5.2 and higher (x64);
6.2 and higher (x86)
 
0x28 (6.2 to 6.3);
0x24
0x48 (5.2 to 6.1);
0x50 (6.2 to 6.3);
0x48
PVOID pClientID;
late 5.2 and higher (x64);
6.2 and higher (x86)
 
0x28 0x50
PVOID DxThread;
10.0 and higher previously at 0x1C and 0x38
0x20 (5.2 to 6.1);
0x2C
0x50 (5.2 to 6.1);
0x58
LIST_ENTRY GdiTmpAllocList;
5.2 only last W32THREAD member in 5.2
LIST_ENTRY GdiTmpTgoList;
6.0 and higher last W32THREAD member in 6.0
0x28 (6.1);
0x34
0x60 (6.1);
0x68
ULONG pRBRecursionCount;
6.1 and higher  
0x2C (6.1);
0x38
0x64 (6.1);
0x6C
ULONG pNonRBRecursionCount;
6.1 and higher  
0x30 (6.1);
0x3C
0x68 (6.1);
0x70
TLSPRITESTATE tlSpriteState;
6.1 and higher  
0x90 (6.1);
0x9C
0x0110 (6.1);
0x0118
PVOID pSpriteState;
6.1 and higher  
0x94 (6.1);
0xA0
0x0118 (6.1);
0x0120
PVOID pDevHTInfo;
6.1 and higher  
0x98 (6.1);
0xA4
0x0120 (6.1);
0x0128
ULONG ulDevHTInfoUniqueness;
6.1 and higher  
0x9C (6.1);
0xA8
0x0128 (6.1);
0x0130
PVOID pdcoAA;
6.1 and higher  
0xA0 (6.1);
0xAC
0x0130 (6.1);
0x0138
PVOID pdcoRender;
6.1 and higher  
0xA4 (6.1);
0xB0
0x0138 (6.1);
0x0140
PVOID pdcoSrc;
6.1 and higher  
0xA8 (6.1);
0xB4
0x0140 (6.1);
0x0148
BOOLEAN bEnableEngUpdateDeviceSurface;
6.1 and higher  
0xA9 (6.1);
0xB5
0x0141 (6.1);
0x0149
BOOLEAN bIncludeSprites;
6.1 and higher  
0xB6 0x014A
BOOLEAN bEnableAppContainerRendering;
6.3 and higher  
0xAC (6.1);
0xB8
0x0144 (6.1);
0x014C
ULONG ulWindowSystemRendering;
6.1 and higher  
0xB0 (6.1);
0xBC
0x0148 (6.1);
0x0150
ULONG iVisRgnUniqueness;
6.1 and higher last W32THREAD member in 6.1;
last W32THREAD member in 6.2 (x86);
last W32THREAD member in 6.3 (x86)
  0x0158
ULONGLONG RefCountInc;
6.2 and higher  
  0x0160
ULONGLONG RefCountDec;
6.2 and higher last W32THREAD member in 6.2 (x64);
last W32THREAD member in 6.3 (x64)
0xC0 0x0168
PVOID pUmfdTls;
10.0 and higher last W32THREAD member in 10.0

THREADINFO Continuation

For the rest of the THREADINFO, type information is known in public symbol files for version 6.1 only. Microsoft’s names for some members in versions 3.51 to 5.0 inclusive are known from the output of debugger commands. Most noticeable is the !dti command. More notable for versions 4.0 and 5.0 is the !dso command as supported by the USERKDX.DLL debugger extensions for these versions. Still, structural details of the THREADINFO are more than usually scarce among public sources. For almost all Windows versions, the tables from here are necessarily the result of deduction, inference and outright guesswork from inspection of executables. Near the end of the structure, this becomes true even of version 6.1 despite Microsoft’s disclosure of type information.

Offset (x86) Offset (x64) Definition Versions Remarks
0x00 (3.10 to 3.51)  
THROBJHEAD head;
3.10 to 3.51  
0x0C (3.10);
0x10 (3.51)
  unknown THREADINFO pointer 3.10 to 3.51  
0x38 (4.0)  
LIST_ENTRY PtiLink;
4.0 only next at 0xA4
0x10 (3.10)   unknown heap handle 3.10 only  
0x14 (3.10)   unknown event handle 3.10 only  
0x14 (3.51);
0x40 (4.0);
0x1C (5.0);
0x28 (5.1 to 6.0);
0xB4 (6.1);
0xC0 (6.2 to 6.3);
0xC4
0x60 (5.2 to 6.0);
0x0150 (6.1);
0x0168 (6.2 to 6.3);
0x0170
TL *ptl;
3.51 and higher  
0x44 (4.0)  
TL *ptlOb;
4.0 only  
0x48 (4.0)  
TL *ptlPool;
4.0 only  
0x4C (4.0)  
INT cEnterCount;
4.0 only next at 0xC4

Version 3.10 has at offset 0x14 a handle to a per-thread event that may correspond in later versions to the per-process InputIdleEvent.

Offset (x86) Offset (x64) Definition Versions Remarks
0x18 (3.10 to 3.51);
0x50 (4.0);
0x20 (5.0);
0x2C (5.1 to 6.0);
0xB8 (6.1);
0xC4 (6.2 to 6.3);
0xC8
0x68 (5.2 to 6.0);
0x0158 (6.1);
0x0170 (6.2 to 6.3);
0x0178
PROCESSINFO *ppi;
all  
0x1C (3.10 to 3.51);
0x54 (4.0);
0x24 (5.0);
0x30 (5.1 to 6.0);
0xBC (6.1);
0xC8 (6.2 to 6.3);
0xCC
0x70 (5.2 to 6.0);
0x0160 (6.1);
0x0178 (6.2 to 6.3);
0x0180
Q *pq;
all  
0x58 (4.0);
0x28 (5.0);
0x34 (5.1 to 6.0);
0xC0 (6.1);
0xCC (6.2 to 6.3);
0xD0
0x78 (5.2 to 6.0);
0x0168 (6.1);
0x0180 (6.2 to 6.3);
0x0188
KL *spklActive;
4.0 and higher  
0x20 (3.10 to 3.51);
0x5C (4.0)
 
MLIST mlPost;
3.10 to 4.0 next at 0xC8
0x68 (4.0)  
USHORT fsChangeBitsRemoved;
4.0 only previously as ULONG at 0x38;
next at 0xD4
0x6A (4.0)  
USHORT cDeskClient;
4.0 only  
0x6C (4.0);
0x2C (5.0);
0x38 (5.1 to 6.0);
0xC4 (6.1);
0xD0 (6.2 to 6.3);
0xD4
0x80 (5.2 to 6.0);
0x0170 (6.1);
0x0188 (6.2 to 6.3);
0x0190
CLIENTTHREADINFO *pcti;
4.0 and higher  
0x70 (4.0)  
CLIENTTHREADINFO cti;
4.0 only next at 0x012C
0x28 (3.10);
0x2C (3.51);
0x80 (4.0)
 
HANDLE hEventQueueClient;
3.51 to 4.0 next at 0x9C
0x2C (3.10);
0x30 (3.51);
0x84 (4.0)
 
HANDLE hEventQueueServer;
3.10 to 3.51  
KEVENT *pEventQueueServer;
4.0 next at 0xA0
0x30 (3.10);
0x34 (3.51)
 
ULONG fsChangeBits;
3.10 to 3.51 next as USHORT in CLIENTTHREADINFO
0x38 (3.51)  
ULONG fsChangeBitsRemovd;
3.51 only next as USHORT at 0x68
0x34 (3.10);
0x3C (3.51)
 
ULONG fsWakeBits;
3.10 to 3.51 next as USHORT in CLIENTTHREADINFO
0x38 (3.10);
0x40 (3.51)
 
ULONG fsWakeMask;
3.10 to 3.51 next as USHORT in CLIENTTHREADINFO

The spelling fsChangeBitsRemovd is Microsoft’s, specifically from the USEREXTS debugger extension from the DDK for Windows NT 3.51. This is as good a moment as any to remind that the text for a debugger extension’s description of a member does not necessarily reproduce the member’s name from whatever header has the member’s source-code definition.

Offset (x86) Offset (x64) Definition Versions Remarks
0x88 (4.0)  
KEVENT **apEvent;
4.0 only next at 0xDC
0x3C (3.10);
0x44 (3.51);
0x8C (4.0);
0x30 (5.0);
0x3C (5.1 to 6.0);
0xC8 (6.1);
0xD4 (6.2 to 6.3);
0xD8
0x88 (5.2 to 6.0);
0x0178 (6.1);
0x0190 (6.2 to 6.3);
0x0198
DESKTOP *spdesk;
3.10 to 3.51  
DESKTOP *rpdesk;
4.0 and higher  
0x48 (3.51)  
DESKTOPINFO *pDeskInfo;
3.51 only next at 0x98
0x40 (3.10);
0x4C (3.51);
0x90 (4.0)
 
HDESK hdesk;
3.10 to 4.0 next at 0x60
0x94 (4.0)  
ACCESS_MASK amdesk;
4.0 only next at 0xE0
0x98 (4.0);
0x34 (5.0);
0x40 (5.1 to 6.0);
0xCC (6.1);
0xD8 (6.2 to 6.3);
0xDC
0x90 (5.2 to 6.0);
0x0180 (6.1);
0x0198 (6.2 to 6.3);
0x01A0
DESKTOPINFO *pDeskInfo;
4.0 and higher previously at 0x48
0x44 (5.2 to 6.0);
0xD0 (6.1);
0xDC (6.2 to 6.3);
0xE0
0x98 (5.2 to 6.0);
0x0188 (6.1);
0x01A0 (6.2 to 6.3);
0x01A8
ULONG_PTR ulClientDelta;
5.2 and higher  
0x9C (4.0);
0x38 (5.0);
0x44 (5.1);
0x48 (5.2 to 6.0);
0xD4 (6.1);
0xE0 (6.2 to 6.3);
0xE4
0xA0 (5.2 to 6.0);
0x0190 (6.1);
0x01A8 (6.2 to 6.3);
0x01B0
CLIENTINFO *pClientInfo;
4.0 and higher  
0x44 (3.10);
0x50 (3.51);
0xA0 (4.0);
0x3C (5.0);
0x48 (5.1);
0x4C (5.2 to 6.0);
0xD8 (6.1);
0xE4 (6.2 to 6.3);
0xE8
0xA8 (5.2 to 6.0);
0x0198 (6.1);
0x01B0 (6.2 to 6.3);
0x01B8
ULONG TIF_flags;
all  
0x48 (3.10);
0x54 (3.51)
 
DWORD idProcessClient;
3.10 to 3.51  
0x4C (3.10);
0x58 (3.51)
 
DWORD idThreadClient;
3.10 to 3.51  
0x50 (3.10);
0x5C (3.51)
 
DWORD idSequenceClient;
3.10 to 3.51  
0x54 (3.10);
0x60 (3.51)
  unknown thread ID 3.10 to 3.51  
0x58 (3.10);
0x64 (3.51);
0xA4 (4.0);
0x40 (5.0);
0x4C (5.1);
0x50 (5.2 to 6.0);
0xDC (6.1);
0xE8 (6.2 to 6.3);
0xEC
0xB0 (5.2 to 6.0);
0x01A0 (6.1);
0x01B8 (6.2 to 6.3);
0x01C0
PWSTR pstrAppName;
3.10 to 3.51  
UNICODE_STRING *pstrAppName;
4.0 and higher  
0x5C (3.10);
0x68 (3.51)
 
ULONG fsHooks;
3.10 to 3.51 next at 0x0104
0x60 (3.10);
0x6C (3.51)
 
HOOK *asphkStart [0x0D];
3.10 to 3.51 next at 0x0108
0x94 (3.10);
0xA0 (3.51)
 
HOOK *sphkCurrent;
3.10 to 3.51 next at 0x0140
0x98 (3.10);
0xA4 (3.51);
0xA8 (4.0);
0x44 (5.0);
0x50 (5.1);
0x54 (5.2 to 6.0);
0xE0 (6.1);
0xEC (6.2 to 6.3);
0xF0
0xB8 (5.2 to 6.0);
0x01A8 (6.1);
0x01C0 (6.2 to 6.3);
0x01C8
SMS *psmsSent;
all  
0x9C (3.10);
0xA8 (3.51);
0xAC (4.0);
0x48 (5.0);
0x54 (5.1);
0x58 (5.2 to 6.0);
0xE4 (6.1);
0xF0 (6.2 to 6.3);
0xF4
0xC0 (5.2 to 6.0);
0x01B0 (6.1);
0x01C8 (6.2 to 6.3);
0x01D0
SMS *psmsCurrent;
all  
0xA0 (3.10);
0xAC (3.51);
0xB0 (4.0);
0x4C (5.0);
0x58 (5.1);
0x5C (5.2 to 6.0);
0xE8 (6.1);
0xF4 (6.2 to 6.3);
0xF8
0xC8 (5.2 to 6.0);
0x01B8 (6.1);
0x01D0 (6.2 to 6.3);
0x01D8
SMS *psmsReceiveList;
3.10 to 6.3  
unknown LIST_ENTRY 10.0 and higher  
0x0100 0x01E8 unknown dword 10.0 and higher  
0xA4 (3.10);
0xB0 (3.51)
 
LONG_PTR ExtraInfo;
3.10 to 3.51 next in Q
0xA8 (3.10);
0xB4 (3.51 to 4.0);
0x50 (5.0);
0x5C (5.1);
0x60 (5.2 to 6.0);
0xEC (6.1);
0xF8 (6.2 to 6.3);
0x0104
0xD0 (5.2 to 6.0);
0x01C0 (6.1);
0x01D8 (6.2 to 6.3);
0x01EC
LONG timeLast;
all  
0xAC (3.10);
0xB8 (3.51 to 4.0)
 
POINT ptLast;
3.10 to 4.0 next at 0xB0
0xB4 (3.10);
0xC0 (3.51 to 4.0);
0x54 (5.0);
0x60 (5.1);
0x64 (5.2 to 6.0);
0xF0 (6.1);
0xFC (6.2 to 6.3);
0x0108
0xD8 (5.2 to 6.0);
0x01C8 (6.1);
0x01E0 (6.2 to 6.3);
0x01F0
ULONG_PTR idLast;
all  
0xBC (3.10);
0xC8 (3.51);
0xC4 (4.0);
0x58 (5.0)
 
INT cQuit;
3.10 to 5.0 next as 0x40000000 bit in TIF_flags
0xC0 (3.10);
0xCC (3.51);
0xC8 (4.0);
0x5C (5.0);
0x64 (5.1);
0x68 (5.2 to 6.0);
0xF4 (6.1);
0x0100 (6.2 to 6.3);
0x010C
0xE0 (5.2 to 6.0);
0x01D0 (6.1);
0x01E8 (6.2 to 6.3);
0x01F8
INT exitCode;
all  
0x60 (5.0);
0x68 (5.1);
0x6C (5.2 to 6.0);
0xF8 (6.1);
0x0104 (6.2 to 6.3);
0x0110
0xE8 (5.2 to 6.0);
0x01D8 (6.1);
0x01F0 (6.2 to 6.3);
0x0200
HDESK hdesk;
5.0 and higher previously at 0x90
0xC4 (3.10);
0xD0 (3.51)
  unaccounted four bytes 3.10 to 3.51  
0xC8 (3.10);
0xD4 (3.51);
0xCC (4.0);
0x64 (5.0);
0x6C (5.1);
0x70 (5.2 to 6.0);
0xFC (6.1);
0x0108 (6.2 to 6.3);
0x0114
0xF0 (5.2 to 6.0);
0x01E0 (6.1);
0x01F8 (6.2 to 6.3);
0x0208
INT cPaintsReady;
all  
0xCC (3.10);
0xD8 (3.51);
0xD0 (4.0);
0x68 (5.0);
0x70 (5.1);
0x74 (5.2 to 6.0);
0x0100 (6.1);
0x010C (6.2 to 6.3);
0x0118
0xF4 (5.2 to 6.0);
0x01E4 (6.1);
0x01FC (6.2 to 6.3);
0x020C
UINT cTimersReady;
all  
0xD0 (3.10);
0xDC (3.51);
0xD4 (4.0);
0x6C (5.0);
0x74 (5.1);
0x78 (5.2 to 6.0);
0x0104 (6.1);
0x0110 (6.2 to 6.3);
0x011C
  unknown MENUSTATE 3.10 to 3.51  
0xF8 (5.2 to 6.0);
0x01E8 (6.1);
0x0200 (6.2 to 6.3);
0x0210
MENUSTATE *pMenuState;
4.0 and higher  
0x0108 (3.10);
0x0104 (3.51)
 
<unknown-type> SBState;
3.10 to 3.51  
0x01B0 (3.10)   unknown MOVESIZEDATA 3.10 only  
0x022C (3.10);
0x01B0 (3.51);
0xD8 (4.0);
0x70 (5.0);
0x78 (5.1)
0x7C (5.2 to 6.0);
0x0108 (6.1);
0x0114 (6.2 to 6.3);
0x0120
0x0100 (5.2 to 6.0);
0x01F0 (6.1);
0x0208 (6.2 to 6.3);
0x0218
union {
    TDB *ptdb;
    WINDOWSTATION *pwinsta;
    DESKTOP *pdeskClient;
};
3.10 to 4.0  
union {
    TDB *ptdb;
    WINDOWSTATION *pwinsta;
};
5.0 and higher  
0x0230 (3.10);
0x01B4 (3.51);
0xDC (4.0);
0x74 (5.0);
0x7C (5.1);
0x80 (5.2 to 6.0);
0x010C (6.1);
0x0118 (6.2 to 6.3);
0x0124
0x0108 (5.2 to 6.0);
0x01F8 (6.1);
0x0210 (6.2 to 6.3);
0x0220
SVR_INSTANCE_INFO *psiiList;
all  
0x0234 (3.10);
0x01B8 (3.51);
0xE0 (4.0);
0x78 (5.0);
0x80 (5.1);
0x84 (5.2 to 6.0);
0x0110 (6.1);
0x011C (6.2 to 6.3);
0x0128
0x0110 (5.2 to 6.0);
0x0200 (6.1);
0x0218 (6.2 to 6.3);
0x0228
DWORD dwExpWinVer;
all  
0x0120 (6.2 to 6.3);
0x012C
0x021C (6.2 to 6.3);
0x022C
DWORD dwManifestWinVer;
6.2 and higher  
0x0238 (3.10);
0x01BC (3.51);
0xE4 (4.0);
0x7C (5.0);
0x84 (5.1);
0x88 (5.2 to 6.0);
0x0114 (6.1);
0x0124 (6.2 to 6.3);
0x0130
0x0114 (5.2 to 6.0);
0x0204 (6.1);
0x0220 (6.2 to 6.3);
0x0230
union {
    DWORD dwCompatFlags;
    struct {
        /* bit fields, follow link */
    };
};
all  
0x023C (3.10)   unknown dword 3.10 only  
0x80 (5.0);
0x88 (5.1);
0x8C (5.2 to 6.0);
0x0118 (6.1);
0x0128 (6.2 to 6.3);
0x0138
0x0118 (5.2 to 6.0);
0x0208 (6.1);
0x0228 (6.2 to 6.3);
0x0238
union {
    DWORD dwCompatFlags2;
    struct {
        /* bit fields, follow link */
    };
};
5.0 to 6.0  
union {
    DWORD dwCompatFlags2;
    ULONGLONG qwCompatFlags2;
    struct {
        /* bit fields, follow link */
    };
};
6.1 and higher  
0x01C0 (3.51);
0xE8 (4.0)
 
UINT cWindows;
3.51 to 4.0 next at 0xE4
0x0240 (3.10);
0x01C4 (3.51);
0xEC (4.0)
 
UINT cVisWindows;
3.10 to 4.0 next at 0xE8
0x0244 (3.10);
0x01C8 (3.51)
 
ULONG hTaskWow;
3.10 to 3.51 next in TDB
0x0248 (3.10);
0x01CC (3.51)
 
HANDLE hThreadClient;
3.10 to 3.51  
0x024C (3.10);
0x01D0 (3.51)
 
HANDLE hThreadServer;
3.10 to 3.51  
0x0250 (3.10);
0x01D4 (3.51)
 
<unknown-type> *pcsrt;
3.10 to 3.51  
0x0254 (3.10);
0x01D8 (3.51)
 
TEB *pteb;
3.10 to 3.51  
0x0258 (3.10);
0x01DC (3.51);
0xF0 (4.0);
0x84 (5.0);
0x8C (5.1);
0x90 (5.2 to 6.0);
0x0120 (6.1);
0x0130 (6.2 to 6.3);
0x0140
0x0120 (5.2 to 6.0);
0x0210 (6.1);
0x0230 (6.2 to 6.3);
0x0240
Q *pqAttach;
all  
0x025C (3.10)   unknown dword 3.10 only  
0x0260 (3.10);
0x01E0 (3.51);
0xF4 (4.0)
 
INT iCursorLevel;
3.10 to 4.0 next at 0xAC
0x0264 (3.10);
0x01E4 (3.51)
 
INT cSpins;
3.10 to 3.51  
0x0268 (3.10);
0x01E8 (3.51);
0xF8 (4.0)
 
ULONG fsReserveKeys;
4.0 only next at 0xD8;
last THREADINFO member in 3.10
0x01EC (3.51);
0xFC (4.0);
0x88 (5.0);
0x90 (5.1);
0x94 (5.2 to 6.0);
0x0124 (6.1);
0x0134 (6.2 to 6.3);
0x0144
0x0128 (5.2 to 6.0);
0x0218 (6.1);
0x0238 (6.2 to 6.3);
0x0248
THREADINFO *ptiSibling;
3.51 and higher  
0x01F0 (3.51);
0x0100 (4.0);
0x8C (5.0);
0x94 (5.1);
0x98 (5.2 to 6.0);
0x0128 (6.1);
0x0138 (6.2 to 6.3);
0x0148
0x0130 (5.2 to 6.0);
0x0220 (6.1);
0x0240 (6.2 to 6.3);
0x0250
MOVESIZEDATA *pmsd;
3.51 and higher  
0x01F4 (3.51)  
WOWTHREADINFO *pwti;
3.51 only next in TDB;
last THREADINFO member in 3.51
0x0104 (4.0);
0x90 (5.0);
0x98 (5.1);
0x9C (5.2 to 6.0);
0x012C (6.1);
0x013C (6.2 to 6.3);
0x014C
0x0138 (5.2 to 6.0);
0x0228 (6.1);
0x0248 (6.2 to 6.3);
0x0258
ULONG fsHooks;
4.0 and higher previously at 0x68
0x0108 (4.0)  
HOOK *asphkStart [0x0E];
early 4.0 only previously at 0x6C
HOOK *asphkStart [0x10];
late 4.0 only next at 0xEC
0x0140 (early 4.0);
0x0148 (late 4.0);
0x94 (5.0);
0x9C (5.1);
0xA0 (5.2 to 6.0);
0x0130 (6.1);
0x0140 (6.2 to 6.3);
0x0150
0x0140 (5.2 to 6.0);
0x0230 (6.1);
0x0250 (6.2 to 6.3);
0x0260
HOOK *sphkCurrent;
4.0 and higher previoustly at 0xA0
0x0134 (6.1);
0x0144 (6.2 to 6.3);
0x0154
0x0238 (6.1);
0x0258 (6.2 to 6.3);
0x0268
LPARAM lParamHkCurrent;
6.1 and higher  
0x0138 (6.1);
0x0148 (6.2 to 6.3);
0x0158
0x0240 (6.1);
0x0260 (6.2 to 6.3);
0x0270
WPARAM wParamHkCurrent;
6.1 and higher  
0x0144 (early 4.0);
0x014C (late 4.0);
0x98 (5.0);
0xA0 (5.1);
0xA4 (5.2 to 6.0);
0x013C (6.1);
0x014C (6.2 to 6.3);
0x015C
0x0148 (5.2 to 6.0);
0x0248 (6.1);
0x0268 (6.2 to 6.3);
0x0278
SBTRACK *pSBTrack;
4.0 and higher last THREADINFO member in 4.0

The unknown LIST_ENTRY elaborates psmsReceiveList from single-linked to double-linked. It seems likely that Microsoft changed the name, but to what is unknown. The unknown dword that follows counts the SMS structures in the list.

A thread has a ptdb or a pwinsta according to whether its TIF_16BIT (0x00000002) bit is set or clear in the TIF_flags.

The name dwManifestWinVer is proposed as a reasonable guess in the style of what it follows. The member is set by a routine that symbol files show to be named SetManifestWinVer

There is, of course, one element in the aphkStart array for each possible hook, as set through the API function SetWindowsHookEx. The hooks are documented and it is well known that the numbering is not zero-based but instead starts at -1 (WH_MSGFILTER). Notwithstanding that a conditional block in Microsoft’s WINUSER.H would have it that WH_KEYBOARD_LL (0x0D) and WH_MOUSE_LL (0x0E) are defined for version 4.0 and higher, they are in fact rejected by the WIN32K.SYS from the original release of Windows NT 4.0. Indeed, look back through Microsoft’s documentation, even as recently as the Software Development Kit (SDK) for Windows 7, and it can be found that the low-level keyboard and mouse hooks require “version 4.0 SP3 or later.”

Appended for Windows 2000

Most members that appear at the end of the THREADINFO in version 5.0 weren’t so much appended as just moved from earlier in the structure, in no particular order for no reason that I yet understand.

Offset (x86) Offset (x64) Definition Versions Remarks
0x9C (5.0);
0xA4 (5.1);
0xA8 (5.2 to 6.0);
0x0140 (6.1);
0x0150 (6.2 to 6.3);
0x0160
0x0150 (5.2 to 6.0);
0x0250 (6.1);
0x0270 (6.2 to 6.3);
0x0280
PVOID hEventQueueClient;
5.0 and higher previously at 0x80
0xA0 (5.0);
0xA8 (5.1);
0xAC (5.2 to 6.0);
0x0144 (6.1);
0x0154 (6.2 to 6.3);
0x0164
0x0158 (5.2 to 6.0);
0x0258 (6.1);
0x0278 (6.2 to 6.3);
0x0288
KEVENT *pEventQueueServer;
5.0 and higher previously at 0x84
0xA4 (5.0);
0xAC (5.1);
0xB0 (5.2 to 6.0);
0x0148 (6.1);
0x0158 (6.2 to 6.3);
0X0168
0x0160 (5.2 to 6.0);
0x0260 (6.1);
0x0280 (6.2 to 6.3);
0x0290
LIST_ENTRY PtiLink;
5.0 and higher previously at 0x38
0xAC (5.0);
0xB4 (5.1);
0xB8 (5.2 to 6.0);
0x0150 (6.1);
0x0160 (6.2 to 6.3);
0x0170
0x0170 (5.2 to 6.0);
0x0270 (6.1);
0x0290 (6.2 to 6.3);
0x02A0
INT iCursorLevel;
5.0 and higher previously at 0xF4
0xB0 (5.0);
0xB8 (5.1);
0xBC (5.2 to 6.0);
0x0154 (6.1);
0x0164 (6.2 to 6.3);
0x0174
0x0174 (5.2 to 6.0);
0x0274 (6.1);
0x0294 (6.2 to 6.3);
0x02A4
POINT ptLast;
5.0 and higher previously at 0xB8
0xC4 (6.0);
0x015C (6.1);
0x016C (6.2 to 6.3);
0x017C
0x017C (6.0);
0x027C (6.1);
0x029C (6.2 to 6.3);
0x02AC
POINT ptLastReal;
6.0 and higher  
0xB8 (5.0);
0xC0 (5.1);
0xC4 (5.2);
0xCC (6.0);
0x0164 (6.1);
0x0174 (6.2 to 6.3);
0x0184
0x0180 (5.2);
0x0188 (6.0);
0x0288 (6.1);
0x02A8 (6.2 to 6.3);
0x02B8
WND *spwndDefaultIme;
5.0 and higher  
0xBC (5.0);
0xC4 (5.1);
0xC8 (5.2);
0xD0 (6.0);
0x0168 (6.1);
0x0178 (6.2 to 6.3);
0x0188
0x0188 (5.2);
0x0190 (6.0);
0x0290 (6.1);
0x02B0 (6.2 to 6.3);
0x02C0
IMC *spDefaultImc;
5.0 and higher  
0xC0 (5.0);
0xC8 (5.1);
0xCC (5.2);
0xD4 (6.0);
0x016C (6.1);
0x017C (6.2 to 6.3);
0x018C
0x0190 (5.2);
0x0198 (6.0);
0x0298 (6.1);
0x02B8 (6.2 to 6.3);
0x02C8
HKL hklPrev;
5.0 and higher  
0xC4 (5.0);
0xCC (5.1);
0xD0 (5.2);
0xD8 (6.0);
0x0170 (6.1);
0x0180 (6.2 to 6.3);
0x0190
0x0198 (5.2);
0x01A0 (6.0);
0x02A0 (6.1);
0x02C0 (6.2 to 6.3);
0x02D0
INT cEnterCount;
5.0 and higher previously at 0x4C
0xC8 (5.0);
0xD0 (5.1);
0xD4 (5.2);
0xDC (6.0);
0x0174 (6.1);
0x0184 (6.2 to 6.3);
0x0194
0x01A0 (5.2);
0x01A8 (6.0);
0x02A8 (6.1);
0x02C8 (6.2 to 6.3);
0x02D8
MLIST mlPost;
5.0 and higher previously at 0x5C
0xD4 (5.0);
0xDC (5.1);
0xE0 (5.2);
0xE8 (6.0);
0x0180 (6.1);
0x0194 (6.2 to 6.3);
0x01A4
0x01B8 (5.2);
0x01C0 (6.0);
0x02C0 (6.1);
0x02E0 (6.2 to 6.3);
0x02F0
USHORT fsChangeBitsRemoved;
5.0 and higher previously at 0x68
0xD6 (5.0);
0xDE (5.1);
0xE2 (5.2);
0xEA (6.0);
0x0182 (6.1);
0x0196 (6.2 to 6.3);
0x01A6
0x01BA (5.2);
0x01C2 (6.0);
0x02C2 (6.1);
0x02E2 (6.2 to 6.3);
0x02F2
WCHAR wchInjected;
5.0 and higher  
0xD8 (5.0);
0xE0 (5.1);
0xE4 (5.2);
0xEC (6.0);
0x0184 (6.1);
0x0198 (6.2 to 6.3);
0x01A8
0x01BC (5.2);
0x01C4 (6.0);
0x02C4 (6.1);
0x02E4 (6.2 to 6.3);
0x02F4
ULONG fsReserveKeys;
5.0 and higher previously at 0xF8
0xDC (5.0);
0xE4 (5.1);
0xE8 (5.2);
0xF0 (6.0);
0x0188 (6.1);
0x019C (6.2 to 6.3);
0x01AC
0x01C0 (5.2);
0x01C8 (6.0);
0x02C8 (6.1);
0x02E8 (6.2 to 6.3);
0x02F8
KEVENT **apEvent;
5.0 and higher previously at 0x88
0xE0 (5.0);
0xE8 (5.1);
0xEC (5.2);
0xF4 (6.0);
0x018C (6.1);
0x01A0 (6.2 to 6.3);
0x01B0
0x01C8 (5.2);
0x01D0 (6.0);
0x02D0 (6.1);
0x02F0 (6.2 to 6.3);
0x0300
ACCESS_MASK amdesk;
5.0 and higher previously at 0x94
0xE4 (5.0);
0xEC (5.1);
0xF0 (5.2);
0xF8 (6.0);
0x0190 (6.1);
0x01A4 (6.2 to 6.3);
0x01B4
0x01CC (5.2);
0x01D4 (6.0);
0x02D4 (6.1);
0x02F4 (6.2 to 6.3);
0x0304
UINT cWindows;
5.0 and higher previously at 0xE8
0xE8 (5.0);
0xF0 (5.1);
0xF4 (5.2);
0xFC (6.0);
0x0194 (6.1);
0x01A8 (6.2 to 6.3);
0x01B8
0x01D0 (5.2);
0x01D8 (6.0);
0x02D8 (6.1);
0x02F8 (6.2 to 6.3);
0x0308
UINT cVisWindows;
5.0 and higher previously at 0xEC
0xEC (5.0);
0xF4 (5.1);
0xF8 (5.2);
0x0100 (6.0);
0x0198 (6.1);
0x01AC (6.2 to 6.3);
0x01BC
0x01D8 (5.2);
0x01E0 (6.0);
0x02E0 (6.1);
0x0300 (6.2 to 6.3);
0x0310
HOOK *aphkStart [0x10];
5.0 and higher previously at 0x0108
0x012C (5.0);
0x0134 (5.1);
0x0138 (5.2);
0x0140 (6.0);
0x01D8 (6.1);
0x01EC (6.2 to 6.3);
0x01FC
0x0258 (5.2);
0x0260 (6.0);
0x0360 (6.1);
0x0380 (6.2 to 6.3);
0x0390
CLIENTTHREADINFO cti;
5.0 and higher previously at 0x70;
last THREADINFO member in 5.0

It is immediately after the cti member that offsets in type information from symbol files for Windows 7 start to go wrong. These symbol files have the CLIENTTHREADINFO as 0x10 bytes in both 32-bit and 64-bit Windows, but for the structure as actually used by WIN32K this size has not been correct since Windows XP added a dword. How the symbol files get built with only a partial CLIENTTHREADINFO is not known. The consequence for the next few THREADINFO members is that offsets that are read mechanically from the Windows 7 symbol files, e.g., for presentation on the Internet as supposedly worthwhile research, are off by four or eight bytes in 32-bit and 64-bit Windows respectively.

Appended Mostly For Windows 7

Offset (x86) Offset (x64) Definition Versions Remarks
0x0148 (5.1);
0x014C (5.2);
0x0154 (6.0);
0x01EC (6.1);
0x0200 (6.2 to 6.3);
0x0210
0x0270 (5.2);
0x0278 (6.0);
0x0378 (6.1);
0x0398 (6.2 to 6.3);
0x03A8
PVOID hPrevHidData;
5.1 and higher last THREADINFO member in 5.1;
last THREADINFO member in 5.2;
0x01E8 and 0x0370 in 6.1 according to symbol files
0x01F0 (6.1);
0x0204 (6.2 to 6.3);
0x0214
0x0380 (6.1);
0x03A0 (6.2 to 6.3);
0x03B0
HTOUCHINPUT hTouchInputCurrent;
6.1 and higher 0x01EC and 0x0378 in 6.1 according to symbol files
0x01F4 (6.1);
0x0208 (6.2 to 6.3);
0x0218
0x0388 (6.1);
0x03A8 (6.2 to 6.3);
0x03B8
HGESTUREINFO hGestureInfoCurrent;
6.1 and higher 0x01F0 and 0x0380 in 6.1 according to symbol files
0x01F8 (6.1) 0x0390 (6.1)
MSGPPINFO MsgPPInfo;
6.1 only 0x01F4 and 0x0388 in 6.1 according to symbol files;
next at 0x024C and 0x0424
0x020C (6.2 to 6.3);
0x021C
0x03B0 (6.2 to 6.3);
0x03C0
unknown THREADINPUTPOINTERLIST 6.2 and higher  
0x0158 (6.0);
0x0200 (6.1);
0x0224 (6.2 to 6.3);
0x0234
0x0280 (6.0);
0x0398 (6.1);
0x03D8 (6.2 to 6.3);
0x03E8
unknown INPUTHANGINFO 6.0 and higher not present in 6.1 according to symbol files;
last THREADINFO member in 6.0
0x020C (6.1);
0x023C (6.2 to 6.3);
0x024C
0x03B0 (6.1);
0x0408 (6.2 to 6.3);
0x0418
UINT cNestedStableVisRgn;
6.1 and higher 0x01F8 and 0x038C in 6.1 according to symbol files
0x0210 (6.1);
0x0240 (6.2 to 6.3);
0x0250
0x03B8 (6.1);
0x0410 (6.2 to 6.3);
0x0420
LIST_ENTRY readyHead;
6.1 and higher 0x01FC and 0x0390 in 6.1 according to symbol files
0x0218 (6.1);
0x0248 (6.2 to 6.3);
0x0258
0x03C8 (6.1);
0x0420 (6.2 to 6.3);
0x0430
union {
    struct {
        /* bit fields, follow link */
    };
    ULONG ulThreadFlags2;
};
6.1 and higher 0x0204 and 0x03A0 in 6.1 according to symbol files;
last THREADINFO member in 6.1

Microsoft’s name THREADINPUTINFOLIST (formally tagTHREADINPUTINFOLIST) for the structure that first appears in version 6.2 at offsets 0x020C and 0x03B0 is known from symbol files, specifically from the names of routines that are written in C++ and take the structure’s address among their arguments. The structure begins with a LIST_ENTRY that links structures whose name is similarly known to be THREADPOINTERDATA (formally tagTHREADPOINTERDATA). Microsoft’s names for these structures’ members are not known.

The MsgPPInfo member is accessed as eight bytes in both 32-bit and 64-bit Windows, yet symbol files for Windows 7 have the MSGPPINFO structure as four bytes in both 32-bit and 64-bit Windows. It is here supposed that the symbol files must be wrong about the MSGPPINFO structure, the alternative being that they’re wrong even about the existence of a MsgPPInfo member (there being no other space for it).

The structure that first appears in version 6.0 at offsets 0x0158 and 0x0280 is operated on by routines that symbol files name as AddUpdateHangInfo, DestroyUpdateHangInfo, etc, and since symbol files for Windows 8.1 (but not Windows 8 or Windows 10) have C++ decorations for these routines Microsoft’s name for the structure is nowadays known to be INPUTHANGINFO (formally tagINPUTHANGINFO). The structure in the THREADINFO itself is the head of a list. The head is for the thread itself. Others are for the thread’s windows. This is where the timeout for hung applications is tested—and it is hard-coded to 5 seconds in version 6.0. Microsoft’s names for the THREADINFO member or for the INPUTHANGINFO members are not known. How the member gets missed in the type information from the symbol files for Windows 7 is not known. Note especially that it cannot be that the symbol files as published are somehow out of date: this INPUTHANGINFO was no last-minute addition during development of Windows 7 but has existed since Windows Vista.

Before version 6.1, timers for all threads go into one list. Version 6.1 has a global list too but improves on it by putting each timer into both the global list and the new per-thread list. The name readyHead from the suspect symbol files is consistent with the cTimersReady counter that is the whole per-thread tracking of timers in earlier versions.

Appended for Windows 8

Microsoft’s names for members that have been added to the THREADINFO since Windows 7 may never be known. On the plus side, if only for neatness of presentation, new members have mostly been added simply by appending. 

Offset (x86) Offset (x64) Definition Versions Remarks
0x024C (6.2 to 6.3);
0x025C
0x0424 (6.2 to 6.3);
0x0434
MSGPPINFO MsgPPInfo;
6.2 and higher previously at 0x01F8 and 0x0390
0x0254 (6.2 to 6.3);
0x0264
0x042C (6.2 to 6.3);
0x043C
unknown byte 6.2 and higher  
0x0258 (6.2 to 6.3);
0x0268
0x0430 (6.2 to 6.3);
0x0440
unknown pointer 6.2 and higher  
0x025C (6.2 to 6.3);
0x026C
0x0438 (6.2 to 6.3);
0x0448
unknown pointer 6.2 and higher  
0x0260 (6.2 to 6.3);
0x0270
0x0440 (6.2 to 6.3);
0x0450
unknown dword (counter) 6.2 and higher  
0x0264 (6.2 to 6.3);
0x0274
0x0448 (6.2 to 6.3);
0x0458
unknown pointer 6.2 and higher  
0x0268 (6.3);
0x0278
0x0450 (6.3);
0x0460
unknown dword 6.3 and higher  
0x0268 (6.2);
0x026C (6.3);
0x027C
0x0450 (6.2);
0x0454 (6.3);
0x0464
unknown POINT 6.2 and higher  
0x0270 (6.2);
0x0274 (6.3);
0x0284
0x0458 (6.2);
0x0460 (6.3);
0x0470
unknown LIST_ENTRY 6.2 and higher last THREADINFO member in 6.2

The unknown LIST_ENTRY is presumed to remain defined for version 10.0 though its use seems to have been discontinued.

Appended for Windows 8.1

Offset (x86) Offset (x64) Definition Versions Remarks
0x027C (6.3);
0x028C
0x0470 (6.3);
0x0480
unknown dword 6.3 and higher  
0x0280 (6.3);
0x0290
0x0474 (6.3);
0x0484
unknown dword 6.3 and higher  
0x0284 (6.3);
0x0294
0x0478 (6.3);
0x0488
unknown MSGPPINFO 6.3 and higher  
0x028C (6.3);
0x029C
0x0480 (6.3);
0x0490
unknown pointer 6.3 and higher  
0x0290 (6.3);
0x02A0
0x0488 (6.3);
0x0498
unknown dword 6.3 and higher last THREADINFO member in 6.3

Appended for Windows 10

Offset (x86) Offset (x64) Definition Versions Remarks
0x02A4 0x04A0 unaccounted 10.0 and higher  
0x02A8 0x04A8 unknown eight bytes 10.0 and higher  
0x02B0 0x04B0 unknown eight bytes 10.0 and higher  
0x02B8 0x04B8 unknown pointer 10.0 and higher  
0x02BC 0x04C0 unknown KEVENT pointer 10.0 and higher  
0x02C0 0x04C8 unknown WND pointer 10.0 and higher  
0x02C4 0x04D0 unknown pointer 10.0 and higher  
0x02C8 0x04D8 unknown dword 10.0 and higher  
0x02CC 0x04DC unknown dword 10.0 and higher last THREADINFO member in 10.0