The Printing Architecture is one of the major components from Windows architecture. It consists of a print spooler and a set of printer drivers. The applications can create print jobs and send them to the printers by calling device-independent Win32 printing and GDI functions. Printer drivers include a user interface component that allows users to control a printer's selectable options (Paper Size, Number of copies, Coloration, Pages per sheet etc.).
An application's calls to Win32 GDI functions are passed to the GDI graphics engine, which either spools the drawing instructions as an enhanced metafile (EMF) file or, in conjunction with a printer driver, renders a printable image that can be sent to the spooler. Spooler components interpret EMF files, and they can insert page layout information and job control instructions into the data stream. The spooler then sends the data stream to the serial, parallel, or network port driver associated with the target printer's I/O port. Spooler and driver components are designed to be replaceable. Support for a new printer usually requires only the creation of new data files for use with one of the Microsoft-supplied printer drivers.
Most of the device drivers work at kernel mode. Some of the device drivers or part of the device drivers work at user mode and kernel mode. Printer drivers work at both modes.
The printing process is divided into three groups of steps:
Each process performs some operations and passes the print job to another process. For e.g., user fires a print document from an application, the client process starts the creation of print job by calling the GDI, and after completing the creation of print job, it sends to the spooler. The spooler will perform some operations on that print job and sends to the printer process. The printer processes receive the print job from the spooler process and translate the print language into a bitmap, and then it prints.
A user sends a print job from an application. The application calls the Graphics Device Interface (GDI). If print output is produced in RAW format, the GDI is not used. The GDI calls the printer driver for information, which the GDI uses to create a job in printer language. The GDI delivers the job to the spooler.
Introduction to Print Spooler: Print spooling is configured by users. Jobs can be sent to the spooler, or sent directly to the printer. If jobs are sent to the spooler, they can be configured to start printing as soon as possible or after the final page in a job has been sent to the spooler. When you send a print job directly to the printer, your computer renders the entire job and then transfers it directly to the printer. When you send a print job to a spooler, your computer creates the job, including meta-information about how the job must be processed, and then sends the job to the spooler. The spooler then renders the job and sends it to the printer.
Sending a print job directly to the printer is good because you remove a potential point of failure in printing documents, and all print job rendering is done on your computer, affording you more control, and you don’t have to wait for other jobs to complete, as you might if you were printing to a queue on a print server that was being used by many users. Conversely, rendering a print job on your computer consumes computing resources, so you might experience reduced performance or have to wait until the print job has completed before doing anything.
Sending a print job to a spooler is good because your computer does not have to render the print job, meaning your computer’s resources are more completely and immediately available. Conversely, sending a print job to a spooler fails if the print server with the spooler is unavailable, and you might have to wait for other jobs to finish spooling before your job is processed.
The primary component of the printing interface is the print spooler. The print spooler is an executable file that manages the printing process. Management of printing involves retrieving the location of the correct printer driver, loading that driver, spooling high-level function calls into a print job, scheduling the print job for printing, and so on. The spooler is loaded at system startup and continues to run until the operating system is shut down. Applications that print create a printer device context (DC). When an application creates a printer DC, the spooler performs necessary tasks such as determining the location of the required printer driver and then loading the appropriate printer driver. It also determines the data type used to record the print job.
The supported data types include enhanced metafiles (EMF), ASCII text, and raw data (all printer specific data types such as PostScript and PCL). Custom data types can be added to the spooler when additional printer drivers and print processors are installed. A print job is a document stored internally (by using one of the supported data types) that may contain one or more pages of output. It may consist of multiple forms; for example, a job may consist of one envelope and three pages of A4 paper. A print job is defined (or bracketed) by the StartDoc
and EndDoc
functions.
The default data type for a print job is the enhanced metafile. An EMF record is a compact structure used to store text output commands, raster graphics commands, and so on. When an application calls StartDoc
, the spooler creates a spool file and a data file and begins storing EMF records in the spool file. The spool and data files are created in an operating system directory. The spooler uses the spool file to store EMF records, and uses the data file to record the type of form, the data type for the print job, the target printer, and so on. The spooler deletes these files when the job has successfully printed.
The Microsoft Windows print spooler is made up of a set of Microsoft-supplied and optional vendor-supplied components, with responsibilities that include:
Windows print spooler support for Directory Services consists of:
The primary components of the Microsoft Windows print spooler are illustrated in the following diagram. The print spooler consists of a group of components that include the print router, the local and remote print provider, the print processor, and the language and port monitors.
If printer hardware is local to the system on which the application is running, the "client" and "server" are the same system (although this is not evident in the diagram).
Note: All spooler components execute in user mode.
This section provides the following topics:
Print providers are responsible for directing print jobs to local or remote print devices. They are also responsible for print queue management operations, such as starting, stopping, and enumerating a server's print queues. Print providers define a high-level, machine-independent, Operating System-independent view of a print server. All print providers implement a common set of print provider capabilities. These capabilities are defined by a set of API functions, which are called by the spooler's router (spoolss.dll).
When viewing the diagram, you should consider the following points:
By supporting predefined sets of API functions, Windows print providers can supply the following capabilities:
These capabilities are implemented as a set of functions defined by print providers. There are many functions supported to define a print provider. Functions are divided into the following groups:
The local print provider for Windows provides job control and printer management capabilities for all printers that are accessed through the local print provider's port monitors. (A client administrator sets up access to such printers by selecting the Local Printer option when using the Add Printer Wizard.) Such printers include those connected to the local system's serial and parallel ports. They can also include devices connected to other I/O channels, such as SCSI ports, along with printers connected to remote non-NT-based-operating system servers.
As the diagram shows, an application creates a print job by calling the Graphics Driver Interface (GDI). Regardless of whether the print job's initial output format is EMF, the local print provider's job creation API creates a spool file. Later, when the job is scheduled, the spool file is read and, if the format is EMF, the EMF print processor sends the job back to GDI for conversion to RAW format, with the help of a printer graphics DLL. The converted data stream can then be sent back through the local print provider to the printer (without being re-spooled).
Printer drivers contain information that is specific to the printer that is used. Printer drivers reside on user’s computers and are used by the GDI to render print jobs. A printer driver is a software program that understands how to communicate with printers and plotters. Printer drivers translate the information a user sends from the computer into commands that the printer understands. Various drivers must be installed on the print server to support different hardware and operating systems. For example, an administrator running Windows 2000 Server who shares a printer with clients running Windows 95 and Windows 98 might want to install the appropriate drivers so the users won't be prompted to install the missing drivers. The printer driver sends the printer-setting information, including the specifications needed to produce each character of the document, to the GDI. It also transmits helper services or utilities required to make the output print correctly.
Printer drivers are composed of three separate files:
All Windows printer drivers consist of the following components:
The print processor is a dynamic-link library (DLL) which calls the printer driver. An application has tried to use a print processor which has not been installed on your computer. The spooler monitors the current print jobs and the target printer to determine an appropriate time to print a job. Once the spooler determines that a job should be printed, it calls the print processor. The print processor works together with the printer driver to move the spooled print jobs from the hard disk.
Print processors are user-mode DLLs that are responsible for converting a print job's spooled data into a format that can be sent to a print monitor. They are also responsible for handling application requests to pause, resume and cancel print jobs.
The print job's spooled data is contained in a spool file. The print processor reads the file, performs conversion operations on the data stream, and writes the converted data to the spooler. The spooler then sends the data stream to the appropriate print monitor.
Microsoft Windows 2000 and later includes the print processors listed in the following table.
Print Processor
Input Data Types
Output Data Types
localspl.dll *
sfmpsprt.dll
PSCRIPT1
RAW
* Beginning with Windows 2000, localmon.dll and winprint.dll are included in localspl.dll.
For information about the data types, see the following topics:
You can create a customized print processor to support a data type that is not supported by Windows 2000 or later operating system versions. You can also provide a customized print processor that supports one or more of the supported data types, thus allowing you to modify the capabilities provided by the supplied print processors. Print processors are associated with printer drivers during driver installation, so multiple print processors supporting the same data type can coexist.
Enhanced Metafile (EMF) data consists of instructions to call GDI functions. The print processor must call the GDI functions to render printable images. The GDI functions make calls to the printer driver's printer graphics DLL, which renders the image and sends it to the spooler as RAW data (by calling EngWritePrinter
). NT-based operating system clients send EMF data to NT-based operating system print servers. EMF data is device independent and can be sent to a server more quickly than RAW data. A print job is also spooled as EMF data when the requesting application is local to the server, allowing a quick return to the application while the EMF data is subsequently rendered by a background spooler thread.
EMF (Enhanced MetaFile) is spool file format used in printing by the Windows operating system. When a print job is sent to the printer, if it is already printing another file, the computer reads the new file and stores it, usually on the hard disk or in memory, for printing at a later time. Spooling allows multiple print jobs to be given to the printer at one time.
The EMF format is the 32-bit version of the original Windows metafile (WMF) format. The EMF format was created to solve the deficiencies of the WMF format in printing graphics from sophisticated graphics programs. The EMF format is device-independent. This means that the dimensions of a graphic are maintained on the printed copy regardless of the resolution in dots per inch of the printer. In a network, the smaller file size of the EMF format reduces network traffic. EMF is the spool file used by the Windows operating system.
RAW data can be sent to a print monitor without further processing. The print processor just sends this data back to the spooler (by calling WritePrinter
, described in the Platform SDK documentation), sometimes inserting form feeds. An example of a RAW data file is one consisting of printer control language (PCL) commands. Print jobs are sent from client to server in RAW format if either the client or the server does not support NT-based-operating system EMF, or if a server administrator has disabled EMF support. In such cases, image rendering is performed on the client before the job is sent to the server. Postscript commands can be considered RAW data if the target printer supports Postscript. On the other hand, the sfmpsprt.dll print processor takes Postscript input and interprets it for non-Postscript printers, so in that case, the Postscript is not RAW data.
A RAW spool file is a one that is sent to the Windows spooler unprocessed (which is why it's called "RAW"). The raw file is used to send Postscript commands to a Postscript printer. The Postscript commands are understood by the printer, but are just plain data to the Windows spooler. The RAW format is device-dependent and slower. If printing problems occur while using the EMF format, they can sometimes be fixed by simply changing the format to "RAW" in the printer Properties.
RAW is data formatted exactly how the printer needs it. Depending on the printer concerned, it could be fully rendered to a dot-by-dot page image or, on more sophisticated printers, incorporate vector elements. A PostScript printer, for example, expects a page to be described by a set of PostScript commands. This is essentially a vector format and that's what the RAW data would contain. EMF (Enhanced Metafile) describes the page in a vector format specific to Windows. EMF is actually a capture of the GDI (Graphics Device Interface) commands that programs use to tell Windows how to draw what you see on the output device, normally the screen. Because EMF is Windows' native image description language, capturing the commands into a spool file is a relatively quick and simple process. Immediately converting data to RAW format involves more processing and may produce a larger quantity of data than the equivalent EMF. Therefore, when printing from an application, EMF gets the immediate business of generating the print job over as soon as possible before returning control to the user.
When the print spooler is ready to send a buffered page to the printer, RAW data can be passed straight through whereas EMF commands must first be rendered into RAW format. This is done as a background process which means you can continue working. On a well-specified PC and/or printer, the effect on overall performance of this background processing may not be noticeable.
That's the theory, but it doesn't always hold true. And you would think print quality should be the same in either case, but I have avoided describing a lot of behind-the-scenes complications. Odd problems can sometimes be solved by switching from EMF to RAW, or occasionally vice-versa. In fact, RAW is the manufacturer's preferred format for some printers. There isn't much you can do about the speed, but make sure the computer has enough memory to avoid excessive use of the swap file and ensure the disk is defragmented. You might also try the spool setting 'Print directly to the printer'. This is not an option when a printer is shared over a network. Your application will take longer to return control to you, but printing time may be reduced, because the job is not being spooled to disk.
TEXT data consists solely of ANSI text. The print processor calls GDI to draw characters using the print device's default font, and sends the resulting RAW-formatted output to the spooler (by calling WritePrinter
, described in the Platform SDK documentation). The process is equivalent to opening the input file with Notepad and then printing the file. (This format is used for printers that do not print text characters.)
When the spooler is ready to send a print job to a print processor, it calls the print processor's OpenPrintProcessor
function. This function performs initialization activities and returns a handle. The spooler can then call PrintDocumentOnPrintProcessor
, which is the print processor function that converts the data stream from the input format to the output format and returns the converted stream to the spooler. If the input format is NT-based-operating system EMF, the PrintDocumentOnPrintProcessor
function can control the playback of the EMF records by using the functions listed in Using GDI Functions in Print Processors. These functions provide an interface between the print processor and the printer driver. This interface allows print processors to control the physical layout of printer pages, and thus facilitates implementing such features as printing multiple document pages per physical page ("N-up" printing), printing pages in reverse order, and printing multiple copies of each page.
A print processor's output data stream must be returned to the spooler. Typically, if the data conversion requires interaction with the printer driver's printer graphics DLL (as is the case for EMF input data), the graphics DLL returns the stream to the spooler by calling EngWritePrinter
. On the other hand, if the conversion does not call the printer graphics DLL (as is the case for RAW input data), then the print processor calls WritePrinter
. The PrintDocumentOnPrintProcessor
function can be interrupted by asynchronous calls from the spooler to the print processor's ControlPrintProcessor
function. This function implements an application's ability to pause, resume, or cancel a print job. After PrintDocumentOnPrintProcessor
finishes converting the data stream and returns, the spooler calls the print processor's ClosePrintProcessor
function.
To install a print processor, an installation application must call the spooler's AddPrintProcessor
function. To associate a print processor with a print queue, list its file name in an INF file in a PrintProcessor
entry. This entry must be included for every print queue to which the print processor is to be associated. For more information, see Printer INF Files. When an installation application calls the spooler's AddPrinter
function, using a PRINTER_INFO_2
structure as an input argument, it specifies the print processor name (obtained from the INF file) as a structure member.
If the PnP manager detects and installs a print queue on a system running either Windows 2000 or Windows XP, and if the INF file used to install the print queue contains a PrintProcessor
entry other than the default Windows print processor, WinPrint
, the print processor will not be associated with the print queue. However, the print processor will be installed. (Note that if you install the print queue using the Add Printer wizard, the print processor is correctly associated with the print queue. Note also that the PnP manager in Microsoft Windows Server™ 2003 and later correctly associates a print processor with the print queue.)
To associate the print processor with the print queue for Plug and Play installations on Windows 2000 and Windows XP, include a PRINTER_EVENT_INITIALIZE
case in the printer interface DLL's DrvPrinterEvent
function. For Microsoft Windows Server™ 2003 and later, it is not necessary to add a PRINTER_EVENT_INITIALIZE
case in the DrvPrinterEvent
function.
Print monitors are responsible for directing a print data stream from the print spooler to an appropriate port driver. Two types of print monitors are defined — language monitors and port monitors.
Language monitors are user-mode DLLs that serve two purposes:
Microsoft provides a language monitor, pjlmon.dll, which supports printer job language (PJL), and provides bidirectional communication for PJL printers. This monitor is included in the DDK as the sample language monitor.
Customized language monitors can be written to support other job control languages, for unidirectional or bidirectional printers.
Language monitors are optional and only associated with a particular printer type if included in the printer's INF file, as described in Installing a Print Monitor.
If a language monitor is associated with a printer, the language monitor receives the printer's data stream from the print processor, modifies it, and passes it to the printer's port monitor.
Port monitors consist of user-mode DLLs. They are responsible for providing a communications path between the user-mode print spooler and the kernel-mode port drivers that access I/O port hardware. A port monitor typically uses the CreateFile
, WriteFile
, ReadFile
, and DeviceIOControl
functions, described in the Platform SDK documentation, to communicate with kernel-mode port drivers. Port monitors are also responsible for management and configuration of a server's printer ports, as described in Managing a Port.
An NT-based-operating system user's view of a "printer" is really a print queue, to which one or more physical printer devices can be connected. A port is the physical connection between the print queue and a single printer device. Each port monitor supports one or more instances of one or more types of ports. For example, localmon.dll, the sample port monitor, can support all of a server's local COM and LPT ports. (The print folder assigns ports to port monitors by calling the Platform SDK documentation's AddPrinter
function.)
For print queues representing multiple printer devices (through multiple ports), the spooler sends each print job to the first available port. If the port monitor indicates that a specified port is busy or has encountered an error, the spooler resubmits the job to the queue, specifying another port supported by the port monitor.
Besides localmon.dll, Windows 2000 and later operating system versions provide several additional port monitors. The Windows 2000 Server Resource Kit describes each of these port monitors. Customized port monitors can be written to support additional types of I/O port hardware.
For Windows 2000 and later, each port monitor is divided into two DLLs:
When the spooler calls LoadLibrary
to load a print monitor DLL, the system immediately calls the DLL's DllEntryPoint
function. It is generally a good idea for the entry point function to call DisableThreadLibraryCalls
, described in the Platform SDK documentation, so the DLL is not unnecessarily notified when threads are created and deleted.
Each DLL exports an initialization function, which the spooler calls after calling LoadLibrary
. Language monitor DLLs and port monitor server DLLs export an InitializePrintMonitor2
function. Port monitor UI DLLs export an InitializePrintMonitorUI
function.
These two initialization functions are responsible for returning pointers to the rest of the functions defined by print monitors, so the spooler can call them. The initialization functions can also perform load-time initialization operations. The monitor's InitializePrintMonitor2
function returns a monitor instance handle. The monitor should allocate local memory to store instance-specific information, and use the monitor handle as an identifier for the allocated memory.
When the spooler is first started, it loads all of the monitor DLLs that have been installed. After calling all monitor initialization functions, the spooler calls each port monitor's EnumPorts
function, which enumerates the ports supported by the monitor. (A monitor supports a port if the port has been added to the monitor's database, as described in Adding a Port.) Each supported port is then opened, as described in Opening and Closing a Port.
After a port has been added, as described in Adding a Port, the spooler can open it by calling the appropriate language monitor's OpenPortEx
function.
The language monitor uses the OpenPortEx
function to create and return a port handle. Typically, a language monitor calls its associated port monitor's OpenPort
function, and the language monitor just returns the handle obtained from the port monitor's OpenPort
.
If a language monitor is not associated with a port, the spooler calls the port monitor's OpenPort
function directly.
The spooler does not allow more than one path to a port to be enabled at one time. Thus, after it has called OpenPortEx
(or OpenPort
) in a particular monitor, it does not attempt to open the same port again before closing it.
After a port has been opened, the spooler can call additional functions to print a job, as described in Printing a Print Job, using the port handle as an input argument. A monitor should be written so that, after a port has been opened, the spooler can send multiple print jobs before closing the port.
The spooler closes a port if a job must be sent through a different language monitor, if no print queues are associated with a port, or when the system shuts down. To close a port, the spooler calls a language monitor's ClosePort
function. The function invalidates the handle that was created when the port was opened. A language monitor typically calls the ClosePort
function defined by its associated port monitor.
If a language monitor is not associated with a port, the spooler calls the port monitor's ClosePort
function directly.
After a port has been opened, as described in Opening and Closing a Port, the spooler can send print jobs to the port.
Each print job is delimited by spooler calls to a language or port monitor's StartDocPort
and EndDocPort
functions. The spooler calls these functions when a print processor calls the spooler's StartDocPrinter
and EndDocPrinter
functions, which are described in the Platform SDK documentation. Within the scope of a set of StartDocPort
and EndDocPort
functions, unlimited spooler calls to a monitor's WritePort
, ReadPort
, and GetPrinterDataFromPort
functions can occur.
Each of these functions requires the port handle returned by OpenPortEx
(or OpenPort
) to be specified as an input argument. Typically, a language monitor implements each of the functions by calling the like-named function in its associated port monitor.
When the spooler calls a language monitor's WritePort
function to send a data stream to the port, the function generally adds language-specific information, such as PJL commands, to the received data stream before passing it to the associated port monitor's WritePort
function.
The ReadPort
function is used for obtaining status information from bidirectional printer hardware, which a language monitor might send to the spooler by calling SetPort
, described in the Platform SDK documentation. The spooler does not call the ReadPort
function.
If printing hardware is bidirectional, both its language monitor and its port monitor should support a GetPrinterDataFromPort
function. A language monitor's GetPrinterDataFromPort
function should accept a registry value name as input, obtain a value for that name (generally by calling associated port monitor's WritePort
and ReadPort
functions), and return the value to the caller. A port monitor's GetPrinterDataFromPort
function should accept an I/O control code as input, call DeviceIoControl
(described in the Platform SDK documentation) to pass the control code to the port driver, and return the result.
This section describes the methods that can be used to install print monitors. (You can install a print monitor with the same INF file that you use to install your printer. For more information about INF files, see Plug and Play and Power Management.)
Installing a Language Monitor: To install a language monitor, you must list its file name in an INF file by using a LanguageMonitor
entry. This entry must be included for every printer driver that controls a printer requiring the use of the language monitor. For more information, see Printer INF Files. The Add Driver wizard or the Add Printer wizard reads this INF file and installs language monitors associated with printer drivers. Alternatively, custom installation applications can install language monitors by calling the spooler's AddMonitor
function, to explicitly install only a specific monitor DLL.
Installing a Port Monitor: To install a port monitor, your installation medium must include a printer INF file (that is, an INF file for which Class = Printer) that contains a PortMonitors
section. The single entry in this section points to an install section containing two entries: an INF CopyFiles
directive that lists all of the files that make up the port monitor, and a PortMonitorDll
entry that specifies which DLL in the previous list implements the port monitor interface. The following example code illustrates these points. The PortMonitors
section points to an install section named SamplePortMon
. In that section, an INF CopyFiles
directive copies three files that make up the port monitor. Following that, a PortMonitorDll
entry identifies the DLL that implements the port monitor interface.
[PortMonitors] "Sample Port Monitor" = SamplePortMon [SamplePortMon] CopyFiles = @file1.dll, @file2.dll, @file3.hlp PortMonitorDll = file1.dll
To install a port monitor, open the Printers folder in Control Panel. On the Printers folder's File menu, select Server Properties. On the File Server Properties dialog, click the Ports tab, and then click the Add Port... button. On the Printer Ports dialog, click the New Port Type... button. Type the path to the INF file in the text input box, and then click OK.
Alternatively, a custom installation application can install the port monitor DLL by a call to the AddMonitor
function.
The spooler provides support for bidirectional ("BiDi") communication between an application or driver and a printer. This support enables the application or driver to send one or more requests to the printer, and the printer to respond to these requests.
The bidi communication support involves two parts: the bidi communication schema and the bidi spooler APIs. The schema describes the requests that an application can make to a device and the format for the requests. The spooler APIs send the requests to the device and also send and receive the bidi data. An application can also send a request to a network print provider for a network printer or a printer that is connected to a remote printer server.
To send a single request to the printer, an application or printer driver must first compose the request, and then call the IBidiSpl::SendRecv
method. To send multiple requests, the application or driver composes a list of requests, and then calls the IBidiSpl::MultiSendRecv
method. After receiving the request, the client-side portion of the spooler (winspool.drv) passes it on to the server-side spooler (spoolsv.exe). The server-side spooler can be on the local computer, or on a remote network print server. When the server-side spooler receives the request, it parses the data in the request. The server-side spooler converts the data to a form suitable for use by the application or driver, and passes it back to the client-side spooler, and finally back to the originator of the request.
Click here to view Bodapati Venkat's online profile.