Geoff Chappell, Software Analyst
SKETCH OF HOW RESEARCH MIGHT CONTINUE AND RESULTS BE PRESENTED
As a CSRSS Server DLL, the user server in WINSRV.DLL implements API routines which a CSRSS client can call through the NTDLL function CsrClientCallServer and which other DLLs in the server process may be allowed to call through the CSRSRV function CsrCallServerFromServer. Although most CSRSS server DLLs allow most API routines to be called from the server process, the user server does not. For the following table, an API routine is invalid as a server call unless explicitly noted as valid.
The caller selects a routine by specifying an API number. The high word is a 0-based index for the user server as a CSRSS server DLL. Known clients and WINSRV itself (for the slightly different matter of accessing server-specific per-process data) assume that this index is 3. Whatever symbolic names Microsoft has for the API numbers as constants to use when calling the corresponding API routines are not known. The tables below give only the name of each API routine as known from public symbol files for WINSRV.DLL.
In an immediate sense, the user server is here named the user server because of the function, named UserServerDllInitialization, that WINSRV exports for CSRSRV is to call for initialising this server rather than the one or two others that WINSRV has hosted. The intended caller of by far the most API routines that the user server has ever implemented is USER32.DLL.
In early versions, the user server does almost all the work that is nowadays done in kernel mode by WIN32K.SYS. Cross-process calls to the user server’s API routines must have been very frequent. Decent performance would be unachievable if every one of them is a Local Procedure Call (LPC) through the CsrClientCallServer function. In these versions, the user server’s API routines are written on the assumption that they are reached through something named QLPC that exchanges messages—indeed, batches of messages—in shared memory and is managed from the client side by calling CsrClientSendMessage instead.
If only in version 3.10, the user server’s API routines may in principle have the usual prototype
ULONG ApiRoutine (CSR_API_MSG *, CSR_REPLY_STATUS *);
for being called by CSRSRV, but the first argument is in fact the address of a CSR_QLPC_API_MSG, not of a CSR_API_MSG. Version 3.51 throws this away in the apparent pursuit of yet more efficiency. The user server in this version sets a routine into the ApiDispatchRoutine member of the CSR_SERVER_DLL such that API routines are not called from CSRSRV. Their distribution is instead an internal matter for WINSRV. One effect is that some (but not all) API routines in version 3.51 have the prototype
ULONG FASTCALL ApiRoutine (CSR_QLPC_API_MSG *, WND *);
Plainly none of this internal detail matters to a client and wouldn’t matter here if the functionality of the API routines could instead be described by naming the API numbers. It’s far from clear that the API routines are even worth listing: were a list to be made, it might go something like…
API Number | API Routine | Versions | Remarks |
---|---|---|---|
0x00030000 (3.51) | __ChildWindowFromPointEx | 3.51 only | |
0x00030001 (3.51) | __CsCreateCaret | 3.51 only | previously 0x003001B |
0x00030002 (3.51) | __CsEndPaint | 3.51 only | previously 0x00030021 |
0x00030003 (3.51) | __CsExcludeUpdateRgn | 3.51 only | previously 0x00030023 |
0x00030004 (3.51) | __CsGetCPD | 3.51 only | previously 0x0003014F |
TO BE DONE | |||
0x00030013 (3.51) | __ServerGetWindowLong | 3.51 | previously 0x00030150 |
TO BE DONE | |||
0x00030000 (3.10); 0x0003006E (3.51) |
__ActivateKeyboardLayout | 3.10 to 3.51 | |
0x00030001 (3.10); 0x0003006F (3.51) |
__AppendMenu | 3.10 to 3.51 | |
0x00030002 (3.10) | __ArrangeIconicWindows | 3.10 only | |
0x00030003 (3.10); 0x00030070 (3.51) |
__AttachThreadInput | 3.10 to 3.51 | |
0x00030004 (3.10) | __BeginDeferWindowPos | 3.10 only | |
0x00030005 (3.10); 0x00030071 (3.51) |
__BringWindowToTop | 3.10 to 3.51 | |
0x00030006 (3.10) | __CalcChildScroll | 3.10 only | |
0x00030007 (3.10); 0x00030072 (3.51) |
__CallMsgFilter | 3.10 to 3.51 | |
TO BE DONE | |||
0x0003001B (3.10) | __CsCreateCaret | 3.10 only | next as 0x00030001 |
TO BE DONE | |||
0x00030021 (3.10) | __CsEndPaint | 3.10 only | next as 0x00030002 |
TO BE DONE | |||
0x00030023 (3.10) | __CsExcludeUpdateRgn | 3.10 only | next as 0x00030003 |
TO BE DONE | |||
0x0003014F (3.10) | __CsGetCPD | 3.10 only | next as 0x00030004 |
0x00030150 (3.10) | __ServerGetWindowLong | 3.10 only | next as 0x00030013 |
0x00030151 (3.10) | __TransferInputBits | 3.10 only | |
0x00030152 (3.10); 0x00030102 (3.51) |
__ResyncKeyState | 3.10 to 3.51 | |
TO BE DONE |
The change to in-process calls in kernel mode left the user server with a greatly reduced role in version 4.0. Not only are there many fewer API routines but they revert to the usual prototype:
ULONG ApiRoutine (CSR_API_MSG *, CSR_REPLY_STATUS *);
Pehaps to avoid all misunderstanding, not that mismatching low-level DLLs such as CSRSRV and USER32 seems likely ever to produce anything but chaos, the API numbers begin with a non-zero base for the low word.
API Number | API Routine | Versions | Remarks |
---|---|---|---|
0x00030A00 (4.0); 0x00030400 |
SrvExitWindowsEx | 4.0 and higher | conditionally valid as server call in 5.0 to 5.2; valid as server call in 6.0 and higher |
0x00030A01 (4.0); 0x00030401 |
SrvEndTask | 4.0 and higher | |
0x00030A02 (4.0) | SrvInitSoundDriver | 4.0 only | valid as server call |
0x00030A03 (4.0) | SrvPlaySound | 4.0 only | valid as server call |
0x00030A04 (4.0); 0x00030402 |
SrvLogon | 4.0 and higher | |
0x00030A05 (4.0) | SrvServiceMessageBox | 4.0 only | |
0x00030A06 (4.0); 0x00030403 (5.0 to 6.0) |
SrvRegisterServicesProcess | 4.0 to 6.0 | |
0x00030A07 (4.0); 0x00030404 (5.0 to 6.0); 0x00030403 |
SrvActivateDebugger | 4.0 and higher | |
0x00030A08 (4.0); 0x00030405 (5.0 to 6.0) |
SrvGetThreadConsoleDesktop | 4.0 to 6.0 | valid as server call |
0x00030406 (5.0 to 6.0); 0x00030404 (6.1 to 6.2) |
SrvDeviceEvent | 5.0 to 6.2 | |
0x00030407 (5.0 to 6.0) | SrvRegisterLogonProcess | 5.0 to 6.0 | |
0x00030408 (5.0 to 5.1) | SrvWin32HeapStat | 5.0 to 5.1 | succeeds trivially |
0x00030409 (5.0 to 5.1) | SrvWin32HeapFail | 5.0 to 5.1 | succeeds trivially |
0x0003040A (5.1); 0x00030408 (5.2 to 6.0); 0x00030405 (6.1 to 6.2); 0x00030404 |
SrvCreateSystemThreads | 5.1 and higher | |
0x00030409 (5.2 to 6.0); 0x00030406 (6.1 to 6.2); 0x00030405 |
SrvRecordShutdownReason | 5.2 and higher | valid as server call |
0x0003040A (6.0); 0x00030407 (6.1 to 6.2); 0x00030406 |
SrvCancelShutdown | 6.0 and higher | |
0x00030408 (6.1) | SrvConsoleHandleOperation | 6.1 only | |
0x0003040B (6.0); 0x00030409 (6.1) |
SrvGetSetShutdownBlockReason | 6.0 to 6.1 |
In versions 5.0 to 5.2 inclusive, the API numbered 0x00030400 (for exiting Windows) is enabled for server-side calls when running on a Terminal Server (in the sense of having the 0x0010 bit set in the product suite).
The two routines SrvWin32HeapStat and SrvWin32HeapFail both succeed trivially and have the same address. It is not known which has which API number! Presumably, they are not trivial in some checked build.