PRINTING

Under DOS, programs send printer commandsè
     Each DOS program must have drivers for each type of printer

Under WINDOWS, programs invoke standard GDI functionsè
     These draw on a DC
          Could be a DC compatible with a printer
     Drivers stored in Windows system DLLs translate to printer commands
     Windows environment supports different types of printers
     User selects a printer from the Control Panel Application
     Driver for that printer used for printing from ALL running apps
  
Printer DC--
     Must be compatible with:
          Printing device
          Its driver
     Must use correct output port

Printer and screen are differentè
     Printer DC is different from screen DC

Some unique printer issues:
     Is printer on line?
     Does printer have paper?
     Is there color support?
     How much graphics support is there?
     Printers are slower than video displays
     Programs reuse video display surface
          Printer must eject completed pages and go on to others
     Printers can jam
     Lots of others

Issues should be addressed without having to use printer-specific commands

Selecting a Printer from Control Panel--

User selects "Start | Printers"  or      
                   "Start | Control Panel | Printers"
Chooses a printer, and from "File" menu selects: "Set as Default"è
     Windows updates WIN.INI file in Windows directory
          Or in the System Registry
     WIN.INI / Registry contains information on current devices/drivers
     Windows reads WIN.INI / Registry when information required
          [windows]:
               Section of WIN.INI containing information on printers

Example--

[windows]
...
device=Panasonic KX-P2130/2135,PAN24_15,LPT1:


Here Windows is informed:
     A device named Panasonic KX-P2130/2135 is installed
     It uses device driver file named PAN24_15.DRV
     Output will go to port LPT1


PRINTER DEVICE CONTEXTS--

To print, program must get a DC compatible with the current printer

Use CreateDC()--

     hDC = CreateDC (drvName, devName, outPort, initData);
     CDC:: CreateDC (drvName, devName, outPort, initData);

Each parameter is a pointer to a character string--
     drvName: printer driver file name (e.g., "PAN24_15")
     devName: device name (e.g., "KX-P2130/2135")
     outPort: output device port name (e.g., "LPT1")
     initData: initialization data, usually set to NULL
The Info contained in "device=" line of [windows] section of WIN.INI

Can use GetProfileString() to read an entry in a section of WIN.INI
     (Mapped to  Registry under NT, 98, 2000, XP)

     n = GetProfileString(section, entry, default, cBuf, maxcnt);

     First four parameters--pointers to strings:
          section: section of WIN.INI containing entry (e.g., "windows")
          entry: entry name (e.g., "device")
          default: default entry name, if not found (e.g., "")
          cBuf: buffer to hold string read from WIN.INI
          maxcnt: maximum number of characters to be read
     Returns number of characters actually read into buffer

Example--
 
     n = GetProfileString("windows", "device", "", lpszPrinter, 64);

Under MFC--
CWinApp:: GetProfileString(section, entry, default, maxcnt);
          Returns a CString

Program then must extract individual fields from the  buffer--
Use C library function strtok():

     char * strtok (char * s1, const char * s2);

     Parses string s1 
     Breaks into tokens separated by string s2

     First call:
          Returns pointer to first character in first token of s1
          Inserts NULL after token

     Subsequent calls (first parameter = NULL):
          Work way through string s1
          Return pointers to first character in each subsequent token


Sample Code to Create a DC for the Default Printer--

HDC   hDC;
char  szPrt[64], *szDrv, *szDev, *szPort;
GetProfileString ("windows","device","",szPrt,64);
szDev = strtok (szPrt, ","); // parsing for commas
szDrv = strtok (NULL, ",");
szPort = strtok (NULL, ",");
// Now each pointer points to correct section of szPrt
hDC = CreateDC (szDrv, szDev, szPort, NULL);
// Now output to printer using standard GDI functions

Getting rid of printer DC--

     DeleteDC (hDC);


Special Printing Functions (most important ones)--

StartDoc (hDC, lpDocinfo);
CDC::StartDoc(lpDocinfo);
     Starts a print job
     Returns a positive integer if successful
     Parameter: pointer to a DOCINFO structure:
          Size in bytes of DOCINFO structure
          Name of document (lpsz)
          Name of output file (lpsz):
               Could be a file for redirected output
               NULLèuse the printer specified in DC

StartPage (hDC);
CDC::StartPage();
     Prepares printer driver to accept data
     Returns positive integer if successful

EndPage (hDC);
CDC::EndPage();
     Signals printer that writing to page is done
     Directs driver to advance printer to new page
     Returns positive integer if successful

EndDoc (hDC);
CDC::EndDoc();
     Ends print job
     Returns positive integer if successful


PRINT1 Example Program--

Outputs a line of text and a rectangle to default printer and to screen

Uses a helper function, OutputStuff()-- 
     Loads a string from a string table stored in the program resources
     Outputs it to location (0,0) on device context specified in first parameter    
     Draws rectangle between (0,40) and (200,100) on specified device context

But printed output looks different from screen output
Reason: Default mapping mode (MM_TEXT) used--
     Size of printer device unit (dot) screen device unit (pixel) differentè
          Different size rectangles
     Text not affected by mapping mode in place, only by font
     Windows keeps default system font about same size on both

To get the Printer Output "Right"--
     Use mapping mode with fixed unit size 
          e.g., MM_LOMETRIC, MM_LOENGLISH, etc.
     Output to screen and printed page will be very similar


PRINT2 Example Program--

Uses MM_LOMETRIC mapping mode
Draws some text enclosed in a rectangle
Draws a black circle
Output goes to both printer and screen

Change helper function OutputStuff()--
     Set mapping mode to MM_LOMETRIC & move paper/screen up 15 mm
     Uses GetTextExtentPoint() to get size of text string
          x,y extent of text returned in SIZE structure pointed to by last param

Paper and screen output are very similar


Getting Information about a Physical Device (e.g., PRINTER)--

Can query device context of a device for associated data 
Stored there by Windows when DC created

     CapValue = GetDeviceCaps (hDC, capability_index);
     CDC::GetDeviceCaps(capability_index);
          Accesses specified DC 
          Returns requested capability value

  (See online help on GetDeviceCaps() for possible capabilities)


DEVCAPS Example Program--

Displays several capabilities of video display and default printer
Uses a string table to store various capability entries

Two helper functions do display--

1. OutStringTable(hDC, hInst, nStringID, nx, ny);

Retrieves string whose ID is nStringID from string table resource
Displays it at (nx,ny) on device context whose handle is hDC

2. OutDevCapValue(hDCOut, hDCData, nCapIndex, nx, ny);

Gets and displays capability value from device context--
     HDCOut: handle to DC where result displayed
     hDCData: handle to DC being queried
     nCapIndex: index of capability
     nx,ny: where to display

Gets capability value with:
    nValue = GetDeviceCaps (hDCdata, nIndex) ;

Formats and displays value with: 
    TextOut (hDCout, nX, nY, cBuf, wsprintf (cBuf, "%d", nValue)) ;
         Here wsprintf() formats the string and returns its length