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
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
35 #include "wine/wingdi16.h"
37 #include "wine/winuser16.h"
40 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
53 LPPRINTDLG16 lpPrintDlg16
;
56 /* Internal Functions */
58 static BOOL
PRINTDLG_CreateDevNames16(HGLOBAL16
*hmem
, const char* DeviceDriverName
,
59 const char* DeviceName
, const char* OutputPort
)
64 LPDEVNAMES lpDevNames
;
66 DWORD dwBufLen
= sizeof(buf
);
68 size
= strlen(DeviceDriverName
) + 1
69 + strlen(DeviceName
) + 1
70 + strlen(OutputPort
) + 1
74 *hmem
= GlobalReAlloc16(*hmem
, size
, GMEM_MOVEABLE
);
76 *hmem
= GlobalAlloc16(GMEM_MOVEABLE
, size
);
80 pDevNamesSpace
= GlobalLock16(*hmem
);
81 lpDevNames
= (LPDEVNAMES
) pDevNamesSpace
;
83 pTempPtr
= pDevNamesSpace
+ sizeof(DEVNAMES
);
84 strcpy(pTempPtr
, DeviceDriverName
);
85 lpDevNames
->wDriverOffset
= pTempPtr
- pDevNamesSpace
;
87 pTempPtr
+= strlen(DeviceDriverName
) + 1;
88 strcpy(pTempPtr
, DeviceName
);
89 lpDevNames
->wDeviceOffset
= pTempPtr
- pDevNamesSpace
;
91 pTempPtr
+= strlen(DeviceName
) + 1;
92 strcpy(pTempPtr
, OutputPort
);
93 lpDevNames
->wOutputOffset
= pTempPtr
- pDevNamesSpace
;
95 GetDefaultPrinterA(buf
, &dwBufLen
);
96 lpDevNames
->wDefault
= (strcmp(buf
, DeviceName
) == 0) ? 1 : 0;
97 GlobalUnlock16(*hmem
);
102 /***********************************************************************
103 * PRINTDLG_WMInitDialog [internal]
105 static LRESULT
PRINTDLG_WMInitDialog16(HWND hDlg
, WPARAM wParam
, PRINT_PTRA16
* ptr16
)
107 PRINT_PTRA
*PrintStructures
= &ptr16
->print32
;
108 LPPRINTDLG16 lppd
= ptr16
->lpPrintDlg16
;
112 UINT comboID
= (lppd
->Flags
& PD_PRINTSETUP
) ? cmb1
: cmb4
;
114 /* load Collate ICONs */
115 PrintStructures
->hCollateIcon
=
116 LoadIconA(COMDLG32_hInstance
, "PD32_COLLATE");
117 PrintStructures
->hNoCollateIcon
=
118 LoadIconA(COMDLG32_hInstance
, "PD32_NOCOLLATE");
119 if(PrintStructures
->hCollateIcon
== 0 ||
120 PrintStructures
->hNoCollateIcon
== 0) {
121 ERR("no icon in resourcefile\n");
122 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
123 EndDialog(hDlg
, FALSE
);
126 /* load Paper Orientation ICON */
127 /* FIXME: not implemented yet */
130 * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
131 * must be registered and the Help button must be shown.
133 if (lppd
->Flags
& PD_SHOWHELP
) {
134 if((PrintStructures
->HelpMessageID
=
135 RegisterWindowMessageA(HELPMSGSTRINGA
)) == 0) {
136 COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL
);
140 PrintStructures
->HelpMessageID
= 0;
142 if (!(lppd
->Flags
& PD_PRINTSETUP
)) {
143 /* We have a print quality combo box. What shall we do? */
144 if (GetDlgItem(hDlg
,cmb1
)) {
147 FIXME("Print quality only displaying currently.\n");
149 pdm
= GlobalLock16(lppd
->hDevMode
);
151 switch (pdm
->u1
.s1
.dmPrintQuality
) {
152 case DMRES_HIGH
: strcpy(buf
,"High");break;
153 case DMRES_MEDIUM
: strcpy(buf
,"Medium");break;
154 case DMRES_LOW
: strcpy(buf
,"Low");break;
155 case DMRES_DRAFT
: strcpy(buf
,"Draft");break;
156 case 0 : strcpy(buf
,"Default");break;
157 default : sprintf(buf
,"%ddpi",pdm
->u1
.s1
.dmPrintQuality
);break;
159 GlobalUnlock16(lppd
->hDevMode
);
161 strcpy(buf
,"Default");
162 SendDlgItemMessageA(hDlg
,cmb1
,CB_ADDSTRING
,0,(LPARAM
)buf
);
163 SendDlgItemMessageA(hDlg
,cmb1
,CB_SETCURSEL
,0,0);
164 EnableWindow(GetDlgItem(hDlg
,cmb1
),FALSE
);
168 /* FIXME: I allow more freedom than either Win95 or WinNT,
169 * which do not agree to what errors should be thrown or not
170 * in case nToPage or nFromPage is out-of-range.
172 if (lppd
->nMaxPage
< lppd
->nMinPage
)
173 lppd
->nMaxPage
= lppd
->nMinPage
;
174 if (lppd
->nMinPage
== lppd
->nMaxPage
)
175 lppd
->Flags
|= PD_NOPAGENUMS
;
176 if (lppd
->nToPage
< lppd
->nMinPage
)
177 lppd
->nToPage
= lppd
->nMinPage
;
178 if (lppd
->nToPage
> lppd
->nMaxPage
)
179 lppd
->nToPage
= lppd
->nMaxPage
;
180 if (lppd
->nFromPage
< lppd
->nMinPage
)
181 lppd
->nFromPage
= lppd
->nMinPage
;
182 if (lppd
->nFromPage
> lppd
->nMaxPage
)
183 lppd
->nFromPage
= lppd
->nMaxPage
;
185 /* If the printer combo box is in the dialog, fill it */
186 if (GetDlgItem(hDlg
,comboID
)) {
189 pdn
= GlobalLock16(lppd
->hDevNames
);
190 pdm
= GlobalLock16(lppd
->hDevMode
);
192 name
= (char*)pdn
+ pdn
->wDeviceOffset
;
194 name
= (char*)pdm
->dmDeviceName
;
195 PRINTDLG_SetUpPrinterListComboA(hDlg
, comboID
, name
);
196 if(pdm
) GlobalUnlock16(lppd
->hDevMode
);
197 if(pdn
) GlobalUnlock16(lppd
->hDevNames
);
199 /* Now find selected printer and update rest of dlg */
200 name
= HeapAlloc(GetProcessHeap(),0,256);
201 if (GetDlgItemTextA(hDlg
, comboID
, name
, 255))
202 PRINTDLG_ChangePrinterA(hDlg
, name
, PrintStructures
);
204 /* else just use default printer */
206 DWORD dwBufLen
= sizeof(name
);
207 BOOL ret
= GetDefaultPrinterA(name
, &dwBufLen
);
210 PRINTDLG_ChangePrinterA(hDlg
, name
, PrintStructures
);
212 FIXME("No default printer found, expect problems!\n");
214 HeapFree(GetProcessHeap(),0,name
);
219 /************************************************************
221 * PRINTDLG_Get16TemplateFrom32 [Internal]
222 * Generates a 16 bits template from the Wine 32 bits resource
225 static HGLOBAL16
PRINTDLG_Get16TemplateFrom32(LPCSTR PrintResourceName
)
234 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
235 PrintResourceName
, (LPSTR
)RT_DIALOG
)))
237 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
240 if (!(hDlgTmpl32
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
241 !(template32
= LockResource( hDlgTmpl32
)))
243 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
246 size
= SizeofResource(COMDLG32_hInstance
, hResInfo
);
247 hGlobal16
= GlobalAlloc16(0, size
);
250 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE
);
251 ERR("alloc failure for %d bytes\n", size
);
254 template = GlobalLock16(hGlobal16
);
257 COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE
);
258 ERR("global lock failure for %x handle\n", hGlobal16
);
259 GlobalFree16(hGlobal16
);
262 ConvertDialog32To16(template32
, size
, template);
263 GlobalUnlock16(hGlobal16
);
267 static BOOL
PRINTDLG_CreateDC16(LPPRINTDLG16 lppd
)
269 DEVNAMES
*pdn
= GlobalLock16(lppd
->hDevNames
);
270 DEVMODEA
*pdm
= GlobalLock16(lppd
->hDevMode
);
272 if(lppd
->Flags
& PD_RETURNDC
) {
273 lppd
->hDC
= HDC_16(CreateDCA((char*)pdn
+ pdn
->wDriverOffset
,
274 (char*)pdn
+ pdn
->wDeviceOffset
,
275 (char*)pdn
+ pdn
->wOutputOffset
,
277 } else if(lppd
->Flags
& PD_RETURNIC
) {
278 lppd
->hDC
= HDC_16(CreateICA((char*)pdn
+ pdn
->wDriverOffset
,
279 (char*)pdn
+ pdn
->wDeviceOffset
,
280 (char*)pdn
+ pdn
->wOutputOffset
,
283 GlobalUnlock16(lppd
->hDevNames
);
284 GlobalUnlock16(lppd
->hDevMode
);
285 return lppd
->hDC
? TRUE
: FALSE
;
288 /************************************************************
290 * PRINTDLG_GetDlgTemplate
293 static HGLOBAL16
PRINTDLG_GetDlgTemplate16(const PRINTDLG16
*lppd
)
295 HGLOBAL16 hDlgTmpl
, hResInfo
;
297 if (lppd
->Flags
& PD_PRINTSETUP
) {
298 if(lppd
->Flags
& PD_ENABLESETUPTEMPLATEHANDLE
) {
299 hDlgTmpl
= lppd
->hSetupTemplate
;
300 } else if(lppd
->Flags
& PD_ENABLESETUPTEMPLATE
) {
301 hResInfo
= FindResource16(lppd
->hInstance
,
302 MapSL(lppd
->lpSetupTemplateName
), (LPSTR
)RT_DIALOG
);
303 hDlgTmpl
= LoadResource16(lppd
->hInstance
, hResInfo
);
305 hDlgTmpl
= PRINTDLG_Get16TemplateFrom32("PRINT32_SETUP");
308 if(lppd
->Flags
& PD_ENABLEPRINTTEMPLATEHANDLE
) {
309 hDlgTmpl
= lppd
->hPrintTemplate
;
310 } else if(lppd
->Flags
& PD_ENABLEPRINTTEMPLATE
) {
311 hResInfo
= FindResource16(lppd
->hInstance
,
312 MapSL(lppd
->lpPrintTemplateName
),
314 hDlgTmpl
= LoadResource16(lppd
->hInstance
, hResInfo
);
316 hDlgTmpl
= PRINTDLG_Get16TemplateFrom32("PRINT32");
322 /**********************************************************************
327 /***********************************************************************
328 * PrintDlg (COMMDLG.20)
330 * Displays the PRINT dialog box, which enables the user to specify
331 * specific properties of the print job.
334 * nonzero if the user pressed the OK button
335 * zero if the user cancelled the window or an error occurred
338 * * calls up to the 32-bit versions of the Dialogs, which look different
339 * * Customizing is *not* implemented.
342 BOOL16 WINAPI
PrintDlg16(
343 LPPRINTDLG16 lppd
/* [in/out] ptr to PRINTDLG struct */
347 HINSTANCE16 hInst
= GetWindowLongPtrW( HWND_32(lppd
->hwndOwner
), GWLP_HINSTANCE
);
349 if(TRACE_ON(commdlg
)) {
350 char flagstr
[1000] = "";
351 const struct pd_flags
*pflag
= pd_flags
;
352 for( ; pflag
->name
; pflag
++) {
353 if(lppd
->Flags
& pflag
->flag
)
354 strcat(flagstr
, pflag
->name
);
356 TRACE("(%p): hwndOwner = %08x, hDevMode = %08x, hDevNames = %08x\n"
357 "pp. %d-%d, min p %d, max p %d, copies %d, hinst %08x\n"
359 lppd
, lppd
->hwndOwner
, lppd
->hDevMode
, lppd
->hDevNames
,
360 lppd
->nFromPage
, lppd
->nToPage
, lppd
->nMinPage
, lppd
->nMaxPage
,
361 lppd
->nCopies
, lppd
->hInstance
, lppd
->Flags
, flagstr
);
364 if(lppd
->lStructSize
!= sizeof(PRINTDLG16
)) {
365 ERR("structure size %d\n",lppd
->lStructSize
);
366 COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE
);
370 if(lppd
->Flags
& PD_RETURNDEFAULT
) {
371 PRINTER_INFO_2A
*pbuf
;
372 DRIVER_INFO_3A
*dbuf
;
376 if(lppd
->hDevMode
|| lppd
->hDevNames
) {
377 WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
378 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE
);
381 if(!PRINTDLG_OpenDefaultPrinter(&hprn
)) {
382 WARN("Can't find default printer\n");
383 COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN
);
387 GetPrinterA(hprn
, 2, NULL
, 0, &needed
);
388 pbuf
= HeapAlloc(GetProcessHeap(), 0, needed
);
389 GetPrinterA(hprn
, 2, (LPBYTE
)pbuf
, needed
, &needed
);
390 GetPrinterDriverA(hprn
, NULL
, 3, NULL
, 0, &needed
);
391 dbuf
= HeapAlloc(GetProcessHeap(),0,needed
);
392 if (!GetPrinterDriverA(hprn
, NULL
, 3, (LPBYTE
)dbuf
, needed
, &needed
)) {
393 ERR("GetPrinterDriverA failed for %s, le %d, fix your config!\n",
394 pbuf
->pPrinterName
,GetLastError());
395 HeapFree(GetProcessHeap(), 0, dbuf
);
396 HeapFree(GetProcessHeap(), 0, pbuf
);
397 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE
);
401 PRINTDLG_CreateDevNames16(&(lppd
->hDevNames
),
405 lppd
->hDevMode
= GlobalAlloc16(GMEM_MOVEABLE
,pbuf
->pDevMode
->dmSize
+
406 pbuf
->pDevMode
->dmDriverExtra
);
407 ptr
= GlobalLock16(lppd
->hDevMode
);
408 memcpy(ptr
, pbuf
->pDevMode
, pbuf
->pDevMode
->dmSize
+
409 pbuf
->pDevMode
->dmDriverExtra
);
410 GlobalUnlock16(lppd
->hDevMode
);
411 HeapFree(GetProcessHeap(), 0, pbuf
);
412 HeapFree(GetProcessHeap(), 0, dbuf
);
416 PRINT_PTRA
*PrintStructures
;
419 /* load Dialog resources,
420 * depending on Flags indicates Print32 or Print32_setup dialog
422 hDlgTmpl
= PRINTDLG_GetDlgTemplate16(lppd
);
424 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
427 ptr16
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PRINT_PTRA16
));
428 ptr16
->lpPrintDlg16
= lppd
;
429 PrintStructures
= &ptr16
->print32
;
430 PrintStructures
->lpPrintDlg
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(PRINTDLGA
));
431 #define CVAL(x) PrintStructures->lpPrintDlg->x = lppd->x;
432 #define MVAL(x) PrintStructures->lpPrintDlg->x = MapSL(lppd->x);
434 PrintStructures
->lpPrintDlg
->hwndOwner
= HWND_32(lppd
->hwndOwner
);
435 PrintStructures
->lpPrintDlg
->hDC
= HDC_32(lppd
->hDC
);
436 CVAL(nFromPage
);CVAL(nToPage
);CVAL(nMinPage
);CVAL(nMaxPage
);
438 PrintStructures
->lpPrintDlg
->hInstance
= HINSTANCE_32(lppd
->hInstance
);
440 MVAL(lpPrintTemplateName
);MVAL(lpSetupTemplateName
);
441 /* Don't copy rest, it is 16 bit specific */
445 PrintStructures
->lpDevMode
= HeapAlloc(GetProcessHeap(),0,sizeof(DEVMODEA
));
447 /* and create & process the dialog .
448 * -1 is failure, 0 is broken hwnd, everything else is ok.
450 bRet
= (0<DialogBoxIndirectParam16(
451 hInst
, hDlgTmpl
, lppd
->hwndOwner
,
452 (DLGPROC16
)GetProcAddress16(GetModuleHandle16("COMMDLG"),(LPCSTR
)21),
453 (LPARAM
)PrintStructures
456 if (!PrintStructures
->lpPrinterInfo
) bRet
= FALSE
;
458 DEVMODEA
*lpdm
= PrintStructures
->lpDevMode
, *lpdmReturn
;
459 PRINTER_INFO_2A
*pi
= PrintStructures
->lpPrinterInfo
;
460 DRIVER_INFO_3A
*di
= PrintStructures
->lpDriverInfo
;
462 if (lppd
->hDevMode
== 0) {
463 TRACE(" No hDevMode yet... Need to create my own\n");
464 lppd
->hDevMode
= GlobalAlloc16(GMEM_MOVEABLE
,
465 lpdm
->dmSize
+ lpdm
->dmDriverExtra
);
468 if((locks
= (GlobalFlags16(lppd
->hDevMode
)&GMEM_LOCKCOUNT
))) {
469 WARN("hDevMode has %d locks on it. Unlocking it now\n", locks
);
471 GlobalUnlock16(lppd
->hDevMode
);
472 TRACE("Now got %d locks\n", locks
);
475 lppd
->hDevMode
= GlobalReAlloc16(lppd
->hDevMode
,
476 lpdm
->dmSize
+ lpdm
->dmDriverExtra
,
479 lpdmReturn
= GlobalLock16(lppd
->hDevMode
);
480 memcpy(lpdmReturn
, lpdm
, lpdm
->dmSize
+ lpdm
->dmDriverExtra
);
482 if (lppd
->hDevNames
!= 0) {
484 if((locks
= (GlobalFlags16(lppd
->hDevNames
)&GMEM_LOCKCOUNT
))) {
485 WARN("hDevNames has %d locks on it. Unlocking it now\n", locks
);
487 GlobalUnlock16(lppd
->hDevNames
);
490 PRINTDLG_CreateDevNames16(&(lppd
->hDevNames
),
495 GlobalUnlock16(lppd
->hDevMode
);
496 /* Copy back the [out] integer parameters */
497 #define CVAL(x) lppd->x = PrintStructures->lpPrintDlg->x;
505 if (!(lppd
->Flags
& (PD_ENABLESETUPTEMPLATEHANDLE
| PD_ENABLESETUPTEMPLATE
)))
506 GlobalFree16(hDlgTmpl
); /* created from the 32 bits resource */
507 HeapFree(GetProcessHeap(), 0, PrintStructures
->lpDevMode
);
508 HeapFree(GetProcessHeap(), 0, PrintStructures
->lpPrinterInfo
);
509 HeapFree(GetProcessHeap(), 0, PrintStructures
->lpDriverInfo
);
510 HeapFree(GetProcessHeap(), 0, ptr16
);
512 if(bRet
&& (lppd
->Flags
& PD_RETURNDC
|| lppd
->Flags
& PD_RETURNIC
))
513 bRet
= PRINTDLG_CreateDC16(lppd
);
515 TRACE("exit! (%d)\n", bRet
);
519 /***********************************************************************
520 * PrintDlgProc (COMMDLG.21)
522 BOOL16 CALLBACK
PrintDlgProc16(HWND16 hDlg16
, UINT16 uMsg
, WPARAM16 wParam
,
525 HWND hDlg
= HWND_32(hDlg16
);
526 PRINT_PTRA16
*PrintStructures
;
529 if (uMsg
!=WM_INITDIALOG
) {
530 PrintStructures
= (PRINT_PTRA16
*)GetPropA(hDlg
,"__WINE_PRINTDLGDATA");
531 if (!PrintStructures
)
534 PrintStructures
= (PRINT_PTRA16
*) lParam
;
535 SetPropA(hDlg
,"__WINE_PRINTDLGDATA",PrintStructures
);
536 res
= PRINTDLG_WMInitDialog16(hDlg
, wParam
, PrintStructures
);
538 if(PrintStructures
->lpPrintDlg16
->Flags
& PD_ENABLEPRINTHOOK
) {
539 res
= CallWindowProc16(
540 (WNDPROC16
)PrintStructures
->lpPrintDlg16
->lpfnPrintHook
,
541 hDlg16
, uMsg
, wParam
, (LPARAM
)PrintStructures
->lpPrintDlg16
547 if(PrintStructures
->lpPrintDlg16
->Flags
& PD_ENABLEPRINTHOOK
) {
548 res
= CallWindowProc16(
549 (WNDPROC16
)PrintStructures
->lpPrintDlg16
->lpfnPrintHook
,
550 hDlg16
,uMsg
, wParam
, lParam
552 if(LOWORD(res
)) return res
;
557 /* We need to map those for the 32bit window procedure, compare
558 * with 32Ato16 mapper in winproc.c
560 return PRINTDLG_WMCommandA(
562 MAKEWPARAM(wParam
,HIWORD(lParam
)),
564 &PrintStructures
->print32
568 DestroyIcon(PrintStructures
->print32
.hCollateIcon
);
569 DestroyIcon(PrintStructures
->print32
.hNoCollateIcon
);
570 /* FIXME: don't forget to delete the paper orientation icons here! */
577 /***********************************************************************
578 * PrintSetupDlgProc (COMMDLG.22)
580 BOOL16 CALLBACK
PrintSetupDlgProc16(HWND16 hWnd16
, UINT16 wMsg
, WPARAM16 wParam
,
583 HWND hWnd
= HWND_32(hWnd16
);
587 TRACE("WM_INITDIALOG lParam=%08lX\n", lParam
);
588 ShowWindow(hWnd
, SW_SHOWNORMAL
);
593 EndDialog(hWnd
, TRUE
);
596 EndDialog(hWnd
, FALSE
);