Introduction

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.

Printing Process:

The printing process is divided into three groups of steps:

Client processes

Spooler processes

Printer processes

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.

Client Processes

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.

Spooler Processes

The client side of the spooler (Winspool.drv) makes an RPC call to the server side spooler (Spoolsv.exe).

Spoolsv.exe calls the print router (Spoolss.dll).

The router (Spoolsv.dll) sends the print job to the Local Print Provider (LPP) or remote print server if the job is being sent to a network printer.

The LPP polls print processors to find one that can handle the data type of the job.

The LPP sends the job to the print processor, which modifies the job as required to make it print properly.

The print processor sends the job to the page separator. A separator page is added, as required.

The job is sent to the appropriate port print monitor. If print is bidirectional, the job is first sent to the language monitor such as the Printer Job Language (PJL) monitor, and then sent on to the port monitor. If the job is unidirectional, the job is sent directly to the port monitor.

Printer Processes

The printer receives the print job from the print spooler.

The printer translates the print language into a bitmap, which it then prints.

Print Spooler Architecture

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:

Determining whether a print job should be handled locally or across a network.

Accepting a data stream created by GDI, in conjunction with a printer driver, for output on a particular type of printer.

Spooling the data to a file (if spooling is enabled).

Selecting the first available physical printer in a logical printer queue.

Converting a data stream from a spooled format (such as enhanced metafile (EMF)) to a format that can be sent to printer hardware (such as printer control language (PCL)).

Sending a data stream to printer hardware.

Maintaining a registry-based database for spooler components and printer forms.

Windows print spooler support for Directory Services consists of:

Publishing print queues.

Maintaining three registry keys.

Allowing access to spooler-maintained registry keys.

Returning a print queue's publication state.

Spooler Components

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.

GDI: The Graphics Device Interface (GDI) includes both user-mode and kernel-mode components. The user-mode component, Win32 GDI, is used by Win32 applications that require graphics support. The kernel-mode component, the graphics engine (or graphics rendering engine), exports services and functions that graphics device drivers can use.

Winspool.drv: Winspool.drv is the client interface into the spooler. It exports the functions that make up the spooler's Win32 API, and provides RPC stubs for accessing the server. (GDI is the primary client, but applications also call some of its Win32 functions.)

Spoolsv.exe: Spoolsv.exe is the spooler's API server. It is implemented as a Windows 2000 (or later) service that is started when the operating system is started. This module exports an RPC interface to the server side of the spooler's Win32 API. Clients of spoolsv.exe include winspool.drv (locally) and Win32spl.dll (remotely). The module implements some API functions, but most function calls are passed to a print provider by means of the router (spoolss.dll).

Router: The router, spoolss.dll, determines which print provider to call, based on a printer name or handle supplied with each function call, and passes the function call to the correct provider.

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.

Print Providers

This section provides the following topics:

Introduction to Print Providers

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).

Print Provider Flow Paths

When viewing the diagram, you should consider the following points:

If the printer is managed by the client system, the print job is handled by the local print provider (localspl.dll). Printers managed by localspl.dll do not have to be physically local to the client; they can be directly connected to network cards.

If the printer is located on a NT-based-operating system server, the network provider (win32spl.dll) uses RPC to redirect calls from the client's router to the server's spoolsv.exe process. Because the printer is local to the server, the server's local print provider will handle the print job.

If the printer is located on some other type of server, it can be accessed by either the local print provider or by a network print provider that supports that server type, using data formats and network protocols supported by the server.

For the local print provider to access a remote printer, it must contain a port monitor that can use network protocols recognized by the remote printer or server.

Print Provider Capabilities

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:

Initialization Functions

Print Queue Management Functions

Printer Driver Management Functions

Print Job Creation Functions

Print Job Scheduling Functions

Forms Management Functions

Print Processor Management Functions

Print Monitor Management Functions

Port Management Functions

Registry Management Functions

Other Functions

Local Print Provider

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.

Control Flow in Local Printer Provider

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 Driver

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:

A printer graphics driver (for example, PSCRIPT.DLL, RASDD.DLL, or PLOTTER.DLL). Graphics drivers are responsible for print rendering (converting GDI commands from the graphics engine into printer commands that a printer can understand). Each graphics driver handles different printer languages. For example:

PSCRIPT.DLL: deals with the PostScript printer language.

PLOTTER.DLL: deals with the HPGL/2 language used by many plotters.

RASDD.DLL: deals with printer languages based on raster (bitmap) images, including PCL and most dot matrix printer languages.

A printer interface driver (for example, PSCRPTUI.DLL, RASDDUI.DLL, or PLOTUI.DLL). This dynamic-link library (DLL) includes the user interface you see when you configure a printer in Print Manager. It is called by the client side of the router (WINSPOOL.DRV).

Printer Driver Components

A printer graphics DLL that assists GDI in rendering a print job, and sends the rendered data stream to the print spooler.

A printer interface DLL that provides both a user interface to the driver's configuration parameters, and an interface the spooler can call to notify the driver of print-related system events.

Print Processors

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.

Introduction to Print Processors

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 *

EMF

RAW

TEXT

RAW

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:

EMF Data Type

RAW Data Type

TEXT Data Type

PSCRIPT1 Data Type

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.

EMF Data Type

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 Type

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.

Difference Between EMF and RAW Data Formats?

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 Type

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.)

Processing a Print Job

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.

Installing a Print Processor

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.

Associating a Print Processor with a PnP-installed Print Queue

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 Monitor

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

Language monitors are user-mode DLLs that serve two purposes:

They provide a full duplex communications path between the print spooler and bidirectional printers that are capable of providing software-accessible status information.

They add printer control information, such as commands defined by a printer job language, to the data stream.

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

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:

Initializing a Print Monitor

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.

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.

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.

Printing a Print Job

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.

Installing a Print Monitor

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.

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.

Bidirectional Communication

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.

Bidirectional Support Architecture

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Hello..
I have a problem.
I Wrote a virtual printer driver(something llike a pdf creator) which is having a print processor and language monitor. I have a UI which is popedup on each print job to my printer. I am invoking this UI from the print processor I installed it in a W2K3 Print server. Added it to a Win XP SP3 machine. Then I tried to print. The print was succesful. But the problem is the UI is poped up in the server. I want it to be in the client itself...
Please help me to solve this issue...
Thanks in advance...

Can anybody help me to resolve the Crash issue in Notepad and wordpad.

I had developed a monolithic bare minimal printer UI driver. The UI is invoking from all applications (file -->print Dialog) exept for notepad and wordpad. For notepad and wordpad it is crashing when I select, the developed driver. I believe I had done something wrong in the Default DEVMODE value. Can anybody suggest a fix for this. Some of the important code sinippt are given below..

if(dph-&gt;fMode &amp; DM_IN_PROMPT)
{
//This flag is never set if the DrvDocumentPropertySheets function's pPSUIInfo
//parameter is NULL.
/*
* comment from DDK help:
* If psui_info is not null, the caller is the CPSUI. In this situation,
* DrvDocumentPropertySheets should follow the implementation guidelines laid
* out in PFNPROPSHEETUI. This function allows vendors to provide
* device-specific document property information to the CPSUI for inclusion as
* a page on a common property sheet.
*/

Thanks for your text.
I have a question about .spl file.
When I use the Print server to print, I can not find .spl,.shd file under the SPOOLS folder.
Is there any way which could make sure I can got the whole .spl file?

Can anyone point me in the direction of some resources on writing and registering a port monitor to get the data that a printer is being sent? Similar to how PDF-Writer like port monitors work. The problem is that some drivers have very specific needs and I'd like to be able to analyze the through-put via my own custom port monitor and see what is happening in that data.

I seem to have the shell started but my port monitor is not showing up in the list of available port monitors.

I know the registry entries are correct because if I substitute the driver name with a working driver then the port monitor name shows up in the list.

I am trying to use InitializePrintMonitor2.

Using ::DebugBreak() I have been able to watch spoolsv load the dll, call the InitializePrintMonitor2 method which executes successfully, but then it detaches from the dll and the port monitor is not in the available list.

I am using VS2005 and not the WDK build enviroment.

I have a port monitor which uses the older InitializePrintMonitor method and is built the same way and functions so I know it is possible to do it.

I have a batch process which prints a number of documents some containing a lot of graphics and others not containing many graphics at all. It is currently using RAW format to print to the spooler. What I am experiencing is that the documents are showing up in the print queue in the wrong order. The submitted time is in the correct order but somehow the ordering is out. Reading you article I am guessing that maybe this is because the RAW processor is taking longer to render for the larger documents and so the smaller ones are being spooled to the print server before the larger ones.

Do you think it would help to print using EMF print processor instead? Is there a way to guarantee that the RAW processor does not work multithreaded?

When you print to a network printer and trap the spool file before it leaves the local PC it looks a lot like EMF but it is not the same format as the EMF found in SHD or SPL files (the spool files for local print). The file in question always has a name like SPLnnn.TMP.

I am writing a server application which deals with printing files and some other tasks. When I send a file to printer, I want to monitor the status of the file whether its printed or printing or queued.

I need to print a text file to a line printer in text mode -not graphics- which contain extended characters (ASCII Code >0x7f).
I found that the only application that can print in text mode is "notepad" and I installed the "generic text only driver".

but when printing with "notepad" through "generic text only driver" only ASCII <0x7f are printed and >0x7f are printed as "." (ASCII 0x2e).
is the problem in the "notepad" or the printer driver???
I don't think it's in something else becouse the spooled file contains the same data printed.
is it matter of codepage?how could I correct it?
do I need to make a newdriver from scratch or could modifing "Characterization files" do the job?

Assuming the printer can handle it, send the text file directly to it. You can use your existing Generic Text Only queue (it won't use the driver), and share the queue - call it "Test" or something.
Open a command prompt and change directory to the folder where your text file is, then type in:
COPY /B file "\\pc_name\Test"
where "file" is the name of the text file, and "pc_name" is the name of your PC.
This will send the text file directly to the printer. If the physical printer supports PCL5 then there are generally options that you can define on the device itself as for the symbol set it will print extended ASCII in - such as PC8 or Roman-8.
This method completely bypasses the driver, it just uses the queue as a spooler.

This is a good approach if you're using the printer on a known printer port.

For some instances, particularly on a Terminal Services environment, the printer port may not be directly known, OR it may be mapped as per the session to another port.

To get to the point. The reason why non-printable characters are not be outputted is in the TextOut function itself! TextOut was designed to "render" a character, as per the selected font in the device context. If use do a RUN>CHARMAP.exe, and pick font, you'll see what TextOut can ONLY DO.

The solution in this artical does NOT select a font, hence, the device context has no idea of line height, so it assumes that there is only ONE in the document (an infinite line).

Therefore, I assume you are trying to send the Ox10 and 0x13 characters (Linefeed, Carridge Return), when you are sending a LF, and CR, you get ".." one period for each ASCII character.

Why? because they are non-printable, so Textout tryings to map those characters to the default remapping of '.'; just like CharMap does when it encounters a character out of the Fontset!

The solution is as follows:1. Select a font that can actually be rendered using TextOut. That is, if you can see it on the screen in Microsoft Word, then TextOut can do it too! 2. CR and LF are non-printable characters. So get them to appear for a ASCII TEXT PRINTER, you need to be able to write on the next vertical line in the DC; once you can do this the driver actually inserts the CR and LF for you (it does this be detecting newlines, and inserting CR LF in their place; why, because in DC everything is ONE LINE, and the CR LF as just delimiters on that line - this includes JPEGS, BMPS, etc.)

// We must tell the device context // that we intended to use a standard font. // Once the DC knows that, then it will (now) know // the concept of line height. Otherwise, without // this, everything will be considered as one infinite line. // The DC doesn't know about \r\n, the driver for the DC does // once the driver gets the new line height info, it inserts // \r\n for each new line the dc informs it of.

I work in the IT department of a professional printing company, and we are experiencing some intermittend problem lately.

When viewing the PDF, everything is fine, and 9/10 times it prints fine as well, but every now & again some of the characters overlap at random when printed.

I would like to create a virtual printer which will give a "Print Preview" of the job after it has been processed by the print spooler. Hopefully the file displayed in the electronic format will then be the same as the output from the printer.

By doing this we can compare the PDF, the post-spooler file, and the final output, to locate the problem area.

I suspect it's the font memory management on your printer. Simplest test is to always print as image from Acrobat.
However, do to what you want, go into the Printer Properties for the printer, under Advanced, disable "Enable Advanced Printing Features", enable "Keep printed documents".
You'll need to manually delete printed jobs that are fine, but when you get a problem, access the spool file from the \Windows\System32\Spool\Printers folder (identify it by the datastamp). The spool file suffix will be .SPL.
If your driver is PostScript then you can find GhostScript on the net and that will enable you to either convert the file to bitmap or simply view it. Otherwise if your driver is PCL then you can download a trial version of SwiftView which will view PCL (5 or 6) files.

I am interested how I can monitor the printer activity on a workstation that does not have a printer connected. Is there a way that I can monitor a local queue before the print job is sent to server? If so, can anyone point me a good article?

I'm programming with the sample sources of a print processor that are in the Windows DDK.
(\WINDDK\3790\src\print\genprint)

The sample sources already implemented a few printing features such as n-up, reverse printing, etc...

i want to make a feature of manual duplex with the sample sources,
but i got a problem.

As you know, the manual duplex feature is that the front data of pages for duplex is printed at first, and then the driver show a message box that inform of the user to put the printed matters on the multi-purpose tray. Finally, the back data of pages for duplex is printed.

So, i refered to the sample code amd made a linked list that store a page information.

i used Gdi functions for a print processor such as GdiStartDocEMF() and GdiEndDocEMF()....

but.. I got a problem..
the problme is that after the front data of pages for duplex is sent to spooler,
i called GdiEndDocEMF() function to eject all the front data of page from printer.
At that time, unforunately.. the emf data is deleted from spooler. T_T

although i called GdiStartDocEMF() to tranlate the back data of pages, the return of the function is failed,(the GetLastErr() is 62)..

what function do the GdiEndDocEMF() replace to eject all data from printer?

Legal Information
This document is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS DOCUMENT.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

Information in this document is subject to change without notice and is provided for informational purposes only. The entire risk of the use or results of the use of this document remains with the user, and Microsoft Corporation makes no warranties, either express or implied. The names of companies, products, people, characters, and/or data mentioned herein are fictitious and are in no way intended to represent any real individual, company, product, or event, unless otherwise noted. Complying with all applicable copyright laws is the responsibility of the user. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation.

ActiveSync, ActiveX, BackOffice, Direct3D, DirectAnimation, DirectDraw, DirectInput, DirectMusic, DirectPlay, DirectShow, DirectSound, DirectX, MSDN, Microsoft, MS-DOS, Outlook, Visual C++, Win32, Windows, Windows NT, Windows XP, and Windows Server 2003 are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Other product and company names mentioned herein may be the trademarks of their respective owners.

This document presents an overview and installation information for the Microsoft® Windows® Driver Development Kit (DDK) for Microsoft Windows Server™ 2003 Service Pack 1 (SP1). Before installing the DDK, read through this document to determine whether you need to install optional DDK components and how to set up your systems for a trouble-free installation. This document contains the following topics:

There have been a number of changes to the Microsoft® Windows® Driver Development Kit (DDK). Some of these changes may affect driver compatibility among versions of Windows. As a result, after installing the DDK, it is important to read the release notes. For your convenience, the release notes can be accessed from the Start menu. Complete the following steps to access the release notes from the Start menu:

1. On the taskbar, click Start, and then click All Programs.

2. Point to Development Kits, point to Windows DDK, point to Help, and then click Release Notes.

Installing the DDK
To install the Microsoft® Windows® Driver Development Kit (DDK) for Microsoft Windows Server™ 2003 Service Pack 1 (SP1), you must be able to access the CD drive from Windows, either locally or through a network.

System Requirements
The system requirements for using this DDK on a driver-development computer are:

Windows Server 2003 SP1, Windows Server 2003, Windows XP SP1, Windows XP, or Windows 2000.
CD drive or Internet access.
A minimum of 128 megabytes (MB) of RAM (256 MB of RAM, or more, is recommended).
A minimum of 910 MB of hard-disk space for a full installation. A maximum of 1.8 gigabytes (GB) of RAM might be required to compile all samples.

The system requirements for using this DDK on a driver-testing computer are:

Windows Server 2003 SP1 for Windows Server 2003 SP1 driver development.
A minimum of 128 MB of RAM if you are running a free or retail build of, or 256 MB of RAM if you are running a checked build. Depending on the particular drivers loaded on the computer, checked builds may require only 128 MB of RAM.
A second computer that is capable of running Windows Server 2003 SP1, Windows XP, or Windows 2000 for kernel debugging of your under-development drivers. This second computer can be your driver-development system.
DDK Installation
Note:
You must have administrator privileges to correctly install the DDK.

Note:
Do not install this DDK over previous versions of this or any other DDK. Improper installation of the DDK can cause the use of old and incorrect files, which will lead to unreliable results in any drivers that you develop.

Note:
The default installation path is x:\WinDDK\. The icons can be found at All Programs\Development Kits\Windows .

To install the DDK, complete the following steps:

Run the Setup.exe file from the CD-ROM.
· If you are installing the DDK on a computer with Windows Server 2003 SP1 or Windows XP, when prompted “Would you like to open the file or save it to your computer?” click Open.

· If you are installing the DDK on a computer with Windows 2000, when prompted "What would you like to do with this file?" click Run the program from its current location.

To start installing the DDK, If installing on a Windows 2000 computer, answer 'Run the program from it's current location' to the question, which asks "What would you like to do with this file?" OR If installing on a Windows Server 2003 Service Pack 1 or Windows XP computer, answer 'Open' to the question, which asks "Would you like to open the file or save it to your computer?"
Click Next.
Read the Software License Agreement, click Accept, and then click Next.
Select the installation path (it is suggested to use the path that is displayed), and then click Next.
Select the components that you would like to install, and then click Next.
Confirm that you want to install the DDK by verifying that the installation path is correct, and then click Next to install the kit.
Note:
On computers with large hard-disk sectors, such as FAT16 file systems, the setup program might miscalculate the amount of space needed to attempt an installation even though the space is not available.

Installing the Debuggers
Debugging Tools for Windows® features WinDbg, a powerful debugger with a graphical interface that can debug both user-mode and kernel-mode code. Debugging Tools for Windows also includes the debuggers KD, NTSD, and CDB, and many additional tools. The documentation in Debugging Tools for Windows describes the use of these debuggers and includes tips for user-mode and kernel-mode debugging.

Debugging Tools for Windows is available in three different versions: a 32-bit version, a native Intel Itanium version, and a native x64 version. The 32-bit version is appropriate for most users. If you are planning on debugging a user-mode application on an Itanium-based processor, you should install the Itanium version of the debuggers. If you are planning on debugging a user-mode application on an x64 processor, you should select the x64 version of the debuggers. The Itanium and x64 debuggers can be installed only on 64-bit versions of Windows.

These debugging tools require approximately 25 MB of hard disk space.

To obtain the most current version of Debugging Tools for Windows, visit the Microsoft® Debugging Tools Web site. If it is not convenient to visit this site, you can install Debugging Tools for Windows directly from this CD, by choosing one of the following links:

· Install Debugging Tools for Windows (32-bit version)

· Install Debugging Tools for Windows (Itanium version)

· Install Debugging Tools for Windows (x64 version)

Since the version of Debugging Tools for Windows on this CD may not be the most recent version, it is recommended that you only use these links if you cannot access the Web site.

Symbols
The new linker strips all debug information from the SYS file and moves the data into a PDB file. The PDB file should be copied to the symbols directory for debugging. Copying the SYS file will not provide debugging information.

Verifying DDK Installation
To verify that you have properly installed the Microsoft® Windows Server™ 2003 Service Pack 1 (SP1) Driver Development Kit (DDK), complete the following steps:

b. Point to Development Kits, point to Windows DDK , point to Build Environments, and then point to Windows Server 2003.

c. Click Windows Server 2003 Checked Build Environment.

At the command prompt, type build –cZ to compile and link the complete set of installed sources. This command can take more than 30 minutes to complete, depending on which DDK components are installed and the system on which the build is being performed.
The build command should complete with no errors and no warnings displayed.

Microsoft DDK Resources
The following Microsoft® Web sites contain additional information for using the Windows® Driver Development Kit (DDK):

==============================================
Examples of Install and Data Section Relationships
It is instructive to look at the two Install sections, [HPPCL5MS.DRV.BIDI] and [HP4ML_V4.SPD], just to see how many of the dozen or so printer keys are used in each one. The [HPLJP_V4.SPD] section is the simplest:

[HP4ML_V4.SPD]
CopyFiles=@HP4ML_V4.SPD,PSCRIPT
DataSection=PSCRIPT_DATA
The CopyFiles key is common to all INF file install sections, so the [HP4ML_V4.SPD] section has only one statement with a printer-specific key:

DataSection=PSCRIPT_DATA
This statement names the only other section in the INF file that can contain printer-specific keys, the Data section. In fact, the Data section will contain only printer-specific keys, as is shown in the following:

[Strings]
PS_MONITOR="PostScript Language Monitor,PSMON.DLL"
Note that since only four printer-specific keys are used in the Install section for this printer model and in its Data section, defaults are used for the other keys during printer installation. Following is a list of the default values that are used:

[UNI_DATA]
HelpFile=UNIDRV.HLP
DefaultDataType=EMF
Printer-specific statements can be distributed between an Install section and a Data section any way that is convenient for you, with the exception that if a DataSection key is used it must be used in the Install section. Note that it is not necessary to use a Data section in your printer INF file, even though both of the preceding example Install sections do use a Data section.

I have read your article and Impressed by the technical content i am seeking some help for a related problem.

I am working on a project ( using c#) that requires to have FULL PATH OF THE Print Job, submitted by any application on a virtual printer. Using PrintUI.DLL and one of the sample GPD files (exported to INF )provided by DDK, i have installed the virtual printer.

At first i have tried to get the Path information using Win32_PrintJob event through WMI. But it turned out that it provides only DOCUMENT NAME and not the full path.

As i have understood from your article, the full path information will only be available to the GDI functions that are called for printing,
or maybe even they are provided with Data.

I was exploring the DDK OEMDLLUNI sample code and was planning to work on DrvStartDoc functions for the task, but in one of the
discussions on net it was mentioned thateven thatdoes not provide full path info.

So sir, the issue is,

"HOW TO GET THE FULL PATH OF THE SUBMITTED DOCUMENT, FOR PRINT "

I am looking forward for your kind support. And any sort of help will be highly appriciated.

I am having the same problem. It has forced me to look into monitoring the ports to get the data. I ahve written an app which monitors whenever a job is sent to the print QUeue and Im trying to redirect it to a file. I cant get he full path to the file.

Quite frankly Microsoft should be ASHAMED of this unbelievable oversight as the File->Print mechanism has print-to-file check box functionality but they have chosen not to expose it via com or dll.

If you get anything pleas inform as I getting my tail kicked trying to write this ddk based code..

Hi,
I am yet to find the solution for the problem. For now i have left the problem unaddressed.
Regarding your approach, i would lke to share info that i learned. Few printers Generates EMF files. There are codes for C# availabe on net somewhere ( i dont recollect now) to read certain versions of the emf file formats.
The approach u have chosen, to read from port directly is another alternate. The following link is a real good source of info on redirecting the data printed from a port. Complete source code is available for C.

I Installed the DDKand am using the the MONITOR@ object which has as members pointer to spooler functions. This object was initialized with InitializePrintMonitor2 and I have code which traps the printJobs. I just dont know what to do from there. The structure's function pointer members are of thei form LcmXXXX where XXX is the functionName
ie Monitor2.pfnWrite = AddressOf(LcmWritePort)

I am looking into creating a project that monitors documents that are being printed on a networked usb printer. I would like to be able to monitor the title of the document and possibly the text for certain keywords. If found, I would like to log some info about the document such as name, time of print, what computer printed from, and who printed it. I have done some research and I am curious if all I need to do is create some sort of print monitor. I will be creating the project using C# so if anyone has any ideas or can point me to some reference material I would be very gracious. I have not had to use any Win32 functions before and I thought a project like this might be good practice.

I have created a character buffer (char buff[]) which contains the data of a word document (the document contains text and images).
i would like to pass this data onto a printer. I have managed to get the handle of the printer using GetPrinterDC. but what i can't figure out is how am i going to pass my buffer data to this DC?
If given the handle of a window, we can find its DC and then pass that data to the printer DC using BitBlt, but in my case i don't have a handle, but only an array of characters which represent some image.
Can somone suggest a method?

"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."

Does it means that we can print postscript file in non-postscript printers?

I would like to implement a printer driver that exposes a functionality similar to FinePrint's "combine multiple pages" feature. My driver should instead be able to expand one page to multiple printed pages.
(http://www.fineprint.com/products/fineprint/)

What pieces of the Architecture described above would I need to implement? Do you know of code that already provides this functionality?

Hi,
This article is very interesting and I would like more info about how to make
spooler component to support bidirectional communication with a particular printer. I think I should make my own language monitor. I read a lot of DDK documentation, and I'm confused about Microsoft spec. It says that I must use the new method InitializePrintMonitor2 whereas the sample code pjlmon uses the old InitializePrintMonitor. I try the 2 methods, and only the old version works fine. With the new method, I receive the message "The specified print monitor is unknown, even if I can see that the spooler loads my library and calls InitializePrintMonitor which successfully finishs. Can I have more info about use of the new version. I have another question about how to make the language monitor for Windows 9x ?
Thank you for your help

Hello everyone.
I want to Backup all the printer drivers installed on a machine and then restore them using the same settings.What are the files like dlls or other settings that we should restore. Plz advise.
Thanks in advance.