The Windows Universal Printer Driver
Abstract
The purpose of
this white paper is to provide an introduction to Windows printer drivers in
general, and to the Universal Printer Driver - UNIDRV - in particular. UNIDRV
runs is available on all versions of Microsoft Windows since Windows NT 4.0 (Service Pack 6),
including Windows 7.x, Windows 8.x, Windows 10.x and Windows 11.x
Outline
The Role of Printer Drivers
Types of Printer Drivers
The Universal Printer Driver
UNDRIV Plug-Ins
The Role of Printer Drivers
A Windows printer driver is an installable component that
converts graphic drawing calls made by applications into device-specific drawing
instructions. When applications send any graphical output to a printer, they
call a portion of the Windows 32-Bit (Win32) Application Programming Interface
known as the Graphics Device Interface or GDI. GDI - or more specifically
GDI32.DLL - loads printer drivers, and calls a printer driver to convert
individual drawing calls into a printer-specific graphic language.
GDI Drawing
Support
The primary graphical library in the Windows API is GDI.
So when a typical application wants to draw - either on the display screen or to
a printer - it calls GDI. A device driver is required for both display devices
and printers/plotters, and in fact the driver interface for both types of
devices is very similar. There are three basic categories of GDI drawing
functions: text, raster, and vector. These same distinctions exist at the device
driver level. To a great extent, understanding the operation of the API will
help in implementing device-driver level graphics functions. One printer driver
developer described how his GDI programming experience was helpful in building
printer drivers in this way: "It was like going through the looking glass -
instead of just calling functions, in the printer driver you were implementing
them."
Text
Drawing
Text, of course, has to do with the display of readable
letters and numbers. The means of controlling the appearance of text - letter
styles, letter height, whether bold or italic - is through a font. Much of the
work of text drawing in a device driver involves identifying available fonts,
describing all the details of available fonts, and working to make those fonts
available to an application when it requests the use of a particular
font. Windows has built-in support for Truetype, a flexible font scaling
technology that helps minimize the differences between fonts that are available
for different devices. In addition to Truetype fonts, some printers support
their own, built-in fonts. In such cases, it is the job of the device driver to
notify GDI that device-specific fonts are available, to provide GDI a detailed
description of these fonts, and to make those fonts appear on the device when an
application requests them.
Raster
Drawing
Rasters mean arrays of pixels, and in many cases when
people say "raster graphics" they mean off-screen bitmaps. GDI provides
applications with quite a number of calls for drawing raster graphics. For
example, a rectangular area can be filled with a solid color - a key capability
in a display device driver. Most of the interesting raster drawing calls operate
on bitmaps, and bitmaps can be stretched, shrunk, rotated, or skewed. GDI
provides support for Device Independent Bitmaps (DIBs). This is a standard for
storing arrays of pixels in a way that the bitmaps can be moved from one device
to another with a minimum loss of information. This standard started out (in
Windows 3.1) as a standard format for storing bitmaps in files, and that is the
format used by painting programs like PBRUSH and MSPAINT. Starting with Windows
NT 4.0, DIBs became an important in-memory format for bitmaps, and since then
device drivers have included support for DIBs. There is, for example, a Win32
function for creating a DIB - CreateDIBSection. This is an important
function because it introduced to Windows the ability to have a dual-ported
bitmap, meaning that applications could directly access the memory of the bitmap
while also drawing into the same bitmap using regular GDI drawing
calls. There are several standard formats for DIBs, including those shown
here:
Description
|
Bits Per
Pixel
|
Planes
|
Possible
Colors
|
Color
Table?
|
Monochrome
|
1
|
1
|
2
|
Y
|
VGA Color
|
4
|
1
|
16
|
Y
|
1 Byte/Pixel
|
8
|
1
|
256
|
Y
|
2 Bytes/Pixel
|
16
|
1
|
64K
|
N
|
3 Bytes/Pixel
|
24
|
1
|
16
Million
|
N
|
4 Bytes/
Pixel
|
32
|
1
|
4 Billion
|
N
|
JPEG |
24
|
1
|
16
Million
|
N
|
PNG
|
8
|
1
|
256
|
Y
|
It is important to note that
support for the last two DIB formats, JPEG and PNG, are optional formats that
are available starting in Windows 2000 and later. If a printer driver (or a
display driver) does not support these formats, it is up to the application to
convert a JPEG (or a PNG) image to another, supported DIB format. The presence
of support for JPEG opens the possibility that high-end printers could have
built-in support for decompression of high-quality photographic images - a
potential market advantage owing to the potential for improved throughput on
such a device.
Vector
Drawing
Vector drawing means polygonal objects provided by GDI
drawing functions like Rectangle, Pie, Polygon, and Polyline. With
some printers, UNIDRV support vector drawing by rendering vector objects onto
off-screen bitmaps and then sending these bitmaps to the printer using the
printer's raster drawing commands. Starting with Windows XP, UNIDRV supports
both HP/GL as well as the vector drawing of PCL/XL. What this means is that a
UNDRIV-based printing solution can now provide a faster, more memory efficient
support for vector-intensive applications. This support is available through the
*Personality keyword in the GPD file. A UNIDRV-based printer driver
can hook out the vector drawing DDI calls (DrvStrokePath, DrvFillPath,
and DrvStrokeAndFillPath) to support any device-specific vector drawing
languages. Support for this involves writing some code and deploying it in a
UNDRV rendering plug-in.
Windows
Printing System Architecture
A printer driver is a dynamic link
library (DLL), which is an executable module that can be loaded into the address
space of any process. Printer drivers are typically loaded into the address
space of two different processes: (1) an application that is printing, and (2)
the spooler. The name of the UNIDRV printer driver component is UNIDRV.DLL.
Figure 1 shows the relationship of UNIDRV.DLL to other system elements when
printing from NOTEPAD. The accompanying figure shows spooling of the print
job as an EMF (Enhanced Metafile) spool file. EMF is a standard format for
storing GDI drawing calls. A key benefit that EMF spooling provides is fast
return-to-application time. The EMF file is created when the application calls
GDI functions to draw. This same file gets played back by the print processor
(LOCALSPL.DLL in Windows 2000 and later, WINPRINT.DLL in Windows NT 4.0) and the
appropriate GDI functions are called, which in turn are used to call into the
rendering driver, UNIDRV.DLL. Figure 1 - UNIDRV.DLL in the System.
 Figure 2 -
UNIDRVUI.DLL in the system.
 In addition to its graphical
output, a printer driver solution will also provide a user-interface - in the
form of dialog boxes and property sheets - by which a user can control how
output appears on the printed page. In previous versions of Windows, graphical
output support and user-interface support were merged in a single DLL. On all
versions of Windows NT, the two elements were split into separate DLLs. The name
of the UNIDRV user-interface support library is UNIDRVUI.DLL. This DLL can be
loaded into any of three different processes: (1) an application that is
printing, (2) the spooler, and (3) the Explorer process. Figure 2 shows the
relationship of UNIDRVUI.DLL to other system elements when printing from
NOTEPAD. This diagram is much simpler than that shown in figure 1, since it
leaves out the spooler entirely. Figure 1 also places the rendering driver -
UNIDRV.DLL - in the address space of the printing application. For the sake of
accuracy, I must point out that this only occurs when sending output to a file
and not to a port. While this is different from figure 1, it accurately
represents the behavior of the system. More to the point, what the two figures
have in common - and what is central to the architecture of Windows printing -
is the fact that it is exclusively the job of GDI32.DLL to call a printer
driver.
Types of
Printer Drivers
When a new printer is developed, a printer driver
team has two basic choices: write an entire driver from scratch - sometimes
known as a "monolithic printer driver", or to use a table-driven driver
framework such as UNIDRV.
A Monolithic
Printer Drivers
The term "Monolithic Printer Driver" basically
means that the printer driver development team builds all the code - typically C
or C++ - needed to enable printing. The first printer drivers that were created
- back in the Windows 1.x days - were by necessity monolithic. One benefit of
monolithic printer drivers is that the development team has total control over
all the source code. There is nothing you cannot do. Unfortunately, there are a
lot of things that you must do to account for application bugs, and there is
just plain a lot of code that goes into a printer driver. One alternative that
has been created is the table-driver printer driver framework.
Table-Driven
Printer Driver Frameworks
Over time, as more and more drivers were
created, it became obvious that a lot of the code in different printer drivers
was the same. In part, this was because new drivers were often created by
porting the code of an existing driver. But more to the point, common code was
present because different printers often work the same way or at least in a
similar fashion. For example, many PCL printers - PCL 3, PCL 4, and PCL 5 - d
issue a Form-Feed (0x0C) to eject a page. But on non-PCL printers, like the
Canon Bubble-Jet BJC-240, the page eject command is different - it is
accomplished with a seven-byte sequence of characters. While the commands might
be different on different printers, there are a common set of operations that
must be accomplished for all print operations. A printer driver framework -
like UNIDRV - provides a mechanism for defining the data needed to drive the
creation of printed output. In theory, at least, this is a simple thing to do.
In an ideal world, someone could simply refer to the technical specifications
for a printer, fill in some tables, and the printer driver framework would do
everything with no coding required at all. In fact, there is almost always a
need for some kind of custom coding. How much depends on the amount of
fine-tuning a driver team wants to provide to tweak the output created by the
framework. UNIDRV is the third major printer driver framework that Microsoft has
created (and third-parties built other frameworks). As each successive framework
was made available, each has provided more and more support for adding code to
supplement the table-driven approach. In UNIDRV, that mechanism is known as the
"plug-in".
The Universal
Printer Driver
The Universal Printer Driver - UNIDRV.DLL - is a
table-driver printer driver solution. It provides support for printers that are
driven by PCL and PCL-like printer display languages (PDLs). While UNIDRV
supports PCL 3, 4, 5, and PCL-XL, it does not support Postscript. A very
basic UNIDRV solution can be implemented without writing any code. Instead all
that is needed is a GPD - Generic Printer Description - file. A GPD file is a
text file that contains details about what printer command to start a print job,
eject a page, and end a print job, along with all the other steps needed to draw
text, raster, and vector objects.
GPD
Files
The role of GPD files is essentially to fill in a table of
capabilities that a printer can support, and to provide the specific command
sequences needed to create graphical output. GPD files are text files, which
mean - aside from a text editor - no special tool is needed to edit them.
Microsoft provides a tool in the DDK to edit GPD files. Figure 3 shows a screen
shot of this tool - the Minidriver Development Tool, or Print MDT for short -
which, in addition to editing, has some other nice features. For example, it
provides rudimentary syntax checking, a color-coded display of a GPD files,
editing of some of the binary files that accompany a printer driver (font files
and character mapping files), and it also create an install (.INF) file for a
driver. Figure 3 - The Print MDT Tool
UNIDRV
Plug-Ins
Strictly
speaking, no code is necessary to create a UNIDRV-based printer driver. However,
there are some situations that require coding. For such cases, you create a
UNIDRV plug-in. There are two basic types of UNIDRV plug-ins - one for each of
the two core UNIDRV modules: 1. Rendering plug-in - which fine-tunes output
from UNIDRV.DLL. 2. User-interface plug-in - which fine-tunes the
user-interface on UNIDRVUI.DLL. Both types of plug-ins are implemented as
Component Object Model (COM) in-process servers. An in-process server is
basically a dynamic link library (DLL) that exports a very specific set of entry
points, the most important one being DllGetClassObject. When called, this
function returns a pointer to a COM class factory. The job of the class factory
component is to manufacture all of the components that a given COM server
supports. In the case of a UNIDRV plug-in, that means either the rendering
plug-in component or the user-interface plug-in component.
Rendering
Plug-Ins
A rendering plug-in lets you fine-tune the graphical
output of the core UNIDRV rendering engine, UNIDRV.DLL. A rendering plug-in lets
you accomplish any of the following: 1. Download non-standard fonts 2.
Filter the PDL stream (Requires Windows XP, or later). 3. Modify individual
PDL commands based on the setting of custom features. 4. Intercept
driver-entry point calls into UNIDRV. 5. Change individual scan-lines as they
are sent out of UNIDRV. 6. Perform customized raster compression. 7.
Modify half-tone patterns 8. Control the downloading of Truetype fonts. 9.
Perform custom or proprietary color management. 10. Handle vector drawing
calls in a custom, proprietary manner. This is by no means a complete list.
In general the purpose of a rendering plug-in is to allow printer driver
developers to take over any drawing, while still allowing UNIDRV to handle the
graphic output that it can. UNIDRV provides a good baseline for all kinds of
rendering. The choice of what to handle in a rendering plug-in depends entirely
on the target market for a specific printer, and the ways that a printer driver
team expects to add value. You can change everything - but in doing so you make
yourself more like a monolithic printer driver. The UNIDRV team expects you to
only change the areas where you can significantly improve on what UNIDRV can
already provide, or in areas that highlight specific features of your printer
that UNIDRV by itself does not address.
User-Interface
Plug-Ins
The second type of plug-in, a user-interface plug-in,
lets you fine-tune the user-interface elements of the user-interface library
UNIDRVUI.DLL. A user-interface plug-in lets you accomplish any of the
following: 1. Install-time actions 2. Add a property sheet to a printer
properties property sheet, or to a document properties property sheet. 3. Add
custom controls to standard property sheets. 4. Provide a custom font
installer dialog box. Once again, this is a partial list. Just like a
rendering plug-in, a user-interface plug-in will tend to be focused on key areas
of major improvements, but the standard UNIDRVUI features provides a fairly rich
set of support for all of the things that UNIDRV can do.
Feedback: " To provide
feedback about the white paper, please send e-mail to 
Acronyms and Terms API Application Programming
Interface COM Component Object Model DDI Device Driver Interface DLL
Dynamic Link Library DDK Device Driver Kit EMF Enhanced Metafile PDL
Printer Description Language SDK Software Development Kit
For more technical details on any of our hands-on training sessions,
Please contact us at the email address at this link:contact information
(c) Copyright 1990-2024
The Paul Yao Company. All rights reserved.
|