Printers are listed in two different sections of the WIN.INI file, reflecting the possibility that a system can have more than one printer attached to it. A single printer is listed in the [windows] section with the keyword device. The string that follows contains the device name, driver name, and output port required in the CreateDC call:
[windows]
[other lines]
device=IBM Graphics,IBMGRX,LPT1:
In this case, the device name is IBM Graphics, the driver name is IBMGRX, and the output port is LPT1. The printer listed in this section of WIN.INI is the most recent printer that the user has selected using the Windows Control Panel. This printer is chosen from the dialog box invoked by the Printer option. It can be considered the ”current printer“ or the ”default printer.“ Most small Windows programs use this printer for printing.
Here is one way to write a function to obtain this string from WIN.INI, parse it into the three components, and call CreateDC to obtain a printer device context handle:
HDC GetPrinterDC ()
{
char szPrinter [80] ;
char *szDevice, *szDriver, *szOutput ;
GetProfileString ("windows", "device", ",,,", szPrinter, 80) ;
if ((szDevice = strtok (szPrinter, "," )) &&
(szDriver = strtok (NULL, ", ")) &&
(szOutput = strtok (NULL, ", ")))
return CreateDC (szDriver, szDevice, szOutput, NULL) ;
return 0 ;
}
GetProfileString looks in the [windows] section for the keyword device and copies up to 80 characters following the equal sign into szPrinter. (The third parameter to GetProfileString is a default string if Windows can't find the [windows] section or the device keyword in WIN.INI.) The string is parsed using the normal C strtok function, which breaks a string into tokens. Note that I use only a comma to find the end of the szDevice string, because the device name can include embedded blanks. Both a comma and space are used to separate the driver name and output port so that leading or trailing blanks are stripped from these strings. (Using strtok is not an entirely satisfactory method of parsing this string, because strtok doesn't take into account the multibyte character codes that can be used in versions of Windows for countries in the Far East. If this is of concern, you can write your own version of strtok that uses AnsiNext to advance through the string.)
The CreateDC function returns 0 if the printer device context could not be created. This can occur if the string in WIN.INI is malformed, if Windows can't find the printer driver, or if the output port name is ”none“ (which means the printer is not connected to an output port). You can, however, obtain an information context for a printer connected to ”none“ by using CreateIC rather than CreateDC.
The [windows] section of WIN.INI lists only one printer. But multiple printers can be listed in the [devices] section of WIN.INI. A printer is listed in this section when a user chooses the Add New Printer option from the Installation menu of CONTROL.EXE. The [devices] section looks something like this:
[devices]
IBM Graphics=IBMGRX,LPT1:
Generic / Text Only=TTY,output.prn
HP Plotter=HPPLOT,COM1:
Postscript Printer=PSCRIPT,COM2:
To the left of each equal sign is the device name; to the right is first the driver name and then the output port. Getting a device context handle using the printer specified in the [windows] section of WIN.INI is essentially the same as getting a device context handle using one of the printers from the [devices] section, except that the latter is more difficult because you have more than one choice.
Some larger Windows programs include a File menu option called Change Printer, which invokes a dialog box that lists all the printers from the [devices] section with the port each printer is connected to. This option allows the user to select a printer other than the one listed in the [windows] section of WIN.INI. A program that includes this option must first call GetProfileString with a NULL second parameter:
static char szAllDevices [4096] ;
[other program lines]
GetProfileString ("devices", NULL, "", szAllDevices,
sizeof szAllDevices) ;
On return, szAllDevices contains a list of the keywords (the device names) in the [devices] section. Each keyword is terminated by a NULL except for the final keyword, which is terminated by two NULLs. For the example list shown above, szAllDevices would contain (using C notation):
IBM Graphics\0Generic / Text Only\0HP Plotter\0Postscript Printer\0\0
You can then present these names to the user. (We'll do this shortly in the DEVCAPS2 program.)
Let's assume that a user selects one of these devices and that you've set the pointer szDevice to the beginning of that device name in szAllDevices. You can then obtain the rest of the string (the driver name and output port) by calling GetProfileString again:
GetProfileString ("devices", szDevice, "", szPrinter, 64) ;
You need to parse the szPrinter string to extract the driver name and the output port name:
szDriver = strtok (szPrinter, ", ") ;
szOutput = strtok (NULL , ", ") ;
Now you have the szDevice, szDriver, and szOutput pointers necessary to call CreateDC or CreateIC.
The valid output ports on a particular system are listed in the [ports] section of WIN.INI. You don't need to access this section of WIN.INI to use the printer. You can assume that the user has identified a particular port for the printer using the Printer option in the Control Panel, and you can further assume that the user has properly defined the communications parameters for serial (COM) ports using the Ports option.
The [ports] section often looks something like this:
[ports]
LPT1:=
LPT2:=
LPT3:=
COM1:=9600,n,8,1
COM2:=1200,n,8,1
output.prn=
The OUTPUT.PRN file (or any file with a .PRN extension) can be listed here to direct printer output to a file. This filename can appear as the output port for a printer in the [windows] section or [devices] section of WIN.INI.