The remote printer uninstall steps are as follows:
1. When a session is disconnected or logged off, RDPDR.SYS sends a device removal event to WLNOTIFY.DLL for each client-side printer and port.
2. WLNOTIFY.DLL purges and deletes all queues for its respective session.
printer Redirection Components
RDPDR(RDPDR.SYS) is a KERNEL-mode driver that redirects Terminal Services client-side devices for clients connected to the Terminal Server using the RDP protocol. RDPDR.SYS uses a Virtual Channel in RDP to send print job data from server to client. This is defined by the name “RDPDR”.
RDPDR.SYS is a root-enumerated virtual bus driver that is loaded at boot time by the operating system. A single instance of RDPDR.SYS is shared by all sessions on the TS server. It is the job of RDPDR.SYS to route and redirect I/O requests from a session to the appropriate TS client machine. RDPDR.SYS plays a central part in the overall TS redirection scenario.
When the USER-mode component RDPWSX.DLL notifies RDPDR.SYS of a session connect, RDPDR.SYS initializes itself and waits for device information from the client.
RDPDR.SYS receives from the client a list of client-side devices that meet the redirection criteria. It uses this list to create and register printer port device interfaces, device paths, printer and port announce events to the USER-mode WLNOTIFY.DLL component, and symbolic links.
RDPDR.SYS handles all printer I/O to the client that is sent from the Spooler/USBMON.DLL.
Terminal Services starts Winlogon (Winlogon.exe) at connection time. In each session, Winlogon loads a library called WLNOTIFY.DLL. Components that reside within WLNOTIFY.DLL expose functions that can be called by Winlogon in response to major events, such as connect, disconnect, and logoff. TS RDP redirected printer queues are installed from this WLNOTIFY.DLL module running inside Winlogon.exe.
The Spooler notifies WLNOTIFY.DLL of any changes to a printer queue configuration, such as paper orientation (portrait or landscape) or printing on both sides. These changes are then persisted by WLNOTIFY.DLL, which sends cache data to the client. For more information, see Printer Queues Creation Process.
New printer queues that are manually added by an Administrator in the session are detected when the Spooler sends an event to WLNOTIFY.DLL. WLNOTIFY.DLL persists this data by sending it to the client. For more information, see Printer Queues Creation Process.
The Spooler (SPOOLSV.EXE) is a system-level service. It is a single-instance process that lives for the duration of the system and handles all the print jobs in the system; it is not limited to a TS environment. The main job of the Spooler in the TS printer redirection scenario is to prepare print jobs and send a job in RAW rendered data specific to the target device’s printer language from the server to the TS client. It communicates with the appropriate print driver via GDI/Win32k to generate the RAW data. For information about how the Spooler determines which print driver to use, see Printer Queues Creation Process.
Because redirected printers are not static (in other words, they can come and go at any time, unlike printers physically attached to a computer), the printer ports that they are attached to are also dynamic.
The Spooler is responsible for generating Notify events to WLNOTIFY.DLL to track any changes in printer queue settings. These changes may include properties such as print orientation (portrait or landscape), number of pages per sheet, etc. The Spooler also generates Notify events to WLNOTIFY.DLL whenever a manual printer queue is created in the session attached to a client-side printer port. For information on this process, see Printer Queues Creation Process.
USBMON.DLL manages all the dynamic TS printer ports that have been registered (created) on the server side. Typically, because of the way the Spooler works, USBMON.DLL never deletes these ports. However, USBMON.DLL allows re-use of several of these ports if they are no longer in use. USBMON.DLL is also responsible for managing USB-based local printer connections in addition to managing the redirected ports.
When the Spooler has finished a print job, it sends the output to USBMON.DLL if it is a TS printer port. USBMON.DLL in turn forwards the output to the KERNEL-mode RDPDR.SYS driver. RDPDR.SYS sends this data to the client.
MSTSCAX.DLL is the Terminal Services Client ActiveX Control. With regard to printing, it is a TS client-side component that implements the RDP Virtual Channel for redirected printing. The client-side RDPDR subcomponent within MSTSCAX.DLL enumerates printers on the client and announces them to the server. Printers are enumerated using the EnumPrinters() API. In RDP 5.0, only printers connected locally to the client machine via COM, Serial, or USB ports are redirected in Terminal Server sessions.
The printers automatically detected via the EnumPrinters() API are always called automatic printer queues. The client sends data for each enumerated printer, including printer name, printer type (for example, network or local), driver name, and any configuration data, such as paper orientation (portrait or landscape) or number of pages per sheet, that was previously saved by the client in the registry.
In addition to the printers that were automatically detected, the client also announces printers that were manually created in a previous session by the user or administrator. These printers were persisted by the client in the registry (see Details of Queue Configuration Changes). These manual printer queues from the previous session now are automatically announced to the server by MSTSCAX.DLL (client RDPDR.LIB) and can now be viewed as automatic printer queues.
printer Redirection Connection and disconnection Process
Printer Redirection Session Connection
The session connection sequence is shown in Figure 5.
Figure 5 Session connection sequence
Details of Session Connect:
1. RDPDR.SYS is notified of a connect from RDPWSX.DLL (the details of how RDPWSX is notified are beyond the scope of this document). RDPDR.SYS sends a Server Announce packet.
2. As part of initializing its connection to the server, MSTSCAX.DLL (client-side RDPDR.LIB) enumerates its printing ports (LPTs and COMs) and sends these ports to the server.
In Windows 2000, the client enumerates ports by iterating through the DOS devices for COM and LPT ports and checking whether the CreateFile call succeeds. If it does, the port exists; otherwise, it doesn’t announce the port.
Printer Queue Enumeration:
Win32 EnumPrinter() APIs return all printer queues that are currently present on the system. In the current RDP 5.0 implementation, only queues connected to LPT, COM, and USB ports are redirected by default. Because these printer queues are automatically detected, they are called automatic printer queues.
3. In addition to the EnumPrinter() API, the client remembers manually created printer queues from previous logons. The manual queue information is preserved under the following registry key:
HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default\AddIns\RDPDR.SYS\<printer queue name> \PrinterCacheData
The client enumerates these subkeys to build the manual created queues list. In a sense, these become automatic printer queues for the current logon because they are “automatically” detected from a previous manual creation.
Client port names for automatic printer queues are always named PRNxxx, where xxx is a number that increases for each printer. Client port names for physical ports are always LPTxxx, COMxxx where xxx represents a number that increases for each port device (for information on naming conventions, see Printer Queues).
4. The client builds the list of devices using all of the above enumerated ports and sends it to the server.
5. For each printing port announced by the client, the KERNEL-mode RDPDR.SYS creates a corresponding TS printing port. These ports are named using the following convention:
where Port Number is a monotonically increasing value representing the next available port. On reboot, all TS ports are deleted.
6. RDPDR.SYS registers a device interface using the PnP APIs, which in turn notify the Spooler of a dynamic printer device. The Spooler then calls USBMON.DLL to enumerate the ports.
7. WLNOTIFY.DLL is loaded by Winlogon and is notified of the connect. A background thread in this module communicates with RDPDR.SYS by using IOCTLs to obtain any events such as printer and port announces.
8. In response to the printer announce event, WLNOTIFY.DLL does the following:
Checks whether a matching driver string name is installed on the server. If not, it checks the user-defined .INF files and NTPRINT.INF.
If a driver string name match is found, it calls a PnP function exposed by PRINTUI.DLL to create the printer queue. If the driver is not found, the printer queue is not installed for the session, the printer is not redirected, and event log entries notifying of the failed redirection attempt are logged. Therefore, this printer cannot be used and is not visible to the user.
Sets the default printer to be the client’s default printer (this information is part of the printer announce data received from the client). If policy does not allow it, the existing default printer is not changed.
Adds the new printer queue to its internal list of devices that includes printer queues.
Restores any configuration information sent by the client (such as paper orientation or the number of pages per sheet).
Sets the default security for the printer to give read/write/print permissions for the logged-on user. Full Control is given to administrators. Redirected TS printers are visible only to the user logged onto the printer’s associated session and to any user with Administrator privileges.
Windows 2000 security helps hide printers. Clients can access and enumerate only those printers for which they have Write access. The same user logged in to multiple TS terminals will have access to all remote printers from each terminal he/she is logged in to.
9. RDPDR.SYS also generates events to announce printer ports (LPT and COM). The WLNOTIFY.DLL component receives this event and saves information related to the printer port in its internal list of devices, which includes printer ports. This list will be used when creating manual printer queues. Note that RDPDR.SYS does not generate events for printer ports associated with Automatic Printer Queues; that is, client port names with PRNxxx do not generate events. Therefore, WLNOTIFY.DLL does not have an internal list of printer ports that belong to Automatic Printer Queues. This differs from local port redirection, because these ports are exposed only as available to printers under the Printers folder.
Printer Redirection Session Disconnection
The session disconnection sequence is shown in Figure 6.
Figure 6 Session disconnection sequence
Details of Session Disconnect/Logoff
Compared to the connect sequence, the disconnect sequence is much simpler.
1. For each printer and port, a notification is sent to WLNOTIFY.DLL to remove the associated USER-mode device.
2. WLNOTIFY.DLL deletes the automatic and manual printer queues for the session by calling DeletePrinter(). This call purges queues of all pending print jobs without any warning to the user, which means that all pending print jobs are lost.
Printer I/O Sequence
The Printer I/O sequence is shown in Figure 7.
Figure 7 Printer I/O sequence
Details of Printer I/O Sequence
1. An application calls the Spooler API to print.
2. The Spooler checks its internal printer port table and determines that RDPDR.SYS is the handler for this request. The Spooler generates a CreateFile on the printer port.
3. KERNEL-mode RDPDR.SYS sends a Create IRP via Virtual Channel to the RDPDR.LIB module of the TS client. This IRP contains the device ID, device name, and other data.
4. The RDPDR.LIB module of the TS client calls OpenPrinter using the device ID on the printer.
5. The Spooler sends a Write IRP to RDPDR.SYS.
6. KERNEL-mode RDPDR.SYS sends a Write IRP via Virtual Channel to the RDPDR.LIB module of the TS client. This IRP contains the device ID, device name, and other data.
7-10. The RDPDR.LIB module of the TS client calls WritePrinter, using the device ID on the printer. Similar operations take place for the Close IRP from the Spooler.
Printer queues Creation Process
Automatic Queue Configuration Changes
A user can modify a printer queue’s settings once he is logged into the session and typically prefers these settings to remain whenever he logs into the session. For this reason, queue configuration changes are persisted on the client. Once set, the changes are applied to the corresponding redirected printer queue from the same client regardless of which server is connected.
Figure 8 illustrates the steps involved in this process.
Figure 8 Automatic queue configuration changes
Details of Queue Configuration Changes
As part of its initialization, WLNOTIFY.DLL registers to the Spooler service to get notification of any changes that might be made to the redirected printer queues it adds for the client.
1. When a user changes printer properties (configuration information such as paper orientation, tray information, or renaming the printer) for a given printer queue, the above registered notification gets triggered. The notification includes the printer name.
2. WLNOTIFY.DLL looks at the notification and checks its internal list of printer queues to see if the printer queue really belongs to it. If WLNOTIFY.DLL cannot find the printer name, it then checks whether this is a new manual printer (see Manual Printer Queues).
3. If the printer queue belongs to the session, a call is made into PRINTUI.DLL to get configuration details of the queue.
4. PRINTUI.DLL calls into Spooler to fetch the configuration information.
5-6-7. WLNOTIFY.DLL reads the configuration information passed to it from PRINTUI.DLL/Spooler as a blob of binary data and creates a configuration update message. This message contains the configuration binary data.
8. The update (or rename if the printer is renamed) message is then sent to the client by an IOCTL to the KERNEL-mode RDPDR.SYS.
9. The TS client-side RDPDR component receives the update and uses the device ID to obtain the printer to which the message applies. The client does not try to interpret it, but simply stores it in the registry, under the following registry key:
HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default\AddIns\RDPDR.SYS\<printer queue name> \AutoPrinterCacheData
During the next server connection, when announcing the same automatic printer, the client reads this information from the registry and includes this blob of binary in the announce data.
To improve server performance, notifications are batched and sent to the client. Therefore, it typically takes 30 seconds to 1 minute for the configuration to be saved on the client side.
Manual Printer Queues
Figure 9 illustrates the steps involved in Manual Printer Queue creation.
Figure 9 Manual printer queues
Details of Manual Printer Queues
Most of the steps in this process are identical to the process for configuration changes. However, there are a few subtleties to note.
As part of its initialization, WLNOTIFY.DLL registers to the Spooler service to get notification for any new printer queues that might be manually added within the session.
1. When an administrator manually adds a printer and associates the printer with a valid client-side port (client-side PRN ports are invalid), the above registered notification gets triggered. The notification includes the printer name.
2. WLNOTIFY.DLL looks at the notification and checks its internal list of printer queues to see whether the printer queue really belongs to it. If WLNOTIFY.DLL cannot find the printer name, it checks whether this is a new manual printer attached to one of its internal device list of ports.
3–4. If it finds the port in its internal list, it creates a temporary file and passes this file name to a call into PRINTUI.DLL to get the printer queue configuration details.
5–6. PRINTUI.DLL calls into Spooler to fetch the configuration information and then saves it in the temporary file that WLNOTIFY.DLL supplied.
7. WLNOTIFY.DLL reads the configuration information to obtain the driver name and other relevant information from the temporary file.
8-9. An Add Printer message is created. This message contains the printer name, driver name, and any other relevant information. This message is then sent to the client by using an IOCTL to the KERNEL-mode RDPDR.SYS.
10. The Terminal Server Client RDPDR.SYS component receives the Add Printer message and looks up the printer name to which the message applies. The client does not try to interpret it, but simply stores it in the registry under the following registry key:
HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default\AddIns\RDPDR.SYS\<printer queue name> \PrinterCacheData
During the next server connection, when announcing the printers, the client reads this information from the registry and includes this printer queue to be redirected.
The following sources are cited in this white paper:
Terminal Services Capacity and Scaling White Paper: http://www.microsoft.com/windows2000/techinfo/administration/terminal/tscaling.asp
Chapter 16 of the Windows 2000 Server Resource Kit – Deploying Terminal Services: http://www.microsoft.com/technet/treeview/default.asp?url=/TechNet/prodtechnol/windows2000serv/reskit/deploy/part4/chapt-16.asp
A list of known applications that require modification to run correctly on Terminal Services can be found at: