The Printing Common Dialog Boxes

The common dialog library provides three common dialog boxes that you can use for printing: Print, which lets the user configure the printer for a particular print job; Print Setup, in which the user can configure the printer for all jobs; and Page Setup, which allows the user to set properties such as margins, paper orientation, and paper source for the current document. The Print Setup common dialog box is supported for backward compatibility with previous versions of Windows; new applications should use the new print dialog boxes—Print and Page Setup. A user can access the printer configuration dialog box through the Page Setup dialog box.

The Print dialog box, shown in Figure 6-13 on the following page, differs from other common dialog boxes in that part of its dialog procedure resides in COMDLG32.DLL and part of it resides in the printer driver. When the user clicks the Properties button in the Print dialog box, the printer driver uses an exported function called ExtDeviceMode to display the Printer Properties property sheet.

Win32-based applications fill out the PRINTDLG structure and call a single function, PrintDlg, to show the Print dialog box or the Print Setup dialog box. The Print dialog box appears by default; to display the Print Setup dialog box, which is shown in Figure 6-14, the application specifies the PD_PRINTSETUP flag.

Figure 6-13.

The Print common dialog box.

Figure 6-14.

The Print Setup common dialog box.

The PRINTDLG structure contains data such as the printer device context, initial values for the dialog box controls (such as number of copies and page range), and hook and template information. The following code shows how the CMNDLG32 sample fills out the structure and prints the contents of its edit buffer. Notice that I included the PD_USEDEVMODECOPIES and PD_COLLATE styles. If the application does not specify these styles, it takes responsibility for simulating the printing of multiple copies or collating.

void PrintFile (HWND hWnd)
{
DOCINFO di;
int nError;

// Initialize the PRINTDLG structure.
pd.lStructSize = sizeof (PRINTDLG);
pd.hwndOwner = hWnd;
pd.hDevMode = (HANDLE)NULL;
pd.hDevNames = (HANDLE)NULL;
pd.nFromPage = 0;
pd.nToPage = 0;
pd.nMinPage = 0;
pd.nMaxPage = 0;
pd.nCopies = 0;
pd.hInstance = (HANDLE)hInst;
pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIES | PD_COLLATE |
PD_NOSELECTION | PD_PRINTSETUP;

switch (wMode)
{
case IDM_STANDARD:
pd.lpfnSetupHook = (LPSETUPHOOKPROC)(FARPROC)NULL;
pd.lpSetupTemplateName = (LPTSTR)NULL;
pd.lpfnPrintHook = (LPPRINTHOOKPROC)(FARPROC)NULL;
pd.lpPrintTemplateName = (LPTSTR)NULL;
break;

case IDM_HOOK:
pd.Flags |= PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK;
pd.lpfnSetupHook = (LPSETUPHOOKPROC)PrintSetupHookProc;
pd.lpSetupTemplateName = (LPTSTR)NULL;
pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDlgHookProc;
pd.lpPrintTemplateName = (LPTSTR)NULL;
break;

case IDM_CUSTOM:
pd.Flags |= PD_ENABLEPRINTHOOK | PD_ENABLEPRINTTEMPLATE |
PD_ENABLESETUPHOOK | PD_ENABLESETUPTEMPLATE;
pd.lpfnSetupHook = (LPSETUPHOOKPROC)PrintSetupHookProc;
pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDlgHookProc;
pd.lpPrintTemplateName = (LPTSTR) MAKEINTRESOURCE (PRINTDLGORD);
pd.lpSetupTemplateName =
(LPTSTR) MAKEINTRESOURCE (PRNSETUPDLGORD);
break;
}

// Print a test page if successful.
if (PrintDlg (&pd) == TRUE)
{
// Fill out the DOCINFO structure.
di.cbSize = sizeof (DOCINFO);
di.lpszDocName = "Printing Test";
di.lpszOutput = (LPTSTR)NULL;
di.fwType = 0;

// Start the document.
StartDoc (pd.hDC, &di);

nError = StartPage (pd.hDC);
if (nError <= 0)
MessageBox (hWnd, "Error in StartPage.", NULL, MB_OK);
else
{
// Print the text.
TextOut (pd.hDC, 5, 5, FileBuf, lstrlen (FileBuf));

// Exit if the user has clicked the Cancel button in the
// AbortPrintJob dialog box; if the button has been clicked,
// call the AbortDoc function. Otherwise, inform the spooler
// that the page is complete.
nError = EndPage (pd.hDC);
if (nError <= 0)
{
MessageBox (hWnd, "Error in EndPage.", NULL, MB_OK);
AbortDoc (pd.hDC);
}
else
{
// The document has ended.
nError = EndDoc (pd.hDC);
if (nError <= 0)
MessageBox (hWnd, "Error in EndDoc.", NULL, MB_OK);
}
}
DeleteDC (pd.hDC);
if (pd.hDevMode)
GlobalFree (pd.hDevMode);
if (pd.hDevNames)
GlobalFree (pd.hDevNames);
}
else
ProcessCDError (CommDlgExtendedError (), hWnd);
}

Using the PD_RETURNDC flag, as I did in this code, causes PrintDlg to return a handle to a printer device context in the hDC member of the PRINTDLG structure. This handle is used in subsequent calls to do the actual printing. In this case, the hDC is sent to the Escape functions, which are used to send instructions to the print manager and spooler.