GPIGuide - Print Job Submission and Manipulation
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
The print subsystem of the OS/2 operating system provides a flexible, high-level interface between your application and an output device. Because most of the internal workings of the subsystem are shielded from both user and programmer, this chapter concentrates on the programming process required to produce hard copy output. Querying of printer resources, working under a specific user's environment, designing for application-specific requirements, and manipulation of print jobs also are described.
About the Print Subsystem
This section describes:
- The print subsystem components
- The print subsystem configuration
- Printing data flow
Print Subsystem Components
The print subsystem comprises the following software components of the operating system:
- Spooler
- Print subsystem user interface
- Queue drivers (queue processors)
- Printer drivers
- File system
- Kernel device drivers
Spooler
The spooler is the central coordinating process for the print subsystem. It gives the user flexibility in organizing and optimizing the use of the system's printers. The spooler has a global view of the system's printing resources, particularly in a server environment and therefore is able to make the best use of those resources.
- The spooler ensures that print output from two separately executing applications cannot be intermixed on the printer. As an optional optimization, the spooler can start a printing job before it is completely queued. Any successive jobs are queued normally.
- The spooler can print a job in the background while the user continues to use the application. Other single-tasking operating systems, such as DOS, require the user to wait until the print output is sent completely to the printer.
- The spooler can send jobs from PM applications across a network to a remote server, without the application's knowledge.
Remarks
The file system handles print jobs from non-PM applications.
- Queues within the spooler can be used for various purposes. For example, one queue could be used for large print jobs that are printed at times when print demand is low. Another queue could be configured to print jobs using a special size paper. Print jobs on this queue would be held until the correct paper is loaded into the printer.
- The spooler can support a number of printers simultaneously. It can be configured so that jobs on a single queue can be shared among all the printers. This load balancing, which is particularly important in server environments, can be achieved without the application's knowledge.
- Jobs can be prioritized while in the queue. For example, an urgent job can be given a higher priority than ordinary jobs.
The spooler consists of one or more print queues, one for each printer object defined by the user. Jobs are created by applications and placed in a queue, waiting to print. When the previous job is completed, the next job in the queue is sent to the printer.
Print Job Formats
The print jobs held in a spooler queue are known as spool files. Spool files contain the following:
- Parameters submitted with the print job
- Print job data
Print job data is in one of two formats:
- PM_Q_STD
Standard output data, PM_Q_STD is spooled as a PM metafile; that is, as a series of graphics orders stored in a packed binary format. PM_Q_STD print jobs are created through the GPI.
An advantage of the PM_Q_STD format is that the files are smaller than PM_Q_RAW format files. The smaller size saves disk space for jobs in the spooler queue and reduces network traffic when transmitting the data to a network server.
The content of PM_Q_STD jobs can be viewed using the PICVIEW application. This is achieved using the job-content menu on a print job in the printer object. The multi-page spool file can be shown in a device-independent manner so that the content of the job can be recognized easily.
After a job is spooled and ready to print, the spooler sends the PM_Q_STD job to the queue driver. The queue driver replays the metafile, through the GPI, to the appropriate printer driver. The driver, in turn, converts the data to printer-specific commands, that is, a printer-specific format.
There are some restrictions on the content of PM_Q_STD jobs that are related to the restrictions for PM metafiles. PM applications that cannot deal with these restrictions should enqueue print jobs using PM_Q_RAW, but there is an increase in required disk space and, possibly, network traffic.
Print jobs sent to network servers that do not support PM are converted automatically to the PM_Q_RAW format by the system. The application still can continue specifying PM_Q_STD.
Remarks
The effect of converting all PM_Q_STD print jobs to PM_Q_RAW can be turned on by the user's selecting Printer-specific format in a printer object settings page.
- PM_Q_RAW
Raw data, PM_Q_RAW, is the actual printer command to print the job. For example, raw data created for an HP** LaserJet** printer contains Printer Command Language (PCL) commands; and raw data created for a PostScript** printer contains PostScript commands.
The content of PM_Q_RAW jobs can be viewed with the system editor. This is achieved using the job content menu on a print job in the printer object. However, it is not always easy to recognize the content of a job. For example, PostScript is very hard to understand and get a visual idea of the actual output.
Print jobs are created by the file system as a result of printing directly to the physical port using either INT 17 or INT 21 under DOS or the OS/2 DosOpen API. These print jobs always are queued using PM_Q_RAW. The actual queue chosen depends on the port used and the configuration of the print subsystem.
PM applications also can use the PM_Q_RAW format, but the overall print-job creation process normally is slower because the printer driver has to perform more work to create the printer-specific format.
If the Print while spooling printer object setting is turned on, the user can perceive a faster response. In particular for a multi-page document, the first page starts printing as soon as the printer driver has completely finished converting the GPI to the printer-specific format.
Remarks
PM applications always should specify the PM_Q_STD format. The difference in disk space used can be from a factor of 2 to a factor of 50. The Printer-specific format and Print while spooling printer object settings can be used to configure optimal performance for the environment.
Although the base operating system supports the two print job formats described above, other formats can be supported by providing an appropriate queue driver.
Disabling the Spooler
The workplace user interface to control the spooler can be found in the System Setup folder. For special circumstances or applications, the spooler object can be used to disable the spooler. Generally, this is not recommended because the output from two applications can intermix, or one application can be paused until the first application has finished sending data to the printer.
Print Subsystem User Interface
The print subsystem user interface is composed of printer objects. The spooler implements each printer object by using a queue to hold the jobs. The queue is connected to a logical device that specifies configuration data about the actual physical device, for example, the port and printer drivers.
The print subsystem user interface performs the following basic functions:
- Print job status
Opening a printer object folder displays an icon or detail view of the print jobs waiting in the spooler queue. Opening the settings on an individual job displays the parameters that were used when the job was queued. Some settings, such as the number of copies, can be changed while the print job is waiting in the queue.
- Print job manipulation
Individual print jobs can be held in or released from the queue. Holding a print job means that it is not printed. Individual or all the print jobs in a queue can be deleted.
- Queue manipulation
Queues also can be held, released, deleted, copied, or created using the printer object context menu.
- Printer object configuration
Opening a printer object settings notebook enables a user to browse and modify the configuration of a printer object. For example, the printer driver can be changed if the user just obtained new printer.
Queue Driver
The queue driver is also called a queue processor. It is used to take print jobs from a queue and print the data using the printer driver. The print job data (either PM_Q_STD or PM_Q_RAW format) is passed through the GPI. For PM_Q_STD jobs, GpiPlayMetaFile is used; and for PM_Q_RAW jobs, the DevEscape DEVESC_RAWDATA is used.
Printer Driver
Printer drivers know all details of the printer they support; therefore, printer drivers are unique for each model of printer supported by the operating system. The printer driver is responsible for:
- Displaying a dialog that enables the user to inform the system how the physical printer is configured; for example, which paper sizes are installed.
- Displaying a dialog that enables the user to configure an individual print job; for example, which orientation (portrait or landscape) to use.
- Responding to application queries for available printer capabilities such as color, resolution and forms.
- Converting the GPI commands in a print job to the printer-specific language commands that will produce the expected output. The printer-specific commands are passed to the file system.
Port Drivers
Port drivers are dynamic link libraries (DLLs) that contain a set of 32-bit functions, which provide helper functions for the spooler and Workplace Shell. For each port driver DLL, there should be a physical port driver (SYS file) installed in the CONFIG.SYS file. The file type of a port driver is .PDR.
The operating system, by default, provides two port drivers; SERIAL.PDR supports COM1 - 4, and PARALLEL.PDR supports LPT1 - 3. For any other port, the supplier of the physical port software is responsible for providing a Presentation Manager port driver if it is necessary.
The functions exported from a port driver are:
- SplPdEnumPort
- SplPdGetPortIcon
- SplPdInitPort
- SplPdInstallPort
- SplPdQueryPort
- SplPdRemovePort
- SplPdSetPort
- SplPdTermPort
File System
The file system is involved in both the spooling process and the printing process. When non-PM applications create print data, the file system intercepts the data and places it on a spooler queue. After a printer driver has processed a print job, the file system sends the data to the appropriate file or device using a kernel device driver.
Kernel Device Driver
The system provides device drivers for physical devices. The two most commonly used by the print subsystem are the parallel device driver and the serial device driver.
Print Subsystem Configuration
From a user's viewpoint, a printer object represents a printer. The user can specify the printer object settings for configuration; for example, which printer driver and port to use.
From a programmer's viewpoint, print configuration is more complicated. Each printer object actually consists of a queue connected to a logical device. The following figure shows some example configurations. The top-left and top-right pictures show one printer object; the bottom-left picture shows two printer objects; the bottom-right picture shows three printer objects.
Multiple queues connected to a single device is termed printer sharing. The advantage of printer sharing is that two queues can have different configurations or be used for different purposes. For example:
- One queue could be used for small jobs that are needed quickly, and the other could be used for large jobs printed during times of low demand, such as overnight.
- One queue could be used for a normal form such as a letter, and the other could be for a special form and so, would be held. When the special form was loaded into the printer, that queue could be released and the normal form queue could be held.
A single queue connected to multiple devices is termed printer pooling. This allows print jobs to be shared among printers for load balancing. The spooler does this by printing a job on the next available printer. For example, one printer usually reserved exclusively for special forms could be connected to a normal form queue during peak loads. The special form queue would be held temporarily.
Remarks
Configuration of a device without a queue is not allowed by the OS/2 operating system.
The logical device has the following configuration parameters that are relevant to application programmers:
- Name and description
- Logical port (for example, LPT1)
- List of printer drivers
For example, a logical device representing an HP LaserJet printer with an installed PostScript option could have both the HP LaserJet printer driver and the PostScript printer driver in its configuration.
Each printer driver in the list also could have printer properties associated with it. Printer properties describe the physical configuration of the printer, such as what size paper is installed.
The queue has the following configuration parameters that are relevant to application programmers:
- Name and description
It is the queue description not the queue name that is used for the printer object title- that is, the text displayed beneath a printer object icon.
- Printer driver
- Default job properties
Job properties describe the parameters that must be used for printing a specific job. An example of a job property is the orientation. The queue's job property defaults are used if none are supplied by the application.
- Queue driver
- Flags for Printer-specific format and Print while spooling settings
- Separator page
- Start and stop times
The configuration data for printer objects is stored in the OS2SYS.INI file. The spooler provides a set of functions that can be used to query and set this data.
Remarks
Older PM applications might still use the Profile functions (for example, PrfQueryProfileString). If so, these applications must be recoded with the new functions to avoid any dependencies on where and how the system stores configuration data.
Printing Data Flow
The data flow between your application, the printer driver, the spooler, and the kernel device driver is shown in the following figure. In addition to the data flow for the printer data stream, the data flow for screen output is shown. From an application's point of view, creating output for a printer is conceptually the same as creating screen output.
There are three routes that the application's printer data can follow:
- Base Printing
Base printing is provided primarily for non-PM programs writing complete printer data streams, including all printer control codes, directly to a printer port. It also provides compatibility for applications that run under DOS or Microsoft** Windows**.
- Queued PM Printing
Queued printing is recommended for all PM programs. It provides the most flexibility, both for the application and the user.
Print jobs created by PM applications are queued on a spooler queue. The spool files are processed and finally sent to the printer asynchronously from the application.
Remarks
If the spooler is disabled, queued print jobs perform as though they were submitted for PM direct printing.
- Direct PM Printing
Conceptually, direct printing is the same as queued printing for the application interface, but the spooler is bypassed. Therefore, the data is sent directly to the printer, and the application has to wait until the printing is finished. Following are some of the reasons for PM applications to avoid direct printing:
- The print job can interfere with other users whose jobs are destined for this printer. Print output could be mixed with the other print jobs.
- The spooler allows only one job at a time to print to a particular port to avoid mixing of print job output. If your application tries to print directly to the same port while another job is printing, your user must wait for the current job to complete before the user's job can begin.
- The printing application loses some of its multitasking advantages because one job must complete before a second job is submitted.
- The printer device driver does not protect a print job from job property and printer property mismatches.
- Pictures printed directly can be different from those printed through a spooler. The default setting for direct printing is to print pictures their actual size, whereas the default for queue printing is scaled to fit for the output area.
Direct printing is recommended only for specialized applications that use dedicated hard copy devices. Print jobs that have a certain degree of security associated with them, such as a corporate payroll or confidential documents, might best be handled with direct printing because files in the spooler can be copied.
Jobs that are very large, that is, over 10MB, that you do not want copied in the spool file, also might best be printed directly.
Using the Print Subsystem
This section covers the following aspects of using the print subsystem:
- Submitting a non-Presentation Manager (base) print job
- Submitting a queued Presentation Manager print job
- Submitting a direct Presentation Manager print job
- Submitting a print job directly to the spooler
- Spooler management and configuration
Submitting a Non-Presentation Manager (Base) Print Job
A program can create a complete printer data stream including all printer control codes (called a raw data stream) by using DosOpen, DosWrite, and DosClose. This is called base printing and it is used by:
- OS/2 and DOS Print command (for example, PRINT CONFIG.SYS /D:LPT2)
- OS/2 and DOS Copy command (for example COPY CONFIG.SYS LPT1:)
- OS/2 and DOS Redirected Output (for example DIR > LPT1: or TYPE C:\CONFIG.SYS > LPT1:) (full screen hard copy)
- All DOS applications
- All family applications (applications running under DOS and OS/2)
- All Microsoft Windows applications
Non-PM applications developed under OS/2 2.0 that must generate graphical data must be able to generate all the necessary Escape Codes, or printer-specific control sequences. Such applications will be coded differently, depending on the printer family-for example, Epson**, HP** LaserJet**, LaserPrinter*, Proprinter*, or PostScript**.
Non-PM applications that successfully drove the printer in the environment for which they were designed-DOS for example-will continue to do so successfully under this operating system.
DOS applications that directly access output hardware registers could have difficulty printing under the operating system. If this is so, these applications might need to be rewritten.
Submitting a Queued Presentation Manager Print Job
There are several stages involved in using the PM programming interface to print your application data. From a user interface point of view, the following four dialogs must be provided. The exact order in which these dialogs are used will govern the order of program execution.
- Page setup dialog
The page setup dialog enables the user to specify the form name or size required. Options on this dialog can include margins on the page, header and footer strings, and whether duplex formatting is required.
The actual contents of the dialog depend on the type of application. The important factor is that this page specify formatting options that also are used to display to a screen.
- Printer setup dialog
The printer setup dialog displays a list of queues available to the user. A Job properties push button on this dialog enables the user to query and modify the job properties for this job.
- Font dialog
Most PM applications must enable the user to specify the font (or fonts) required. Once the user has chosen a printer, an option on the fonts dialog enables the user to choose from device fonts as well as system fonts.
- Print dialog
The application should have a Print menu item on the File menu to invoke an application-specific print dialog. It is recommended that Shift+Print Screen be used as an accelerator for printing the client area. The Print-Screen key, unshifted, is used to capture and print a window or the whole screen.
Page Setup Dialog
The page setup dialog is concerned with formatting options for the document. The user must be able to specify the form name, margins, and other application-specific formatting options such as page duplexing; that is, different formats for left and right pages in a multi-page document.
Remarks
The application is responsible for storing the user-defined margins for the form. The application must not allow the user to specify margins smaller than those returned by the printer driver.
Forms Selection
If the user has not chosen a specific printer, the application can supply a list of standard form sizes- for example, Letter, Legal, Ledger, A4, and A3. The application also must consider, at a minimum, a 0.4 inch (10mm) margin on the form to be within the hardware clip limits of most printers. See the following table for the common form sizes.
Form Name | Size in inches | Size in mm |
---|---|---|
Letter | 8.5 x 11 | 216 x 279 |
Legal | 8.5 x 14 | 216 x 356 |
Ledger | 11 x 17 | 279 x 432 |
A4 | 8.3 x 11.7 | 210 x 297 |
A3 | 11.7 x 16.5 | 297 x 420 |
When a printer is chosen, it must be queried, using DevQueryHardcopyCaps for the forms it supports and the hardware clip margins. First, however, a device context must be created. It is recommended that a OD_INFO context be used, because OD_QUEUED can result in the creation of a print job. See the following figure for a sample code fragment.
PPRDINFO3 pprd3Device; /* From SplQueryDevice */ PPRQINFO3 pprq3Queue; /* From SplQueryQueue */ PSZ pszTmp; /* Temporary pointer */ HDC hdc; /* Device context handle */ DEVOPENSTRUC dopData; /* DEVOPEN structure */ LONG clForms; /* Number of forms */ /* The device */ PHCINFO pchinfo; /* Forms information */ /* structure */ ULONG ulrc=DEV_OK; /* Return code */ /* Fill in data for devopendata for OD_INFO */ dopData.pszLogAddress = pprd3Device->pszLogAddr; pszTmp = strchr(pprq3Queue->pszDriverName,'.'); if (pszTmp) *pszTmp = '\0'; dopData.pszDriverName = pprq3Queue->pszDriverName; dopData.pdriv = pprq3Queue->pDriverData; /* Open the information device context */ hdc = DevOpenDC ( (HAB)0, OD_INFO, /* Type */ "*", /* Default token */ 3L, /* Count */ &dopData, /* Pointer to data */ (HDC)0); /* Comp dc */ /* Query number of forms available on the device */ clForms = DevQueryHardcopyCaps(hdc, 0L, /* Start at beginning of list */ 0L, /* Get number of forms */ NULL); /* Allocate memory block for forms */ if (DosAllocMem((PPVOID(&pchinfo), clForms*sizeof(HCINFO), fALLOC)) { DevCloseDC(hdc); return(DEV_ERROR); } /* Query forms data */ ulrc = DevQueryHardcopyCaps(hdc, 0L, /* Start with first form */ clForms, /* Query all forms */ pchinfo); /* Structure to hold returned */ /* data */ /* Close the information device context */ DevCloseDC (hdc); /* Close the information */ /* device context */ /* Now use forms information in pchinfo */
DevQueryHardcopyCaps returns one HCINFO structure for each form. The contents of the structure are:
- ASCIIZ name of the form (for example, Letter)
- Width and height (in millimeters) of the paper
- Clipping limits (in millimeters) of the paper
- Number of pels between clipping limits
- Whether this form is the one installed currently on the device, or whether it is selectable from another paper bin
Then the list of forms can be displayed to the user. The form preselected in the list should be one of the forms marked with the HCINFO structure flag HCAPS_CURRENT.
It is recommended that an application indicate to the user which forms are currently installed in the printer. This is done by including the HCINFO structure flag HCAPS_SELECTABLE. Then users can decide whether they want a quick print on a form available from the printer or to install a different paper tray in the printer.
Printer Setup Dialog
In a printer setup dialog, an application should offer a list of printer objects that are available to the user and enable the user to select one. (The list of printer objects actually is a list of queues.) If none are available, an appropriate message must be displayed. An application must query the list of available printer objects each time the printer setup dialog is displayed because the user might have created or modified the printer configuration while the application was executing.
Remarks
If the document was formatted for a particular device and the user selects a different printer, the application must ask the user's permission before reformatting the document for the new printer.
Use SplEnumQueue to query the list of printers (printer objects); printer objects essentially are spool queues. SplEnumQueue returns both a list of queues and information about each queue on the local workstation in an array of PRQINFO3 structures. It also returns information about local workstation queues that reference network print queues.
Because the number of queues might vary for each use of your application, it is essential to allocate sufficient storage to hold the data returned by SplEnumQueue. Usually the application issues the query twice: the first time, the application determines the necessary size of the information buffer; after allocating a memory block, the second query actually retrieves the information.
The SplEnumQueue parameter pcTotal contains the number of queues available on the local system. The application should display an appropriate message box if the value is 0.
The queue description (returned in the structure PRQINFO3 field name pszComment) is the printer object title. This is much more familiar to the user than the queue name, which is displayed only on the view settings page of a printer object. Therefore, the printer setup dialog should show the queue descriptions instead of the queue names.
SplEnumQueue returns information about the queue that might influence the user's or application's decision to print to this queue; for example, the queue priority, or the number of jobs already in the queue. SplEnumQueue also returns the default job properties for the queue. This data can be used by the application for the Job properties push button on the printer setup dialog.
Less sophisticated applications might decide to dispense with the printer setup dialog and just print to the default queue. The default queue can be queried using PrfQueryProfileString, with an application name of PM_SPOOLER and a keyname of QUEUE. The spooler function SplQueryQueue then can be called to retrieve the default job properties.
Job Properties Considerations
Job properties are options on a per-job basis- for example, orientation, resolution, and form selection. The job properties dialog is displayed by the printer driver. Each driver has a different dialog, depending on the capabilities of the printer. The job properties are held in a printer driver-specific format in the abGeneralData field of the DRIVDATA structure.
Remarks
Job properties from one printer driver should not be given to another printer driver; the job properties probably will not be understood, and the printer driver will either return an error or substitute some default job properties. Then the user will see a change in job properties stored previously.
The user should be given the opportunity to change the job properties before the job is printed. This can be achieved by supplying a Job properties push button on the printer setup dialog.
Changing job properties requires two steps:
- Retrieving job properties
- Displaying the job properties dialog
Retrieving Job Properties
The application can retrieve job properties from the following:
- Previously saved job properties with the document
- Current application session job properties
- Default job properties from the queue (from pDriverData in the PRQINFO3 data structure)
- Printer driver device defaults (from DevPostDeviceModes using the DPDM_QUERYJOBPROP flag)
If no job properties were saved with the document, then there may be job properties that are being used by another document that also is to be printed to the same queue.
If job properties still cannot be found, then the default job properties stored with the queue can be used. It may be that the user has not set up any default job properties for the queue. Last, query the printer driver for its device defaults using DevPostDeviceModes with the DPDM_QUERYJOBPROP flag.
Displaying Job Properties Dialog
The sample code in the following figure shows how to display the job properties dialog. All the parameters required are available from the PRQINFO3 structure returned by SplEnumQueue or SplQueryQueue.
In the case of printer pooling, the pszPrinters field of the PRQINFO3 structure contains a list of device names, separated by commas. It is sufficient to choose the first printer in the list because the printer object ensures that the configuration of each spooled printer is the same.
Remarks
It is possible that the printer driver now uses a larger buffer for the job properties than the application is expecting. This occurs when a new version of a printer driver that supports some additional features is installed. In this case, the application must discard the existing document job properties, after a confirmation from the user, and query the printer driver for its device defaults, using the DPDM_QUERYJOBPROPS parameter to DevPostDeviceModes.
#define INCL_DEV #define INCL_DOS #include <os2.h> #include <memory.h> { ULONG ulrc=FALSE; HAB hab; PPRQINFO3 pprq3Queue; /* From SplEnumQueue or SplQueryQueue */ PSZ pszDriverName,pszDeviceName,pszTmp; HDC hdc=NULL; LONG cbBuf; /* Use the first device name in the PRQINFO3 structure */ pszTmp = strchr(pprq3Queue->pszPrinters, ','); if (pszTmp) *pszTmp = '\0'; /* Use just the driver name from the driver.device string */ pszDeviceName = strchr(pprq3Queue->pszDriverName, '.'); if (pszDeviceName) { *pszDeviceName = '\0'; pszDeviceName++; } /* Check size of buffer required for job properties */ cbBuf = DevPostDeviceModes( hab, (PDRIVDATA)NULL, pprq3Queue->pszDriverName, pszDeviceName, pprq3Queue->pszPrinters, DPDM_POSTJOBPROP ); /* Return error to caller */ if (cbBuf<=0) return(cbBuf); /* Return BUFFER TOO SMALL error to caller */ if (cbBuf > pprq3Queue->pDriverData->cb) return(DPDM_ERROR); /* Display job properties dialog & get updated job properties from driver */ ulrc = DevPostDeviceModes( hab, pprq3Queue->pDriverData, pprq3Queue->pszDriverName, pszDeviceName, pprq3Queue->pszPrinters, DPDM_POSTJOBPROP ); return(ulrc); }
Font Dialog and Device Font Considerations
There are two types of fonts:
- System fonts, which can be used for both displays and printers, and therefore, are generally more flexible.
- Device fonts, which are specific to a particular device. Device fonts for printers can be built-in or be installed with font cartridges by a user. Device fonts also can be available on diskette (also termed soft fonts) and can be downloaded to the printer as required by the printer driver.
The advantage of device fonts is that, usually, they are printed in the highest resolution of the device and are faster than system fonts.
Remarks
Some printer drivers, in particular, the HP LaserJet (LASERJET) and the LaserPrinter (IBM4019) printer drivers provide an intermediate solution. An option on the job properties dialog enables system fonts to be downloaded to the printer as soft fonts.
As stated earlier, an application must provide the user with the ability to choose fonts and, in particular, to choose a device font over a system font to achieve better performance. A standard font dialog box should be used (see WinFontDlg).
When an application uses device fonts, and the output mixes text and graphics pictures, the device fonts are clipped per character. System fonts give more precise clipping to the pel. The following figure illustrates the results from clipping two lines of text: one generated in a system font; the other, in a device font.
The available device fonts can be queried, using GpiQueryFonts, in either an OD_INFO or an OD_QUEUED device context. Device fonts are returned with negative lMatch numbers. Then the appropriate logical font can be used after calling GpiCreateLogFont.
If, during the printing process, a logical font is not created, the printer driver uses its default font for the printer, which usually is 12-point Courier.
There are two design choices for device fonts:
- Use system fonts for the display. When printing, query the printer driver and attempt to choose a device font that closely matches the system font. If no match is found, then print using the system font. A device's font metrics and character spacing might not match exactly, so the printed output might not be exactly the same as the display.
- Use a printer font if the user selects one. Determine the metrics and find a system font that shares the same characteristics (for example, a style such as Courier or Serifed). The character string to be displayed is sent to the printer driver and the inter-character spacing is returned, using GpiQueryCharStringPos. The individual character positions are used when the string is sent to the display, using GpiCharStringPos with the flOptions parameter of CHS_VECTOR. While the display output can take longer to display to the screen, true WYSIWYG (What You See Is What You Get) is achievable.
Print Dialog and Print Processing
The print menu must display a dialog to enable the user to specify the number of copies, start page, end page, or any other application-specific print options. A confirm push button (for example, Print) initiates the print.
The Printer entry field is the read-only name of the printer object (queue) that the user chose from the Printer Setup dialog. The Preview checkbox is used to preview the printed output on the screen. This can be achieved by opening an OD_MEMORY device context to the printer driver and drawing the picture into the bit map. A BITBLT (Bit Block Logical Transfer) to the screen shows the resultant page. System fonts should be used instead of device fonts.
Once the user has initiated the print, a PM application must execute the following steps:
1. Create a new thread.
Then, on this new thread:
2. Open a device context. 3. Associate a presentation space. 4. Start the print job. 5. Query the device capabilities. 6. Format the page. 7. Start the next page.
Repeat steps 6 through 7 for each page.
8. End the print job.
For another print job, repeat from step 4.
9. Disassociate the presentation space. 10. Close the device context.
The following sections describe each of the above steps in turn.
Creating a New Thread
Once the print process has been confirmed by the user, the application must use a separate thread to perform the actual printing. This maintains user responsiveness and avoids displaying the hourglass pointer. While the printing is in progress, the application should dim certain menu options, such as drawing. Other options, such as page down, zoom, or help still must be available.
Opening a Queued Device Context
Before you can send data to a printer using device functions, you must open a device context with DevOpenDC. The parameters of DevOpenDC are influenced by the queue and job properties the user has chosen previously.
DevOpenDC accepts the following parameters as input:
- hab The anchor-block handle from a WinInitialize call.
- lType The type of device context. This always is OD_QUEUED to specify a queued device context.
- pszToken The device-information token. Always use an asterisk (*) for this parameter to force the system to get device information from the pdopData parameter.
- lCount The number of data elements supplied in the pdopData parameter. The minimum number of parameters for a queued device context is 4.
- pdopData The device-context data area. This is a pointer to a structure of the type DEVOPENSTRUC. The elements of this structure are described below.
- hdcComp The compatible-device-context handle. This must be NULL for a device context of type OD_QUEUED.
DevOpenDC returns a device-context handle of type HDC. The handle is used in other functions beginning with the Dev prefix and for GpiCreatePS and GpiAssociate.
The DEVOPENSTRUC structure contains all the data needed to define a device context.
The individual elements of the DEVOPENSTRUC structure are described below. At least the first four structure members must be provided for queued device contexts.
- pszLogAddress Name of the queue. It is the pszName field of the PRQINFO3 structure.
Remarks
For device contexts of type OD_INFO, pszLogAddress is the port name. This can be retrieved by calling SplQueryDevice using the pszPrinters device name. The pszLogAddr field in the PRQINFO3 structure is the port name.
- pszDriverName Character string identifying the printer driver, for example, LASERJET. The pszDriverName field of the PRQINFO3 structure, associated with the required print queue, gives the driver and device name, separated by a period, for example LASERJET.HP LaserJet IIID. The pszDriverName field can contain only the name up to the period, for example LASERJET.
- pdriv This is a pointer to the job properties data returned by the printer driver from DevPostDeviceModes or the default job properties from pDriverData in the PRQINFO3 structure.
Remarks
The DRIVDATA structure contains the particular device name to be used. Therefore, it is a programming error to set this parameter to NULL.
- pszDataType It is recommended that PM_Q_STD always be used for the data type.
- pszComment Optional character string that the printer object displays to the user in a job settings notebook. It is recommended that the application include its own name in this comment string.
Remarks
The job title text is derived from the document name.
- pszQueueProcName Queue processor name (optional). The queue processor (also termed queue driver) name is available from the pszPrProc field of the PRQINFO3 structure. The default queue processor provided by the operating system is PMPRINT. The user also can install a queue processor (PMPLOT) that is used to provide reverse clipping for vector devices such as plotters.
For specialized applications, it is possible to use an alternative queue processor to the default specified for the queue. The list of installed queue processors is available from the OS2SYS.INI file using the application name PM_SPOOLER_QP.
- pszQueueProcParams Queue processor parameters (optional). They can include information such as the number of copies you want to print and the size of the output area on the printed page. See PMPRINT/PMPLOT Queue Processor Parameters for details.
- pszSpoolerParams Spooler parameters (optional) are separated by spaces. They are used for scheduling print jobs and are as follows:
* The form names that identify the paper to be used, for example, FORM=A4,A5,ENV. The form names are optional, but if they are provided, the spooler is able to hold off printing the jobs until the required form is installed in the printer. If the form name is not provided, the spooler attempts to print the job. The printer driver recognizes that there is a forms problem and displays a FORMS MISMATCH message box. * Priority of the print job, for example, PRTY=60. The priority is specified as an integer in the range 1 through 99; 99 is the highest. The default priority value is 50. The application can use the spooler priority parameter to prioritize its own jobs. However, it is not good practice for an application always to use priority 99 in an attempt to get its jobs printed first.
- pszNetworkParams Optional parameter that can be used to specify network options; for example, USER=JOESMITH.
Associating a Presentation Space
In order to print, a device context must be associated with a GPI presentation space (PS).
In most circumstances, a presentation space already exists for the screen. In such cases, the PS can be disassociated with the window device context and associated with the printer device context by using GpiAssociate, as shown in the following figure.
Reassociating Presentation Space with Device Contexts
If a presentation space does not exist or a different one is to be used, the application must call GpiCreatePS and use the GPI_ASSOC flag to associate the printer device context.
- Device-Independence Considerations
The operating system supports true WYSIWYG. The same GPI functions the application used to create the picture or document on the display screen can be used to create the output on a printer. This is the major advantage of device independence.
An application must be designed around the options provided by the PM to ensure device independence, as a display (VGA) typically is 96 dpi, while a printer typically is 300 dpi.
Following are some application design considerations:
- Use DevQueryHardopyCaps to determine the horizontal and vertical width of the form and the maximum printable area.
- Create a presentation space with a presentation page size of 0 to ensure that the maximum window size and maximum page size are used.
- Use device-independent coordinates, such as LO_ENGLISH, or TWIPS. If you program in pels, transferring your output from screen to hard copy will compress the image, as shown in the following figure.
An Effect of Programming in Pels
Reassociating a presentation space defined in pels or other device dependent units can affect the dimension of the picture. If the pels are not square on the display device, the shape and scale (aspect ratio) will be different as well.
Starting a Print Job
The application signals the beginning of a print job by using DevEscape with the escape parameter DEVESC_STARTDOC. The application must specify a document name; usually this is related to the name of file being printed. Any GPI calls made before this DevEscape (DEVESC_STARTDOC) are ignored.
Querying the Device Capabilities
DevQueryCaps can be used to provide over 40 pieces of information about a specific device-for example, default character box size, horizontal and vertical resolution, or number of device-specific fonts.
Knowing that the device has only 1-bit color support (monochrome) might influence the application to use line style and patterns instead of colors for output.
Formatting the Page
Before print processing actually starts, it is recommended that an application's modal dialog be displayed, showing page progress and enabling the user to cancel the print job. If the user presses Cancel on this dialog, the application must call DevEscape with the parameter DEVESC_ABORTDOC. This allows the spooler and printer driver to clean up. A job is not created in the queue.
Usually the output on a page is generated by a series of GPI calls from the application. By calculating the size of character strings or graphics written to the presentation space, the application must be able to decide when to move to the next page in a multi-page document.
Starting the Next Page
When the application has finished processing a page, it must call DevEscape with the DEVESC_NEWFRAME parameter. The progress dialog must be updated. The DevEscape DEVESC_NEWFRAME can be used to generate blank pages. The printer driver always issues a page eject whenever this DevEscape is received.
Issuing the DEVESC_NEWFRAME escape does not reset any attributes or fonts. However, the bounds and any clipping regions are reset.
Ending the Print Job
The end of a print document is signalled by the application's calling DevEscape with the DEVESC_ENDDOC parameter. The spooler returns a job identifier that can be used for job manipulation.
The following figure shows the processing carried out by a printer driver as it receives device escapes and graphics from the GPI. Flow for Device Escapes
Remarks
Each device-escape pair of DEVESC_STARTDOC and DEVESC_ENDDOC creates one print job in a spooler queue. If the application needs to create multiple print jobs, use the following sequence:
DevOpenDC GpiCreatePS DevEscape(DEVESC_STARTDOC) . . . DevEscape(DEVESC_ENDDOC) DevEscape(DEVESC_STARTDOC) . . . DevEscape(DEVESC_ENDDOC) DevCloseDC
Disassociating the Presentation Space
When the print job is complete, the presentation space can be disassociated with the printer device context using GpiAssociate with a NULL parameter. Then the presentation space can be reassociated with the display device context.
Closing the Device Context
A device context is closed using DevCloseDC. The print thread must signal print termination to the main processing loop. The main loop can terminate the print thread and dismiss the Page Progress message box.
An application can display a message box to the user indicating a successful print and show the job ID returned by the spooler.
Print-to-File Considerations
Print-to-file means that the print data destined for a printer is stored in a file instead. The advantage of doing this is that the file can be used later, possibly on a different machine or different environment, and the data printed without requiring the original application.
The system provides three ways to print to file:
- The user can specify Print to file on the Output settings page of a printer object. When a print is requested, the system displays a dialog in which the user can enter a file name.
This method is preferred because the application does not have to be aware; the user has full control of the system.
- The application can specify OD_DIRECT on a DevOpenDC call. The pszLogAddress field of the DEVOPENSTRUC structure specifies the file name as shown in the following example:
C:\TMP\MYPRINT.DAT \\SERVER\DISK1\MYPRINT.DAT -- UNC file name \\PIPE\PRTPIPE1 -- A pipe LPT1 -- A port device
- The application can create the printer-specific format data and write it to a file using DosOpen.
Network Printing Considerations
The architecture of PM requires a printer driver during the print job creation process to deal with queries, such as DevQueryHardcopyCaps, and to provide the job properties dialog by way of DevPostDeviceModes. To do any printing across a network, a locally installed printer driver is required. In some cases, such as when the network server does not run PM, this is an advantage, in that all the conversion to printer-specific commands can be done on the requestor.
The printer object in the workplace provides seamless access to network printers; the user need only install the appropriate printer driver.
The application programmer also is helped. A network printer that is accessed by the user has a hidden shadow on the requestor. The job properties for the shadow printer object can be altered and are stored on the requestor. This enables the user to configure one or more variations on the original configuration without requiring intervention from a system administrator to create many network printer objects, each with a slightly different default job property configuration.
The shadow printer object is created on the requestor by creating a local queue and local device with no port connection. The application can enumerate these queues using SplEnumQueue, as before. The only difference is in the PRQINFO6 structure; there are two extra fields not in the PRQINFO3 structure. These two extra fields, named pszRemoteComputerName and pszRemoteQueueName contain the name of the remote server and the remote queue. The spooler uses these fields to automatically reroute print data, submitted by an application to the local shadow, to the appropriate network queue.
The printer object creates a local shadow only when the network printer object has been used or modified, because there could be a large number of network printer objects, and the spooler does not know which one the user wants to use. The local shadow of a network printer object is created in the following cases:
- When a file is dragged and dropped on the network printer object
- When the network printer object is moved, copied, or shadowed outside its original server folder
- When the printer or job properties are modified
Drag/Drop Protocol Considerations
When an application data file is dropped on a printer object, the application can receive a DM_PRINTOBJECT message if the application is running currently.
One DM_PRINTOBJECT parameter gives a DRAGITEM structure that describes the object that was dropped. The other parameter gives a PRINTDEST structure that contains all the parameters required to call DevPostDeviceModes and DevOpenDC.
The PD_JOB_PROPERTY flag indicates to the application that the user has requested a job properties dialog before printing. If this flag is not set, the application must not display the job properties dialog; it must use the job properties passed in the PRINTDEST structure.
The rest of the printing process follows the procedure described in Submitting a Queued Presentation Manager Print Job.
PMPRINT/PMPLOT Queue Processor Parameters
How the queue processor processes a print job is controlled by the optional queue-processor parameters that you can specify in the pdopData parameter of DevOpenDC. The PM adds these parameter values to the spool file.
The PMPRINT/PMPLOT queue processor parameters enable an application to do the following:
- Specify the number of copies of a print job
- Restrict printing to a specific area on the page
- Specify which part of a picture is to be printed
- Specify color output (if your printer allows this)
- Specify the foreground and background colors in a monochrome print
Remarks
The application need not use queue processor parameters if all that is required is a single copy of a picture, scaled to fit the page. These are the default settings of the queue-processor parameters.
The first parameter (COP) is used for all spool-file formats. The remaining parameters are valid for PM_Q_STD spool files only. Because PM_Q_STD data are used mainly for graphic data, these parameters are described in relation to the printing of picture files.
The PMPRINT/PMPLOT queue-processor parameters are separated by spaces and are:
- COP=n The COP parameter specifies the number of copies of the spool file that you want printed. The value of n must be an integer in the range of 1 through 999.
The default is COP=1.
- ARE=C | w,h,l,t The ARE parameter determines the size and position of the output area. This is the area of the physical page to which printing is restricted.
The default value of ARE=C means that the output area is the whole page. Note, however, that the printer cannot print outside its own device clip limits.
To size and position the output area at a specific point on the page, use ARE=w,h,l,t, where:
- w, h are the width and height of the desired output area
- l, t are the offsets of the upper-left corner of the output area from the left (l) and from the top (t) of the maximum output area
These four values must be given as percentages of the maximum output dimensions. The maximum output area is the area within the device clip limits.
- FIT=S | l,t The FIT parameter determines which part of the picture is to be printed. You can request the whole of the picture, scaled to fit the output area; or you can position the picture (actual size) anywhere within the output area. This could mean that the picture is clipped at the boundaries of the output area.
The default value of FIT=S causes the output to be scaled until the larger of the height or width just fits within the defined output area. The aspect ratio of the picture is maintained.
To print the picture in actual size, use FIT=l,t, where l,t are the coordinates of the point in the picture that you want positioned at the center of the output area: l is measured from the left edge of the picture, and t is measured from the top edge. The coordinates must be given as percentages of the actual dimensions of the picture.
- XFM=0 | 1 The XFM parameter enables you to override the picture-positioning and clipping instructions that are provided by the ARE and FIT parameters, including their defaults.
The default value of XFM= allows the appearance of the output to be determined by the settings of the ARE and FIT parameters.
A value of XFM=0 yields output as specified in the picture file. For example, applications that use many different forms can define different positions on each form for their output.
- COL=M | C The COL parameter enables you to specify color output if you have a color printer.
A value of COL=M creates monochrome output (black foreground with no background color). This is supported by all devices.
A value of COL=C creates color output. If you request color output on a monochrome device, the printer presentation driver tries to satisfy your request, which can cause problems because the only color available is black. For example, if the picture file specifies a red line on a blue background, both are drawn in black.
The default is COL=M when you are addressing a monochrome printer and COL=C when you are addressing a color printer.
- MAP=N | A The MAP parameter enables you to decide how the neutral colors (those that are not specified in the picture file) are printed.
The default value of MAP=N yields a normal representation of the screen picture on a printed page, which means that the page background is white and the foreground is black.
A value of MAP=A provides the reverse of the normal representation: the background is black and the foreground is white on the printed page.
Remarks
Pictures from a spool file can be printed differently than those printed when the spooler is not selected, because the default setting without the spooler is to print pictures their actual size, whereas the default for the queue-processor FIT parameter is "scaled to fit" the output area.
The queue-processor parameters must be separated by one or more blank spaces; for example,
"COP=3 ARE=C FIT=S".
The parameters can be listed in any order. Default values are used for parameters that are omitted or entered incorrectly.
Bit-map or image data (data constructed by setting pels on or off) is not affected by the ARE and FIT parameters. Consequently, if your picture contains bit-map or image data, the printed version will be different from the screen version if you use these parameters.
Examples Using the ARE and FIT Parameters
The application uses the ARE and FIT parameters to determine which part of the picture is printed, and where on the physical page it is printed. The following figure provides practical examples of how to use these parameters. Examples Using the ARE and FIT Parameters
Submitting a Direct Presentation Manager Print Job
PM direct printing is done through a device context of type OD_DIRECT, as follows:
- Output from the PM printer driver goes directly to the printer instead of to the spooler.
- The application must specify OD_DIRECT in the DevOpenDC function.
- The pszLogAddress field of the DEVOPENSTRUC structure is a port name (for example LPT1). The port name is held in the pszLogAddr field of the PRDINFO3 structure returned by SplEnumDevice or SplQueryDevice.
- All fields following the pdriv field in the DEVOPENSTRUC structure are ignored by the system.
The remaining steps in the printing process are the same as those for OD_QUEUED device contexts.
Submitting a Print Job Directly to the Spooler
The spooler provides functions that enable applications to submit print data directly to a spool queue. Normally, these functions are used by printer drivers to add a print job to a spool queue. However, this is not a recommended method unless the application is special-purpose.
The advantage of submitting print data directly to a spool queue is to bypass the GPI presentation layer. This can be useful, particularly, for sending print jobs to a network printer that is on a server that does not run the OS/2 operating system. However, there are certain requirements for direct spooling:
- Because the data bypasses the printer presentation driver, it must be in a format the printer can understand. Therefore, the application must be aware of and send the printer-specific commands.
- If the spooler is not active, the print jobs never will be printed.
The following steps are required to create a print job using the spooler directly:
- Use SplQmOpen to open the PM. (Functionally, this is similar to using DevOpenDC, which is detailed in Opening a Queued Device Context.) You must specify a queue name of PMQOPENDATA for the logical address element, pszLogAddress. PMQOPENDATA is a data structure, identical to DEVOPENSTRUC, to be used with the SplQmxxx functions.
- Use SplQmStartDoc to signal the start of your document. (This is same as using DevEscape with DEVESC_STARTDOC as used in PM printing.)
- Use SplQmWrite to write data to the spool file.
- Use SplQmEndDoc to signal the end of your document. (This is the same as DevEscape with DEVESC_ENDDOC as used in PM printing.)
- Use SplQmClose to close the PM. (Functionally, this is similar to DevCloseDC.)
Spooler Management and Configuration
The spooler provides a set of functions that allows management of all aspects of the print subsystem. There are five categories:
- Job querying and manipulation (SplxxxJob)
- Queue creation, querying, and manipulation (SplxxxQueue)
- Device creation, querying, and manipulation (SplxxxDevice)
- Listing ports, printer drivers, queue processors (SplEnumyyy)
- Listing printers across a network (SplEnumPrinter)
The symbol xxx typically represents Add, Delete, Enum, Query, and Set. For jobs and queues, xxx also includes Hold and Release. For devices, xxx includes Control. The symbol yyy is either Port, PrinterDriver, or QueueProcessor.
It is anticipated that most applications will not use any spooler functions at all except SplEnumQueue, SplQueryQueue, and SplQueryDevice. However, there are some specialized applications that might use the spooler functions for the following:
- An administrative tool to manage queues and jobs
- An automatic printer object configurator
A new printer object can be created by using SplCreateDevice and SplCreateQueue. The print subsystem recognizes that this has occurred and puts a printer object directly on the desktop.
When the spooler is disabled, the following spooler functions do not return any results:
No function is available to enable or disable the spooler under application control; this is a user decision. It is recommended that the spooler always be enabled.
Print Job Management
Some sophisticated applications might need to manipulate jobs in the following ways after they have been spooled into a queue:
- Modify the job parameters (for example, copies); use SplSetJob.
- Increase the priority of a particular job; use SplSetJob.
- Delete a job because a job based on newer data was created; use SplDeleteJob.