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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
35 #include "wine/wingdi16.h"
37 #include "wine/winuser16.h"
40 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
51 static BOOL
PRINTDLG_CreateDevNames16(HGLOBAL16
*hmem
, char* DeviceDriverName
,
52 char* DeviceName
, char* OutputPort
)
57 LPDEVNAMES lpDevNames
;
59 DWORD dwBufLen
= sizeof(buf
);
61 size
= strlen(DeviceDriverName
) + 1
62 + strlen(DeviceName
) + 1
63 + strlen(OutputPort
) + 1
67 *hmem
= GlobalReAlloc16(*hmem
, size
, GMEM_MOVEABLE
);
69 *hmem
= GlobalAlloc16(GMEM_MOVEABLE
, size
);
73 pDevNamesSpace
= GlobalLock16(*hmem
);
74 lpDevNames
= (LPDEVNAMES
) pDevNamesSpace
;
76 pTempPtr
= pDevNamesSpace
+ sizeof(DEVNAMES
);
77 strcpy(pTempPtr
, DeviceDriverName
);
78 lpDevNames
->wDriverOffset
= pTempPtr
- pDevNamesSpace
;
80 pTempPtr
+= strlen(DeviceDriverName
) + 1;
81 strcpy(pTempPtr
, DeviceName
);
82 lpDevNames
->wDeviceOffset
= pTempPtr
- pDevNamesSpace
;
84 pTempPtr
+= strlen(DeviceName
) + 1;
85 strcpy(pTempPtr
, OutputPort
);
86 lpDevNames
->wOutputOffset
= pTempPtr
- pDevNamesSpace
;
88 GetDefaultPrinterA(buf
, &dwBufLen
);
89 lpDevNames
->wDefault
= (strcmp(buf
, DeviceName
) == 0) ? 1 : 0;
90 GlobalUnlock16(*hmem
);
95 /***********************************************************************
96 * PRINTDLG_WMInitDialog [internal]
98 static LRESULT
PRINTDLG_WMInitDialog16(HWND hDlg
, WPARAM wParam
,
99 PRINT_PTRA
* PrintStructures
)
101 LPPRINTDLG16 lppd
= PrintStructures
->dlg
.lpPrintDlg16
;
105 UINT comboID
= (lppd
->Flags
& PD_PRINTSETUP
) ? cmb1
: cmb4
;
107 /* load Collate ICONs */
108 PrintStructures
->hCollateIcon
=
109 LoadIconA(COMDLG32_hInstance
, "PD32_COLLATE");
110 PrintStructures
->hNoCollateIcon
=
111 LoadIconA(COMDLG32_hInstance
, "PD32_NOCOLLATE");
112 if(PrintStructures
->hCollateIcon
== 0 ||
113 PrintStructures
->hNoCollateIcon
== 0) {
114 ERR("no icon in resourcefile\n");
115 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
116 EndDialog(hDlg
, FALSE
);
119 /* load Paper Orientation ICON */
120 /* FIXME: not implemented yet */
123 * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
124 * must be registered and the Help button must be shown.
126 if (lppd
->Flags
& PD_SHOWHELP
) {
127 if((PrintStructures
->HelpMessageID
=
128 RegisterWindowMessageA(HELPMSGSTRINGA
)) == 0) {
129 COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL
);
133 PrintStructures
->HelpMessageID
= 0;
135 if (!(lppd
->Flags
& PD_PRINTSETUP
)) {
136 /* We have a print quality combo box. What shall we do? */
137 if (GetDlgItem(hDlg
,cmb1
)) {
140 FIXME("Print quality only displaying currently.\n");
142 pdm
= GlobalLock16(lppd
->hDevMode
);
144 switch (pdm
->dmPrintQuality
) {
145 case DMRES_HIGH
: strcpy(buf
,"High");break;
146 case DMRES_MEDIUM
: strcpy(buf
,"Medium");break;
147 case DMRES_LOW
: strcpy(buf
,"Low");break;
148 case DMRES_DRAFT
: strcpy(buf
,"Draft");break;
149 case 0 : strcpy(buf
,"Default");break;
150 default : sprintf(buf
,"%ddpi",pdm
->dmPrintQuality
);break;
152 GlobalUnlock16(lppd
->hDevMode
);
154 strcpy(buf
,"Default");
155 SendDlgItemMessageA(hDlg
,cmb1
,CB_ADDSTRING
,0,(LPARAM
)buf
);
156 SendDlgItemMessageA(hDlg
,cmb1
,CB_SETCURSEL
,0,0);
157 EnableWindow(GetDlgItem(hDlg
,cmb1
),FALSE
);
161 /* FIXME: I allow more freedom than either Win95 or WinNT,
162 * which do not agree to what errors should be thrown or not
163 * in case nToPage or nFromPage is out-of-range.
165 if (lppd
->nMaxPage
< lppd
->nMinPage
)
166 lppd
->nMaxPage
= lppd
->nMinPage
;
167 if (lppd
->nMinPage
== lppd
->nMaxPage
)
168 lppd
->Flags
|= PD_NOPAGENUMS
;
169 if (lppd
->nToPage
< lppd
->nMinPage
)
170 lppd
->nToPage
= lppd
->nMinPage
;
171 if (lppd
->nToPage
> lppd
->nMaxPage
)
172 lppd
->nToPage
= lppd
->nMaxPage
;
173 if (lppd
->nFromPage
< lppd
->nMinPage
)
174 lppd
->nFromPage
= lppd
->nMinPage
;
175 if (lppd
->nFromPage
> lppd
->nMaxPage
)
176 lppd
->nFromPage
= lppd
->nMaxPage
;
178 /* If the printer combo box is in the dialog, fill it */
179 if (GetDlgItem(hDlg
,comboID
)) {
182 pdn
= GlobalLock16(lppd
->hDevNames
);
183 pdm
= GlobalLock16(lppd
->hDevMode
);
185 name
= (char*)pdn
+ pdn
->wDeviceOffset
;
187 name
= pdm
->dmDeviceName
;
188 PRINTDLG_SetUpPrinterListComboA(hDlg
, comboID
, name
);
189 if(pdm
) GlobalUnlock16(lppd
->hDevMode
);
190 if(pdn
) GlobalUnlock16(lppd
->hDevNames
);
192 /* Now find selected printer and update rest of dlg */
193 name
= HeapAlloc(GetProcessHeap(),0,256);
194 if (GetDlgItemTextA(hDlg
, comboID
, name
, 255))
195 PRINTDLG_ChangePrinterA(hDlg
, name
, PrintStructures
);
197 /* else just use default printer */
199 DWORD dwBufLen
= sizeof(name
);
200 BOOL ret
= GetDefaultPrinterA(name
, &dwBufLen
);
203 PRINTDLG_ChangePrinterA(hDlg
, name
, PrintStructures
);
205 FIXME("No default printer found, expect problems!\n");
207 HeapFree(GetProcessHeap(),0,name
);
212 /************************************************************
214 * PRINTDLG_Get16TemplateFrom32 [Internal]
215 * Generates a 16 bits template from the Wine 32 bits resource
218 static HGLOBAL16
PRINTDLG_Get16TemplateFrom32(LPCSTR PrintResourceName
)
227 if (!(hResInfo
= FindResourceA(COMDLG32_hInstance
,
228 PrintResourceName
, (LPSTR
)RT_DIALOG
)))
230 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE
);
233 if (!(hDlgTmpl32
= LoadResource(COMDLG32_hInstance
, hResInfo
)) ||
234 !(template32
= LockResource( hDlgTmpl32
)))
236 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
239 size
= SizeofResource(COMDLG32_hInstance
, hResInfo
);
240 hGlobal16
= GlobalAlloc16(0, size
);
243 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE
);
244 ERR("alloc failure for %ld bytes\n", size
);
247 template = GlobalLock16(hGlobal16
);
250 COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE
);
251 ERR("global lock failure for %x handle\n", hGlobal16
);
252 GlobalFree16(hGlobal16
);
255 ConvertDialog32To16((LPVOID
)template32
, size
, (LPVOID
)template);
256 GlobalUnlock16(hGlobal16
);
260 static BOOL
PRINTDLG_CreateDC16(LPPRINTDLG16 lppd
)
262 DEVNAMES
*pdn
= GlobalLock16(lppd
->hDevNames
);
263 DEVMODEA
*pdm
= GlobalLock16(lppd
->hDevMode
);
265 if(lppd
->Flags
& PD_RETURNDC
) {
266 lppd
->hDC
= HDC_16(CreateDCA((char*)pdn
+ pdn
->wDriverOffset
,
267 (char*)pdn
+ pdn
->wDeviceOffset
,
268 (char*)pdn
+ pdn
->wOutputOffset
,
270 } else if(lppd
->Flags
& PD_RETURNIC
) {
271 lppd
->hDC
= HDC_16(CreateICA((char*)pdn
+ pdn
->wDriverOffset
,
272 (char*)pdn
+ pdn
->wDeviceOffset
,
273 (char*)pdn
+ pdn
->wOutputOffset
,
276 GlobalUnlock16(lppd
->hDevNames
);
277 GlobalUnlock16(lppd
->hDevMode
);
278 return lppd
->hDC
? TRUE
: FALSE
;
281 /************************************************************
283 * PRINTDLG_GetDlgTemplate
286 static HGLOBAL16
PRINTDLG_GetDlgTemplate16(PRINTDLG16
*lppd
)
288 HGLOBAL16 hDlgTmpl
, hResInfo
;
290 if (lppd
->Flags
& PD_PRINTSETUP
) {
291 if(lppd
->Flags
& PD_ENABLESETUPTEMPLATEHANDLE
) {
292 hDlgTmpl
= lppd
->hSetupTemplate
;
293 } else if(lppd
->Flags
& PD_ENABLESETUPTEMPLATE
) {
294 hResInfo
= FindResource16(lppd
->hInstance
,
295 MapSL(lppd
->lpSetupTemplateName
), (LPSTR
)RT_DIALOG
);
296 hDlgTmpl
= LoadResource16(lppd
->hInstance
, hResInfo
);
298 hDlgTmpl
= PRINTDLG_Get16TemplateFrom32("PRINT32_SETUP");
301 if(lppd
->Flags
& PD_ENABLEPRINTTEMPLATEHANDLE
) {
302 hDlgTmpl
= lppd
->hPrintTemplate
;
303 } else if(lppd
->Flags
& PD_ENABLEPRINTTEMPLATE
) {
304 hResInfo
= FindResource16(lppd
->hInstance
,
305 MapSL(lppd
->lpPrintTemplateName
),
307 hDlgTmpl
= LoadResource16(lppd
->hInstance
, hResInfo
);
309 hDlgTmpl
= PRINTDLG_Get16TemplateFrom32("PRINT32");
315 /***********************************************************************
316 * PrintDlg (COMMDLG.20)
318 * Displays the the PRINT dialog box, which enables the user to specify
319 * specific properties of the print job.
322 * nonzero if the user pressed the OK button
323 * zero if the user cancelled the window or an error occurred
326 * * calls up to the 32-bit versions of the Dialogs, which look different
327 * * Customizing is *not* implemented.
330 BOOL16 WINAPI
PrintDlg16(
331 LPPRINTDLG16 lppd
/* [in/out] ptr to PRINTDLG struct */
335 HINSTANCE16 hInst
= GetWindowWord( HWND_32(lppd
->hwndOwner
), GWL_HINSTANCE
);
337 if(TRACE_ON(commdlg
)) {
338 char flagstr
[1000] = "";
339 struct pd_flags
*pflag
= pd_flags
;
340 for( ; pflag
->name
; pflag
++) {
341 if(lppd
->Flags
& pflag
->flag
)
342 strcat(flagstr
, pflag
->name
);
344 TRACE("(%p): hwndOwner = %08x, hDevMode = %08x, hDevNames = %08x\n"
345 "pp. %d-%d, min p %d, max p %d, copies %d, hinst %08x\n"
346 "flags %08lx (%s)\n",
347 lppd
, lppd
->hwndOwner
, lppd
->hDevMode
, lppd
->hDevNames
,
348 lppd
->nFromPage
, lppd
->nToPage
, lppd
->nMinPage
, lppd
->nMaxPage
,
349 lppd
->nCopies
, lppd
->hInstance
, lppd
->Flags
, flagstr
);
352 if(lppd
->lStructSize
!= sizeof(PRINTDLG16
)) {
353 ERR("structure size (%ld/%d)\n",lppd
->lStructSize
,sizeof(PRINTDLG16
));
354 COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE
);
358 if(lppd
->Flags
& PD_RETURNDEFAULT
) {
359 PRINTER_INFO_2A
*pbuf
;
360 DRIVER_INFO_3A
*dbuf
;
364 if(lppd
->hDevMode
|| lppd
->hDevNames
) {
365 WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
366 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE
);
369 if(!PRINTDLG_OpenDefaultPrinter(&hprn
)) {
370 WARN("Can't find default printer\n");
371 COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN
);
375 GetPrinterA(hprn
, 2, NULL
, 0, &needed
);
376 pbuf
= HeapAlloc(GetProcessHeap(), 0, needed
);
377 GetPrinterA(hprn
, 2, (LPBYTE
)pbuf
, needed
, &needed
);
378 GetPrinterDriverA(hprn
, NULL
, 3, NULL
, 0, &needed
);
379 dbuf
= HeapAlloc(GetProcessHeap(),0,needed
);
380 if (!GetPrinterDriverA(hprn
, NULL
, 3, (LPBYTE
)dbuf
, needed
, &needed
)) {
381 ERR("GetPrinterDriverA failed for %s, le %ld, fix your config!\n",
382 pbuf
->pPrinterName
,GetLastError());
383 HeapFree(GetProcessHeap(), 0, dbuf
);
384 COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE
);
388 PRINTDLG_CreateDevNames16(&(lppd
->hDevNames
),
392 lppd
->hDevMode
= GlobalAlloc16(GMEM_MOVEABLE
,pbuf
->pDevMode
->dmSize
+
393 pbuf
->pDevMode
->dmDriverExtra
);
394 ptr
= GlobalLock16(lppd
->hDevMode
);
395 memcpy(ptr
, pbuf
->pDevMode
, pbuf
->pDevMode
->dmSize
+
396 pbuf
->pDevMode
->dmDriverExtra
);
397 GlobalUnlock16(lppd
->hDevMode
);
398 HeapFree(GetProcessHeap(), 0, pbuf
);
399 HeapFree(GetProcessHeap(), 0, dbuf
);
403 PRINT_PTRA
*PrintStructures
;
405 /* load Dialog resources,
406 * depending on Flags indicates Print32 or Print32_setup dialog
408 hDlgTmpl
= PRINTDLG_GetDlgTemplate16(lppd
);
410 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE
);
413 PrintStructures
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
415 PrintStructures
->dlg
.lpPrintDlg16
= lppd
;
416 PrintStructures
->dlg
.lpPrintDlg
= (LPPRINTDLGA
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(PRINTDLGA
));
417 #define CVAL(x) PrintStructures->dlg.lpPrintDlg->x = lppd->x;
418 #define MVAL(x) PrintStructures->dlg.lpPrintDlg->x = MapSL(lppd->x);
420 PrintStructures
->dlg
.lpPrintDlg
->hwndOwner
= HWND_32(lppd
->hwndOwner
);
421 PrintStructures
->dlg
.lpPrintDlg
->hDC
= HDC_32(lppd
->hDC
);
422 CVAL(nFromPage
);CVAL(nToPage
);CVAL(nMinPage
);CVAL(nMaxPage
);
424 PrintStructures
->dlg
.lpPrintDlg
->hInstance
= HINSTANCE_32(lppd
->hInstance
);
426 MVAL(lpPrintTemplateName
);MVAL(lpSetupTemplateName
);
427 /* Don't copy rest, it is 16 bit specific */
431 PrintStructures
->lpDevMode
= HeapAlloc(GetProcessHeap(),0,sizeof(DEVMODEA
));
433 /* and create & process the dialog .
434 * -1 is failure, 0 is broken hwnd, everything else is ok.
436 bRet
= (0<DialogBoxIndirectParam16(
437 hInst
, hDlgTmpl
, lppd
->hwndOwner
,
438 (DLGPROC16
)GetProcAddress16(GetModuleHandle16("COMMDLG"),(LPCSTR
)21),
439 (LPARAM
)PrintStructures
442 if (!PrintStructures
->lpPrinterInfo
) bRet
= FALSE
;
444 DEVMODEA
*lpdm
= PrintStructures
->lpDevMode
, *lpdmReturn
;
445 PRINTER_INFO_2A
*pi
= PrintStructures
->lpPrinterInfo
;
446 DRIVER_INFO_3A
*di
= PrintStructures
->lpDriverInfo
;
448 if (lppd
->hDevMode
== 0) {
449 TRACE(" No hDevMode yet... Need to create my own\n");
450 lppd
->hDevMode
= GlobalAlloc16(GMEM_MOVEABLE
,
451 lpdm
->dmSize
+ lpdm
->dmDriverExtra
);
454 if((locks
= (GlobalFlags16(lppd
->hDevMode
)&GMEM_LOCKCOUNT
))) {
455 WARN("hDevMode has %d locks on it. Unlocking it now\n", locks
);
457 GlobalUnlock16(lppd
->hDevMode
);
458 TRACE("Now got %d locks\n", locks
);
461 lppd
->hDevMode
= GlobalReAlloc16(lppd
->hDevMode
,
462 lpdm
->dmSize
+ lpdm
->dmDriverExtra
,
465 lpdmReturn
= GlobalLock16(lppd
->hDevMode
);
466 memcpy(lpdmReturn
, lpdm
, lpdm
->dmSize
+ lpdm
->dmDriverExtra
);
468 if (lppd
->hDevNames
!= 0) {
470 if((locks
= (GlobalFlags16(lppd
->hDevNames
)&GMEM_LOCKCOUNT
))) {
471 WARN("hDevNames has %d locks on it. Unlocking it now\n", locks
);
473 GlobalUnlock16(lppd
->hDevNames
);
476 PRINTDLG_CreateDevNames16(&(lppd
->hDevNames
),
481 GlobalUnlock16(lppd
->hDevMode
);
483 if (!(lppd
->Flags
& (PD_ENABLESETUPTEMPLATEHANDLE
| PD_ENABLESETUPTEMPLATE
)))
484 GlobalFree16(hDlgTmpl
); /* created from the 32 bits resource */
485 HeapFree(GetProcessHeap(), 0, PrintStructures
->lpDevMode
);
486 HeapFree(GetProcessHeap(), 0, PrintStructures
->lpPrinterInfo
);
487 HeapFree(GetProcessHeap(), 0, PrintStructures
->lpDriverInfo
);
488 HeapFree(GetProcessHeap(), 0, PrintStructures
);
490 if(bRet
&& (lppd
->Flags
& PD_RETURNDC
|| lppd
->Flags
& PD_RETURNIC
))
491 bRet
= PRINTDLG_CreateDC16(lppd
);
493 TRACE("exit! (%d)\n", bRet
);
497 /**********************************************************************
502 /***********************************************************************
503 * PrintDlgProc (COMMDLG.21)
505 BOOL16 CALLBACK
PrintDlgProc16(HWND16 hDlg16
, UINT16 uMsg
, WPARAM16 wParam
,
508 HWND hDlg
= HWND_32(hDlg16
);
509 PRINT_PTRA
* PrintStructures
;
512 if (uMsg
!=WM_INITDIALOG
) {
513 PrintStructures
= (PRINT_PTRA
*)GetPropA(hDlg
,"__WINE_PRINTDLGDATA");
514 if (!PrintStructures
)
517 PrintStructures
= (PRINT_PTRA
*) lParam
;
518 SetPropA(hDlg
,"__WINE_PRINTDLGDATA",PrintStructures
);
519 res
= PRINTDLG_WMInitDialog16(hDlg
, wParam
, PrintStructures
);
521 if(PrintStructures
->dlg
.lpPrintDlg16
->Flags
& PD_ENABLEPRINTHOOK
) {
522 res
= CallWindowProc16(
523 (WNDPROC16
)PrintStructures
->dlg
.lpPrintDlg16
->lpfnPrintHook
,
524 hDlg16
, uMsg
, wParam
, (LPARAM
)PrintStructures
->dlg
.lpPrintDlg16
530 if(PrintStructures
->dlg
.lpPrintDlg16
->Flags
& PD_ENABLEPRINTHOOK
) {
531 res
= CallWindowProc16(
532 (WNDPROC16
)PrintStructures
->dlg
.lpPrintDlg16
->lpfnPrintHook
,
533 hDlg16
,uMsg
, wParam
, lParam
535 if(LOWORD(res
)) return res
;
540 /* We need to map those for the 32bit window procedure, compare
541 * with 32Ato16 mapper in winproc.c
543 return PRINTDLG_WMCommandA(
545 MAKEWPARAM(wParam
,HIWORD(lParam
)),
551 DestroyIcon(PrintStructures
->hCollateIcon
);
552 DestroyIcon(PrintStructures
->hNoCollateIcon
);
553 /* FIXME: don't forget to delete the paper orientation icons here! */
560 /***********************************************************************
561 * PrintSetupDlgProc (COMMDLG.22)
563 BOOL16 CALLBACK
PrintSetupDlgProc16(HWND16 hWnd16
, UINT16 wMsg
, WPARAM16 wParam
,
566 HWND hWnd
= HWND_32(hWnd16
);
570 TRACE("WM_INITDIALOG lParam=%08lX\n", lParam
);
571 ShowWindow(hWnd
, SW_SHOWNORMAL
);
576 EndDialog(hWnd
, TRUE
);
579 EndDialog(hWnd
, FALSE
);