2 * COMMDLG - Print Dialog
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1999 Klaas van Gend
7 * Copyright 2000 Huw D M Davies
16 #include "wine/wingdi16.h"
18 #include "wine/winuser16.h"
22 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(commdlg
);
32 /* This PRINTDLGA internal structure stores
33 * pointers to several throughout useful structures.
39 LPPRINTDLGA lpPrintDlg
;
40 LPPRINTER_INFO_2A lpPrinterInfo
;
42 HICON hCollateIcon
; /* PrintDlg only */
43 HICON hNoCollateIcon
; /* PrintDlg only */
44 HICON hPortraitIcon
; /* PrintSetupDlg only */
45 HICON hLandscapeIcon
; /* PrintSetupDlg only */
49 static struct pd_flags
{
53 {PD_SELECTION
, "PD_SELECTION "},
54 {PD_PAGENUMS
, "PD_PAGENUMS "},
55 {PD_NOSELECTION
, "PD_NOSELECTION "},
56 {PD_NOPAGENUMS
, "PD_NOPAGENUMS "},
57 {PD_COLLATE
, "PD_COLLATE "},
58 {PD_PRINTTOFILE
, "PD_PRINTTOFILE "},
59 {PD_PRINTSETUP
, "PD_PRINTSETUP "},
60 {PD_NOWARNING
, "PD_NOWARNING "},
61 {PD_RETURNDC
, "PD_RETURNDC "},
62 {PD_RETURNIC
, "PD_RETURNIC "},
63 {PD_RETURNDEFAULT
, "PD_RETURNDEFAULT "},
64 {PD_SHOWHELP
, "PD_SHOWHELP "},
65 {PD_ENABLEPRINTHOOK
, "PD_ENABLEPRINTHOOK "},
66 {PD_ENABLESETUPHOOK
, "PD_ENABLESETUPHOOK "},
67 {PD_ENABLEPRINTTEMPLATE
, "PD_ENABLEPRINTTEMPLATE "},
68 {PD_ENABLESETUPTEMPLATE
, "PD_ENABLESETUPTEMPLATE "},
69 {PD_ENABLEPRINTTEMPLATEHANDLE
, "PD_ENABLEPRINTTEMPLATEHANDLE "},
70 {PD_ENABLESETUPTEMPLATEHANDLE
, "PD_ENABLESETUPTEMPLATEHANDLE "},
71 {PD_USEDEVMODECOPIES
, "PD_USEDEVMODECOPIES[ANDCOLLATE] "},
72 {PD_DISABLEPRINTTOFILE
, "PD_DISABLEPRINTTOFILE "},
73 {PD_HIDEPRINTTOFILE
, "PD_HIDEPRINTTOFILE "},
74 {PD_NONETWORKBUTTON
, "PD_NONETWORKBUTTON "},
79 /***********************************************************************
80 * PRINTDLG_GetDefaultPrinterName
82 * Returns the default printer name in buf.
83 * Even under WinNT/2000 default printer is retrieved via GetProfileString -
84 * these entries are mapped somewhere in the registry rather than win.ini.
86 * Returns TRUE on success else FALSE
88 static BOOL
PRINTDLG_GetDefaultPrinterName(LPSTR buf
, DWORD len
)
92 if(!GetProfileStringA("windows", "device", "", buf
, len
))
94 if((ptr
= strchr(buf
, ',')) == NULL
)
100 /***********************************************************************
101 * PRINTDLG_OpenDefaultPrinter
103 * Returns a winspool printer handle to the default printer in *hprn
104 * Caller must call ClosePrinter on the handle
106 * Returns TRUE on success else FALSE
108 static BOOL
PRINTDLG_OpenDefaultPrinter(HANDLE
*hprn
)
111 if(!PRINTDLG_GetDefaultPrinterName(buf
, sizeof(buf
)))
113 return OpenPrinterA(buf
, hprn
, NULL
);
116 /***********************************************************************
117 * PRINTDLG_SetUpPrinterListCombo
119 * Initializes printer list combox.
120 * hDlg: HWND of dialog
121 * id: Control id of combo
122 * name: Name of printer to select
124 * Initializes combo with list of available printers. Selects printer 'name'
125 * If name is NULL or does not exist select the default printer.
127 * Returns number of printers added to list.
129 static INT
PRINTDLG_SetUpPrinterListCombo(HWND hDlg
, UINT id
, LPCSTR name
)
133 LPPRINTER_INFO_2A pi
;
134 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 2, NULL
, 0, &needed
, &num
);
135 pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
136 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 2, (LPBYTE
)pi
, needed
, &needed
,
139 for(i
= 0; i
< num
; i
++) {
140 SendDlgItemMessageA(hDlg
, id
, CB_ADDSTRING
, 0,
141 (LPARAM
)pi
[i
].pPrinterName
);
143 HeapFree(GetProcessHeap(), 0, pi
);
145 (i
= SendDlgItemMessageA(hDlg
, id
, CB_FINDSTRINGEXACT
, -1,
146 (LPARAM
)name
)) == CB_ERR
) {
149 TRACE("Can't find '%s' in printer list so trying to find default\n",
151 if(!PRINTDLG_GetDefaultPrinterName(buf
, sizeof(buf
)))
153 i
= SendDlgItemMessageA(hDlg
, id
, CB_FINDSTRINGEXACT
, -1, (LPARAM
)buf
);
155 TRACE("Can't find default printer in printer list\n");
157 SendDlgItemMessageA(hDlg
, id
, CB_SETCURSEL
, i
, 0);
161 /***********************************************************************
162 * PRINTDLG_CreateDevNames [internal]
165 * creates a DevNames structure.
167 * (NB. when we handle unicode the offsets will be in wchars).
169 static BOOL
PRINTDLG_CreateDevNames(HGLOBAL
*hmem
, char* DeviceDriverName
,
170 char* DeviceName
, char* OutputPort
)
173 char* pDevNamesSpace
;
175 LPDEVNAMES lpDevNames
;
178 size
= strlen(DeviceDriverName
) + 1
179 + strlen(DeviceName
) + 1
180 + strlen(OutputPort
) + 1
184 *hmem
= GlobalReAlloc(*hmem
, size
, GMEM_MOVEABLE
);
186 *hmem
= GlobalAlloc(GMEM_MOVEABLE
, size
);
190 pDevNamesSpace
= GlobalLock(*hmem
);
191 lpDevNames
= (LPDEVNAMES
) pDevNamesSpace
;
193 pTempPtr
= pDevNamesSpace
+ sizeof(DEVNAMES
);
194 strcpy(pTempPtr
, DeviceDriverName
);
195 lpDevNames
->wDriverOffset
= pTempPtr
- pDevNamesSpace
;
197 pTempPtr
+= strlen(DeviceDriverName
) + 1;
198 strcpy(pTempPtr
, DeviceName
);
199 lpDevNames
->wDeviceOffset
= pTempPtr
- pDevNamesSpace
;
201 pTempPtr
+= strlen(DeviceName
) + 1;
202 strcpy(pTempPtr
, OutputPort
);
203 lpDevNames
->wOutputOffset
= pTempPtr
- pDevNamesSpace
;
205 PRINTDLG_GetDefaultPrinterName(buf
, sizeof(buf
));
206 lpDevNames
->wDefault
= (strcmp(buf
, DeviceName
) == 0) ? 1 : 0;
211 /***********************************************************************
212 * PRINTDLG_UpdatePrintDlg [internal]
215 * updates the PrintDlg structure for returnvalues.
218 * FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values)
221 static BOOL
PRINTDLG_UpdatePrintDlg(HWND hDlg
,
222 PRINT_PTRA
* PrintStructures
)
224 LPPRINTDLGA lppd
= PrintStructures
->lpPrintDlg
;
225 PDEVMODEA lpdm
= PrintStructures
->lpDevMode
;
226 LPPRINTER_INFO_2A pi
= PrintStructures
->lpPrinterInfo
;
229 if(!lpdm
) return FALSE
;
232 if(!(lppd
->Flags
& PD_PRINTSETUP
)) {
233 /* check whether nFromPage and nToPage are within range defined by
234 * nMinPage and nMaxPage
236 if (IsDlgButtonChecked(hDlg
, rad3
) == BST_CHECKED
) { /* Pages */
239 nFromPage
= GetDlgItemInt(hDlg
, edt1
, NULL
, FALSE
);
240 nToPage
= GetDlgItemInt(hDlg
, edt2
, NULL
, FALSE
);
241 if (nFromPage
< lppd
->nMinPage
|| nFromPage
> lppd
->nMaxPage
||
242 nToPage
< lppd
->nMinPage
|| nToPage
> lppd
->nMaxPage
) {
243 char resourcestr
[256];
245 LoadStringA(COMDLG32_hInstance
, PD32_INVALID_PAGE_RANGE
,
247 sprintf(resultstr
,resourcestr
, lppd
->nMinPage
, lppd
->nMaxPage
);
248 LoadStringA(COMDLG32_hInstance
, PD32_PRINT_TITLE
,
250 MessageBoxA(hDlg
, resultstr
, resourcestr
,
251 MB_OK
| MB_ICONWARNING
);
254 lppd
->nFromPage
= nFromPage
;
255 lppd
->nToPage
= nToPage
;
258 if (IsDlgButtonChecked(hDlg
, chx1
) == BST_CHECKED
) {/* Print to file */
259 lppd
->Flags
|= PD_PRINTTOFILE
;
260 pi
->pPortName
= "FILE:";
263 if (IsDlgButtonChecked(hDlg
, chx2
) == BST_CHECKED
) { /* Collate */
264 FIXME("Collate lppd not yet implemented as output\n");
267 /* set PD_Collate and nCopies */
268 if (lppd
->Flags
& PD_USEDEVMODECOPIESANDCOLLATE
) {
269 /* The application doesn't support multiple copies or collate...
271 lppd
->Flags
&= ~PD_COLLATE
;
273 /* if the printer driver supports it... store info there
274 * otherwise no collate & multiple copies !
276 if (lpdm
->dmFields
& DM_COLLATE
)
278 (IsDlgButtonChecked(hDlg
, chx2
) == BST_CHECKED
);
279 if (lpdm
->dmFields
& DM_COPIES
)
280 lpdm
->dmCopies
= GetDlgItemInt(hDlg
, edt3
, NULL
, FALSE
);
282 if (IsDlgButtonChecked(hDlg
, chx2
) == BST_CHECKED
)
283 lppd
->Flags
|= PD_COLLATE
;
285 lppd
->Flags
&= ~PD_COLLATE
;
286 lppd
->nCopies
= GetDlgItemInt(hDlg
, edt3
, NULL
, FALSE
);
293 /************************************************************************
294 * PRINTDLG_SetUpPaperComboBox
296 * Initialize either the papersize or inputslot combos of the Printer Setup
297 * dialog. We store the associated word (eg DMPAPER_A4) as the item data.
298 * We also try to re-select the old selection.
300 static BOOL
PRINTDLG_SetUpPaperComboBox(HWND hDlg
,
313 int fwCapability_Names
;
314 int fwCapability_Words
;
316 TRACE(" Printer: %s, ComboID: %d\n",PrinterName
,nIDComboBox
);
318 /* query the dialog box for the current selected value */
319 Sel
= SendDlgItemMessageA(hDlg
, nIDComboBox
, CB_GETCURSEL
, 0, 0);
321 oldWord
= SendDlgItemMessageA(hDlg
, nIDComboBox
, CB_GETITEMDATA
, Sel
,
325 if (nIDComboBox
== cmb2
) {
327 fwCapability_Names
= DC_PAPERNAMES
;
328 fwCapability_Words
= DC_PAPERS
;
332 fwCapability_Names
= DC_BINNAMES
;
333 fwCapability_Words
= DC_BINS
;
336 /* for some printer drivers, DeviceCapabilities calls a VXD to obtain the
337 * paper settings. As Wine doesn't allow VXDs, this results in a crash.
339 WARN(" if your printer driver uses VXDs, expect a crash now!\n");
340 NrOfEntries
= DeviceCapabilitiesA(PrinterName
, PortName
,
341 fwCapability_Names
, NULL
, dm
);
342 if (NrOfEntries
== 0)
343 WARN("no Name Entries found!\n");
345 if(DeviceCapabilitiesA(PrinterName
, PortName
, fwCapability_Words
, NULL
, dm
)
347 ERR("Number of caps is different\n");
351 Names
= HeapAlloc(GetProcessHeap(),0, NrOfEntries
*NamesSize
);
352 Words
= HeapAlloc(GetProcessHeap(),0, NrOfEntries
*sizeof(WORD
));
353 NrOfEntries
= DeviceCapabilitiesA(PrinterName
, PortName
,
354 fwCapability_Names
, Names
, dm
);
355 NrOfEntries
= DeviceCapabilitiesA(PrinterName
, PortName
,
356 fwCapability_Words
, (LPSTR
)Words
, dm
);
358 /* reset any current content in the combobox */
359 SendDlgItemMessageA(hDlg
, nIDComboBox
, CB_RESETCONTENT
, 0, 0);
361 /* store new content */
362 for (i
= 0; i
< NrOfEntries
; i
++) {
363 DWORD pos
= SendDlgItemMessageA(hDlg
, nIDComboBox
, CB_ADDSTRING
, 0,
364 (LPARAM
)(&Names
[i
*NamesSize
]) );
365 SendDlgItemMessageA(hDlg
, nIDComboBox
, CB_SETITEMDATA
, pos
,
369 /* Look for old selection - can't do this is previous loop since
370 item order will change as more items are added */
372 for (i
= 0; i
< NrOfEntries
; i
++) {
373 if(SendDlgItemMessageA(hDlg
, nIDComboBox
, CB_GETITEMDATA
, i
, 0) ==
379 SendDlgItemMessageA(hDlg
, nIDComboBox
, CB_SETCURSEL
, Sel
, 0);
381 HeapFree(GetProcessHeap(),0,Words
);
382 HeapFree(GetProcessHeap(),0,Names
);
386 /***********************************************************************
387 * PRINTDLG_UpdatePrinterInfoTexts [internal]
389 static void PRINTDLG_UpdatePrinterInfoTexts(HWND hDlg
, LPPRINTER_INFO_2A pi
)
392 char ResourceString
[256];
398 /* add all status messages */
399 for (i
= 0; i
< 25; i
++) {
400 if (pi
->Status
& (1<<i
)) {
401 LoadStringA(COMDLG32_hInstance
, PD32_PRINTER_STATUS_PAUSED
+i
,
402 ResourceString
, 255);
403 strcat(StatusMsg
,ResourceString
);
407 /* FIXME: status==ready must only be appended if really so.
408 but how to detect? */
409 LoadStringA(COMDLG32_hInstance
, PD32_PRINTER_STATUS_READY
,
410 ResourceString
, 255);
411 strcat(StatusMsg
,ResourceString
);
413 SendDlgItemMessageA(hDlg
, stc12
, WM_SETTEXT
, 0, (LPARAM
)StatusMsg
);
415 /* set all other printer info texts */
416 SendDlgItemMessageA(hDlg
, stc11
, WM_SETTEXT
, 0, (LPARAM
)pi
->pDriverName
);
417 if (pi
->pLocation
!= NULL
&& pi
->pLocation
[0] != '\0')
418 SendDlgItemMessageA(hDlg
, stc14
, WM_SETTEXT
, 0,(LPARAM
)pi
->pLocation
);
420 SendDlgItemMessageA(hDlg
, stc14
, WM_SETTEXT
, 0,(LPARAM
)pi
->pPortName
);
421 SendDlgItemMessageA(hDlg
, stc13
, WM_SETTEXT
, 0, (LPARAM
)pi
->pComment
);
426 /*******************************************************************
428 * PRINTDLG_ChangePrinter
431 static BOOL
PRINTDLG_ChangePrinter(HWND hDlg
, char *name
,
432 PRINT_PTRA
*PrintStructures
)
434 LPPRINTDLGA lppd
= PrintStructures
->lpPrintDlg
;
435 LPDEVMODEA lpdm
= NULL
;
440 if(PrintStructures
->lpPrinterInfo
)
441 HeapFree(GetProcessHeap(),0, PrintStructures
->lpPrinterInfo
);
442 if(!OpenPrinterA(name
, &hprn
, NULL
)) {
443 ERR("Can't open printer %s\n", name
);
446 GetPrinterA(hprn
, 2, NULL
, 0, &needed
);
447 PrintStructures
->lpPrinterInfo
= HeapAlloc(GetProcessHeap(),0,needed
);
448 GetPrinterA(hprn
, 2, (LPBYTE
)PrintStructures
->lpPrinterInfo
, needed
,
452 PRINTDLG_UpdatePrinterInfoTexts(hDlg
, PrintStructures
->lpPrinterInfo
);
454 if(PrintStructures
->lpDevMode
) {
455 HeapFree(GetProcessHeap(), 0, PrintStructures
->lpDevMode
);
456 PrintStructures
->lpDevMode
= NULL
;
459 dmSize
= DocumentPropertiesA(0, 0, name
, NULL
, NULL
, 0);
461 ERR("DocumentProperties fails on %s\n", debugstr_a(name
));
464 PrintStructures
->lpDevMode
= HeapAlloc(GetProcessHeap(), 0, dmSize
);
465 dmSize
= DocumentPropertiesA(0, 0, name
, PrintStructures
->lpDevMode
, NULL
,
467 if(lppd
->hDevMode
&& (lpdm
= GlobalLock(lppd
->hDevMode
)) &&
468 !strcmp(lpdm
->dmDeviceName
,
469 PrintStructures
->lpDevMode
->dmDeviceName
)) {
470 /* Supplied devicemode matches current printer so try to use it */
471 DocumentPropertiesA(0, 0, name
, PrintStructures
->lpDevMode
, lpdm
,
472 DM_OUT_BUFFER
| DM_IN_BUFFER
);
475 GlobalUnlock(lppd
->hDevMode
);
477 lpdm
= PrintStructures
->lpDevMode
; /* use this as a shortcut */
479 if(!(lppd
->Flags
& PD_PRINTSETUP
)) {
480 /* Print range (All/Range/Selection) */
481 SetDlgItemInt(hDlg
, edt1
, lppd
->nFromPage
, FALSE
);
482 SetDlgItemInt(hDlg
, edt2
, lppd
->nToPage
, FALSE
);
483 CheckRadioButton(hDlg
, rad1
, rad3
, rad1
); /* default */
484 if (lppd
->Flags
& PD_NOSELECTION
)
485 EnableWindow(GetDlgItem(hDlg
, rad2
), FALSE
);
487 if (lppd
->Flags
& PD_SELECTION
)
488 CheckRadioButton(hDlg
, rad1
, rad3
, rad2
);
489 if (lppd
->Flags
& PD_NOPAGENUMS
) {
490 EnableWindow(GetDlgItem(hDlg
, rad3
), FALSE
);
491 EnableWindow(GetDlgItem(hDlg
, stc2
),FALSE
);
492 EnableWindow(GetDlgItem(hDlg
, edt1
), FALSE
);
493 EnableWindow(GetDlgItem(hDlg
, stc3
),FALSE
);
494 EnableWindow(GetDlgItem(hDlg
, edt2
), FALSE
);
496 if (lppd
->Flags
& PD_PAGENUMS
)
497 CheckRadioButton(hDlg
, rad1
, rad3
, rad3
);
499 /* "All xxx pages"... */
501 char resourcestr
[64];
503 LoadStringA(COMDLG32_hInstance
, PD32_PRINT_ALL_X_PAGES
,
505 sprintf(result
,resourcestr
,lppd
->nMaxPage
- lppd
->nMinPage
+ 1);
506 SendDlgItemMessageA(hDlg
, rad1
, WM_SETTEXT
, 0, (LPARAM
) result
);
511 * FIXME: The ico3 is not displayed for some reason. I don't know why.
513 if (lppd
->Flags
& PD_COLLATE
) {
514 SendDlgItemMessageA(hDlg
, ico3
, STM_SETIMAGE
, (WPARAM
) IMAGE_ICON
,
515 (LPARAM
)PrintStructures
->hCollateIcon
);
516 CheckDlgButton(hDlg
, chx2
, 1);
518 SendDlgItemMessageA(hDlg
, ico3
, STM_SETIMAGE
, (WPARAM
) IMAGE_ICON
,
519 (LPARAM
)PrintStructures
->hNoCollateIcon
);
520 CheckDlgButton(hDlg
, chx2
, 0);
523 if (lppd
->Flags
& PD_USEDEVMODECOPIESANDCOLLATE
) {
524 /* if printer doesn't support it: no Collate */
525 if (!(lpdm
->dmFields
& DM_COLLATE
)) {
526 EnableWindow(GetDlgItem(hDlg
, chx2
), FALSE
);
527 EnableWindow(GetDlgItem(hDlg
, ico3
), FALSE
);
532 if (lppd
->hDevMode
== 0)
533 SetDlgItemInt(hDlg
, edt3
, lppd
->nCopies
, FALSE
);
535 SetDlgItemInt(hDlg
, edt3
, lpdm
->dmCopies
, FALSE
);
537 if (lppd
->Flags
& PD_USEDEVMODECOPIESANDCOLLATE
) {
538 /* if printer doesn't support it: no nCopies */
539 if (!(lpdm
->dmFields
& DM_COPIES
)) {
540 EnableWindow(GetDlgItem(hDlg
, edt3
), FALSE
);
541 EnableWindow(GetDlgItem(hDlg
, stc5
), FALSE
);
546 CheckDlgButton(hDlg
, chx1
, (lppd
->Flags
& PD_PRINTTOFILE
) ? 1 : 0);
547 if (lppd
->Flags
& PD_DISABLEPRINTTOFILE
)
548 EnableWindow(GetDlgItem(hDlg
, chx1
), FALSE
);
549 if (lppd
->Flags
& PD_HIDEPRINTTOFILE
)
550 ShowWindow(GetDlgItem(hDlg
, chx1
), SW_HIDE
);
552 } else { /* PD_PRINTSETUP */
553 PRINTDLG_SetUpPaperComboBox(hDlg
, cmb2
,
554 PrintStructures
->lpPrinterInfo
->pPrinterName
,
555 PrintStructures
->lpPrinterInfo
->pPortName
,
557 PRINTDLG_SetUpPaperComboBox(hDlg
, cmb3
,
558 PrintStructures
->lpPrinterInfo
->pPrinterName
,
559 PrintStructures
->lpPrinterInfo
->pPortName
,
561 CheckRadioButton(hDlg
, rad1
, rad2
,
562 (lpdm
->u1
.s1
.dmOrientation
== DMORIENT_PORTRAIT
) ?
567 if ((lppd
->Flags
& PD_SHOWHELP
)==0) {
568 /* hide if PD_SHOWHELP not specified */
569 ShowWindow(GetDlgItem(hDlg
, pshHelp
), SW_HIDE
);
575 /***********************************************************************
576 * PRINTDLG_WMInitDialog [internal]
578 static LRESULT
PRINTDLG_WMInitDialog(HWND hDlg
, WPARAM wParam
,
579 PRINT_PTRA
* PrintStructures
)
581 LPPRINTDLGA lppd
= PrintStructures
->lpPrintDlg
;
585 UINT comboID
= (lppd
->Flags
& PD_PRINTSETUP
) ? cmb1
: cmb4
;
587 /* load Collate ICONs */
588 PrintStructures
->hCollateIcon
=
589 LoadIconA(COMDLG32_hInstance
, "PD32_COLLATE");
590 PrintStructures
->hNoCollateIcon
=
591 LoadIconA(COMDLG32_hInstance
, "PD32_NOCOLLATE");
592 if(PrintStructures
->hCollateIcon
== 0 ||
593 PrintStructures
->hNoCollateIcon
== 0) {
594 ERR("no icon in resourcefile\n");
595 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
596 EndDialog(hDlg
, FALSE
);
599 /* load Paper Orientation ICON */
600 /* FIXME: not implemented yet */
603 * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
604 * must be registered and the Help button must be shown.
606 if (lppd
->Flags
& PD_SHOWHELP
) {
607 if((PrintStructures
->HelpMessageID
=
608 RegisterWindowMessageA(HELPMSGSTRING
)) == 0) {
609 COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL
);
613 PrintStructures
->HelpMessageID
= 0;
615 /* FIXME: I allow more freedom than either Win95 or WinNT,
616 * which do not agree to what errors should be thrown or not
617 * in case nToPage or nFromPage is out-of-range.
619 if (lppd
->nMaxPage
< lppd
->nMinPage
)
620 lppd
->nMaxPage
= lppd
->nMinPage
;
621 if (lppd
->nMinPage
== lppd
->nMaxPage
)
622 lppd
->Flags
|= PD_NOPAGENUMS
;
623 if (lppd
->nToPage
< lppd
->nMinPage
)
624 lppd
->nToPage
= lppd
->nMinPage
;
625 if (lppd
->nToPage
> lppd
->nMaxPage
)
626 lppd
->nToPage
= lppd
->nMaxPage
;
627 if (lppd
->nFromPage
< lppd
->nMinPage
)
628 lppd
->nFromPage
= lppd
->nMinPage
;
629 if (lppd
->nFromPage
> lppd
->nMaxPage
)
630 lppd
->nFromPage
= lppd
->nMaxPage
;
634 pdn
= GlobalLock(lppd
->hDevNames
);
635 pdm
= GlobalLock(lppd
->hDevMode
);
637 name
= (char*)pdn
+ pdn
->wDeviceOffset
;
639 name
= pdm
->dmDeviceName
;
640 PRINTDLG_SetUpPrinterListCombo(hDlg
, comboID
, name
);
641 if(pdm
) GlobalUnlock(lppd
->hDevMode
);
642 if(pdn
) GlobalUnlock(lppd
->hDevNames
);
644 /* Now find selected printer and update rest of dlg */
645 name
= HeapAlloc(GetProcessHeap(),0,256);
646 GetDlgItemTextA(hDlg
, comboID
, name
, 255);
647 PRINTDLG_ChangePrinter(hDlg
, name
, PrintStructures
);
648 HeapFree(GetProcessHeap(),0,name
);
653 /***********************************************************************
654 * PRINTDLG_WMCommand [internal]
656 static LRESULT
PRINTDLG_WMCommand(HWND hDlg
, WPARAM wParam
,
657 LPARAM lParam
, PRINT_PTRA
* PrintStructures
)
659 LPPRINTDLGA lppd
= PrintStructures
->lpPrintDlg
;
660 UINT PrinterComboID
= (lppd
->Flags
& PD_PRINTSETUP
) ? cmb1
: cmb4
;
661 LPDEVMODEA lpdm
= PrintStructures
->lpDevMode
;
663 switch (LOWORD(wParam
)) {
665 TRACE(" OK button was hit\n");
666 if (PRINTDLG_UpdatePrintDlg(hDlg
, PrintStructures
)!=TRUE
)
668 EndDialog(hDlg
, TRUE
);
672 TRACE(" CANCEL button was hit\n");
673 EndDialog(hDlg
, FALSE
);
677 TRACE(" HELP button was hit\n");
678 SendMessageA(lppd
->hwndOwner
, PrintStructures
->HelpMessageID
,
679 (WPARAM
) hDlg
, (LPARAM
) lppd
);
682 case chx2
: /* collate pages checkbox */
683 if (IsDlgButtonChecked(hDlg
, chx2
) == BST_CHECKED
)
684 SendDlgItemMessageA(hDlg
, ico3
, STM_SETIMAGE
, (WPARAM
) IMAGE_ICON
,
685 (LPARAM
)PrintStructures
->hCollateIcon
);
687 SendDlgItemMessageA(hDlg
, ico3
, STM_SETIMAGE
, (WPARAM
) IMAGE_ICON
,
688 (LPARAM
)PrintStructures
->hNoCollateIcon
);
690 case edt1
: /* from page nr editbox */
691 case edt2
: /* to page nr editbox */
692 if (HIWORD(wParam
)==EN_CHANGE
) {
695 nFromPage
= GetDlgItemInt(hDlg
, edt1
, NULL
, FALSE
);
696 nToPage
= GetDlgItemInt(hDlg
, edt2
, NULL
, FALSE
);
697 if (nFromPage
!= lppd
->nFromPage
|| nToPage
!= lppd
->nToPage
)
698 CheckRadioButton(hDlg
, rad1
, rad3
, rad3
);
701 case psh2
: /* Properties button */
704 char PrinterName
[256];
706 GetDlgItemTextA(hDlg
, PrinterComboID
, PrinterName
, 255);
707 if (!OpenPrinterA(PrinterName
, &hPrinter
, NULL
)) {
708 WARN(" Call to OpenPrinter did not succeed!\n");
711 DocumentPropertiesA(hDlg
, hPrinter
, PrinterName
,
712 PrintStructures
->lpDevMode
,
713 PrintStructures
->lpDevMode
,
714 DM_IN_BUFFER
| DM_OUT_BUFFER
| DM_IN_PROMPT
);
715 ClosePrinter(hPrinter
);
720 case cmb4
: /* Printer combobox */
721 if (HIWORD(wParam
)==CBN_SELCHANGE
) {
722 char PrinterName
[256];
723 GetDlgItemTextA(hDlg
, LOWORD(wParam
), PrinterName
, 255);
724 PRINTDLG_ChangePrinter(hDlg
, PrinterName
, PrintStructures
);
728 case cmb2
: /* Papersize */
730 DWORD Sel
= SendDlgItemMessageA(hDlg
, cmb2
, CB_GETCURSEL
, 0, 0);
732 lpdm
->u1
.s1
.dmPaperSize
= SendDlgItemMessageA(hDlg
, cmb2
,
740 DWORD Sel
= SendDlgItemMessageA(hDlg
, cmb3
, CB_GETCURSEL
, 0, 0);
742 lpdm
->dmDefaultSource
= SendDlgItemMessageA(hDlg
, cmb3
,
751 /***********************************************************************
752 * PrintDlgProcA [internal]
754 BOOL WINAPI
PrintDlgProcA(HWND hDlg
, UINT uMsg
, WPARAM wParam
,
757 PRINT_PTRA
* PrintStructures
;
760 if (uMsg
!=WM_INITDIALOG
) {
761 PrintStructures
= (PRINT_PTRA
*) GetWindowLongA(hDlg
, DWL_USER
);
762 if (!PrintStructures
)
765 PrintStructures
= (PRINT_PTRA
*) lParam
;
766 SetWindowLongA(hDlg
, DWL_USER
, lParam
);
767 res
= PRINTDLG_WMInitDialog(hDlg
, wParam
, PrintStructures
);
769 if(PrintStructures
->lpPrintDlg
->Flags
& PD_ENABLEPRINTHOOK
) {
770 res
= PrintStructures
->lpPrintDlg
->lpfnPrintHook(hDlg
, uMsg
,
772 (LPARAM
)PrintStructures
->lpPrintDlg
);
777 if(PrintStructures
->lpPrintDlg
->Flags
& PD_ENABLEPRINTHOOK
) {
778 res
= PrintStructures
->lpPrintDlg
->lpfnPrintHook(hDlg
, uMsg
, wParam
,
785 return PRINTDLG_WMCommand(hDlg
, wParam
, lParam
, PrintStructures
);
788 DestroyIcon(PrintStructures
->hCollateIcon
);
789 DestroyIcon(PrintStructures
->hNoCollateIcon
);
790 /* FIXME: don't forget to delete the paper orientation icons here! */
797 /************************************************************
799 * PRINTDLG_GetDlgTemplate
802 static HGLOBAL
PRINTDLG_GetDlgTemplate(PRINTDLGA
*lppd
)
804 HGLOBAL hDlgTmpl
, hResInfo
;
806 if (lppd
->Flags
& PD_PRINTSETUP
) {
807 if(lppd
->Flags
& PD_ENABLESETUPTEMPLATEHANDLE
) {
808 hDlgTmpl
= lppd
->hSetupTemplate
;
809 } else if(lppd
->Flags
& PD_ENABLESETUPTEMPLATE
) {
810 hResInfo
= FindResourceA(lppd
->hInstance
,
811 lppd
->lpSetupTemplateName
, RT_DIALOGA
);
812 hDlgTmpl
= LoadResource(lppd
->hInstance
, hResInfo
);
814 hResInfo
= FindResourceA(COMDLG32_hInstance
, "PRINT32_SETUP",
816 hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
);
819 if(lppd
->Flags
& PD_ENABLEPRINTTEMPLATEHANDLE
) {
820 hDlgTmpl
= lppd
->hPrintTemplate
;
821 } else if(lppd
->Flags
& PD_ENABLEPRINTTEMPLATE
) {
822 hResInfo
= FindResourceA(lppd
->hInstance
,
823 lppd
->lpPrintTemplateName
,
825 hDlgTmpl
= LoadResource(lppd
->hInstance
, hResInfo
);
827 hResInfo
= FindResourceA(COMDLG32_hInstance
, "PRINT32",
829 hDlgTmpl
= LoadResource(COMDLG32_hInstance
, hResInfo
);
835 /***********************************************************************
840 static BOOL
PRINTDLG_CreateDC(LPPRINTDLGA lppd
)
842 DEVNAMES
*pdn
= GlobalLock(lppd
->hDevNames
);
843 DEVMODEA
*pdm
= GlobalLock(lppd
->hDevMode
);
845 if(lppd
->Flags
& PD_RETURNDC
) {
846 lppd
->hDC
= CreateDCA((char*)pdn
+ pdn
->wDriverOffset
,
847 (char*)pdn
+ pdn
->wDeviceOffset
,
848 (char*)pdn
+ pdn
->wOutputOffset
,
850 } else if(lppd
->Flags
& PD_RETURNIC
) {
851 lppd
->hDC
= CreateICA((char*)pdn
+ pdn
->wDriverOffset
,
852 (char*)pdn
+ pdn
->wDeviceOffset
,
853 (char*)pdn
+ pdn
->wOutputOffset
,
856 GlobalUnlock(lppd
->hDevNames
);
857 GlobalUnlock(lppd
->hDevMode
);
858 return lppd
->hDC
? TRUE
: FALSE
;
861 /***********************************************************************
862 * PrintDlgA (COMDLG32.17)
864 * Displays the the PRINT dialog box, which enables the user to specify
865 * specific properties of the print job.
868 * nonzero if the user pressed the OK button
869 * zero if the user cancelled the window or an error occurred
873 * * The Collate Icons do not display, even though they are in the code.
874 * * The Properties Button(s) should call DocumentPropertiesA().
876 * * The Paper Orientation Icons are not implemented yet.
877 * * The Properties Button(s) should call DocumentPropertiesA().
878 * * Settings are not yet taken from a provided DevMode or
879 * default printer settings.
881 BOOL WINAPI
PrintDlgA(
882 LPPRINTDLGA lppd
/* [in/out] ptr to PRINTDLG32 struct */
887 HINSTANCE hInst
= GetWindowLongA( lppd
->hwndOwner
, GWL_HINSTANCE
);
889 if(TRACE_ON(commdlg
)) {
890 char flagstr
[1000] = "";
891 struct pd_flags
*pflag
= pd_flags
;
892 for( ; pflag
->name
; pflag
++) {
893 if(lppd
->Flags
& pflag
->flag
)
894 strcat(flagstr
, pflag
->name
);
896 TRACE("(%p): hwndOwner = %08x, hDevMode = %08x, hDevNames = %08x\n"
897 "pp. %d-%d, min p %d, max p %d, copies %d, hinst %08x\n"
898 "flags %08lx (%s)\n",
899 lppd
, lppd
->hwndOwner
, lppd
->hDevMode
, lppd
->hDevNames
,
900 lppd
->nFromPage
, lppd
->nToPage
, lppd
->nMinPage
, lppd
->nMaxPage
,
901 lppd
->nCopies
, lppd
->hInstance
, lppd
->Flags
, flagstr
);
904 if(lppd
->lStructSize
!= sizeof(PRINTDLGA
)) {
905 WARN("structure size failure !!!\n");
906 COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE
);
910 if(lppd
->Flags
& PD_RETURNDEFAULT
) {
911 PRINTER_INFO_2A
*pbuf
;
915 if(lppd
->hDevMode
|| lppd
->hDevNames
) {
916 WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
917 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE
);
920 if(!PRINTDLG_OpenDefaultPrinter(&hprn
)) {
921 WARN("Can't find default printer\n");
922 COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN
);
926 GetPrinterA(hprn
, 2, NULL
, 0, &needed
);
927 pbuf
= HeapAlloc(GetProcessHeap(), 0, needed
);
928 GetPrinterA(hprn
, 2, (LPBYTE
)pbuf
, needed
, &needed
);
930 PRINTDLG_CreateDevNames(&(lppd
->hDevNames
), "winspool",
931 pbuf
->pDevMode
->dmDeviceName
,
933 lppd
->hDevMode
= GlobalAlloc(GMEM_MOVEABLE
, pbuf
->pDevMode
->dmSize
+
934 pbuf
->pDevMode
->dmDriverExtra
);
935 ptr
= GlobalLock(lppd
->hDevMode
);
936 memcpy(ptr
, pbuf
->pDevMode
, pbuf
->pDevMode
->dmSize
+
937 pbuf
->pDevMode
->dmDriverExtra
);
938 GlobalUnlock(lppd
->hDevMode
);
939 HeapFree(GetProcessHeap(), 0, pbuf
);
943 PRINT_PTRA
*PrintStructures
;
945 /* load Dialog resources,
946 * depending on Flags indicates Print32 or Print32_setup dialog
948 hDlgTmpl
= PRINTDLG_GetDlgTemplate(lppd
);
949 if (!(hDlgTmpl
) || !(ptr
= LockResource( hDlgTmpl
))) {
950 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
953 PrintStructures
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
955 PrintStructures
->lpPrintDlg
= lppd
;
957 /* and create & process the dialog .
958 * -1 is failure, 0 is broken hwnd, everything else is ok.
960 bRet
= (0<DialogBoxIndirectParamA(hInst
, ptr
, lppd
->hwndOwner
,
962 (LPARAM
)PrintStructures
));
965 DEVMODEA
*lpdm
= PrintStructures
->lpDevMode
, *lpdmReturn
;
966 PRINTER_INFO_2A
*pi
= PrintStructures
->lpPrinterInfo
;
968 if (lppd
->hDevMode
== 0) {
969 TRACE(" No hDevMode yet... Need to create my own\n");
970 lppd
->hDevMode
= GlobalAlloc(GMEM_MOVEABLE
,
971 lpdm
->dmSize
+ lpdm
->dmDriverExtra
);
974 if((locks
= (GlobalFlags(lppd
->hDevMode
) & GMEM_LOCKCOUNT
))) {
975 WARN("hDevMode has %d locks on it. Unlocking it now\n", locks
);
977 GlobalUnlock(lppd
->hDevMode
);
978 TRACE("Now got %d locks\n", locks
);
981 lppd
->hDevMode
= GlobalReAlloc(lppd
->hDevMode
,
982 lpdm
->dmSize
+ lpdm
->dmDriverExtra
,
985 lpdmReturn
= GlobalLock(lppd
->hDevMode
);
986 memcpy(lpdmReturn
, lpdm
, lpdm
->dmSize
+ lpdm
->dmDriverExtra
);
988 if (lppd
->hDevNames
!= 0) {
990 if((locks
= (GlobalFlags(lppd
->hDevNames
) & GMEM_LOCKCOUNT
))) {
991 WARN("hDevNames has %d locks on it. Unlocking it now\n", locks
);
993 GlobalUnlock(lppd
->hDevNames
);
996 PRINTDLG_CreateDevNames(&(lppd
->hDevNames
), "winspool",
997 lpdmReturn
->dmDeviceName
, pi
->pPortName
);
998 GlobalUnlock(lppd
->hDevMode
);
1000 HeapFree(GetProcessHeap(), 0, PrintStructures
->lpDevMode
);
1001 HeapFree(GetProcessHeap(), 0, PrintStructures
->lpPrinterInfo
);
1002 HeapFree(GetProcessHeap(), 0, PrintStructures
);
1004 if(bRet
&& (lppd
->Flags
& PD_RETURNDC
|| lppd
->Flags
& PD_RETURNIC
))
1005 bRet
= PRINTDLG_CreateDC(lppd
);
1007 TRACE("exit! (%d)\n", bRet
);
1013 /***********************************************************************
1014 * PrintDlgW (COMDLG32.18)
1016 BOOL WINAPI
PrintDlgW( LPPRINTDLGW printdlg
)
1018 FIXME("A really empty stub\n" );
1022 /***********************************************************************
1027 /***********************************************************************
1028 * PageSetupDlgA (COMDLG32.15)
1030 BOOL WINAPI
PageSetupDlgA(LPPAGESETUPDLGA setupdlg
) {
1031 FIXME("(%p), stub!\n",setupdlg
);
1034 /***********************************************************************
1035 * PageSetupDlgW (COMDLG32.16)
1037 BOOL WINAPI
PageSetupDlgW(LPPAGESETUPDLGW setupdlg
) {
1038 FIXME("(%p), stub!\n",setupdlg
);
1042 /**********************************************************************
1047 /***********************************************************************
1048 * PrintDlgProc16 (COMMDLG.21)
1050 LRESULT WINAPI
PrintDlgProc16(HWND16 hWnd
, UINT16 wMsg
, WPARAM16 wParam
,
1056 TRACE("WM_INITDIALOG lParam=%08lX\n", lParam
);
1057 ShowWindow(hWnd
, SW_SHOWNORMAL
);
1063 EndDialog(hWnd
, TRUE
);
1066 EndDialog(hWnd
, FALSE
);
1075 /***********************************************************************
1076 * PrintSetupDlgProc16 (COMMDLG.22)
1078 LRESULT WINAPI
PrintSetupDlgProc16(HWND16 hWnd
, UINT16 wMsg
, WPARAM16 wParam
,
1084 TRACE("WM_INITDIALOG lParam=%08lX\n", lParam
);
1085 ShowWindow(hWnd
, SW_SHOWNORMAL
);
1090 EndDialog(hWnd
, TRUE
);
1093 EndDialog(hWnd
, FALSE
);
1102 /***********************************************************************
1103 * PrintDlg16 (COMMDLG.20)
1105 * Displays the the PRINT dialog box, which enables the user to specify
1106 * specific properties of the print job.
1109 * nonzero if the user pressed the OK button
1110 * zero if the user cancelled the window or an error occurred
1113 * * calls up to the 32-bit versions of the Dialogs, which look different
1114 * * Customizing is *not* implemented.
1116 BOOL16 WINAPI
PrintDlg16( LPPRINTDLG16 lpPrint
)
1123 memset(&Print32
, 0, sizeof(Print32
));
1124 Print32
.lStructSize
= sizeof(Print32
);
1125 Print32
.hwndOwner
= lpPrint
->hwndOwner
;
1126 if(lpPrint
->hDevMode
) {
1127 size
= GlobalSize16(lpPrint
->hDevMode
);
1128 Print32
.hDevMode
= GlobalAlloc(GMEM_MOVEABLE
, size
);
1129 ptr
= GlobalLock(Print32
.hDevMode
);
1130 ptr16
= GlobalLock16(lpPrint
->hDevMode
);
1131 memcpy(ptr
, ptr16
, size
);
1132 GlobalFree16(lpPrint
->hDevMode
);
1133 GlobalUnlock(Print32
.hDevMode
);
1135 Print32
.hDevMode
= 0;
1136 if(lpPrint
->hDevNames
) {
1137 size
= GlobalSize16(lpPrint
->hDevNames
);
1138 Print32
.hDevNames
= GlobalAlloc(GMEM_MOVEABLE
, size
);
1139 ptr
= GlobalLock(Print32
.hDevNames
);
1140 ptr16
= GlobalLock16(lpPrint
->hDevNames
);
1141 memcpy(ptr
, ptr16
, size
);
1142 GlobalFree16(lpPrint
->hDevNames
);
1143 GlobalUnlock(Print32
.hDevNames
);
1145 Print32
.hDevNames
= 0;
1146 Print32
.Flags
= lpPrint
->Flags
;
1147 Print32
.nFromPage
= lpPrint
->nFromPage
;
1148 Print32
.nToPage
= lpPrint
->nToPage
;
1149 Print32
.nMinPage
= lpPrint
->nMinPage
;
1150 Print32
.nMaxPage
= lpPrint
->nMaxPage
;
1151 Print32
.nCopies
= lpPrint
->nCopies
;
1152 Print32
.hInstance
= lpPrint
->hInstance
;
1153 Print32
.lCustData
= lpPrint
->lCustData
;
1154 if(lpPrint
->lpfnPrintHook
) {
1155 FIXME("Need to allocate thunk\n");
1156 /* Print32.lpfnPrintHook = lpPrint->lpfnPrintHook;*/
1158 if(lpPrint
->lpfnSetupHook
) {
1159 FIXME("Need to allocate thunk\n");
1160 /* Print32.lpfnSetupHook = lpPrint->lpfnSetupHook;*/
1162 Print32
.lpPrintTemplateName
= PTR_SEG_TO_LIN(lpPrint
->lpPrintTemplateName
);
1163 Print32
.lpSetupTemplateName
= PTR_SEG_TO_LIN(lpPrint
->lpSetupTemplateName
);
1164 Print32
.hPrintTemplate
= lpPrint
->hPrintTemplate
;
1165 Print32
.hSetupTemplate
= lpPrint
->hSetupTemplate
;
1167 ret
= PrintDlgA(&Print32
);
1169 if(Print32
.hDevMode
) {
1170 size
= GlobalSize(Print32
.hDevMode
);
1171 lpPrint
->hDevMode
= GlobalAlloc16(GMEM_MOVEABLE
, size
);
1172 ptr16
= GlobalLock16(lpPrint
->hDevMode
);
1173 ptr
= GlobalLock(Print32
.hDevMode
);
1174 memcpy(ptr16
, ptr
, size
);
1175 GlobalFree(Print32
.hDevMode
);
1176 GlobalUnlock16(lpPrint
->hDevMode
);
1178 lpPrint
->hDevMode
= 0;
1179 if(Print32
.hDevNames
) {
1180 size
= GlobalSize(Print32
.hDevNames
);
1181 lpPrint
->hDevNames
= GlobalAlloc16(GMEM_MOVEABLE
, size
);
1182 ptr16
= GlobalLock16(lpPrint
->hDevNames
);
1183 ptr
= GlobalLock(Print32
.hDevNames
);
1184 memcpy(ptr16
, ptr
, size
);
1185 GlobalFree(Print32
.hDevNames
);
1186 GlobalUnlock16(lpPrint
->hDevNames
);
1188 lpPrint
->hDevNames
= 0;
1189 lpPrint
->hDC
= Print32
.hDC
;
1190 lpPrint
->Flags
= Print32
.Flags
;
1191 lpPrint
->nFromPage
= Print32
.nFromPage
;
1192 lpPrint
->nToPage
= Print32
.nToPage
;
1193 lpPrint
->nCopies
= Print32
.nCopies
;
1198 /***********************************************************************
1201 HRESULT WINAPI
PrintDlgExA(LPVOID lpPrintDlgExA
) /* [???] FIXME: LPPRINTDLGEXA */
1206 /***********************************************************************
1209 HRESULT WINAPI
PrintDlgExW(LPVOID lpPrintDlgExW
) /* [???] FIXME: LPPRINTDLGEXW */