Geoff Chappell, Software Analyst
The QMSG structure (formally tagQMSG) is how WIN32K.SYS—and before it, WINSRV.DLL—dresses up a window message while it’s in a message queue. If you like, it is the internal wrapper around the documented MSG structure.
The QMSG is not documented. Though symbol files for WIN32K.SYS in Windows 8 and higher name the QMSG in the C++ decorations of internal routines, type information for the structure is present only in symbol files for Windows 7—not before and not since.
The symbol files for Windows 7 are anyway incorrect. Windows 7 appended a MSGPPINFO which the symbol files have as four bytes even though the matching executable plainly understands the structure to be eight bytes. The size of the QMSG as given in the symbol file for the 32-bit WIN32K is thus wrong by four bytes. For the 64-bit build, the extra four bytes are covered by the QMSG structure’s eight-byte alignment. Over the whole history, the following changes of size are known:
Version | Size (x86) | Size (x64) | Remarks |
---|---|---|---|
3.10 to 5.2 | 0x30 | 0x58 | |
6.0 | 0x38 | 0x60 | |
6.1 | 0x44 | 0x68 | 0x40 (x86) according to symbol files |
6.2 | 0x60 | 0x88 | |
6.3 | 0x60 | 0x90 | |
10.0 | 0x68 | 0x90 |
For versions other than 6.1, these sizes, and the offsets that the next table shows for members, are obtained by inspecting the executable for correspondences with the executable from version 6.1 and assuming as much continuity as possible for the names or types. Microsoft’s names and types for members that have been added since version 6.1 may never be known.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 | 0x00 |
QMSG *pqmsgNext; |
all | |
0x04 | 0x08 |
QMSG *pqmsgPrev; |
all | |
0x08 | 0x10 |
MSG msg; |
all | |
0x24 | 0x40 | unaccounted | 6.2 and higher | |
0x24 (3.10 to 6.1); 0x28 |
0x40 (5.2 to 6.1); 0x48 |
LONG_PTR ExtraInfo; |
all | |
0x28 (6.0 to 6.1); 0x2C |
0x48 (6.0 to 6.1); 0x50 |
POINT ptMouseReal; |
6.0 and higher | |
0x28 (3.10 to 5.2); 0x30 (6.0 to 6.1); 0x34 |
DWORD dwQEvent; |
3.10 to early 5.2 | ||
0x48 (5.2); 0x50 (6.0 to 6.1); 0x58 |
struct { /* bit fields, see below */ }; |
late 5.2 to 6.1 | ||
DWORD dwQEvent; |
6.2 and higher | |||
0x34 (6.1); 0x38 |
0x54 (6.1); 0x5C |
struct { /* bit fields, see below */ }; |
6.1 and higher | |
0x2C (3.10 to 5.2); 0x34 (6.0); 0x38 (6.1); 0x3C |
0x50 (5.2); 0x58 (6.0 to 6.1); 0x60 |
THREADINFO *pti; |
all | last member in 3.10 to 6.0 |
0x40 | 0x68 | unknown qword | 6.2 and higher | |
0x3C (6.1); 0x48 |
0x60 (6.1); 0x70 |
MSGPPINFO MsgPPInfo; |
6.1 and higher | last member in 6.1 |
0x50 | 0x78 | unknown qword | 6.2 and higher | |
0x58 | 0x80 | unknown pointer | 6.3 and higher | |
00x58 (6.2); 0x5C |
0x80 (6.2); 0x88 |
unknown dword | 6.2 and higher | last member in 6.2 to 10.0 |
Description of the two sets of bit flags is a little complicated by their not being in union with an integral member for accessing them all together. The chronologically first flags were squeezed in as high bits of what had been the dwQEvent member as a DWORD—and later is because these high bits soon became the low bits of a new set of purposely designed bit fields.
Mask | Definition | Versions | Remarks |
---|---|---|---|
0x7FFFFFFF (late 5.2); 0x3FFFFFFF (6.0 to 6.1) |
DWORD dwQEvent : 31; |
late 5.2 | |
DWORD dwQEvent : 30; |
6.0 to 6.1 | ||
0x80000000 (late 5.2); 0x40000000 (6.0) |
DWORD Wow64Message : 1; |
late 5.2 to 6.1 | next as 0x00000001 bit in second flags |
0x80000000 (6.0) |
DWORD NoCoalesce : 1; |
6.0 only | next as 0x00000002 bit in second flags |
DWORD Padding : 2; |
6.1 only |
For the second set of flags, the following are known to be defined:
Mask | Definition | Versions | Remarks |
---|---|---|---|
0x00000001 |
INT Wow64Message : 1; |
6.1 and higher | previously combined with dwQEvent |
0x00000002 |
INT NoCoalesce : 1; |
6.1 and higher | previously combined with dwQEvent |
0x00000004 |
INT FromTouch : 1; |
6.1 and higher | |
0x00000008 |
INT FromPen : 1; |
6.1 and higher | |
unaccounted | 6.2 and higher |
More have been defined since version 6.1, inevitably, but Microsoft’s names are not known.