xref: /reactos/dll/win32/comdlg32/printdlg.c (revision 682f85ad)
1 /*
2  * COMMDLG - Print Dialog
3  *
4  * Copyright 1994 Martin Ayotte
5  * Copyright 1996 Albrecht Kleine
6  * Copyright 1999 Klaas van Gend
7  * Copyright 2000 Huw D M Davies
8  * Copyright 2010 Vitaly Perov
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30 
31 #define COBJMACROS
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wingdi.h"
37 #include "winuser.h"
38 #include "winspool.h"
39 #include "winerror.h"
40 #include "objbase.h"
41 #include "commdlg.h"
42 
43 #include "wine/debug.h"
44 
45 #include "dlgs.h"
46 #include "cderr.h"
47 #include "cdlg.h"
48 
49 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
50 
51 /* Yes these constants are the same, but we're just copying win98 */
52 #define UPDOWN_ID 0x270f
53 #define MAX_COPIES 9999
54 
55 /* This PRINTDLGA internal structure stores
56  * pointers to several throughout useful structures.
57  */
58 
59 typedef struct
60 {
61   LPDEVMODEA        lpDevMode;
62   LPPRINTDLGA       lpPrintDlg;
63   LPPRINTER_INFO_2A lpPrinterInfo;
64   LPDRIVER_INFO_3A  lpDriverInfo;
65   UINT              HelpMessageID;
66   HICON             hCollateIcon;    /* PrintDlg only */
67   HICON             hNoCollateIcon;  /* PrintDlg only */
68   HICON             hPortraitIcon;   /* PrintSetupDlg only */
69   HICON             hLandscapeIcon;  /* PrintSetupDlg only */
70   HWND              hwndUpDown;
71 } PRINT_PTRA;
72 
73 typedef struct
74 {
75   LPDEVMODEW        lpDevMode;
76   LPPRINTDLGW       lpPrintDlg;
77   LPPRINTER_INFO_2W lpPrinterInfo;
78   LPDRIVER_INFO_3W  lpDriverInfo;
79   UINT              HelpMessageID;
80   HICON             hCollateIcon;    /* PrintDlg only */
81   HICON             hNoCollateIcon;  /* PrintDlg only */
82   HICON             hPortraitIcon;   /* PrintSetupDlg only */
83   HICON             hLandscapeIcon;  /* PrintSetupDlg only */
84   HWND              hwndUpDown;
85 } PRINT_PTRW;
86 
87 /* Debugging info */
88 struct pd_flags
89 {
90   DWORD  flag;
91   LPCSTR name;
92 };
93 
94 static const struct pd_flags psd_flags[] = {
95   {PSD_MINMARGINS,"PSD_MINMARGINS"},
96   {PSD_MARGINS,"PSD_MARGINS"},
97   {PSD_INTHOUSANDTHSOFINCHES,"PSD_INTHOUSANDTHSOFINCHES"},
98   {PSD_INHUNDREDTHSOFMILLIMETERS,"PSD_INHUNDREDTHSOFMILLIMETERS"},
99   {PSD_DISABLEMARGINS,"PSD_DISABLEMARGINS"},
100   {PSD_DISABLEPRINTER,"PSD_DISABLEPRINTER"},
101   {PSD_NOWARNING,"PSD_NOWARNING"},
102   {PSD_DISABLEORIENTATION,"PSD_DISABLEORIENTATION"},
103   {PSD_RETURNDEFAULT,"PSD_RETURNDEFAULT"},
104   {PSD_DISABLEPAPER,"PSD_DISABLEPAPER"},
105   {PSD_SHOWHELP,"PSD_SHOWHELP"},
106   {PSD_ENABLEPAGESETUPHOOK,"PSD_ENABLEPAGESETUPHOOK"},
107   {PSD_ENABLEPAGESETUPTEMPLATE,"PSD_ENABLEPAGESETUPTEMPLATE"},
108   {PSD_ENABLEPAGESETUPTEMPLATEHANDLE,"PSD_ENABLEPAGESETUPTEMPLATEHANDLE"},
109   {PSD_ENABLEPAGEPAINTHOOK,"PSD_ENABLEPAGEPAINTHOOK"},
110   {PSD_DISABLEPAGEPAINTING,"PSD_DISABLEPAGEPAINTING"},
111   {-1, NULL}
112 };
113 
114 static const struct pd_flags pd_flags[] = {
115   {PD_SELECTION, "PD_SELECTION "},
116   {PD_PAGENUMS, "PD_PAGENUMS "},
117   {PD_NOSELECTION, "PD_NOSELECTION "},
118   {PD_NOPAGENUMS, "PD_NOPAGENUMS "},
119   {PD_COLLATE, "PD_COLLATE "},
120   {PD_PRINTTOFILE, "PD_PRINTTOFILE "},
121   {PD_PRINTSETUP, "PD_PRINTSETUP "},
122   {PD_NOWARNING, "PD_NOWARNING "},
123   {PD_RETURNDC, "PD_RETURNDC "},
124   {PD_RETURNIC, "PD_RETURNIC "},
125   {PD_RETURNDEFAULT, "PD_RETURNDEFAULT "},
126   {PD_SHOWHELP, "PD_SHOWHELP "},
127   {PD_ENABLEPRINTHOOK, "PD_ENABLEPRINTHOOK "},
128   {PD_ENABLESETUPHOOK, "PD_ENABLESETUPHOOK "},
129   {PD_ENABLEPRINTTEMPLATE, "PD_ENABLEPRINTTEMPLATE "},
130   {PD_ENABLESETUPTEMPLATE, "PD_ENABLESETUPTEMPLATE "},
131   {PD_ENABLEPRINTTEMPLATEHANDLE, "PD_ENABLEPRINTTEMPLATEHANDLE "},
132   {PD_ENABLESETUPTEMPLATEHANDLE, "PD_ENABLESETUPTEMPLATEHANDLE "},
133   {PD_USEDEVMODECOPIES, "PD_USEDEVMODECOPIES[ANDCOLLATE] "},
134   {PD_DISABLEPRINTTOFILE, "PD_DISABLEPRINTTOFILE "},
135   {PD_HIDEPRINTTOFILE, "PD_HIDEPRINTTOFILE "},
136   {PD_NONETWORKBUTTON, "PD_NONETWORKBUTTON "},
137   {-1, NULL}
138 };
139 /* address of wndproc for subclassed Static control */
140 static WNDPROC lpfnStaticWndProc;
141 static WNDPROC edit_wndproc;
142 /* the text of the fake document to render for the Page Setup dialog */
143 static WCHAR wszFakeDocumentText[1024];
144 static const WCHAR pd32_collateW[] = { 'P', 'D', '3', '2', '_', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 };
145 static const WCHAR pd32_nocollateW[] = { 'P', 'D', '3', '2', '_', 'N', 'O', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 };
146 static const WCHAR pd32_portraitW[] = { 'P', 'D', '3', '2', '_', 'P', 'O', 'R', 'T', 'R', 'A', 'I', 'T', 0 };
147 static const WCHAR pd32_landscapeW[] = { 'P', 'D', '3', '2', '_', 'L', 'A', 'N', 'D', 'S', 'C', 'A', 'P', 'E', 0 };
148 static const WCHAR printdlg_prop[] = {'_','_','W','I','N','E','_','P','R','I','N','T','D','L','G','D','A','T','A',0};
149 static const WCHAR pagesetupdlg_prop[] = { '_', '_', 'W', 'I', 'N', 'E', '_', 'P', 'A', 'G', 'E',
150                                            'S', 'E', 'T', 'U', 'P', 'D', 'L', 'G', 'D', 'A', 'T', 'A', 0 };
151 
152 
153 static LPWSTR strdupW(LPCWSTR p)
154 {
155     LPWSTR ret;
156     DWORD len;
157 
158     if(!p) return NULL;
159     len = (lstrlenW(p) + 1) * sizeof(WCHAR);
160     ret = HeapAlloc(GetProcessHeap(), 0, len);
161     memcpy(ret, p, len);
162     return ret;
163 }
164 
165 /***********************************************************************
166  * get_driver_info [internal]
167  *
168  * get DRIVER_INFO_3W for the current printer handle,
169  * alloc the buffer, when needed
170  */
171 static DRIVER_INFO_3W * get_driver_infoW(HANDLE hprn)
172 {
173     DRIVER_INFO_3W *di3 = NULL;
174     DWORD needed = 0;
175     BOOL res;
176 
177     res = GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
178     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
179         di3 = HeapAlloc(GetProcessHeap(), 0, needed);
180         res = GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)di3, needed, &needed);
181     }
182 
183     if (res)
184         return di3;
185 
186     TRACE("GetPrinterDriverW failed with %u\n", GetLastError());
187     HeapFree(GetProcessHeap(), 0, di3);
188     return NULL;
189 }
190 
191 static DRIVER_INFO_3A * get_driver_infoA(HANDLE hprn)
192 {
193     DRIVER_INFO_3A *di3 = NULL;
194     DWORD needed = 0;
195     BOOL res;
196 
197     res = GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed);
198     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
199         di3 = HeapAlloc(GetProcessHeap(), 0, needed);
200         res = GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)di3, needed, &needed);
201     }
202 
203     if (res)
204         return di3;
205 
206     TRACE("GetPrinterDriverA failed with %u\n", GetLastError());
207     HeapFree(GetProcessHeap(), 0, di3);
208     return NULL;
209 }
210 
211 
212 /***********************************************************************
213  * get_printer_info [internal]
214  *
215  * get PRINTER_INFO_2W for the current printer handle,
216  * alloc the buffer, when needed
217  */
218 static PRINTER_INFO_2W * get_printer_infoW(HANDLE hprn)
219 {
220     PRINTER_INFO_2W *pi2 = NULL;
221     DWORD needed = 0;
222     BOOL res;
223 
224     res = GetPrinterW(hprn, 2, NULL, 0, &needed);
225     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
226         pi2 = HeapAlloc(GetProcessHeap(), 0, needed);
227         res = GetPrinterW(hprn, 2, (LPBYTE)pi2, needed, &needed);
228     }
229 
230     if (res)
231         return pi2;
232 
233     TRACE("GetPrinterW failed with %u\n", GetLastError());
234     HeapFree(GetProcessHeap(), 0, pi2);
235     return NULL;
236 }
237 
238 static PRINTER_INFO_2A * get_printer_infoA(HANDLE hprn)
239 {
240     PRINTER_INFO_2A *pi2 = NULL;
241     DWORD needed = 0;
242     BOOL res;
243 
244     res = GetPrinterA(hprn, 2, NULL, 0, &needed);
245     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
246         pi2 = HeapAlloc(GetProcessHeap(), 0, needed);
247         res = GetPrinterA(hprn, 2, (LPBYTE)pi2, needed, &needed);
248     }
249 
250     if (res)
251         return pi2;
252 
253     TRACE("GetPrinterA failed with %u\n", GetLastError());
254     HeapFree(GetProcessHeap(), 0, pi2);
255     return NULL;
256 }
257 
258 
259 /***********************************************************************
260  * update_devmode_handle [internal]
261  *
262  * update a devmode handle for the given DEVMODE, alloc the buffer, when needed
263  */
264 static HGLOBAL update_devmode_handleW(HGLOBAL hdm, DEVMODEW *dm)
265 {
266     SIZE_T size = GlobalSize(hdm);
267     LPVOID ptr;
268 
269     /* Increase / alloc the global memory block, when needed */
270     if ((dm->dmSize + dm->dmDriverExtra) > size) {
271         if (hdm)
272             hdm = GlobalReAlloc(hdm, dm->dmSize + dm->dmDriverExtra, 0);
273         else
274             hdm = GlobalAlloc(GMEM_MOVEABLE, dm->dmSize + dm->dmDriverExtra);
275     }
276 
277     if (hdm) {
278         ptr = GlobalLock(hdm);
279         if (ptr) {
280             memcpy(ptr, dm, dm->dmSize + dm->dmDriverExtra);
281             GlobalUnlock(hdm);
282         }
283         else
284         {
285             GlobalFree(hdm);
286             hdm = NULL;
287         }
288     }
289     return hdm;
290 }
291 
292 static HGLOBAL update_devmode_handleA(HGLOBAL hdm, DEVMODEA *dm)
293 {
294     SIZE_T size = GlobalSize(hdm);
295     LPVOID ptr;
296 
297     /* Increase / alloc the global memory block, when needed */
298     if ((dm->dmSize + dm->dmDriverExtra) > size) {
299         if (hdm)
300             hdm = GlobalReAlloc(hdm, dm->dmSize + dm->dmDriverExtra, 0);
301         else
302             hdm = GlobalAlloc(GMEM_MOVEABLE, dm->dmSize + dm->dmDriverExtra);
303     }
304 
305     if (hdm) {
306         ptr = GlobalLock(hdm);
307         if (ptr) {
308             memcpy(ptr, dm, dm->dmSize + dm->dmDriverExtra);
309             GlobalUnlock(hdm);
310         }
311         else
312         {
313             GlobalFree(hdm);
314             hdm = NULL;
315         }
316     }
317     return hdm;
318 }
319 
320 /***********************************************************
321  * convert_to_devmodeA
322  *
323  * Creates an ansi copy of supplied devmode
324  */
325 static DEVMODEA *convert_to_devmodeA(const DEVMODEW *dmW)
326 {
327     DEVMODEA *dmA;
328     DWORD size;
329 
330     if (!dmW) return NULL;
331     size = dmW->dmSize - CCHDEVICENAME -
332                         ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
333 
334     dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
335     if (!dmA) return NULL;
336 
337     WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
338                         (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
339 
340     if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize)
341     {
342         memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
343                dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
344     }
345     else
346     {
347         memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
348                FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
349         WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
350                             (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
351 
352         memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
353     }
354 
355     dmA->dmSize = size;
356     memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
357     return dmA;
358 }
359 
360 /***********************************************************************
361  *    PRINTDLG_OpenDefaultPrinter
362  *
363  * Returns a winspool printer handle to the default printer in *hprn
364  * Caller must call ClosePrinter on the handle
365  *
366  * Returns TRUE on success else FALSE
367  */
368 static BOOL PRINTDLG_OpenDefaultPrinter(HANDLE *hprn)
369 {
370     WCHAR buf[260];
371     DWORD dwBufLen = ARRAY_SIZE(buf);
372     BOOL res;
373     if(!GetDefaultPrinterW(buf, &dwBufLen))
374         return FALSE;
375     res = OpenPrinterW(buf, hprn, NULL);
376     if (!res)
377         WARN("Could not open printer %s\n", debugstr_w(buf));
378     return res;
379 }
380 
381 /***********************************************************************
382  *    PRINTDLG_SetUpPrinterListCombo
383  *
384  * Initializes printer list combox.
385  * hDlg:  HWND of dialog
386  * id:    Control id of combo
387  * name:  Name of printer to select
388  *
389  * Initializes combo with list of available printers.  Selects printer 'name'
390  * If name is NULL or does not exist select the default printer.
391  *
392  * Returns number of printers added to list.
393  */
394 static INT PRINTDLG_SetUpPrinterListComboA(HWND hDlg, UINT id, LPCSTR name)
395 {
396     DWORD needed, num;
397     INT i;
398     LPPRINTER_INFO_2A pi;
399     EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
400     pi = HeapAlloc(GetProcessHeap(), 0, needed);
401     EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed,
402 		  &num);
403 
404     SendDlgItemMessageA(hDlg, id, CB_RESETCONTENT, 0, 0);
405 
406     for(i = 0; i < num; i++) {
407         SendDlgItemMessageA(hDlg, id, CB_ADDSTRING, 0,
408 			    (LPARAM)pi[i].pPrinterName );
409     }
410     HeapFree(GetProcessHeap(), 0, pi);
411     if(!name ||
412        (i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1,
413 				(LPARAM)name)) == CB_ERR) {
414 
415         char buf[260];
416         DWORD dwBufLen = ARRAY_SIZE(buf);
417         if (name != NULL)
418             WARN("Can't find %s in printer list so trying to find default\n",
419 	        debugstr_a(name));
420 	if(!GetDefaultPrinterA(buf, &dwBufLen))
421 	    return num;
422 	i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf);
423 	if(i == CB_ERR)
424 	    FIXME("Can't find default printer in printer list\n");
425     }
426     SendDlgItemMessageA(hDlg, id, CB_SETCURSEL, i, 0);
427     return num;
428 }
429 
430 static INT PRINTDLG_SetUpPrinterListComboW(HWND hDlg, UINT id, LPCWSTR name)
431 {
432     DWORD needed, num;
433     INT i;
434     LPPRINTER_INFO_2W pi;
435     EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
436     pi = HeapAlloc(GetProcessHeap(), 0, needed);
437     EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed,
438 		  &num);
439 
440     for(i = 0; i < num; i++) {
441         SendDlgItemMessageW(hDlg, id, CB_ADDSTRING, 0,
442 			    (LPARAM)pi[i].pPrinterName );
443     }
444     HeapFree(GetProcessHeap(), 0, pi);
445     if(!name ||
446        (i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1,
447 				(LPARAM)name)) == CB_ERR) {
448         WCHAR buf[260];
449         DWORD dwBufLen = ARRAY_SIZE(buf);
450         if (name != NULL)
451             WARN("Can't find %s in printer list so trying to find default\n",
452 	        debugstr_w(name));
453 	if(!GetDefaultPrinterW(buf, &dwBufLen))
454 	    return num;
455 	i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf);
456 	if(i == CB_ERR)
457 	    TRACE("Can't find default printer in printer list\n");
458     }
459     SendDlgItemMessageW(hDlg, id, CB_SETCURSEL, i, 0);
460     return num;
461 }
462 
463 #ifdef __REACTOS__
464 static const CHAR  cDriverName[] = "winspool";
465 static const WCHAR wDriverName[] = L"winspool";
466 #endif
467 
468 /***********************************************************************
469  *             PRINTDLG_CreateDevNames          [internal]
470  *
471  *
472  *   creates a DevNames structure.
473  *
474  *  (NB. when we handle unicode the offsets will be in wchars).
475  */
476 static BOOL PRINTDLG_CreateDevNames(HGLOBAL *hmem, const char* DeviceDriverName,
477 				    const char* DeviceName, const char* OutputPort)
478 {
479     long size;
480     char*   pDevNamesSpace;
481     char*   pTempPtr;
482     LPDEVNAMES lpDevNames;
483     char buf[260];
484     DWORD dwBufLen = ARRAY_SIZE(buf);
485     const char *p;
486 
487     p = strrchr( DeviceDriverName, '\\' );
488     if (p) DeviceDriverName = p + 1;
489 #ifndef __REACTOS__
490     size = strlen(DeviceDriverName) + 1
491 #else
492     size = strlen(cDriverName) + 1
493 #endif
494             + strlen(DeviceName) + 1
495             + strlen(OutputPort) + 1
496             + sizeof(DEVNAMES);
497 
498     if(*hmem)
499         *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
500     else
501         *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
502     if (*hmem == 0)
503         return FALSE;
504 
505     pDevNamesSpace = GlobalLock(*hmem);
506     lpDevNames = (LPDEVNAMES) pDevNamesSpace;
507 
508     pTempPtr = pDevNamesSpace + sizeof(DEVNAMES);
509 #ifndef __REACTOS__
510     strcpy(pTempPtr, DeviceDriverName);
511 #else
512     strcpy(pTempPtr, cDriverName);
513 #endif
514     lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
515 
516     pTempPtr += strlen(DeviceDriverName) + 1;
517     strcpy(pTempPtr, DeviceName);
518     lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
519 
520     pTempPtr += strlen(DeviceName) + 1;
521     strcpy(pTempPtr, OutputPort);
522     lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
523 
524     GetDefaultPrinterA(buf, &dwBufLen);
525     lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0;
526     GlobalUnlock(*hmem);
527     return TRUE;
528 }
529 
530 static BOOL PRINTDLG_CreateDevNamesW(HGLOBAL *hmem, LPCWSTR DeviceDriverName,
531 				    LPCWSTR DeviceName, LPCWSTR OutputPort)
532 {
533     long size;
534     LPWSTR   pDevNamesSpace;
535     LPWSTR   pTempPtr;
536     LPDEVNAMES lpDevNames;
537     WCHAR bufW[260];
538     DWORD dwBufLen = ARRAY_SIZE(bufW);
539     const WCHAR *p;
540 
541     p = wcsrchr( DeviceDriverName, '\\' );
542     if (p) DeviceDriverName = p + 1;
543 #ifndef __REACTOS__
544     size = sizeof(WCHAR)*lstrlenW(DeviceDriverName) + 2
545 #else
546     size = sizeof(WCHAR)*lstrlenW(wDriverName) + 2
547 #endif
548             + sizeof(WCHAR)*lstrlenW(DeviceName) + 2
549             + sizeof(WCHAR)*lstrlenW(OutputPort) + 2
550             + sizeof(DEVNAMES);
551 
552     if(*hmem)
553         *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
554     else
555         *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
556     if (*hmem == 0)
557         return FALSE;
558 
559     pDevNamesSpace = GlobalLock(*hmem);
560     lpDevNames = (LPDEVNAMES) pDevNamesSpace;
561 
562     pTempPtr = (LPWSTR)((LPDEVNAMES)pDevNamesSpace + 1);
563 #ifndef __REACTOS__
564     lstrcpyW(pTempPtr, DeviceDriverName);
565 #else
566     lstrcpyW(pTempPtr, wDriverName);
567 #endif
568     lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
569 
570     pTempPtr += lstrlenW(DeviceDriverName) + 1;
571     lstrcpyW(pTempPtr, DeviceName);
572     lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
573 
574     pTempPtr += lstrlenW(DeviceName) + 1;
575     lstrcpyW(pTempPtr, OutputPort);
576     lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
577 
578     GetDefaultPrinterW(bufW, &dwBufLen);
579     lpDevNames->wDefault = (lstrcmpW(bufW, DeviceName) == 0) ? 1 : 0;
580     GlobalUnlock(*hmem);
581     return TRUE;
582 }
583 
584 /***********************************************************************
585  *             PRINTDLG_UpdatePrintDlg          [internal]
586  *
587  *
588  *   updates the PrintDlg structure for return values.
589  *
590  * RETURNS
591  *   FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values)
592  *   TRUE  if successful.
593  */
594 static BOOL PRINTDLG_UpdatePrintDlgA(HWND hDlg,
595 				    PRINT_PTRA* PrintStructures)
596 {
597     LPPRINTDLGA       lppd = PrintStructures->lpPrintDlg;
598     PDEVMODEA         lpdm = PrintStructures->lpDevMode;
599     LPPRINTER_INFO_2A pi = PrintStructures->lpPrinterInfo;
600 
601 
602     if(!lpdm) {
603 	FIXME("No lpdm ptr?\n");
604 	return FALSE;
605     }
606 
607 
608     if(!(lppd->Flags & PD_PRINTSETUP)) {
609         /* check whether nFromPage and nToPage are within range defined by
610 	 * nMinPage and nMaxPage
611 	 */
612         if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
613 	    WORD nToPage;
614 	    WORD nFromPage;
615             BOOL translated;
616 	    nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
617 	    nToPage   = GetDlgItemInt(hDlg, edt2, &translated, FALSE);
618 
619 	    /* if no ToPage value is entered, use the FromPage value */
620 	    if(!translated) nToPage = nFromPage;
621 
622 	    if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
623 		nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
624 	        WCHAR resourcestr[256];
625 		WCHAR resultstr[256];
626 		LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, resourcestr, 255);
627 		wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage);
628 		LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, resourcestr, 255);
629 		MessageBoxW(hDlg, resultstr, resourcestr, MB_OK | MB_ICONWARNING);
630 		return FALSE;
631 	    }
632 	    lppd->nFromPage = nFromPage;
633 	    lppd->nToPage   = nToPage;
634 	    lppd->Flags |= PD_PAGENUMS;
635 	}
636 	else
637 	    lppd->Flags &= ~PD_PAGENUMS;
638 
639         if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */
640             lppd->Flags |= PD_SELECTION;
641         else
642             lppd->Flags &= ~PD_SELECTION;
643 
644 	if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
645 	    static char file[] = "FILE:";
646 	    lppd->Flags |= PD_PRINTTOFILE;
647 	    pi->pPortName = file;
648 	}
649 
650 	if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
651 	    FIXME("Collate lppd not yet implemented as output\n");
652 	}
653 
654 	/* set PD_Collate and nCopies */
655 	if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
656 	  /*  The application doesn't support multiple copies or collate...
657 	   */
658 	    lppd->Flags &= ~PD_COLLATE;
659 	    lppd->nCopies = 1;
660 	  /* if the printer driver supports it... store info there
661 	   * otherwise no collate & multiple copies !
662 	   */
663 	    if (lpdm->dmFields & DM_COLLATE)
664 	        lpdm->dmCollate =
665 		  (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
666 	    if (lpdm->dmFields & DM_COPIES)
667 	        lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
668 	} else {
669             /* Application is responsible for multiple copies */
670 	    if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
671 	        lppd->Flags |= PD_COLLATE;
672             else
673                lppd->Flags &= ~PD_COLLATE;
674             lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
675             /* multiple copies already included in the document. Driver must print only one copy */
676             lpdm->u1.s1.dmCopies = 1;
677 	}
678 
679 	/* Print quality, PrintDlg16 */
680 	if(GetDlgItem(hDlg, cmb1))
681 	{
682 	    HWND hQuality = GetDlgItem(hDlg, cmb1);
683 	    int Sel = SendMessageA(hQuality, CB_GETCURSEL, 0, 0);
684 
685 	    if(Sel != CB_ERR)
686 	    {
687 		LONG dpi = SendMessageA(hQuality, CB_GETITEMDATA, Sel, 0);
688 		lpdm->dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION;
689 		lpdm->u1.s1.dmPrintQuality = LOWORD(dpi);
690 		lpdm->dmYResolution = HIWORD(dpi);
691 	    }
692 	}
693     }
694     return TRUE;
695 }
696 
697 static BOOL PRINTDLG_UpdatePrintDlgW(HWND hDlg,
698 				    PRINT_PTRW* PrintStructures)
699 {
700     LPPRINTDLGW       lppd = PrintStructures->lpPrintDlg;
701     PDEVMODEW         lpdm = PrintStructures->lpDevMode;
702     LPPRINTER_INFO_2W pi = PrintStructures->lpPrinterInfo;
703 
704 
705     if(!lpdm) {
706 	FIXME("No lpdm ptr?\n");
707 	return FALSE;
708     }
709 
710 
711     if(!(lppd->Flags & PD_PRINTSETUP)) {
712         /* check whether nFromPage and nToPage are within range defined by
713 	 * nMinPage and nMaxPage
714 	 */
715         if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
716 	    WORD nToPage;
717 	    WORD nFromPage;
718             BOOL translated;
719 	    nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
720 	    nToPage   = GetDlgItemInt(hDlg, edt2, &translated, FALSE);
721 
722 	    /* if no ToPage value is entered, use the FromPage value */
723 	    if(!translated) nToPage = nFromPage;
724 
725 	    if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
726 		nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
727 	        WCHAR resourcestr[256];
728 		WCHAR resultstr[256];
729                 DWORD_PTR args[2];
730 		LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE,
731 			    resourcestr, 255);
732                 args[0] = lppd->nMinPage;
733                 args[1] = lppd->nMaxPage;
734                 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
735                                resourcestr, 0, 0, resultstr,
736                                ARRAY_SIZE(resultstr),
737                                (__ms_va_list*)args);
738 		LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE,
739 			    resourcestr, 255);
740 		MessageBoxW(hDlg, resultstr, resourcestr,
741 			    MB_OK | MB_ICONWARNING);
742 		return FALSE;
743 	    }
744 	    lppd->nFromPage = nFromPage;
745 	    lppd->nToPage   = nToPage;
746 	    lppd->Flags |= PD_PAGENUMS;
747 	}
748 	else
749 	    lppd->Flags &= ~PD_PAGENUMS;
750 
751         if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */
752             lppd->Flags |= PD_SELECTION;
753         else
754             lppd->Flags &= ~PD_SELECTION;
755 
756 	if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
757 	    static WCHAR file[] = {'F','I','L','E',':',0};
758 	    lppd->Flags |= PD_PRINTTOFILE;
759 	    pi->pPortName = file;
760 	}
761 
762 	if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
763 	    FIXME("Collate lppd not yet implemented as output\n");
764 	}
765 
766 	/* set PD_Collate and nCopies */
767 	if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
768 	  /*  The application doesn't support multiple copies or collate...
769 	   */
770 	    lppd->Flags &= ~PD_COLLATE;
771 	    lppd->nCopies = 1;
772 	  /* if the printer driver supports it... store info there
773 	   * otherwise no collate & multiple copies !
774 	   */
775 	    if (lpdm->dmFields & DM_COLLATE)
776 	        lpdm->dmCollate =
777 		  (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
778 	    if (lpdm->dmFields & DM_COPIES)
779 	        lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
780 	} else {
781 	    if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
782 	        lppd->Flags |= PD_COLLATE;
783             else
784                lppd->Flags &= ~PD_COLLATE;
785             lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
786 	}
787     }
788     return TRUE;
789 }
790 
791 /************************************************************************
792  * PRINTDLG_SetUpPaperComboBox
793  *
794  * Initialize either the papersize or inputslot combos of the Printer Setup
795  * dialog.  We store the associated word (eg DMPAPER_A4) as the item data.
796  * We also try to re-select the old selection.
797  */
798 static BOOL PRINTDLG_SetUpPaperComboBoxA(HWND hDlg,
799 					int   nIDComboBox,
800 					char* PrinterName,
801 					char* PortName,
802 					LPDEVMODEA dm)
803 {
804     int     i;
805     int     NrOfEntries;
806     char*   Names;
807     WORD*   Words;
808     DWORD   Sel, old_Sel;
809     WORD    oldWord = 0, newWord = 0; /* DMPAPER_ and DMBIN_ start at 1 */
810     int     NamesSize;
811     int     fwCapability_Names;
812     int     fwCapability_Words;
813 
814     TRACE(" Printer: %s, Port: %s, ComboID: %d\n",PrinterName,PortName,nIDComboBox);
815 
816     /* query the dialog box for the current selected value */
817     Sel = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
818     if(Sel != CB_ERR) {
819         /* we enter here only if a different printer is selected after
820          * the Print Setup dialog is opened. The current settings are
821          * stored into the newly selected printer.
822          */
823         oldWord = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA,
824                                       Sel, 0);
825         if(oldWord >= DMPAPER_USER) /* DMPAPER_USER == DMBIN_USER */
826             oldWord = 0; /* There's no point in trying to keep custom
827                             paper / bin sizes across printers */
828     }
829 
830     if (dm)
831         newWord = (nIDComboBox == cmb2) ? dm->u1.s1.dmPaperSize : dm->u1.s1.dmDefaultSource;
832 
833     if (nIDComboBox == cmb2) {
834          NamesSize          = 64;
835          fwCapability_Names = DC_PAPERNAMES;
836          fwCapability_Words = DC_PAPERS;
837     } else {
838          nIDComboBox        = cmb3;
839          NamesSize          = 24;
840          fwCapability_Names = DC_BINNAMES;
841          fwCapability_Words = DC_BINS;
842     }
843 
844     NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
845                                       fwCapability_Names, NULL, dm);
846     if (NrOfEntries == 0)
847          WARN("no Name Entries found!\n");
848     else if (NrOfEntries < 0)
849          return FALSE;
850 
851     if(DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Words, NULL, dm)
852        != NrOfEntries) {
853         ERR("Number of caps is different\n");
854 	NrOfEntries = 0;
855     }
856 
857     Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(char)*NamesSize);
858     Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
859     DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Names, Names, dm);
860     NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
861 				      fwCapability_Words, (LPSTR)Words, dm);
862 
863     /* reset any current content in the combobox */
864     SendDlgItemMessageA(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
865 
866     /* store new content */
867     for (i = 0; i < NrOfEntries; i++) {
868         DWORD pos = SendDlgItemMessageA(hDlg, nIDComboBox, CB_ADDSTRING, 0,
869 					(LPARAM)(&Names[i*NamesSize]) );
870 	SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETITEMDATA, pos,
871 			    Words[i]);
872     }
873 
874     /* Look for old selection or the new default.
875        Can't do this is previous loop since item order will change as more items are added */
876     Sel = 0;
877     old_Sel = NrOfEntries;
878     for (i = 0; i < NrOfEntries; i++) {
879         if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
880 	   oldWord) {
881 	    old_Sel = i;
882 	    break;
883 	}
884         if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == newWord)
885 	    Sel = i;
886     }
887 
888     if(old_Sel < NrOfEntries)
889     {
890         if (dm)
891         {
892             if(nIDComboBox == cmb2)
893                 dm->u1.s1.dmPaperSize = oldWord;
894             else
895                 dm->u1.s1.dmDefaultSource = oldWord;
896         }
897         Sel = old_Sel;
898     }
899 
900     SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
901 
902     HeapFree(GetProcessHeap(),0,Words);
903     HeapFree(GetProcessHeap(),0,Names);
904     return TRUE;
905 }
906 
907 static BOOL PRINTDLG_SetUpPaperComboBoxW(HWND hDlg,
908 					int   nIDComboBox,
909 					const WCHAR* PrinterName,
910 					const WCHAR* PortName,
911 					LPDEVMODEW dm)
912 {
913     int     i;
914     int     NrOfEntries;
915     WCHAR*  Names;
916     WORD*   Words;
917     DWORD   Sel, old_Sel;
918     WORD    oldWord = 0, newWord = 0; /* DMPAPER_ and DMBIN_ start at 1 */
919     int     NamesSize;
920     int     fwCapability_Names;
921     int     fwCapability_Words;
922 
923     TRACE(" Printer: %s, Port: %s, ComboID: %d\n",debugstr_w(PrinterName),debugstr_w(PortName),nIDComboBox);
924 
925     /* query the dialog box for the current selected value */
926     Sel = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
927     if(Sel != CB_ERR) {
928         /* we enter here only if a different printer is selected after
929          * the Print Setup dialog is opened. The current settings are
930          * stored into the newly selected printer.
931          */
932         oldWord = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA,
933                                       Sel, 0);
934 
935         if(oldWord >= DMPAPER_USER) /* DMPAPER_USER == DMBIN_USER */
936             oldWord = 0; /* There's no point in trying to keep custom
937                             paper / bin sizes across printers */
938     }
939 
940     if (dm)
941         newWord = (nIDComboBox == cmb2) ? dm->u1.s1.dmPaperSize : dm->u1.s1.dmDefaultSource;
942 
943     if (nIDComboBox == cmb2) {
944          NamesSize          = 64;
945          fwCapability_Names = DC_PAPERNAMES;
946          fwCapability_Words = DC_PAPERS;
947     } else {
948          nIDComboBox        = cmb3;
949          NamesSize          = 24;
950          fwCapability_Names = DC_BINNAMES;
951          fwCapability_Words = DC_BINS;
952     }
953 
954     NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
955                                       fwCapability_Names, NULL, dm);
956     if (NrOfEntries == 0)
957          WARN("no Name Entries found!\n");
958     else if (NrOfEntries < 0)
959          return FALSE;
960 
961     if(DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Words, NULL, dm)
962        != NrOfEntries) {
963         ERR("Number of caps is different\n");
964 	NrOfEntries = 0;
965     }
966 
967     Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WCHAR)*NamesSize);
968     Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
969     DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Names, Names, dm);
970     NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
971                                       fwCapability_Words, Words, dm);
972 
973     /* reset any current content in the combobox */
974     SendDlgItemMessageW(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
975 
976     /* store new content */
977     for (i = 0; i < NrOfEntries; i++) {
978         DWORD pos = SendDlgItemMessageW(hDlg, nIDComboBox, CB_ADDSTRING, 0,
979 					(LPARAM)(&Names[i*NamesSize]) );
980 	SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETITEMDATA, pos,
981 			    Words[i]);
982     }
983 
984     /* Look for old selection or the new default.
985        Can't do this is previous loop since item order will change as more items are added */
986     Sel = 0;
987     old_Sel = NrOfEntries;
988     for (i = 0; i < NrOfEntries; i++) {
989         if(SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
990 	   oldWord) {
991 	    old_Sel = i;
992 	    break;
993 	}
994         if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == newWord)
995             Sel = i;
996     }
997 
998     if(old_Sel < NrOfEntries)
999     {
1000         if (dm)
1001         {
1002             if(nIDComboBox == cmb2)
1003                 dm->u1.s1.dmPaperSize = oldWord;
1004             else
1005                 dm->u1.s1.dmDefaultSource = oldWord;
1006         }
1007         Sel = old_Sel;
1008     }
1009 
1010     SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
1011 
1012     HeapFree(GetProcessHeap(),0,Words);
1013     HeapFree(GetProcessHeap(),0,Names);
1014     return TRUE;
1015 }
1016 
1017 
1018 /***********************************************************************
1019  *               PRINTDLG_UpdatePrinterInfoTexts               [internal]
1020  */
1021 static void PRINTDLG_UpdatePrinterInfoTextsA(HWND hDlg, const PRINTER_INFO_2A *pi)
1022 {
1023     char   StatusMsg[256];
1024     char   ResourceString[256];
1025     int    i;
1026 
1027     /* Status Message */
1028     StatusMsg[0]='\0';
1029 
1030     /* add all status messages */
1031     for (i = 0; i < 25; i++) {
1032         if (pi->Status & (1<<i)) {
1033 	    LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i,
1034 			ResourceString, 255);
1035 	    strcat(StatusMsg,ResourceString);
1036         }
1037     }
1038     /* append "ready" */
1039     /* FIXME: status==ready must only be appended if really so.
1040               but how to detect? */
1041     LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY,
1042 		ResourceString, 255);
1043     strcat(StatusMsg,ResourceString);
1044     SetDlgItemTextA(hDlg, stc12, StatusMsg);
1045 
1046     /* set all other printer info texts */
1047     SetDlgItemTextA(hDlg, stc11, pi->pDriverName);
1048 
1049     if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
1050         SetDlgItemTextA(hDlg, stc14, pi->pLocation);
1051     else
1052         SetDlgItemTextA(hDlg, stc14, pi->pPortName);
1053     SetDlgItemTextA(hDlg, stc13, pi->pComment ? pi->pComment : "");
1054     return;
1055 }
1056 
1057 static void PRINTDLG_UpdatePrinterInfoTextsW(HWND hDlg, const PRINTER_INFO_2W *pi)
1058 {
1059     WCHAR   StatusMsg[256];
1060     WCHAR   ResourceString[256];
1061     static const WCHAR emptyW[] = {0};
1062     int    i;
1063 
1064     /* Status Message */
1065     StatusMsg[0]='\0';
1066 
1067     /* add all status messages */
1068     for (i = 0; i < 25; i++) {
1069         if (pi->Status & (1<<i)) {
1070 	    LoadStringW(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i,
1071 			ResourceString, 255);
1072 	    lstrcatW(StatusMsg,ResourceString);
1073         }
1074     }
1075     /* append "ready" */
1076     /* FIXME: status==ready must only be appended if really so.
1077               but how to detect? */
1078     LoadStringW(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY,
1079 		ResourceString, 255);
1080     lstrcatW(StatusMsg,ResourceString);
1081     SetDlgItemTextW(hDlg, stc12, StatusMsg);
1082 
1083     /* set all other printer info texts */
1084     SetDlgItemTextW(hDlg, stc11, pi->pDriverName);
1085     if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
1086         SetDlgItemTextW(hDlg, stc14, pi->pLocation);
1087     else
1088         SetDlgItemTextW(hDlg, stc14, pi->pPortName);
1089     SetDlgItemTextW(hDlg, stc13, pi->pComment ? pi->pComment : emptyW);
1090 }
1091 
1092 
1093 /*******************************************************************
1094  *
1095  *                 PRINTDLG_ChangePrinter
1096  *
1097  */
1098 static BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name, PRINT_PTRA *PrintStructures)
1099 {
1100     LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
1101     LPDEVMODEA lpdm = NULL;
1102     LONG dmSize;
1103     DWORD needed;
1104     HANDLE hprn;
1105 
1106     HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo);
1107     HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo);
1108     if(!OpenPrinterA(name, &hprn, NULL)) {
1109         ERR("Can't open printer %s\n", name);
1110 	return FALSE;
1111     }
1112     GetPrinterA(hprn, 2, NULL, 0, &needed);
1113     PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed);
1114     GetPrinterA(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed,
1115 		&needed);
1116     GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed);
1117     PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed);
1118     if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo,
1119 	    needed, &needed)) {
1120 	ERR("GetPrinterDriverA failed for %s, fix your config!\n",PrintStructures->lpPrinterInfo->pPrinterName);
1121 	return FALSE;
1122     }
1123     ClosePrinter(hprn);
1124 
1125     PRINTDLG_UpdatePrinterInfoTextsA(hDlg, PrintStructures->lpPrinterInfo);
1126 
1127     HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
1128     PrintStructures->lpDevMode = NULL;
1129 
1130     dmSize = DocumentPropertiesA(0, 0, name, NULL, NULL, 0);
1131     if(dmSize == -1) {
1132         ERR("DocumentProperties fails on %s\n", debugstr_a(name));
1133 	return FALSE;
1134     }
1135     PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize);
1136     dmSize = DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, NULL,
1137 				 DM_OUT_BUFFER);
1138     if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) &&
1139 			  !lstrcmpA( (LPSTR) lpdm->dmDeviceName,
1140 				     (LPSTR) PrintStructures->lpDevMode->dmDeviceName)) {
1141       /* Supplied devicemode matches current printer so try to use it */
1142         DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, lpdm,
1143 			    DM_OUT_BUFFER | DM_IN_BUFFER);
1144     }
1145     if(lpdm)
1146         GlobalUnlock(lppd->hDevMode);
1147 
1148     lpdm = PrintStructures->lpDevMode;  /* use this as a shortcut */
1149 
1150     if(!(lppd->Flags & PD_PRINTSETUP)) {
1151 	/* Print range (All/Range/Selection) */
1152 	if(lppd->nFromPage != 0xffff)
1153 	    SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE);
1154 	if(lppd->nToPage != 0xffff)
1155 	    SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE);
1156 
1157 	CheckRadioButton(hDlg, rad1, rad3, rad1);		/* default */
1158 	if (lppd->Flags & PD_NOSELECTION)
1159 	    EnableWindow(GetDlgItem(hDlg, rad2), FALSE);
1160 	else
1161 	    if (lppd->Flags & PD_SELECTION)
1162 	        CheckRadioButton(hDlg, rad1, rad3, rad2);
1163 	if (lppd->Flags & PD_NOPAGENUMS) {
1164 	    EnableWindow(GetDlgItem(hDlg, rad3), FALSE);
1165 	    EnableWindow(GetDlgItem(hDlg, stc2),FALSE);
1166 	    EnableWindow(GetDlgItem(hDlg, edt1), FALSE);
1167 	    EnableWindow(GetDlgItem(hDlg, stc3),FALSE);
1168 	    EnableWindow(GetDlgItem(hDlg, edt2), FALSE);
1169 	} else {
1170 	    if (lppd->Flags & PD_PAGENUMS)
1171 	        CheckRadioButton(hDlg, rad1, rad3, rad3);
1172 	}
1173 
1174 	/* Collate pages
1175 	 *
1176 	 * FIXME: The ico3 is not displayed for some reason. I don't know why.
1177 	 */
1178 	if (lppd->Flags & PD_COLLATE) {
1179             SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON,
1180 				(LPARAM)PrintStructures->hCollateIcon);
1181 	    CheckDlgButton(hDlg, chx2, 1);
1182 	} else {
1183             SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON,
1184 				(LPARAM)PrintStructures->hNoCollateIcon);
1185 	    CheckDlgButton(hDlg, chx2, 0);
1186 	}
1187 
1188 	if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1189 	  /* if printer doesn't support it: no Collate */
1190 	    if (!(lpdm->dmFields & DM_COLLATE)) {
1191 	        EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1192 		EnableWindow(GetDlgItem(hDlg, ico3), FALSE);
1193 	    }
1194 	}
1195 
1196 	/* nCopies */
1197 	{
1198 	  INT copies;
1199 	  if (lppd->hDevMode == 0)
1200 	      copies = lppd->nCopies;
1201 	  else
1202 	      copies = lpdm->u1.s1.dmCopies;
1203 	  if(copies == 0) copies = 1;
1204 	  else if(copies < 0) copies = MAX_COPIES;
1205 	  SetDlgItemInt(hDlg, edt3, copies, FALSE);
1206 	}
1207 
1208 	if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1209 	  /* if printer doesn't support it: no nCopies */
1210 	    if (!(lpdm->dmFields & DM_COPIES)) {
1211 	        EnableWindow(GetDlgItem(hDlg, edt3), FALSE);
1212 		EnableWindow(GetDlgItem(hDlg, stc5), FALSE);
1213 	    }
1214 	}
1215 
1216 	/* print to file */
1217 	CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0);
1218 	if (lppd->Flags & PD_DISABLEPRINTTOFILE)
1219             EnableWindow(GetDlgItem(hDlg, chx1), FALSE);
1220 	if (lppd->Flags & PD_HIDEPRINTTOFILE)
1221             ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE);
1222 
1223 	/* Fill print quality combo, PrintDlg16 */
1224 	if(GetDlgItem(hDlg, cmb1))
1225 	{
1226 	    DWORD numResolutions = DeviceCapabilitiesA(PrintStructures->lpPrinterInfo->pPrinterName,
1227 						       PrintStructures->lpPrinterInfo->pPortName,
1228 						       DC_ENUMRESOLUTIONS, NULL, lpdm);
1229 
1230 	    if(numResolutions != -1)
1231 	    {
1232 		HWND hQuality = GetDlgItem(hDlg, cmb1);
1233 		LONG* Resolutions;
1234 		char buf[255];
1235 		DWORD i;
1236 		int dpiX, dpiY;
1237 		HDC hPrinterDC = CreateDCA(PrintStructures->lpPrinterInfo->pDriverName,
1238 					   PrintStructures->lpPrinterInfo->pPrinterName,
1239 					   0, lpdm);
1240 
1241 		Resolutions = HeapAlloc(GetProcessHeap(), 0, numResolutions*sizeof(LONG)*2);
1242 		DeviceCapabilitiesA(PrintStructures->lpPrinterInfo->pPrinterName,
1243 				    PrintStructures->lpPrinterInfo->pPortName,
1244 				    DC_ENUMRESOLUTIONS, (LPSTR)Resolutions, lpdm);
1245 
1246 		dpiX = GetDeviceCaps(hPrinterDC, LOGPIXELSX);
1247 		dpiY = GetDeviceCaps(hPrinterDC, LOGPIXELSY);
1248 		DeleteDC(hPrinterDC);
1249 
1250 		SendMessageA(hQuality, CB_RESETCONTENT, 0, 0);
1251 		for(i = 0; i < (numResolutions * 2); i += 2)
1252 		{
1253 		    BOOL IsDefault = FALSE;
1254 		    LRESULT Index;
1255 
1256 		    if(Resolutions[i] == Resolutions[i+1])
1257 		    {
1258 			if(dpiX == Resolutions[i])
1259 			    IsDefault = TRUE;
1260 			sprintf(buf, "%d dpi", Resolutions[i]);
1261 		    } else
1262 		    {
1263 			if(dpiX == Resolutions[i] && dpiY == Resolutions[i+1])
1264 			    IsDefault = TRUE;
1265 			sprintf(buf, "%d dpi x %d dpi", Resolutions[i], Resolutions[i+1]);
1266 		    }
1267 
1268 		    Index = SendMessageA(hQuality, CB_ADDSTRING, 0, (LPARAM)buf);
1269 
1270 		    if(IsDefault)
1271 			SendMessageA(hQuality, CB_SETCURSEL, Index, 0);
1272 
1273 		    SendMessageA(hQuality, CB_SETITEMDATA, Index, MAKELONG(dpiX,dpiY));
1274 		}
1275 		HeapFree(GetProcessHeap(), 0, Resolutions);
1276 	    }
1277 	}
1278     } else { /* PD_PRINTSETUP */
1279       BOOL bPortrait = (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT);
1280 
1281       PRINTDLG_SetUpPaperComboBoxA(hDlg, cmb2,
1282 				  PrintStructures->lpPrinterInfo->pPrinterName,
1283 				  PrintStructures->lpPrinterInfo->pPortName,
1284 				  lpdm);
1285       PRINTDLG_SetUpPaperComboBoxA(hDlg, cmb3,
1286 				  PrintStructures->lpPrinterInfo->pPrinterName,
1287 				  PrintStructures->lpPrinterInfo->pPortName,
1288 				  lpdm);
1289       CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2);
1290       SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON,
1291                           (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon :
1292                                    PrintStructures->hLandscapeIcon));
1293 
1294     }
1295 
1296     /* help button */
1297     if ((lppd->Flags & PD_SHOWHELP)==0) {
1298         /* hide if PD_SHOWHELP not specified */
1299         ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE);
1300     }
1301     return TRUE;
1302 }
1303 
1304 static BOOL PRINTDLG_ChangePrinterW(HWND hDlg, WCHAR *name,
1305 				   PRINT_PTRW *PrintStructures)
1306 {
1307     LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
1308     LPDEVMODEW lpdm = NULL;
1309     LONG dmSize;
1310     DWORD needed;
1311     HANDLE hprn;
1312 
1313     HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo);
1314     HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo);
1315     if(!OpenPrinterW(name, &hprn, NULL)) {
1316         ERR("Can't open printer %s\n", debugstr_w(name));
1317 	return FALSE;
1318     }
1319     GetPrinterW(hprn, 2, NULL, 0, &needed);
1320     PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed);
1321     GetPrinterW(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed,
1322 		&needed);
1323     GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
1324     PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed);
1325     if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo,
1326 	    needed, &needed)) {
1327 	ERR("GetPrinterDriverA failed for %s, fix your config!\n",debugstr_w(PrintStructures->lpPrinterInfo->pPrinterName));
1328 	return FALSE;
1329     }
1330     ClosePrinter(hprn);
1331 
1332     PRINTDLG_UpdatePrinterInfoTextsW(hDlg, PrintStructures->lpPrinterInfo);
1333 
1334     HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
1335     PrintStructures->lpDevMode = NULL;
1336 
1337     dmSize = DocumentPropertiesW(0, 0, name, NULL, NULL, 0);
1338     if(dmSize == -1) {
1339         ERR("DocumentProperties fails on %s\n", debugstr_w(name));
1340 	return FALSE;
1341     }
1342     PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize);
1343     dmSize = DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, NULL,
1344 				 DM_OUT_BUFFER);
1345     if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) &&
1346 			  !lstrcmpW(lpdm->dmDeviceName,
1347 				  PrintStructures->lpDevMode->dmDeviceName)) {
1348       /* Supplied devicemode matches current printer so try to use it */
1349         DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, lpdm,
1350 			    DM_OUT_BUFFER | DM_IN_BUFFER);
1351     }
1352     if(lpdm)
1353         GlobalUnlock(lppd->hDevMode);
1354 
1355     lpdm = PrintStructures->lpDevMode;  /* use this as a shortcut */
1356 
1357     if(!(lppd->Flags & PD_PRINTSETUP)) {
1358 	/* Print range (All/Range/Selection) */
1359 	if(lppd->nFromPage != 0xffff)
1360 	    SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE);
1361 	if(lppd->nToPage != 0xffff)
1362 	    SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE);
1363 
1364 	CheckRadioButton(hDlg, rad1, rad3, rad1);		/* default */
1365 	if (lppd->Flags & PD_NOSELECTION)
1366 	    EnableWindow(GetDlgItem(hDlg, rad2), FALSE);
1367 	else
1368 	    if (lppd->Flags & PD_SELECTION)
1369 	        CheckRadioButton(hDlg, rad1, rad3, rad2);
1370 	if (lppd->Flags & PD_NOPAGENUMS) {
1371 	    EnableWindow(GetDlgItem(hDlg, rad3), FALSE);
1372 	    EnableWindow(GetDlgItem(hDlg, stc2),FALSE);
1373 	    EnableWindow(GetDlgItem(hDlg, edt1), FALSE);
1374 	    EnableWindow(GetDlgItem(hDlg, stc3),FALSE);
1375 	    EnableWindow(GetDlgItem(hDlg, edt2), FALSE);
1376 	} else {
1377 	    if (lppd->Flags & PD_PAGENUMS)
1378 	        CheckRadioButton(hDlg, rad1, rad3, rad3);
1379 	}
1380 
1381 	/* Collate pages
1382 	 *
1383 	 * FIXME: The ico3 is not displayed for some reason. I don't know why.
1384 	 */
1385 	if (lppd->Flags & PD_COLLATE) {
1386             SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON,
1387 				(LPARAM)PrintStructures->hCollateIcon);
1388 	    CheckDlgButton(hDlg, chx2, 1);
1389 	} else {
1390             SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON,
1391 				(LPARAM)PrintStructures->hNoCollateIcon);
1392 	    CheckDlgButton(hDlg, chx2, 0);
1393 	}
1394 
1395 	if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1396 	  /* if printer doesn't support it: no Collate */
1397 	    if (!(lpdm->dmFields & DM_COLLATE)) {
1398 	        EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1399 		EnableWindow(GetDlgItem(hDlg, ico3), FALSE);
1400 	    }
1401 	}
1402 
1403 	/* nCopies */
1404 	{
1405 	  INT copies;
1406 	  if (lppd->hDevMode == 0)
1407 	      copies = lppd->nCopies;
1408 	  else
1409 	      copies = lpdm->u1.s1.dmCopies;
1410 	  if(copies == 0) copies = 1;
1411 	  else if(copies < 0) copies = MAX_COPIES;
1412 	  SetDlgItemInt(hDlg, edt3, copies, FALSE);
1413 	}
1414 
1415 	if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
1416 	  /* if printer doesn't support it: no nCopies */
1417 	    if (!(lpdm->dmFields & DM_COPIES)) {
1418 	        EnableWindow(GetDlgItem(hDlg, edt3), FALSE);
1419 		EnableWindow(GetDlgItem(hDlg, stc5), FALSE);
1420 	    }
1421 	}
1422 
1423 	/* print to file */
1424 	CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0);
1425 	if (lppd->Flags & PD_DISABLEPRINTTOFILE)
1426             EnableWindow(GetDlgItem(hDlg, chx1), FALSE);
1427 	if (lppd->Flags & PD_HIDEPRINTTOFILE)
1428             ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE);
1429 
1430     } else { /* PD_PRINTSETUP */
1431       BOOL bPortrait = (lpdm->u1.s1.dmOrientation == DMORIENT_PORTRAIT);
1432 
1433       PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2,
1434 				  PrintStructures->lpPrinterInfo->pPrinterName,
1435 				  PrintStructures->lpPrinterInfo->pPortName,
1436 				  lpdm);
1437       PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3,
1438 				  PrintStructures->lpPrinterInfo->pPrinterName,
1439 				  PrintStructures->lpPrinterInfo->pPortName,
1440 				  lpdm);
1441       CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2);
1442       SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON,
1443                           (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon :
1444                                    PrintStructures->hLandscapeIcon));
1445 
1446     }
1447 
1448     /* help button */
1449     if ((lppd->Flags & PD_SHOWHELP)==0) {
1450         /* hide if PD_SHOWHELP not specified */
1451         ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE);
1452     }
1453     return TRUE;
1454 }
1455 
1456  /***********************************************************************
1457  *           check_printer_setup			[internal]
1458  */
1459 static LRESULT check_printer_setup(HWND hDlg)
1460 {
1461     DWORD needed,num;
1462     WCHAR resourcestr[256],resultstr[256];
1463 
1464     EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
1465     if(needed == 0)
1466     {
1467           EnumPrintersW(PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &num);
1468     }
1469     if(needed > 0)
1470           return TRUE;
1471     else
1472     {
1473           LoadStringW(COMDLG32_hInstance, PD32_NO_DEVICES,resultstr, 255);
1474           LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE,resourcestr, 255);
1475           MessageBoxW(hDlg, resultstr, resourcestr,MB_OK | MB_ICONWARNING);
1476           return FALSE;
1477     }
1478 }
1479 
1480 /***********************************************************************
1481  *           PRINTDLG_WMInitDialog                      [internal]
1482  */
1483 static LRESULT PRINTDLG_WMInitDialog(HWND hDlg,
1484 				     PRINT_PTRA* PrintStructures)
1485 {
1486     LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
1487     DEVNAMES *pdn;
1488     DEVMODEA *pdm;
1489     char *name = NULL;
1490     UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1491 
1492     /* load Collate ICONs */
1493     /* We load these with LoadImage because they are not a standard
1494        size and we don't want them rescaled */
1495     PrintStructures->hCollateIcon =
1496       LoadImageA(COMDLG32_hInstance, "PD32_COLLATE", IMAGE_ICON, 0, 0, 0);
1497     PrintStructures->hNoCollateIcon =
1498       LoadImageA(COMDLG32_hInstance, "PD32_NOCOLLATE", IMAGE_ICON, 0, 0, 0);
1499 
1500     /* These can be done with LoadIcon */
1501     PrintStructures->hPortraitIcon =
1502       LoadIconA(COMDLG32_hInstance, "PD32_PORTRAIT");
1503     PrintStructures->hLandscapeIcon =
1504       LoadIconA(COMDLG32_hInstance, "PD32_LANDSCAPE");
1505 
1506     /* display the collate/no_collate icon */
1507     SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON,
1508                         (LPARAM)PrintStructures->hNoCollateIcon);
1509 
1510     if(PrintStructures->hCollateIcon == 0 ||
1511        PrintStructures->hNoCollateIcon == 0 ||
1512        PrintStructures->hPortraitIcon == 0 ||
1513        PrintStructures->hLandscapeIcon == 0) {
1514         ERR("no icon in resource file\n");
1515 	COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
1516 	EndDialog(hDlg, FALSE);
1517     }
1518 
1519     /*
1520      * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
1521      * must be registered and the Help button must be shown.
1522      */
1523     if (lppd->Flags & PD_SHOWHELP) {
1524         if((PrintStructures->HelpMessageID =
1525 	    RegisterWindowMessageA(HELPMSGSTRINGA)) == 0) {
1526 	    COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL);
1527 	    return FALSE;
1528 	}
1529     } else
1530         PrintStructures->HelpMessageID = 0;
1531 
1532     if(!(lppd->Flags &PD_PRINTSETUP)) {
1533         PrintStructures->hwndUpDown =
1534 	  CreateUpDownControl(WS_CHILD | WS_VISIBLE | WS_BORDER |
1535 			      UDS_NOTHOUSANDS | UDS_ARROWKEYS |
1536 			      UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0,
1537 			      hDlg, UPDOWN_ID, COMDLG32_hInstance,
1538 			      GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1);
1539     }
1540 
1541     /* FIXME: I allow more freedom than either Win95 or WinNT,
1542      *        which do not agree on what errors should be thrown or not
1543      *        in case nToPage or nFromPage is out-of-range.
1544      */
1545     if (lppd->nMaxPage < lppd->nMinPage)
1546     	lppd->nMaxPage = lppd->nMinPage;
1547     if (lppd->nMinPage == lppd->nMaxPage)
1548     	lppd->Flags |= PD_NOPAGENUMS;
1549     if (lppd->nToPage < lppd->nMinPage)
1550         lppd->nToPage = lppd->nMinPage;
1551     if (lppd->nToPage > lppd->nMaxPage)
1552         lppd->nToPage = lppd->nMaxPage;
1553     if (lppd->nFromPage < lppd->nMinPage)
1554         lppd->nFromPage = lppd->nMinPage;
1555     if (lppd->nFromPage > lppd->nMaxPage)
1556         lppd->nFromPage = lppd->nMaxPage;
1557 
1558     /* if we have the combo box, fill it */
1559     if (GetDlgItem(hDlg,comboID)) {
1560 	/* Fill Combobox
1561 	 */
1562 	pdn = GlobalLock(lppd->hDevNames);
1563 	pdm = GlobalLock(lppd->hDevMode);
1564 	if(pdn)
1565 	    name = (char*)pdn + pdn->wDeviceOffset;
1566 	else if(pdm)
1567 	    name = (char*)pdm->dmDeviceName;
1568 	PRINTDLG_SetUpPrinterListComboA(hDlg, comboID, name);
1569 	if(pdm) GlobalUnlock(lppd->hDevMode);
1570 	if(pdn) GlobalUnlock(lppd->hDevNames);
1571 
1572 	/* Now find selected printer and update rest of dlg */
1573 	name = HeapAlloc(GetProcessHeap(),0,256);
1574 	if (GetDlgItemTextA(hDlg, comboID, name, 255))
1575 	    PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures);
1576 	HeapFree(GetProcessHeap(),0,name);
1577     } else {
1578 	/* else use default printer */
1579 	char name[200];
1580         DWORD dwBufLen = ARRAY_SIZE(name);
1581 	BOOL ret = GetDefaultPrinterA(name, &dwBufLen);
1582 
1583 	if (ret)
1584 	    PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures);
1585 	else
1586 	    FIXME("No default printer found, expect problems!\n");
1587     }
1588     return TRUE;
1589 }
1590 
1591 static LRESULT PRINTDLG_WMInitDialogW(HWND hDlg,
1592 				     PRINT_PTRW* PrintStructures)
1593 {
1594     LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
1595     DEVNAMES *pdn;
1596     DEVMODEW *pdm;
1597     WCHAR *name = NULL;
1598     UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1599 
1600     /* load Collate ICONs */
1601     /* We load these with LoadImage because they are not a standard
1602        size and we don't want them rescaled */
1603     PrintStructures->hCollateIcon =
1604       LoadImageW(COMDLG32_hInstance, pd32_collateW, IMAGE_ICON, 0, 0, 0);
1605     PrintStructures->hNoCollateIcon =
1606       LoadImageW(COMDLG32_hInstance, pd32_nocollateW, IMAGE_ICON, 0, 0, 0);
1607 
1608     /* These can be done with LoadIcon */
1609     PrintStructures->hPortraitIcon =
1610       LoadIconW(COMDLG32_hInstance, pd32_portraitW);
1611     PrintStructures->hLandscapeIcon =
1612       LoadIconW(COMDLG32_hInstance, pd32_landscapeW);
1613 
1614     /* display the collate/no_collate icon */
1615     SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON,
1616                         (LPARAM)PrintStructures->hNoCollateIcon);
1617 
1618     if(PrintStructures->hCollateIcon == 0 ||
1619        PrintStructures->hNoCollateIcon == 0 ||
1620        PrintStructures->hPortraitIcon == 0 ||
1621        PrintStructures->hLandscapeIcon == 0) {
1622         ERR("no icon in resource file\n");
1623 	COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
1624 	EndDialog(hDlg, FALSE);
1625     }
1626 
1627     /*
1628      * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message
1629      * must be registered and the Help button must be shown.
1630      */
1631     if (lppd->Flags & PD_SHOWHELP) {
1632         if((PrintStructures->HelpMessageID =
1633 	    RegisterWindowMessageW(HELPMSGSTRINGW)) == 0) {
1634 	    COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL);
1635 	    return FALSE;
1636 	}
1637     } else
1638         PrintStructures->HelpMessageID = 0;
1639 
1640     if(!(lppd->Flags &PD_PRINTSETUP)) {
1641         PrintStructures->hwndUpDown =
1642 	  CreateUpDownControl(WS_CHILD | WS_VISIBLE | WS_BORDER |
1643 			      UDS_NOTHOUSANDS | UDS_ARROWKEYS |
1644 			      UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0,
1645 			      hDlg, UPDOWN_ID, COMDLG32_hInstance,
1646 			      GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1);
1647     }
1648 
1649     /* FIXME: I allow more freedom than either Win95 or WinNT,
1650      *        which do not agree to what errors should be thrown or not
1651      *        in case nToPage or nFromPage is out-of-range.
1652      */
1653     if (lppd->nMaxPage < lppd->nMinPage)
1654     	lppd->nMaxPage = lppd->nMinPage;
1655     if (lppd->nMinPage == lppd->nMaxPage)
1656     	lppd->Flags |= PD_NOPAGENUMS;
1657     if (lppd->nToPage < lppd->nMinPage)
1658         lppd->nToPage = lppd->nMinPage;
1659     if (lppd->nToPage > lppd->nMaxPage)
1660         lppd->nToPage = lppd->nMaxPage;
1661     if (lppd->nFromPage < lppd->nMinPage)
1662         lppd->nFromPage = lppd->nMinPage;
1663     if (lppd->nFromPage > lppd->nMaxPage)
1664         lppd->nFromPage = lppd->nMaxPage;
1665 
1666     /* if we have the combo box, fill it */
1667     if (GetDlgItem(hDlg,comboID)) {
1668 	/* Fill Combobox
1669 	 */
1670 	pdn = GlobalLock(lppd->hDevNames);
1671 	pdm = GlobalLock(lppd->hDevMode);
1672 	if(pdn)
1673 	    name = (WCHAR*)pdn + pdn->wDeviceOffset;
1674 	else if(pdm)
1675 	    name = pdm->dmDeviceName;
1676 	PRINTDLG_SetUpPrinterListComboW(hDlg, comboID, name);
1677 	if(pdm) GlobalUnlock(lppd->hDevMode);
1678 	if(pdn) GlobalUnlock(lppd->hDevNames);
1679 
1680 	/* Now find selected printer and update rest of dlg */
1681 	/* ansi is ok here */
1682 	name = HeapAlloc(GetProcessHeap(),0,256*sizeof(WCHAR));
1683 	if (GetDlgItemTextW(hDlg, comboID, name, 255))
1684 	    PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures);
1685 	HeapFree(GetProcessHeap(),0,name);
1686     } else {
1687 	/* else use default printer */
1688 	WCHAR name[200];
1689         DWORD dwBufLen = ARRAY_SIZE(name);
1690 	BOOL ret = GetDefaultPrinterW(name, &dwBufLen);
1691 
1692 	if (ret)
1693 	    PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures);
1694 	else
1695 	    FIXME("No default printer found, expect problems!\n");
1696     }
1697     return TRUE;
1698 }
1699 
1700 /***********************************************************************
1701  *                              PRINTDLG_WMCommand               [internal]
1702  */
1703 static LRESULT PRINTDLG_WMCommandA(HWND hDlg, WPARAM wParam,
1704                                    PRINT_PTRA* PrintStructures)
1705 {
1706     LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
1707     UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1708     LPDEVMODEA lpdm = PrintStructures->lpDevMode;
1709 
1710     switch (LOWORD(wParam))  {
1711     case IDOK:
1712         TRACE(" OK button was hit\n");
1713         if (!PRINTDLG_UpdatePrintDlgA(hDlg, PrintStructures)) {
1714 	    FIXME("Update printdlg was not successful!\n");
1715 	    return(FALSE);
1716 	}
1717 	EndDialog(hDlg, TRUE);
1718 	return(TRUE);
1719 
1720     case IDCANCEL:
1721         TRACE(" CANCEL button was hit\n");
1722         EndDialog(hDlg, FALSE);
1723 	return(FALSE);
1724 
1725      case pshHelp:
1726         TRACE(" HELP button was hit\n");
1727         SendMessageA(lppd->hwndOwner, PrintStructures->HelpMessageID,
1728         			(WPARAM) hDlg, (LPARAM) lppd);
1729         break;
1730 
1731      case chx2:                         /* collate pages checkbox */
1732         if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
1733             SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON,
1734                                     (LPARAM)PrintStructures->hCollateIcon);
1735         else
1736             SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON,
1737                                     (LPARAM)PrintStructures->hNoCollateIcon);
1738         break;
1739      case edt1:                         /* from page nr editbox */
1740      case edt2:                         /* to page nr editbox */
1741         if (HIWORD(wParam)==EN_CHANGE) {
1742 	    WORD nToPage;
1743 	    WORD nFromPage;
1744 	    nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
1745 	    nToPage   = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
1746             if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage)
1747 	        CheckRadioButton(hDlg, rad1, rad3, rad3);
1748 	}
1749         break;
1750 
1751     case edt3:
1752         if(HIWORD(wParam) == EN_CHANGE) {
1753 	    INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
1754 	    if(copies <= 1)
1755 	        EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1756 	    else
1757 	        EnableWindow(GetDlgItem(hDlg, chx2), TRUE);
1758 	}
1759 	break;
1760 
1761      case psh2:                       /* Properties button */
1762        {
1763          HANDLE hPrinter;
1764          char   PrinterName[256];
1765 
1766          GetDlgItemTextA(hDlg, PrinterComboID, PrinterName, 255);
1767          if (!OpenPrinterA(PrinterName, &hPrinter, NULL)) {
1768 	     FIXME(" Call to OpenPrinter did not succeed!\n");
1769 	     break;
1770 	 }
1771 	 DocumentPropertiesA(hDlg, hPrinter, PrinterName,
1772 			     PrintStructures->lpDevMode,
1773 			     PrintStructures->lpDevMode,
1774 			     DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT);
1775 	 ClosePrinter(hPrinter);
1776          break;
1777        }
1778 
1779     case rad1: /* Paperorientation */
1780         if (lppd->Flags & PD_PRINTSETUP)
1781         {
1782               lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1783               SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON,
1784                           (LPARAM)(PrintStructures->hPortraitIcon));
1785         }
1786         break;
1787 
1788     case rad2: /* Paperorientation */
1789         if (lppd->Flags & PD_PRINTSETUP)
1790         {
1791               lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
1792               SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON,
1793                           (LPARAM)(PrintStructures->hLandscapeIcon));
1794         }
1795         break;
1796 
1797     case cmb1: /* Printer Combobox in PRINT SETUP, quality combobox in PRINT16 */
1798 	 if (PrinterComboID != LOWORD(wParam)) {
1799 	     break;
1800 	 }
1801 	 /* FALLTHROUGH */
1802     case cmb4:                         /* Printer combobox */
1803          if (HIWORD(wParam)==CBN_SELCHANGE) {
1804 	     char   *PrinterName;
1805 	     INT index = SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETCURSEL, 0, 0);
1806 	     INT length = SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETLBTEXTLEN, index, 0);
1807 	     PrinterName = HeapAlloc(GetProcessHeap(),0,length+1);
1808 	     SendDlgItemMessageA(hDlg, LOWORD(wParam), CB_GETLBTEXT, index, (LPARAM)PrinterName);
1809 	     PRINTDLG_ChangePrinterA(hDlg, PrinterName, PrintStructures);
1810 	     HeapFree(GetProcessHeap(),0,PrinterName);
1811 	 }
1812 	 break;
1813 
1814     case cmb2: /* Papersize */
1815       {
1816 	  DWORD Sel = SendDlgItemMessageA(hDlg, cmb2, CB_GETCURSEL, 0, 0);
1817 	  if(Sel != CB_ERR) {
1818 	      lpdm->u1.s1.dmPaperSize = SendDlgItemMessageA(hDlg, cmb2,
1819 							    CB_GETITEMDATA,
1820 							    Sel, 0);
1821 	      GetDlgItemTextA(hDlg, cmb2, (char *)lpdm->dmFormName, CCHFORMNAME);
1822 	  }
1823       }
1824       break;
1825 
1826     case cmb3: /* Bin */
1827       {
1828 	  DWORD Sel = SendDlgItemMessageA(hDlg, cmb3, CB_GETCURSEL, 0, 0);
1829 	  if(Sel != CB_ERR)
1830 	      lpdm->u1.s1.dmDefaultSource = SendDlgItemMessageA(hDlg, cmb3,
1831 							  CB_GETITEMDATA, Sel,
1832 							  0);
1833       }
1834       break;
1835     }
1836     if(lppd->Flags & PD_PRINTSETUP) {
1837         switch (LOWORD(wParam)) {
1838 	case rad1:                         /* orientation */
1839 	case rad2:
1840 	    if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) {
1841 	        if(lpdm->u1.s1.dmOrientation != DMORIENT_PORTRAIT) {
1842 		    lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1843                     SendDlgItemMessageA(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON,
1844 					(LPARAM)PrintStructures->hPortraitIcon);
1845                     SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON,
1846 					(LPARAM)PrintStructures->hPortraitIcon);
1847 		}
1848 	    } else {
1849 	        if(lpdm->u1.s1.dmOrientation != DMORIENT_LANDSCAPE) {
1850 	            lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
1851                     SendDlgItemMessageA(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON,
1852 					(LPARAM)PrintStructures->hLandscapeIcon);
1853                     SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON,
1854 					(LPARAM)PrintStructures->hLandscapeIcon);
1855 		}
1856 	    }
1857 	    break;
1858 	}
1859     }
1860     return FALSE;
1861 }
1862 
1863 static LRESULT PRINTDLG_WMCommandW(HWND hDlg, WPARAM wParam,
1864 			           PRINT_PTRW* PrintStructures)
1865 {
1866     LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
1867     UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4;
1868     LPDEVMODEW lpdm = PrintStructures->lpDevMode;
1869 
1870     switch (LOWORD(wParam))  {
1871     case IDOK:
1872         TRACE(" OK button was hit\n");
1873         if (!PRINTDLG_UpdatePrintDlgW(hDlg, PrintStructures)) {
1874 	    FIXME("Update printdlg was not successful!\n");
1875 	    return(FALSE);
1876 	}
1877 	EndDialog(hDlg, TRUE);
1878 	return(TRUE);
1879 
1880     case IDCANCEL:
1881         TRACE(" CANCEL button was hit\n");
1882         EndDialog(hDlg, FALSE);
1883 	return(FALSE);
1884 
1885      case pshHelp:
1886         TRACE(" HELP button was hit\n");
1887         SendMessageW(lppd->hwndOwner, PrintStructures->HelpMessageID,
1888         			(WPARAM) hDlg, (LPARAM) lppd);
1889         break;
1890 
1891      case chx2:                         /* collate pages checkbox */
1892         if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
1893             SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON,
1894                                     (LPARAM)PrintStructures->hCollateIcon);
1895         else
1896             SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, IMAGE_ICON,
1897                                     (LPARAM)PrintStructures->hNoCollateIcon);
1898         break;
1899      case edt1:                         /* from page nr editbox */
1900      case edt2:                         /* to page nr editbox */
1901         if (HIWORD(wParam)==EN_CHANGE) {
1902 	    WORD nToPage;
1903 	    WORD nFromPage;
1904 	    nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
1905 	    nToPage   = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
1906             if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage)
1907 	        CheckRadioButton(hDlg, rad1, rad3, rad3);
1908 	}
1909         break;
1910 
1911     case edt3:
1912         if(HIWORD(wParam) == EN_CHANGE) {
1913 	    INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
1914 	    if(copies <= 1)
1915 	        EnableWindow(GetDlgItem(hDlg, chx2), FALSE);
1916 	    else
1917                 EnableWindow(GetDlgItem(hDlg, chx2), TRUE);
1918         }
1919         break;
1920 
1921      case psh2:                       /* Properties button */
1922        {
1923          HANDLE hPrinter;
1924          WCHAR  PrinterName[256];
1925 
1926          if (!GetDlgItemTextW(hDlg, PrinterComboID, PrinterName, 255)) break;
1927          if (!OpenPrinterW(PrinterName, &hPrinter, NULL)) {
1928 	     FIXME(" Call to OpenPrinter did not succeed!\n");
1929 	     break;
1930 	 }
1931 	 DocumentPropertiesW(hDlg, hPrinter, PrinterName,
1932 			     PrintStructures->lpDevMode,
1933 			     PrintStructures->lpDevMode,
1934 			     DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT);
1935 	 ClosePrinter(hPrinter);
1936          break;
1937        }
1938 
1939     case rad1: /* Paperorientation */
1940         if (lppd->Flags & PD_PRINTSETUP)
1941         {
1942               lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1943               SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON,
1944                           (LPARAM)(PrintStructures->hPortraitIcon));
1945         }
1946         break;
1947 
1948     case rad2: /* Paperorientation */
1949         if (lppd->Flags & PD_PRINTSETUP)
1950         {
1951               lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
1952               SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON,
1953                           (LPARAM)(PrintStructures->hLandscapeIcon));
1954         }
1955         break;
1956 
1957     case cmb1: /* Printer Combobox in PRINT SETUP */
1958 	 /* FALLTHROUGH */
1959     case cmb4:                         /* Printer combobox */
1960          if (HIWORD(wParam)==CBN_SELCHANGE) {
1961 	     WCHAR *PrinterName;
1962 	     INT index = SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETCURSEL, 0, 0);
1963 	     INT length = SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETLBTEXTLEN, index, 0);
1964 
1965 	     PrinterName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(length+1));
1966 	     SendDlgItemMessageW(hDlg, LOWORD(wParam), CB_GETLBTEXT, index, (LPARAM)PrinterName);
1967 	     PRINTDLG_ChangePrinterW(hDlg, PrinterName, PrintStructures);
1968 	     HeapFree(GetProcessHeap(),0,PrinterName);
1969 	 }
1970 	 break;
1971 
1972     case cmb2: /* Papersize */
1973       {
1974 	  DWORD Sel = SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0);
1975 	  if(Sel != CB_ERR) {
1976 	      lpdm->u1.s1.dmPaperSize = SendDlgItemMessageW(hDlg, cmb2,
1977 							    CB_GETITEMDATA,
1978 							    Sel, 0);
1979 	      GetDlgItemTextW(hDlg, cmb2, lpdm->dmFormName, CCHFORMNAME);
1980 	  }
1981       }
1982       break;
1983 
1984     case cmb3: /* Bin */
1985       {
1986 	  DWORD Sel = SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0);
1987 	  if(Sel != CB_ERR)
1988 	      lpdm->u1.s1.dmDefaultSource = SendDlgItemMessageW(hDlg, cmb3,
1989 							  CB_GETITEMDATA, Sel,
1990 							  0);
1991       }
1992       break;
1993     }
1994     if(lppd->Flags & PD_PRINTSETUP) {
1995         switch (LOWORD(wParam)) {
1996 	case rad1:                         /* orientation */
1997 	case rad2:
1998 	    if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) {
1999 	        if(lpdm->u1.s1.dmOrientation != DMORIENT_PORTRAIT) {
2000 		    lpdm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2001                     SendDlgItemMessageW(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON,
2002 					(LPARAM)PrintStructures->hPortraitIcon);
2003                     SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON,
2004 					(LPARAM)PrintStructures->hPortraitIcon);
2005 		}
2006 	    } else {
2007 	        if(lpdm->u1.s1.dmOrientation != DMORIENT_LANDSCAPE) {
2008 	            lpdm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
2009                     SendDlgItemMessageW(hDlg, stc10, STM_SETIMAGE, IMAGE_ICON,
2010 					(LPARAM)PrintStructures->hLandscapeIcon);
2011                     SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, IMAGE_ICON,
2012 					(LPARAM)PrintStructures->hLandscapeIcon);
2013 		}
2014 	    }
2015 	    break;
2016 	}
2017     }
2018     return FALSE;
2019 }
2020 
2021 /***********************************************************************
2022  *           PrintDlgProcA			[internal]
2023  */
2024 static INT_PTR CALLBACK PrintDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam,
2025                                       LPARAM lParam)
2026 {
2027     PRINT_PTRA* PrintStructures;
2028     INT_PTR res = FALSE;
2029 
2030     if (uMsg!=WM_INITDIALOG) {
2031         PrintStructures = GetPropW(hDlg, printdlg_prop);
2032 	if (!PrintStructures)
2033 	    return FALSE;
2034     } else {
2035         PrintStructures = (PRINT_PTRA*) lParam;
2036         SetPropW(hDlg, printdlg_prop, PrintStructures);
2037         if(!check_printer_setup(hDlg))
2038         {
2039             EndDialog(hDlg,FALSE);
2040             return FALSE;
2041         }
2042 	res = PRINTDLG_WMInitDialog(hDlg, PrintStructures);
2043 
2044 	if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK)
2045 	    res = PrintStructures->lpPrintDlg->lpfnPrintHook(
2046 		hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg
2047 	    );
2048 	return res;
2049     }
2050 
2051     if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) {
2052         res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam,
2053 							 lParam);
2054 	if(res) return res;
2055     }
2056 
2057     switch (uMsg) {
2058     case WM_COMMAND:
2059         return PRINTDLG_WMCommandA(hDlg, wParam, PrintStructures);
2060 
2061     case WM_DESTROY:
2062 	DestroyIcon(PrintStructures->hCollateIcon);
2063 	DestroyIcon(PrintStructures->hNoCollateIcon);
2064         DestroyIcon(PrintStructures->hPortraitIcon);
2065         DestroyIcon(PrintStructures->hLandscapeIcon);
2066 	if(PrintStructures->hwndUpDown)
2067 	    DestroyWindow(PrintStructures->hwndUpDown);
2068         return FALSE;
2069     }
2070     return res;
2071 }
2072 
2073 static INT_PTR CALLBACK PrintDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam,
2074                                       LPARAM lParam)
2075 {
2076     PRINT_PTRW* PrintStructures;
2077     INT_PTR res = FALSE;
2078 
2079     if (uMsg!=WM_INITDIALOG) {
2080         PrintStructures = GetPropW(hDlg, printdlg_prop);
2081 	if (!PrintStructures)
2082 	    return FALSE;
2083     } else {
2084         PrintStructures = (PRINT_PTRW*) lParam;
2085         SetPropW(hDlg, printdlg_prop, PrintStructures);
2086         if(!check_printer_setup(hDlg))
2087         {
2088             EndDialog(hDlg,FALSE);
2089             return FALSE;
2090         }
2091 	res = PRINTDLG_WMInitDialogW(hDlg, PrintStructures);
2092 
2093 	if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK)
2094 	    res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg);
2095 	return res;
2096     }
2097 
2098     if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) {
2099         res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, lParam);
2100 	if(res) return res;
2101     }
2102 
2103     switch (uMsg) {
2104     case WM_COMMAND:
2105         return PRINTDLG_WMCommandW(hDlg, wParam, PrintStructures);
2106 
2107     case WM_DESTROY:
2108 	DestroyIcon(PrintStructures->hCollateIcon);
2109 	DestroyIcon(PrintStructures->hNoCollateIcon);
2110         DestroyIcon(PrintStructures->hPortraitIcon);
2111         DestroyIcon(PrintStructures->hLandscapeIcon);
2112 	if(PrintStructures->hwndUpDown)
2113 	    DestroyWindow(PrintStructures->hwndUpDown);
2114         return FALSE;
2115     }
2116     return res;
2117 }
2118 
2119 /************************************************************
2120  *
2121  *      PRINTDLG_GetDlgTemplate
2122  *
2123  */
2124 static HGLOBAL PRINTDLG_GetDlgTemplateA(const PRINTDLGA *lppd)
2125 {
2126     HRSRC hResInfo;
2127     HGLOBAL hDlgTmpl;
2128 
2129     if (lppd->Flags & PD_PRINTSETUP) {
2130 	if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) {
2131 	    hDlgTmpl = lppd->hSetupTemplate;
2132 	} else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) {
2133 	    hResInfo = FindResourceA(lppd->hInstance,
2134 				     lppd->lpSetupTemplateName, (LPSTR)RT_DIALOG);
2135 	    hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2136 	} else {
2137 	    hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32_SETUP",
2138 				     (LPSTR)RT_DIALOG);
2139 	    hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2140 	}
2141     } else {
2142 	if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) {
2143 	    hDlgTmpl = lppd->hPrintTemplate;
2144 	} else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) {
2145 	    hResInfo = FindResourceA(lppd->hInstance,
2146 				     lppd->lpPrintTemplateName,
2147 				     (LPSTR)RT_DIALOG);
2148 	    hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2149 	} else {
2150 	    hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32",
2151 				     (LPSTR)RT_DIALOG);
2152 	    hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2153 	}
2154     }
2155     return hDlgTmpl;
2156 }
2157 
2158 static HGLOBAL PRINTDLG_GetDlgTemplateW(const PRINTDLGW *lppd)
2159 {
2160     HRSRC hResInfo;
2161     HGLOBAL hDlgTmpl;
2162     static const WCHAR xpsetup[] = { 'P','R','I','N','T','3','2','_','S','E','T','U','P',0};
2163     static const WCHAR xprint[] = { 'P','R','I','N','T','3','2',0};
2164 
2165     if (lppd->Flags & PD_PRINTSETUP) {
2166 	if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) {
2167 	    hDlgTmpl = lppd->hSetupTemplate;
2168 	} else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) {
2169 	    hResInfo = FindResourceW(lppd->hInstance,
2170 				     lppd->lpSetupTemplateName, (LPWSTR)RT_DIALOG);
2171 	    hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2172 	} else {
2173 	    hResInfo = FindResourceW(COMDLG32_hInstance, xpsetup, (LPWSTR)RT_DIALOG);
2174 	    hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2175 	}
2176     } else {
2177 	if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) {
2178 	    hDlgTmpl = lppd->hPrintTemplate;
2179 	} else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) {
2180 	    hResInfo = FindResourceW(lppd->hInstance,
2181 				     lppd->lpPrintTemplateName,
2182 				     (LPWSTR)RT_DIALOG);
2183 	    hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2184 	} else {
2185 	    hResInfo = FindResourceW(COMDLG32_hInstance, xprint, (LPWSTR)RT_DIALOG);
2186 	    hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo);
2187 	}
2188     }
2189     return hDlgTmpl;
2190 }
2191 
2192 /***********************************************************************
2193  *
2194  *      PRINTDLG_CreateDC
2195  *
2196  */
2197 static BOOL PRINTDLG_CreateDCA(LPPRINTDLGA lppd)
2198 {
2199     DEVNAMES *pdn = GlobalLock(lppd->hDevNames);
2200     DEVMODEA *pdm = GlobalLock(lppd->hDevMode);
2201 
2202     if(lppd->Flags & PD_RETURNDC) {
2203         lppd->hDC = CreateDCA((char*)pdn + pdn->wDriverOffset,
2204 			      (char*)pdn + pdn->wDeviceOffset,
2205 			      (char*)pdn + pdn->wOutputOffset,
2206 			      pdm );
2207     } else if(lppd->Flags & PD_RETURNIC) {
2208         lppd->hDC = CreateICA((char*)pdn + pdn->wDriverOffset,
2209 			      (char*)pdn + pdn->wDeviceOffset,
2210 			      (char*)pdn + pdn->wOutputOffset,
2211 			      pdm );
2212     }
2213     GlobalUnlock(lppd->hDevNames);
2214     GlobalUnlock(lppd->hDevMode);
2215     return lppd->hDC != NULL;
2216 }
2217 
2218 static BOOL PRINTDLG_CreateDCW(LPPRINTDLGW lppd)
2219 {
2220     DEVNAMES *pdn = GlobalLock(lppd->hDevNames);
2221     DEVMODEW *pdm = GlobalLock(lppd->hDevMode);
2222 
2223     if(lppd->Flags & PD_RETURNDC) {
2224         lppd->hDC = CreateDCW((WCHAR*)pdn + pdn->wDriverOffset,
2225 			      (WCHAR*)pdn + pdn->wDeviceOffset,
2226 			      (WCHAR*)pdn + pdn->wOutputOffset,
2227 			      pdm );
2228     } else if(lppd->Flags & PD_RETURNIC) {
2229         lppd->hDC = CreateICW((WCHAR*)pdn + pdn->wDriverOffset,
2230 			      (WCHAR*)pdn + pdn->wDeviceOffset,
2231 			      (WCHAR*)pdn + pdn->wOutputOffset,
2232 			      pdm );
2233     }
2234     GlobalUnlock(lppd->hDevNames);
2235     GlobalUnlock(lppd->hDevMode);
2236     return lppd->hDC != NULL;
2237 }
2238 
2239 /***********************************************************************
2240  *           PrintDlgA   (COMDLG32.@)
2241  *
2242  *  Displays the PRINT dialog box, which enables the user to specify
2243  *  specific properties of the print job.
2244  *
2245  * PARAMS
2246  *  lppd  [IO] ptr to PRINTDLG32 struct
2247  *
2248  * RETURNS
2249  *  nonzero if the user pressed the OK button
2250  *  zero    if the user cancelled the window or an error occurred
2251  *
2252  * BUGS
2253  *  PrintDlg:
2254  *  * The Collate Icons do not display, even though they are in the code.
2255  *  * The Properties Button(s) should call DocumentPropertiesA().
2256  */
2257 
2258 BOOL WINAPI PrintDlgA(LPPRINTDLGA lppd)
2259 {
2260     BOOL      bRet = FALSE;
2261     LPVOID    ptr;
2262     HINSTANCE hInst;
2263 
2264     if (!lppd)
2265     {
2266         COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION);
2267         return FALSE;
2268     }
2269 
2270     if(TRACE_ON(commdlg)) {
2271         char flagstr[1000] = "";
2272 	const struct pd_flags *pflag = pd_flags;
2273 	for( ; pflag->name; pflag++) {
2274 	    if(lppd->Flags & pflag->flag)
2275 	        strcat(flagstr, pflag->name);
2276 	}
2277 	TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
2278               "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n"
2279               "flags %08x (%s)\n",
2280 	      lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames,
2281 	      lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage,
2282 	      lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr);
2283     }
2284 
2285     if(lppd->lStructSize != sizeof(PRINTDLGA)) {
2286         WARN("structure size failure!!!\n");
2287 	COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE);
2288 	return FALSE;
2289     }
2290 
2291     if(lppd->Flags & PD_RETURNDEFAULT) {
2292         PRINTER_INFO_2A *pbuf;
2293 	DRIVER_INFO_3A	*dbuf;
2294 	HANDLE hprn;
2295 	DWORD needed;
2296 
2297 	if(lppd->hDevMode || lppd->hDevNames) {
2298 	    WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
2299 	    COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE);
2300 	    return FALSE;
2301 	}
2302         if(!PRINTDLG_OpenDefaultPrinter(&hprn)) {
2303 	    WARN("Can't find default printer\n");
2304 	    COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN);
2305 	    return FALSE;
2306 	}
2307 
2308 	GetPrinterA(hprn, 2, NULL, 0, &needed);
2309 	pbuf = HeapAlloc(GetProcessHeap(), 0, needed);
2310 	GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed);
2311 
2312 	GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed);
2313 	dbuf = HeapAlloc(GetProcessHeap(),0,needed);
2314 	if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) {
2315 	    ERR("GetPrinterDriverA failed, le %d, fix your config for printer %s!\n",
2316 	        GetLastError(),pbuf->pPrinterName);
2317 	    HeapFree(GetProcessHeap(), 0, dbuf);
2318 	    HeapFree(GetProcessHeap(), 0, pbuf);
2319 	    COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE);
2320 	    return FALSE;
2321 	}
2322 	ClosePrinter(hprn);
2323 
2324 	PRINTDLG_CreateDevNames(&(lppd->hDevNames),
2325 				  dbuf->pDriverPath,
2326 				  pbuf->pPrinterName,
2327 				  pbuf->pPortName);
2328 	lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize +
2329 				     pbuf->pDevMode->dmDriverExtra);
2330 	ptr = GlobalLock(lppd->hDevMode);
2331 	memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize +
2332 	       pbuf->pDevMode->dmDriverExtra);
2333 	GlobalUnlock(lppd->hDevMode);
2334 	HeapFree(GetProcessHeap(), 0, pbuf);
2335 	HeapFree(GetProcessHeap(), 0, dbuf);
2336 	bRet = TRUE;
2337     } else {
2338 	HGLOBAL hDlgTmpl;
2339 	PRINT_PTRA *PrintStructures;
2340 
2341     /* load Dialog resources,
2342      * depending on Flags indicates Print32 or Print32_setup dialog
2343      */
2344 	hDlgTmpl = PRINTDLG_GetDlgTemplateA(lppd);
2345 	if (!hDlgTmpl) {
2346 	    COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
2347 	    return FALSE;
2348 	}
2349 	ptr = LockResource( hDlgTmpl );
2350 	if (!ptr) {
2351 	    COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
2352 	    return FALSE;
2353 	}
2354 
2355         PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2356 				    sizeof(PRINT_PTRA));
2357 	PrintStructures->lpPrintDlg = lppd;
2358 
2359 	/* and create & process the dialog .
2360 	 * -1 is failure, 0 is broken hwnd, everything else is ok.
2361 	 */
2362         hInst = COMDLG32_hInstance;
2363 	if (lppd->Flags & (PD_ENABLESETUPTEMPLATE | PD_ENABLEPRINTTEMPLATE)) hInst = lppd->hInstance;
2364 	bRet = (0<DialogBoxIndirectParamA(hInst, ptr, lppd->hwndOwner,
2365 					   PrintDlgProcA,
2366 					   (LPARAM)PrintStructures));
2367 
2368 	if(bRet) {
2369 	    DEVMODEA *lpdm = PrintStructures->lpDevMode, *lpdmReturn;
2370 	    PRINTER_INFO_2A *pi = PrintStructures->lpPrinterInfo;
2371 	    DRIVER_INFO_3A *di = PrintStructures->lpDriverInfo;
2372 
2373 	    if (lppd->hDevMode == 0) {
2374 	        TRACE(" No hDevMode yet... Need to create my own\n");
2375 		lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE,
2376 					lpdm->dmSize + lpdm->dmDriverExtra);
2377 	    } else {
2378 		lppd->hDevMode = GlobalReAlloc(lppd->hDevMode,
2379 					       lpdm->dmSize + lpdm->dmDriverExtra,
2380 					       GMEM_MOVEABLE);
2381 	    }
2382 	    lpdmReturn = GlobalLock(lppd->hDevMode);
2383 	    memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra);
2384 
2385 	    PRINTDLG_CreateDevNames(&(lppd->hDevNames),
2386 		    di->pDriverPath,
2387 		    pi->pPrinterName,
2388 		    pi->pPortName
2389 	    );
2390 	    GlobalUnlock(lppd->hDevMode);
2391 	}
2392 	HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
2393 	HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo);
2394 	HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo);
2395 	HeapFree(GetProcessHeap(), 0, PrintStructures);
2396     }
2397     if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC))
2398         bRet = PRINTDLG_CreateDCA(lppd);
2399 
2400     TRACE("exit! (%d)\n", bRet);
2401     return bRet;
2402 }
2403 
2404 /***********************************************************************
2405  *           PrintDlgW   (COMDLG32.@)
2406  *
2407  * See PrintDlgA.
2408  */
2409 BOOL WINAPI PrintDlgW(LPPRINTDLGW lppd)
2410 {
2411     BOOL      bRet = FALSE;
2412     LPVOID    ptr;
2413     HINSTANCE hInst;
2414 
2415     if (!lppd)
2416     {
2417         COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION);
2418         return FALSE;
2419     }
2420 
2421     if(TRACE_ON(commdlg)) {
2422         char flagstr[1000] = "";
2423 	const struct pd_flags *pflag = pd_flags;
2424 	for( ; pflag->name; pflag++) {
2425 	    if(lppd->Flags & pflag->flag)
2426 	        strcat(flagstr, pflag->name);
2427 	}
2428 	TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
2429               "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n"
2430               "flags %08x (%s)\n",
2431 	      lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames,
2432 	      lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage,
2433 	      lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr);
2434     }
2435 
2436     if(lppd->lStructSize != sizeof(PRINTDLGW)) {
2437         WARN("structure size failure!!!\n");
2438 	COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE);
2439 	return FALSE;
2440     }
2441 
2442     if(lppd->Flags & PD_RETURNDEFAULT) {
2443         PRINTER_INFO_2W *pbuf;
2444 	DRIVER_INFO_3W	*dbuf;
2445 	HANDLE hprn;
2446 	DWORD needed;
2447 
2448 	if(lppd->hDevMode || lppd->hDevNames) {
2449 	    WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
2450 	    COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE);
2451 	    return FALSE;
2452 	}
2453         if(!PRINTDLG_OpenDefaultPrinter(&hprn)) {
2454 	    WARN("Can't find default printer\n");
2455 	    COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN);
2456 	    return FALSE;
2457 	}
2458 
2459 	GetPrinterW(hprn, 2, NULL, 0, &needed);
2460 	pbuf = HeapAlloc(GetProcessHeap(), 0, needed);
2461 	GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed);
2462 
2463 	GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
2464 	dbuf = HeapAlloc(GetProcessHeap(),0,needed);
2465 	if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) {
2466 	    ERR("GetPrinterDriverA failed, le %d, fix your config for printer %s!\n",
2467 	        GetLastError(),debugstr_w(pbuf->pPrinterName));
2468 	    HeapFree(GetProcessHeap(), 0, dbuf);
2469 	    HeapFree(GetProcessHeap(), 0, pbuf);
2470 	    COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE);
2471 	    return FALSE;
2472 	}
2473 	ClosePrinter(hprn);
2474 
2475 	PRINTDLG_CreateDevNamesW(&(lppd->hDevNames),
2476 				  dbuf->pDriverPath,
2477 				  pbuf->pPrinterName,
2478 				  pbuf->pPortName);
2479 	lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize +
2480 				     pbuf->pDevMode->dmDriverExtra);
2481 	ptr = GlobalLock(lppd->hDevMode);
2482 	memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize +
2483 	       pbuf->pDevMode->dmDriverExtra);
2484 	GlobalUnlock(lppd->hDevMode);
2485 	HeapFree(GetProcessHeap(), 0, pbuf);
2486 	HeapFree(GetProcessHeap(), 0, dbuf);
2487 	bRet = TRUE;
2488     } else {
2489 	HGLOBAL hDlgTmpl;
2490 	PRINT_PTRW *PrintStructures;
2491 
2492     /* load Dialog resources,
2493      * depending on Flags indicates Print32 or Print32_setup dialog
2494      */
2495 	hDlgTmpl = PRINTDLG_GetDlgTemplateW(lppd);
2496 	if (!hDlgTmpl) {
2497 	    COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
2498 	    return FALSE;
2499 	}
2500 	ptr = LockResource( hDlgTmpl );
2501 	if (!ptr) {
2502 	    COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
2503 	    return FALSE;
2504 	}
2505 
2506         PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2507 				    sizeof(PRINT_PTRW));
2508 	PrintStructures->lpPrintDlg = lppd;
2509 
2510 	/* and create & process the dialog .
2511 	 * -1 is failure, 0 is broken hwnd, everything else is ok.
2512 	 */
2513         hInst = COMDLG32_hInstance;
2514 	if (lppd->Flags & (PD_ENABLESETUPTEMPLATE | PD_ENABLEPRINTTEMPLATE)) hInst = lppd->hInstance;
2515 	bRet = (0<DialogBoxIndirectParamW(hInst, ptr, lppd->hwndOwner,
2516 					   PrintDlgProcW,
2517 					   (LPARAM)PrintStructures));
2518 
2519 	if(bRet) {
2520 	    DEVMODEW *lpdm = PrintStructures->lpDevMode, *lpdmReturn;
2521 	    PRINTER_INFO_2W *pi = PrintStructures->lpPrinterInfo;
2522 	    DRIVER_INFO_3W *di = PrintStructures->lpDriverInfo;
2523 
2524 	    if (lppd->hDevMode == 0) {
2525 	        TRACE(" No hDevMode yet... Need to create my own\n");
2526 		lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE,
2527 					lpdm->dmSize + lpdm->dmDriverExtra);
2528 	    } else {
2529 	        WORD locks;
2530 		if((locks = (GlobalFlags(lppd->hDevMode) & GMEM_LOCKCOUNT))) {
2531 		    WARN("hDevMode has %d locks on it. Unlocking it now\n", locks);
2532 		    while(locks--) {
2533 		        GlobalUnlock(lppd->hDevMode);
2534 			TRACE("Now got %d locks\n", locks);
2535 		    }
2536 		}
2537 		lppd->hDevMode = GlobalReAlloc(lppd->hDevMode,
2538 					       lpdm->dmSize + lpdm->dmDriverExtra,
2539 					       GMEM_MOVEABLE);
2540 	    }
2541 	    lpdmReturn = GlobalLock(lppd->hDevMode);
2542 	    memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra);
2543 
2544 	    if (lppd->hDevNames != 0) {
2545 	        WORD locks;
2546 		if((locks = (GlobalFlags(lppd->hDevNames) & GMEM_LOCKCOUNT))) {
2547 		    WARN("hDevNames has %d locks on it. Unlocking it now\n", locks);
2548 		    while(locks--)
2549 		        GlobalUnlock(lppd->hDevNames);
2550 		}
2551 	    }
2552 	    PRINTDLG_CreateDevNamesW(&(lppd->hDevNames),
2553 		    di->pDriverPath,
2554 		    pi->pPrinterName,
2555 		    pi->pPortName
2556 	    );
2557 	    GlobalUnlock(lppd->hDevMode);
2558 	}
2559 	HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode);
2560 	HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo);
2561 	HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo);
2562 	HeapFree(GetProcessHeap(), 0, PrintStructures);
2563     }
2564     if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC))
2565         bRet = PRINTDLG_CreateDCW(lppd);
2566 
2567     TRACE("exit! (%d)\n", bRet);
2568     return bRet;
2569 }
2570 
2571 /***********************************************************************
2572  *
2573  *          PageSetupDlg
2574  * rad1 - portrait
2575  * rad2 - landscape
2576  * cmb1 - printer select (not in standard dialog template)
2577  * cmb2 - paper size
2578  * cmb3 - source (tray?)
2579  * edt4 - border left
2580  * edt5 - border top
2581  * edt6 - border right
2582  * edt7 - border bottom
2583  * psh3 - "Printer..."
2584  */
2585 
2586 typedef struct
2587 {
2588     BOOL unicode;
2589     union
2590     {
2591         LPPAGESETUPDLGA dlga;
2592         LPPAGESETUPDLGW dlgw;
2593     } u;
2594     HWND hDlg;                /* Page Setup dialog handle */
2595     RECT rtDrawRect;          /* Drawing rect for page */
2596 } pagesetup_data;
2597 
2598 static inline DWORD pagesetup_get_flags(const pagesetup_data *data)
2599 {
2600     return data->u.dlgw->Flags;
2601 }
2602 
2603 static inline BOOL is_metric(const pagesetup_data *data)
2604 {
2605     return pagesetup_get_flags(data) & PSD_INHUNDREDTHSOFMILLIMETERS;
2606 }
2607 
2608 static inline LONG tenths_mm_to_size(const pagesetup_data *data, LONG size)
2609 {
2610     if (is_metric(data))
2611         return 10 * size;
2612     else
2613         return 10 * size * 100 / 254;
2614 }
2615 
2616 static inline LONG thousandths_inch_to_size(const pagesetup_data *data, LONG size)
2617 {
2618     if (is_metric(data))
2619         return size * 254 / 100;
2620     else
2621         return size;
2622 }
2623 
2624 static WCHAR get_decimal_sep(void)
2625 {
2626     static WCHAR sep;
2627 
2628     if(!sep)
2629     {
2630         WCHAR buf[] = {'.', 0};
2631         GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buf, ARRAY_SIZE(buf));
2632         sep = buf[0];
2633     }
2634     return sep;
2635 }
2636 
2637 static void size2str(const pagesetup_data *data, DWORD size, LPWSTR strout)
2638 {
2639     static const WCHAR integer_fmt[] = {'%','d',0};
2640     static const WCHAR hundredths_fmt[] = {'%','d','%','c','%','0','2','d',0};
2641     static const WCHAR thousandths_fmt[] = {'%','d','%','c','%','0','3','d',0};
2642 
2643     /* FIXME use LOCALE_SDECIMAL when the edit parsing code can cope */
2644 
2645     if (is_metric(data))
2646     {
2647         if(size % 100)
2648             wsprintfW(strout, hundredths_fmt, size / 100, get_decimal_sep(), size % 100);
2649         else
2650             wsprintfW(strout, integer_fmt, size / 100);
2651     }
2652     else
2653     {
2654         if(size % 1000)
2655             wsprintfW(strout, thousandths_fmt, size / 1000, get_decimal_sep(), size % 1000);
2656         else
2657             wsprintfW(strout, integer_fmt, size / 1000);
2658 
2659     }
2660 }
2661 
2662 static inline BOOL is_default_metric(void)
2663 {
2664     DWORD system;
2665     GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER,
2666                    (LPWSTR)&system, sizeof(system));
2667     return system == 0;
2668 }
2669 
2670 /**********************************************
2671  *           rotate_rect
2672  * Cyclically permute the four members of rc
2673  * If sense is TRUE l -> t -> r -> b
2674  * otherwise        l <- t <- r <- b
2675  */
2676 static inline void rotate_rect(RECT *rc, BOOL sense)
2677 {
2678     INT tmp;
2679     if(sense)
2680     {
2681         tmp        = rc->bottom;
2682         rc->bottom = rc->right;
2683         rc->right  = rc->top;
2684         rc->top    = rc->left;
2685         rc->left   = tmp;
2686     }
2687     else
2688     {
2689         tmp        = rc->left;
2690         rc->left   = rc->top;
2691         rc->top    = rc->right;
2692         rc->right  = rc->bottom;
2693         rc->bottom = tmp;
2694     }
2695 }
2696 
2697 static void pagesetup_set_orientation(pagesetup_data *data, WORD orient)
2698 {
2699     DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2700 
2701     assert(orient == DMORIENT_PORTRAIT || orient == DMORIENT_LANDSCAPE);
2702 
2703     if(data->unicode)
2704         dm->u1.s1.dmOrientation = orient;
2705     else
2706     {
2707         DEVMODEA *dmA = (DEVMODEA *)dm;
2708         dmA->u1.s1.dmOrientation = orient;
2709     }
2710     GlobalUnlock(data->u.dlgw->hDevMode);
2711 }
2712 
2713 static WORD pagesetup_get_orientation(const pagesetup_data *data)
2714 {
2715     DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2716     WORD orient;
2717 
2718     if(data->unicode)
2719         orient = dm->u1.s1.dmOrientation;
2720     else
2721     {
2722         DEVMODEA *dmA = (DEVMODEA *)dm;
2723         orient = dmA->u1.s1.dmOrientation;
2724     }
2725     GlobalUnlock(data->u.dlgw->hDevMode);
2726     return orient;
2727 }
2728 
2729 static void pagesetup_set_papersize(pagesetup_data *data, WORD paper)
2730 {
2731     DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2732 
2733     if(data->unicode)
2734         dm->u1.s1.dmPaperSize = paper;
2735     else
2736     {
2737         DEVMODEA *dmA = (DEVMODEA *)dm;
2738         dmA->u1.s1.dmPaperSize = paper;
2739     }
2740     GlobalUnlock(data->u.dlgw->hDevMode);
2741 }
2742 
2743 static WORD pagesetup_get_papersize(const pagesetup_data *data)
2744 {
2745     DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2746     WORD paper;
2747 
2748     if(data->unicode)
2749         paper = dm->u1.s1.dmPaperSize;
2750     else
2751     {
2752         DEVMODEA *dmA = (DEVMODEA *)dm;
2753         paper = dmA->u1.s1.dmPaperSize;
2754     }
2755     GlobalUnlock(data->u.dlgw->hDevMode);
2756     return paper;
2757 }
2758 
2759 static void pagesetup_set_defaultsource(pagesetup_data *data, WORD source)
2760 {
2761     DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2762 
2763     if(data->unicode)
2764         dm->u1.s1.dmDefaultSource = source;
2765     else
2766     {
2767         DEVMODEA *dmA = (DEVMODEA *)dm;
2768         dmA->u1.s1.dmDefaultSource = source;
2769     }
2770     GlobalUnlock(data->u.dlgw->hDevMode);
2771 }
2772 
2773 typedef enum
2774 {
2775     devnames_driver_name,
2776     devnames_device_name,
2777     devnames_output_name
2778 } devnames_name;
2779 
2780 
2781 static inline WORD get_devname_offset(const DEVNAMES *dn, devnames_name which)
2782 {
2783     switch(which)
2784     {
2785     case devnames_driver_name: return dn->wDriverOffset;
2786     case devnames_device_name: return dn->wDeviceOffset;
2787     case devnames_output_name: return dn->wOutputOffset;
2788     }
2789     ERR("Shouldn't be here\n");
2790     return 0;
2791 }
2792 
2793 static WCHAR *pagesetup_get_a_devname(const pagesetup_data *data, devnames_name which)
2794 {
2795     DEVNAMES *dn;
2796     WCHAR *name;
2797 
2798     dn = GlobalLock(data->u.dlgw->hDevNames);
2799     if(data->unicode)
2800         name = strdupW((WCHAR *)dn + get_devname_offset(dn, which));
2801     else
2802     {
2803         int len = MultiByteToWideChar(CP_ACP, 0, (char*)dn + get_devname_offset(dn, which), -1, NULL, 0);
2804         name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2805         MultiByteToWideChar(CP_ACP, 0, (char*)dn + get_devname_offset(dn, which), -1, name, len);
2806     }
2807     GlobalUnlock(data->u.dlgw->hDevNames);
2808     return name;
2809 }
2810 
2811 static WCHAR *pagesetup_get_drvname(const pagesetup_data *data)
2812 {
2813     return pagesetup_get_a_devname(data, devnames_driver_name);
2814 }
2815 
2816 static WCHAR *pagesetup_get_devname(const pagesetup_data *data)
2817 {
2818     return pagesetup_get_a_devname(data, devnames_device_name);
2819 }
2820 
2821 static WCHAR *pagesetup_get_portname(const pagesetup_data *data)
2822 {
2823     return pagesetup_get_a_devname(data, devnames_output_name);
2824 }
2825 
2826 static void pagesetup_release_a_devname(const pagesetup_data *data, WCHAR *name)
2827 {
2828     HeapFree(GetProcessHeap(), 0, name);
2829 }
2830 
2831 static void pagesetup_set_devnames(pagesetup_data *data, LPCWSTR drv, LPCWSTR devname, LPCWSTR port)
2832 {
2833     DEVNAMES *dn;
2834     WCHAR def[256];
2835     DWORD len = sizeof(DEVNAMES), drv_len, dev_len, port_len;
2836 
2837     if(data->unicode)
2838     {
2839         drv_len  = (lstrlenW(drv) + 1) * sizeof(WCHAR);
2840         dev_len  = (lstrlenW(devname) + 1) * sizeof(WCHAR);
2841         port_len = (lstrlenW(port) + 1) * sizeof(WCHAR);
2842     }
2843     else
2844     {
2845         drv_len = WideCharToMultiByte(CP_ACP, 0, drv, -1, NULL, 0, NULL, NULL);
2846         dev_len = WideCharToMultiByte(CP_ACP, 0, devname, -1, NULL, 0, NULL, NULL);
2847         port_len = WideCharToMultiByte(CP_ACP, 0, port, -1, NULL, 0, NULL, NULL);
2848     }
2849     len += drv_len + dev_len + port_len;
2850 
2851     if(data->u.dlgw->hDevNames)
2852         data->u.dlgw->hDevNames = GlobalReAlloc(data->u.dlgw->hDevNames, len, GMEM_MOVEABLE);
2853     else
2854         data->u.dlgw->hDevNames = GlobalAlloc(GMEM_MOVEABLE, len);
2855 
2856     dn = GlobalLock(data->u.dlgw->hDevNames);
2857 
2858     if(data->unicode)
2859     {
2860         WCHAR *ptr = (WCHAR *)(dn + 1);
2861         len = sizeof(DEVNAMES) / sizeof(WCHAR);
2862         dn->wDriverOffset = len;
2863         lstrcpyW(ptr, drv);
2864         ptr += drv_len / sizeof(WCHAR);
2865         len += drv_len / sizeof(WCHAR);
2866         dn->wDeviceOffset = len;
2867         lstrcpyW(ptr, devname);
2868         ptr += dev_len / sizeof(WCHAR);
2869         len += dev_len / sizeof(WCHAR);
2870         dn->wOutputOffset = len;
2871         lstrcpyW(ptr, port);
2872     }
2873     else
2874     {
2875         char *ptr = (char *)(dn + 1);
2876         len = sizeof(DEVNAMES);
2877         dn->wDriverOffset = len;
2878         WideCharToMultiByte(CP_ACP, 0, drv, -1, ptr, drv_len, NULL, NULL);
2879         ptr += drv_len;
2880         len += drv_len;
2881         dn->wDeviceOffset = len;
2882         WideCharToMultiByte(CP_ACP, 0, devname, -1, ptr, dev_len, NULL, NULL);
2883         ptr += dev_len;
2884         len += dev_len;
2885         dn->wOutputOffset = len;
2886         WideCharToMultiByte(CP_ACP, 0, port, -1, ptr, port_len, NULL, NULL);
2887     }
2888 
2889     dn->wDefault = 0;
2890     len = ARRAY_SIZE(def);
2891     GetDefaultPrinterW(def, &len);
2892     if(!lstrcmpW(def, devname))
2893         dn->wDefault = 1;
2894 
2895     GlobalUnlock(data->u.dlgw->hDevNames);
2896 }
2897 
2898 static DEVMODEW *pagesetup_get_devmode(const pagesetup_data *data)
2899 {
2900     DEVMODEW *dm = GlobalLock(data->u.dlgw->hDevMode);
2901     DEVMODEW *ret;
2902 
2903     if(data->unicode)
2904     {
2905         /* We make a copy even in the unicode case because the ptr
2906            may get passed back to us in pagesetup_set_devmode. */
2907         ret = HeapAlloc(GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra);
2908         memcpy(ret, dm, dm->dmSize + dm->dmDriverExtra);
2909     }
2910     else
2911         ret = GdiConvertToDevmodeW((DEVMODEA *)dm);
2912 
2913     GlobalUnlock(data->u.dlgw->hDevMode);
2914     return ret;
2915 }
2916 
2917 static void pagesetup_release_devmode(const pagesetup_data *data, DEVMODEW *dm)
2918 {
2919     HeapFree(GetProcessHeap(), 0, dm);
2920 }
2921 
2922 static void pagesetup_set_devmode(pagesetup_data *data, DEVMODEW *dm)
2923 {
2924     DEVMODEA *dmA = NULL;
2925     void *src, *dst;
2926     DWORD size;
2927 
2928     if(data->unicode)
2929     {
2930         size = dm->dmSize + dm->dmDriverExtra;
2931         src = dm;
2932     }
2933     else
2934     {
2935         dmA = convert_to_devmodeA(dm);
2936         size = dmA->dmSize + dmA->dmDriverExtra;
2937         src = dmA;
2938     }
2939 
2940     if(data->u.dlgw->hDevMode)
2941         data->u.dlgw->hDevMode = GlobalReAlloc(data->u.dlgw->hDevMode, size,
2942                                                GMEM_MOVEABLE);
2943     else
2944         data->u.dlgw->hDevMode = GlobalAlloc(GMEM_MOVEABLE, size);
2945 
2946     dst = GlobalLock(data->u.dlgw->hDevMode);
2947     memcpy(dst, src, size);
2948     GlobalUnlock(data->u.dlgw->hDevMode);
2949     HeapFree(GetProcessHeap(), 0, dmA);
2950 }
2951 
2952 static inline POINT *pagesetup_get_papersize_pt(const pagesetup_data *data)
2953 {
2954     return &data->u.dlgw->ptPaperSize;
2955 }
2956 
2957 static inline RECT *pagesetup_get_margin_rect(const pagesetup_data *data)
2958 {
2959     return &data->u.dlgw->rtMargin;
2960 }
2961 
2962 typedef enum
2963 {
2964     page_setup_hook,
2965     page_paint_hook
2966 } hook_type;
2967 
2968 static inline LPPAGESETUPHOOK pagesetup_get_hook(const pagesetup_data *data, hook_type which)
2969 {
2970     switch(which)
2971     {
2972     case page_setup_hook: return data->u.dlgw->lpfnPageSetupHook;
2973     case page_paint_hook: return data->u.dlgw->lpfnPagePaintHook;
2974     }
2975     return NULL;
2976 }
2977 
2978 /* This should only be used in calls to hook procs so we return the ptr
2979    already cast to LPARAM */
2980 static inline LPARAM pagesetup_get_dlg_struct(const pagesetup_data *data)
2981 {
2982     return (LPARAM)data->u.dlgw;
2983 }
2984 
2985 static inline void swap_point(POINT *pt)
2986 {
2987     LONG tmp = pt->x;
2988     pt->x = pt->y;
2989     pt->y = tmp;
2990 }
2991 
2992 static BOOL pagesetup_update_papersize(pagesetup_data *data)
2993 {
2994     DEVMODEW *dm;
2995     LPWSTR devname, portname;
2996     int i, num;
2997     WORD *words = NULL, paperword;
2998     POINT *points = NULL;
2999     BOOL retval = FALSE;
3000 
3001     dm       = pagesetup_get_devmode(data);
3002     devname  = pagesetup_get_devname(data);
3003     portname = pagesetup_get_portname(data);
3004 
3005     num = DeviceCapabilitiesW(devname, portname, DC_PAPERS, NULL, dm);
3006     if (num <= 0)
3007     {
3008         FIXME("No papernames found for %s/%s\n", debugstr_w(devname), debugstr_w(portname));
3009         goto end;
3010     }
3011 
3012     words = HeapAlloc(GetProcessHeap(), 0, num * sizeof(WORD));
3013     points = HeapAlloc(GetProcessHeap(), 0, num * sizeof(POINT));
3014 
3015     if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERS, (LPWSTR)words, dm))
3016     {
3017         FIXME("Number of returned words is not %d\n", num);
3018         goto end;
3019     }
3020 
3021     if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERSIZE, (LPWSTR)points, dm))
3022     {
3023         FIXME("Number of returned sizes is not %d\n", num);
3024         goto end;
3025     }
3026 
3027     paperword = pagesetup_get_papersize(data);
3028 
3029     for (i = 0; i < num; i++)
3030         if (words[i] == paperword)
3031             break;
3032 
3033     if (i == num)
3034     {
3035         FIXME("Papersize %d not found in list?\n", paperword);
3036         goto end;
3037     }
3038 
3039     /* this is _10ths_ of a millimeter */
3040     pagesetup_get_papersize_pt(data)->x = tenths_mm_to_size(data, points[i].x);
3041     pagesetup_get_papersize_pt(data)->y = tenths_mm_to_size(data, points[i].y);
3042 
3043     if(pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE)
3044         swap_point(pagesetup_get_papersize_pt(data));
3045 
3046     retval = TRUE;
3047 
3048 end:
3049     HeapFree(GetProcessHeap(), 0, words);
3050     HeapFree(GetProcessHeap(), 0, points);
3051     pagesetup_release_a_devname(data, portname);
3052     pagesetup_release_a_devname(data, devname);
3053     pagesetup_release_devmode(data, dm);
3054 
3055     return retval;
3056 }
3057 
3058 /**********************************************************************************************
3059  * pagesetup_change_printer
3060  *
3061  * Redefines hDevMode and hDevNames HANDLES and initialises it.
3062  *
3063  */
3064 static BOOL pagesetup_change_printer(LPWSTR name, pagesetup_data *data)
3065 {
3066     HANDLE hprn;
3067     DWORD needed;
3068     PRINTER_INFO_2W *prn_info = NULL;
3069     DRIVER_INFO_3W *drv_info = NULL;
3070     DEVMODEW *dm = NULL;
3071     BOOL retval = FALSE;
3072 
3073     if(!OpenPrinterW(name, &hprn, NULL))
3074     {
3075         ERR("Can't open printer %s\n", debugstr_w(name));
3076         goto end;
3077     }
3078 
3079     GetPrinterW(hprn, 2, NULL, 0, &needed);
3080     prn_info = HeapAlloc(GetProcessHeap(), 0, needed);
3081     GetPrinterW(hprn, 2, (LPBYTE)prn_info, needed, &needed);
3082     GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
3083     drv_info = HeapAlloc(GetProcessHeap(), 0, needed);
3084     if(!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)drv_info, needed, &needed))
3085     {
3086         ERR("GetPrinterDriverA failed for %s, fix your config!\n", debugstr_w(prn_info->pPrinterName));
3087         goto end;
3088     }
3089     ClosePrinter(hprn);
3090 
3091     needed = DocumentPropertiesW(0, 0, name, NULL, NULL, 0);
3092     if(needed == -1)
3093     {
3094         ERR("DocumentProperties fails on %s\n", debugstr_w(name));
3095         goto end;
3096     }
3097 
3098     dm = HeapAlloc(GetProcessHeap(), 0, needed);
3099     DocumentPropertiesW(0, 0, name, dm, NULL, DM_OUT_BUFFER);
3100 
3101     pagesetup_set_devmode(data, dm);
3102     pagesetup_set_devnames(data, drv_info->pDriverPath, prn_info->pPrinterName,
3103                            prn_info->pPortName);
3104 
3105     retval = TRUE;
3106 end:
3107     HeapFree(GetProcessHeap(), 0, dm);
3108     HeapFree(GetProcessHeap(), 0, prn_info);
3109     HeapFree(GetProcessHeap(), 0, drv_info);
3110     return retval;
3111 }
3112 
3113 /****************************************************************************************
3114  *  pagesetup_init_combos
3115  *
3116  *  Fills Printers, Paper and Source combos
3117  *
3118  */
3119 static void pagesetup_init_combos(HWND hDlg, pagesetup_data *data)
3120 {
3121     DEVMODEW *dm;
3122     LPWSTR devname, portname;
3123 
3124     dm       = pagesetup_get_devmode(data);
3125     devname  = pagesetup_get_devname(data);
3126     portname = pagesetup_get_portname(data);
3127 
3128     PRINTDLG_SetUpPrinterListComboW(hDlg, cmb1, devname);
3129     PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2, devname, portname, dm);
3130     PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3, devname, portname, dm);
3131 
3132     pagesetup_release_a_devname(data, portname);
3133     pagesetup_release_a_devname(data, devname);
3134     pagesetup_release_devmode(data, dm);
3135 }
3136 
3137 
3138 /****************************************************************************************
3139  *  pagesetup_change_printer_dialog
3140  *
3141  *  Pops up another dialog that lets the user pick another printer.
3142  *
3143  *  For now we display the PrintDlg, this should display a striped down version of it.
3144  */
3145 static void pagesetup_change_printer_dialog(HWND hDlg, pagesetup_data *data)
3146 {
3147     PRINTDLGW prnt;
3148     LPWSTR drvname, devname, portname;
3149     DEVMODEW *tmp_dm, *dm;
3150 
3151     memset(&prnt, 0, sizeof(prnt));
3152     prnt.lStructSize = sizeof(prnt);
3153     prnt.Flags     = 0;
3154     prnt.hwndOwner = hDlg;
3155 
3156     drvname = pagesetup_get_drvname(data);
3157     devname = pagesetup_get_devname(data);
3158     portname = pagesetup_get_portname(data);
3159     prnt.hDevNames = 0;
3160     PRINTDLG_CreateDevNamesW(&prnt.hDevNames, drvname, devname, portname);
3161     pagesetup_release_a_devname(data, portname);
3162     pagesetup_release_a_devname(data, devname);
3163     pagesetup_release_a_devname(data, drvname);
3164 
3165     tmp_dm = pagesetup_get_devmode(data);
3166     prnt.hDevMode = GlobalAlloc(GMEM_MOVEABLE, tmp_dm->dmSize + tmp_dm->dmDriverExtra);
3167     dm = GlobalLock(prnt.hDevMode);
3168     memcpy(dm, tmp_dm, tmp_dm->dmSize + tmp_dm->dmDriverExtra);
3169     GlobalUnlock(prnt.hDevMode);
3170     pagesetup_release_devmode(data, tmp_dm);
3171 
3172     if (PrintDlgW(&prnt))
3173     {
3174         DEVMODEW *dm = GlobalLock(prnt.hDevMode);
3175         DEVNAMES *dn = GlobalLock(prnt.hDevNames);
3176 
3177         pagesetup_set_devnames(data, (WCHAR*)dn + dn->wDriverOffset,
3178                                (WCHAR*)dn + dn->wDeviceOffset, (WCHAR *)dn + dn->wOutputOffset);
3179         pagesetup_set_devmode(data, dm);
3180         GlobalUnlock(prnt.hDevNames);
3181         GlobalUnlock(prnt.hDevMode);
3182         pagesetup_init_combos(hDlg, data);
3183     }
3184 
3185     GlobalFree(prnt.hDevMode);
3186     GlobalFree(prnt.hDevNames);
3187 
3188 }
3189 
3190 /******************************************************************************************
3191  * pagesetup_change_preview
3192  *
3193  * Changes paper preview size / position
3194  *
3195  */
3196 static void pagesetup_change_preview(const pagesetup_data *data)
3197 {
3198     LONG width, height, x, y;
3199     RECT tmp;
3200     const int shadow = 4;
3201 
3202     if(pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE)
3203     {
3204         width  = data->rtDrawRect.right - data->rtDrawRect.left;
3205         height = pagesetup_get_papersize_pt(data)->y * width / pagesetup_get_papersize_pt(data)->x;
3206     }
3207     else
3208     {
3209         height = data->rtDrawRect.bottom - data->rtDrawRect.top;
3210         width  = pagesetup_get_papersize_pt(data)->x * height / pagesetup_get_papersize_pt(data)->y;
3211     }
3212     x = (data->rtDrawRect.right + data->rtDrawRect.left - width) / 2;
3213     y = (data->rtDrawRect.bottom + data->rtDrawRect.top - height) / 2;
3214     TRACE("draw rect %s x=%d, y=%d, w=%d, h=%d\n",
3215           wine_dbgstr_rect(&data->rtDrawRect), x, y, width, height);
3216 
3217     MoveWindow(GetDlgItem(data->hDlg, rct2), x + width, y + shadow, shadow, height, FALSE);
3218     MoveWindow(GetDlgItem(data->hDlg, rct3), x + shadow, y + height, width, shadow, FALSE);
3219     MoveWindow(GetDlgItem(data->hDlg, rct1), x, y, width, height, FALSE);
3220 
3221     tmp = data->rtDrawRect;
3222     tmp.right  += shadow;
3223     tmp.bottom += shadow;
3224     InvalidateRect(data->hDlg, &tmp, TRUE);
3225 }
3226 
3227 static inline LONG *element_from_margin_id(RECT *rc, WORD id)
3228 {
3229     switch(id)
3230     {
3231     case edt4: return &rc->left;
3232     case edt5: return &rc->top;
3233     case edt6: return &rc->right;
3234     case edt7: return &rc->bottom;
3235     }
3236     return NULL;
3237 }
3238 
3239 static void update_margin_edits(HWND hDlg, const pagesetup_data *data, WORD id)
3240 {
3241     WCHAR str[100];
3242     WORD idx;
3243 
3244     for(idx = edt4; idx <= edt7; idx++)
3245     {
3246         if(id == 0 || id == idx)
3247         {
3248             size2str(data, *element_from_margin_id(pagesetup_get_margin_rect(data), idx), str);
3249             SetDlgItemTextW(hDlg, idx, str);
3250         }
3251     }
3252 }
3253 
3254 static void margin_edit_notification(HWND hDlg, const pagesetup_data *data, WORD msg, WORD id)
3255 {
3256     switch (msg)
3257     {
3258     case EN_CHANGE:
3259       {
3260         WCHAR buf[10];
3261         LONG val = 0;
3262         LONG *value = element_from_margin_id(pagesetup_get_margin_rect(data), id);
3263 
3264         if (GetDlgItemTextW(hDlg, id, buf, ARRAY_SIZE(buf)) != 0)
3265         {
3266             WCHAR *end;
3267             WCHAR decimal = get_decimal_sep();
3268 
3269             val = wcstol(buf, &end, 10);
3270             if(end != buf || *end == decimal)
3271             {
3272                 int mult = is_metric(data) ? 100 : 1000;
3273                 val *= mult;
3274                 if(*end == decimal)
3275                 {
3276                     while(mult > 1)
3277                     {
3278                         end++;
3279                         mult /= 10;
3280                         if(iswdigit(*end))
3281                             val += (*end - '0') * mult;
3282                         else
3283                             break;
3284                     }
3285                 }
3286             }
3287         }
3288         *value = val;
3289         return;
3290       }
3291 
3292     case EN_KILLFOCUS:
3293         update_margin_edits(hDlg, data, id);
3294         return;
3295     }
3296 }
3297 
3298 static void set_margin_groupbox_title(HWND hDlg, const pagesetup_data *data)
3299 {
3300     WCHAR title[256];
3301 
3302     if(LoadStringW(COMDLG32_hInstance, is_metric(data) ? PD32_MARGINS_IN_MILLIMETERS : PD32_MARGINS_IN_INCHES,
3303                    title, ARRAY_SIZE(title)))
3304         SetDlgItemTextW(hDlg, grp4, title);
3305 }
3306 
3307 static void pagesetup_update_orientation_buttons(HWND hDlg, const pagesetup_data *data)
3308 {
3309     if (pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE)
3310         CheckRadioButton(hDlg, rad1, rad2, rad2);
3311     else
3312         CheckRadioButton(hDlg, rad1, rad2, rad1);
3313 }
3314 
3315 /****************************************************************************************
3316  *  pagesetup_printer_properties
3317  *
3318  *  Handle invocation of the 'Properties' button (not present in the default template).
3319  */
3320 static void pagesetup_printer_properties(HWND hDlg, pagesetup_data *data)
3321 {
3322     HANDLE hprn;
3323     LPWSTR devname;
3324     DEVMODEW *dm;
3325     LRESULT count;
3326     int i;
3327 
3328     devname = pagesetup_get_devname(data);
3329 
3330     if (!OpenPrinterW(devname, &hprn, NULL))
3331     {
3332         FIXME("Call to OpenPrinter did not succeed!\n");
3333         pagesetup_release_a_devname(data, devname);
3334         return;
3335     }
3336 
3337     dm = pagesetup_get_devmode(data);
3338     DocumentPropertiesW(hDlg, hprn, devname, dm, dm, DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT);
3339     pagesetup_set_devmode(data, dm);
3340     pagesetup_release_devmode(data, dm);
3341     pagesetup_release_a_devname(data, devname);
3342     ClosePrinter(hprn);
3343 
3344     /* Changing paper */
3345     pagesetup_update_papersize(data);
3346     pagesetup_update_orientation_buttons(hDlg, data);
3347 
3348     /* Changing paper preview */
3349     pagesetup_change_preview(data);
3350 
3351     /* Selecting paper in combo */
3352     count = SendDlgItemMessageW(hDlg, cmb2, CB_GETCOUNT, 0, 0);
3353     if(count != CB_ERR)
3354     {
3355         WORD paperword = pagesetup_get_papersize(data);
3356         for(i = 0; i < count; i++)
3357         {
3358             if(SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, i, 0) == paperword) {
3359                 SendDlgItemMessageW(hDlg, cmb2, CB_SETCURSEL, i, 0);
3360                 break;
3361             }
3362         }
3363     }
3364 }
3365 
3366 /********************************************************************************
3367  * pagesetup_wm_command
3368  * process WM_COMMAND message for PageSetupDlg
3369  *
3370  * PARAMS
3371  *  hDlg 	[in] 	Main dialog HANDLE
3372  *  wParam 	[in]	WM_COMMAND wParam
3373  *  lParam	[in]	WM_COMMAND lParam
3374  *  pda		[in/out] ptr to PageSetupDataA
3375  */
3376 
3377 static BOOL pagesetup_wm_command(HWND hDlg, WPARAM wParam, LPARAM lParam, pagesetup_data *data)
3378 {
3379     WORD msg = HIWORD(wParam);
3380     WORD id  = LOWORD(wParam);
3381 
3382     TRACE("loword (lparam) %d, wparam 0x%lx, lparam %08lx\n",
3383 	    LOWORD(lParam),wParam,lParam);
3384     switch (id)  {
3385     case IDOK:
3386 	EndDialog(hDlg, TRUE);
3387 	return TRUE ;
3388 
3389     case IDCANCEL:
3390         EndDialog(hDlg, FALSE);
3391 	return FALSE ;
3392 
3393     case psh3: /* Printer... */
3394         pagesetup_change_printer_dialog(hDlg, data);
3395         return TRUE;
3396 
3397     case rad1: /* Portrait */
3398     case rad2: /* Landscape */
3399         if((id == rad1 && pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE) ||
3400            (id == rad2 && pagesetup_get_orientation(data) == DMORIENT_PORTRAIT))
3401 	{
3402             pagesetup_set_orientation(data, (id == rad1) ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE);
3403             pagesetup_update_papersize(data);
3404             rotate_rect(pagesetup_get_margin_rect(data), (id == rad2));
3405             update_margin_edits(hDlg, data, 0);
3406             pagesetup_change_preview(data);
3407 	}
3408 	break;
3409     case cmb1: /* Printer combo */
3410         if(msg == CBN_SELCHANGE)
3411         {
3412             WCHAR *name;
3413             INT index = SendDlgItemMessageW(hDlg, id, CB_GETCURSEL, 0, 0);
3414             INT length = SendDlgItemMessageW(hDlg, id, CB_GETLBTEXTLEN, index, 0);
3415             name = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(length+1));
3416             SendDlgItemMessageW(hDlg, id, CB_GETLBTEXT, index, (LPARAM)name);
3417             pagesetup_change_printer(name, data);
3418             pagesetup_init_combos(hDlg, data);
3419             HeapFree(GetProcessHeap(),0,name);
3420         }
3421         break;
3422     case cmb2: /* Paper combo */
3423         if(msg == CBN_SELCHANGE)
3424         {
3425             DWORD paperword = SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA,
3426                                                   SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0), 0);
3427             if (paperword != CB_ERR)
3428             {
3429                 pagesetup_set_papersize(data, paperword);
3430                 pagesetup_update_papersize(data);
3431                 pagesetup_change_preview(data);
3432 	    } else
3433                 FIXME("could not get dialog text for papersize cmbbox?\n");
3434         }
3435         break;
3436     case cmb3: /* Paper Source */
3437         if(msg == CBN_SELCHANGE)
3438         {
3439             WORD source = SendDlgItemMessageW(hDlg, cmb3, CB_GETITEMDATA,
3440                                               SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0), 0);
3441             pagesetup_set_defaultsource(data, source);
3442         }
3443         break;
3444     case psh2: /* Printer Properties button */
3445         pagesetup_printer_properties(hDlg, data);
3446         break;
3447     case edt4:
3448     case edt5:
3449     case edt6:
3450     case edt7:
3451         margin_edit_notification(hDlg, data, msg, id);
3452         break;
3453     }
3454     InvalidateRect(GetDlgItem(hDlg, rct1), NULL, TRUE);
3455     return FALSE;
3456 }
3457 
3458 /***********************************************************************
3459  *           default_page_paint_hook
3460  * Default hook paint procedure that receives WM_PSD_* messages from the dialog box
3461  * whenever the sample page is redrawn.
3462  */
3463 static UINT_PTR default_page_paint_hook(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam,
3464                                         const pagesetup_data *data)
3465 {
3466     LPRECT lprc = (LPRECT) lParam;
3467     HDC hdc = (HDC) wParam;
3468     HPEN hpen, holdpen;
3469     LOGFONTW lf;
3470     HFONT hfont, holdfont;
3471     INT oldbkmode;
3472     TRACE("uMsg: WM_USER+%d\n",uMsg-WM_USER);
3473     /* Call user paint hook if enable */
3474     if (pagesetup_get_flags(data) & PSD_ENABLEPAGEPAINTHOOK)
3475         if (pagesetup_get_hook(data, page_paint_hook)(hwndDlg, uMsg, wParam, lParam))
3476             return TRUE;
3477 
3478     switch (uMsg) {
3479        /* LPPAGESETUPDLG in lParam */
3480        case WM_PSD_PAGESETUPDLG:
3481        /* Inform about the sample page rectangle */
3482        case WM_PSD_FULLPAGERECT:
3483        /* Inform about the margin rectangle */
3484        case WM_PSD_MINMARGINRECT:
3485             return FALSE;
3486 
3487         /* Draw dashed rectangle showing margins */
3488         case WM_PSD_MARGINRECT:
3489             hpen = CreatePen(PS_DASH, 1, GetSysColor(COLOR_3DSHADOW));
3490             holdpen = SelectObject(hdc, hpen);
3491             Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom);
3492             DeleteObject(SelectObject(hdc, holdpen));
3493             return TRUE;
3494         /* Draw the fake document */
3495         case WM_PSD_GREEKTEXTRECT:
3496             /* select a nice scalable font, because we want the text really small */
3497             SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0);
3498             lf.lfHeight = 6; /* value chosen based on visual effect */
3499             hfont = CreateFontIndirectW(&lf);
3500             holdfont = SelectObject(hdc, hfont);
3501 
3502             /* if text not loaded, then do so now */
3503             if (wszFakeDocumentText[0] == '\0')
3504                  LoadStringW(COMDLG32_hInstance,
3505                         IDS_FAKEDOCTEXT,
3506                         wszFakeDocumentText,
3507                         ARRAY_SIZE(wszFakeDocumentText));
3508 
3509             oldbkmode = SetBkMode(hdc, TRANSPARENT);
3510             DrawTextW(hdc, wszFakeDocumentText, -1, lprc, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_WORDBREAK);
3511             SetBkMode(hdc, oldbkmode);
3512 
3513             DeleteObject(SelectObject(hdc, holdfont));
3514             return TRUE;
3515 
3516         /* Envelope stamp */
3517         case WM_PSD_ENVSTAMPRECT:
3518         /* Return address */
3519         case WM_PSD_YAFULLPAGERECT:
3520             FIXME("envelope/stamp is not implemented\n");
3521             return FALSE;
3522         default:
3523             FIXME("Unknown message %x\n",uMsg);
3524             return FALSE;
3525     }
3526     return TRUE;
3527 }
3528 
3529 /***********************************************************************
3530  *           PagePaintProc
3531  * The main paint procedure for the PageSetupDlg function.
3532  * The Page Setup dialog box includes an image of a sample page that shows how
3533  * the user's selections affect the appearance of the printed output.
3534  * The image consists of a rectangle that represents the selected paper
3535  * or envelope type, with a dotted-line rectangle representing
3536  * the current margins, and partial (Greek text) characters
3537  * to show how text looks on the printed page.
3538  *
3539  * The following messages in the order sends to user hook procedure:
3540  *   WM_PSD_PAGESETUPDLG    Draw the contents of the sample page
3541  *   WM_PSD_FULLPAGERECT    Inform about the bounding rectangle
3542  *   WM_PSD_MINMARGINRECT   Inform about the margin rectangle (min margin?)
3543  *   WM_PSD_MARGINRECT      Draw the margin rectangle
3544  *   WM_PSD_GREEKTEXTRECT   Draw the Greek text inside the margin rectangle
3545  * If any of first three messages returns TRUE, painting done.
3546  *
3547  * PARAMS:
3548  *   hWnd   [in] Handle to the Page Setup dialog box
3549  *   uMsg   [in] Received message
3550  *
3551  * TODO:
3552  *   WM_PSD_ENVSTAMPRECT    Draw in the envelope-stamp rectangle (for envelopes only)
3553  *   WM_PSD_YAFULLPAGERECT  Draw the return address portion (for envelopes and other paper sizes)
3554  *
3555  * RETURNS:
3556  *   FALSE if all done correctly
3557  *
3558  */
3559 
3560 
3561 static LRESULT CALLBACK
3562 PRINTDLG_PagePaintProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3563 {
3564     PAINTSTRUCT ps;
3565     RECT rcClient, rcMargin;
3566     HPEN hpen, holdpen;
3567     HDC hdc;
3568     HBRUSH hbrush, holdbrush;
3569     pagesetup_data *data;
3570     int papersize=0, orientation=0; /* FIXME: set these values for the user paint hook */
3571     double scalx, scaly;
3572 
3573     if (uMsg != WM_PAINT)
3574         return CallWindowProcA(lpfnStaticWndProc, hWnd, uMsg, wParam, lParam);
3575 
3576     /* Processing WM_PAINT message */
3577     data = GetPropW(hWnd, pagesetupdlg_prop);
3578     if (!data) {
3579         WARN("__WINE_PAGESETUPDLGDATA prop not set?\n");
3580         return FALSE;
3581     }
3582     if (default_page_paint_hook(hWnd, WM_PSD_PAGESETUPDLG, MAKELONG(papersize, orientation),
3583                                 pagesetup_get_dlg_struct(data), data))
3584         return FALSE;
3585 
3586     hdc = BeginPaint(hWnd, &ps);
3587     GetClientRect(hWnd, &rcClient);
3588 
3589     scalx = rcClient.right  / (double)pagesetup_get_papersize_pt(data)->x;
3590     scaly = rcClient.bottom / (double)pagesetup_get_papersize_pt(data)->y;
3591     rcMargin = rcClient;
3592 
3593     rcMargin.left   += pagesetup_get_margin_rect(data)->left   * scalx;
3594     rcMargin.top    += pagesetup_get_margin_rect(data)->top    * scaly;
3595     rcMargin.right  -= pagesetup_get_margin_rect(data)->right  * scalx;
3596     rcMargin.bottom -= pagesetup_get_margin_rect(data)->bottom * scaly;
3597 
3598     /* if the space is too small then we make sure to not draw anything */
3599     rcMargin.left = min(rcMargin.left, rcMargin.right);
3600     rcMargin.top = min(rcMargin.top, rcMargin.bottom);
3601 
3602     if (!default_page_paint_hook(hWnd, WM_PSD_FULLPAGERECT, (WPARAM)hdc, (LPARAM)&rcClient, data) &&
3603         !default_page_paint_hook(hWnd, WM_PSD_MINMARGINRECT, (WPARAM)hdc, (LPARAM)&rcMargin, data) )
3604     {
3605         /* fill background */
3606         hbrush = GetSysColorBrush(COLOR_3DHIGHLIGHT);
3607         FillRect(hdc, &rcClient, hbrush);
3608         holdbrush = SelectObject(hdc, hbrush);
3609 
3610         hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
3611         holdpen = SelectObject(hdc, hpen);
3612 
3613         /* paint left edge */
3614         MoveToEx(hdc, rcClient.left, rcClient.top, NULL);
3615         LineTo(hdc, rcClient.left, rcClient.bottom-1);
3616 
3617         /* paint top edge */
3618         MoveToEx(hdc, rcClient.left, rcClient.top, NULL);
3619         LineTo(hdc, rcClient.right, rcClient.top);
3620 
3621         hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DDKSHADOW));
3622         DeleteObject(SelectObject(hdc, hpen));
3623 
3624         /* paint right edge */
3625         MoveToEx(hdc, rcClient.right-1, rcClient.top, NULL);
3626         LineTo(hdc, rcClient.right-1, rcClient.bottom);
3627 
3628         /* paint bottom edge */
3629         MoveToEx(hdc, rcClient.left, rcClient.bottom-1, NULL);
3630         LineTo(hdc, rcClient.right, rcClient.bottom-1);
3631 
3632         DeleteObject(SelectObject(hdc, holdpen));
3633         DeleteObject(SelectObject(hdc, holdbrush));
3634 
3635         default_page_paint_hook(hWnd, WM_PSD_MARGINRECT, (WPARAM)hdc, (LPARAM)&rcMargin, data);
3636 
3637         /* give text a bit of a space from the frame */
3638         InflateRect(&rcMargin, -2, -2);
3639 
3640         /* if the space is too small then we make sure to not draw anything */
3641         rcMargin.left = min(rcMargin.left, rcMargin.right);
3642         rcMargin.top = min(rcMargin.top, rcMargin.bottom);
3643 
3644         default_page_paint_hook(hWnd, WM_PSD_GREEKTEXTRECT, (WPARAM)hdc, (LPARAM)&rcMargin, data);
3645     }
3646 
3647     EndPaint(hWnd, &ps);
3648     return FALSE;
3649 }
3650 
3651 /*******************************************************
3652  * The margin edit controls are subclassed to filter
3653  * anything other than numbers and the decimal separator.
3654  */
3655 static LRESULT CALLBACK pagesetup_margin_editproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
3656 {
3657     if (msg == WM_CHAR)
3658     {
3659         WCHAR decimal = get_decimal_sep();
3660         WCHAR wc = (WCHAR)wparam;
3661         if(!iswdigit(wc) && wc != decimal && wc != VK_BACK) return 0;
3662     }
3663     return CallWindowProcW(edit_wndproc, hwnd, msg, wparam, lparam);
3664 }
3665 
3666 static void subclass_margin_edits(HWND hDlg)
3667 {
3668     int id;
3669     WNDPROC old_proc;
3670 
3671     for(id = edt4; id <= edt7; id++)
3672     {
3673         old_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hDlg, id),
3674                                               GWLP_WNDPROC,
3675                                               (ULONG_PTR)pagesetup_margin_editproc);
3676         InterlockedCompareExchangePointer((void**)&edit_wndproc, old_proc, NULL);
3677     }
3678 }
3679 
3680 /***********************************************************************
3681  *           pagesetup_dlg_proc
3682  *
3683  * Message handler for PageSetupDlg
3684  */
3685 static INT_PTR CALLBACK pagesetup_dlg_proc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
3686 {
3687     pagesetup_data *data;
3688     INT_PTR		res = FALSE;
3689     HWND 		hDrawWnd;
3690 
3691     if (uMsg == WM_INITDIALOG) { /*Init dialog*/
3692         data = (pagesetup_data *)lParam;
3693         data->hDlg = hDlg;
3694 
3695 	hDrawWnd = GetDlgItem(hDlg, rct1);
3696         TRACE("set property to %p\n", data);
3697         SetPropW(hDlg, pagesetupdlg_prop, data);
3698         SetPropW(hDrawWnd, pagesetupdlg_prop, data);
3699         GetWindowRect(hDrawWnd, &data->rtDrawRect); /* Calculating rect in client coordinates where paper draws */
3700         MapWindowPoints( 0, hDlg, (LPPOINT)&data->rtDrawRect, 2 );
3701         lpfnStaticWndProc = (WNDPROC)SetWindowLongPtrW(
3702             hDrawWnd,
3703             GWLP_WNDPROC,
3704             (ULONG_PTR)PRINTDLG_PagePaintProc);
3705 
3706 	/* FIXME: Paint hook. Must it be at begin of initialization or at end? */
3707 	res = TRUE;
3708         if (pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPHOOK)
3709         {
3710             if (!pagesetup_get_hook(data, page_setup_hook)(hDlg, uMsg, wParam,
3711                                                            pagesetup_get_dlg_struct(data)))
3712 		FIXME("Setup page hook failed?\n");
3713 	}
3714 
3715 	/* if printer button disabled */
3716         if (pagesetup_get_flags(data) & PSD_DISABLEPRINTER)
3717             EnableWindow(GetDlgItem(hDlg, psh3), FALSE);
3718 	/* if margin edit boxes disabled */
3719         if (pagesetup_get_flags(data) & PSD_DISABLEMARGINS)
3720         {
3721             EnableWindow(GetDlgItem(hDlg, edt4), FALSE);
3722             EnableWindow(GetDlgItem(hDlg, edt5), FALSE);
3723             EnableWindow(GetDlgItem(hDlg, edt6), FALSE);
3724             EnableWindow(GetDlgItem(hDlg, edt7), FALSE);
3725 	}
3726 
3727         /* Set orientation radiobuttons properly */
3728         pagesetup_update_orientation_buttons(hDlg, data);
3729 
3730 	/* if orientation disabled */
3731         if (pagesetup_get_flags(data) & PSD_DISABLEORIENTATION)
3732         {
3733 	    EnableWindow(GetDlgItem(hDlg,rad1),FALSE);
3734 	    EnableWindow(GetDlgItem(hDlg,rad2),FALSE);
3735 	}
3736 
3737 	/* We fill them out enabled or not */
3738         if (!(pagesetup_get_flags(data) & PSD_MARGINS))
3739         {
3740             /* default is 1 inch */
3741             LONG size = thousandths_inch_to_size(data, 1000);
3742             SetRect(pagesetup_get_margin_rect(data), size, size, size, size);
3743         }
3744         update_margin_edits(hDlg, data, 0);
3745         subclass_margin_edits(hDlg);
3746         set_margin_groupbox_title(hDlg, data);
3747 
3748 	/* if paper disabled */
3749         if (pagesetup_get_flags(data) & PSD_DISABLEPAPER)
3750         {
3751 	    EnableWindow(GetDlgItem(hDlg,cmb2),FALSE);
3752 	    EnableWindow(GetDlgItem(hDlg,cmb3),FALSE);
3753 	}
3754 
3755 	/* filling combos: printer, paper, source. selecting current printer (from DEVMODEA) */
3756         pagesetup_init_combos(hDlg, data);
3757         pagesetup_update_papersize(data);
3758         pagesetup_set_defaultsource(data, DMBIN_FORMSOURCE); /* FIXME: This is the auto select bin. Is this correct? */
3759 
3760 	/* Drawing paper prev */
3761         pagesetup_change_preview(data);
3762 	return TRUE;
3763     } else {
3764         data = GetPropW(hDlg, pagesetupdlg_prop);
3765         if (!data)
3766         {
3767 	    WARN("__WINE_PAGESETUPDLGDATA prop not set?\n");
3768 	    return FALSE;
3769 	}
3770         if (pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPHOOK)
3771         {
3772             res = pagesetup_get_hook(data, page_setup_hook)(hDlg, uMsg, wParam, lParam);
3773 	    if (res) return res;
3774 	}
3775     }
3776     switch (uMsg) {
3777     case WM_COMMAND:
3778         return pagesetup_wm_command(hDlg, wParam, lParam, data);
3779     }
3780     return FALSE;
3781 }
3782 
3783 static WCHAR *get_default_printer(void)
3784 {
3785     WCHAR *name = NULL;
3786     DWORD len = 0;
3787 
3788     GetDefaultPrinterW(NULL, &len);
3789     if(len)
3790     {
3791         name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3792         GetDefaultPrinterW(name, &len);
3793     }
3794     return name;
3795 }
3796 
3797 static void pagesetup_dump_dlg_struct(const pagesetup_data *data)
3798 {
3799     if(TRACE_ON(commdlg))
3800     {
3801         char flagstr[1000] = "";
3802 	const struct pd_flags *pflag = psd_flags;
3803         for( ; pflag->name; pflag++)
3804         {
3805             if(pagesetup_get_flags(data) & pflag->flag)
3806             {
3807                 strcat(flagstr, pflag->name);
3808                 strcat(flagstr, "|");
3809             }
3810         }
3811         TRACE("%s: (%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
3812               "hinst %p, flags %08x (%s)\n",
3813               data->unicode ? "unicode" : "ansi",
3814               data->u.dlgw, data->u.dlgw->hwndOwner, data->u.dlgw->hDevMode,
3815               data->u.dlgw->hDevNames, data->u.dlgw->hInstance,
3816               pagesetup_get_flags(data), flagstr);
3817     }
3818 }
3819 
3820 static void *pagesetup_get_template(pagesetup_data *data)
3821 {
3822     HRSRC res;
3823     HGLOBAL tmpl_handle;
3824 
3825     if(pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPTEMPLATEHANDLE)
3826     {
3827 	tmpl_handle = data->u.dlgw->hPageSetupTemplate;
3828     }
3829     else if(pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPTEMPLATE)
3830     {
3831         if(data->unicode)
3832             res = FindResourceW(data->u.dlgw->hInstance,
3833                                 data->u.dlgw->lpPageSetupTemplateName, (LPWSTR)RT_DIALOG);
3834         else
3835             res = FindResourceA(data->u.dlga->hInstance,
3836                                 data->u.dlga->lpPageSetupTemplateName, (LPSTR)RT_DIALOG);
3837         tmpl_handle = LoadResource(data->u.dlgw->hInstance, res);
3838     }
3839     else
3840     {
3841         res = FindResourceW(COMDLG32_hInstance, MAKEINTRESOURCEW(PAGESETUPDLGORD),
3842                             (LPWSTR)RT_DIALOG);
3843         tmpl_handle = LoadResource(COMDLG32_hInstance, res);
3844     }
3845     return LockResource(tmpl_handle);
3846 }
3847 
3848 static BOOL pagesetup_common(pagesetup_data *data)
3849 {
3850     BOOL ret;
3851     void *tmpl;
3852 
3853     if(!pagesetup_get_dlg_struct(data))
3854     {
3855         COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION);
3856         return FALSE;
3857     }
3858 
3859     pagesetup_dump_dlg_struct(data);
3860 
3861     if(data->u.dlgw->lStructSize != sizeof(PAGESETUPDLGW))
3862     {
3863         COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE);
3864         return FALSE;
3865     }
3866 
3867     if ((pagesetup_get_flags(data) & PSD_ENABLEPAGEPAINTHOOK) &&
3868         (pagesetup_get_hook(data, page_paint_hook) == NULL))
3869     {
3870         COMDLG32_SetCommDlgExtendedError(CDERR_NOHOOK);
3871         return FALSE;
3872     }
3873 
3874     if(!(pagesetup_get_flags(data) & (PSD_INTHOUSANDTHSOFINCHES | PSD_INHUNDREDTHSOFMILLIMETERS)))
3875         data->u.dlgw->Flags |= is_default_metric() ?
3876             PSD_INHUNDREDTHSOFMILLIMETERS : PSD_INTHOUSANDTHSOFINCHES;
3877 
3878     if (!data->u.dlgw->hDevMode || !data->u.dlgw->hDevNames)
3879     {
3880         WCHAR *def = get_default_printer();
3881         if(!def)
3882         {
3883             if (!(pagesetup_get_flags(data) & PSD_NOWARNING))
3884             {
3885                 WCHAR errstr[256];
3886                 LoadStringW(COMDLG32_hInstance, PD32_NO_DEFAULT_PRINTER, errstr, 255);
3887                 MessageBoxW(data->u.dlgw->hwndOwner, errstr, 0, MB_OK | MB_ICONERROR);
3888             }
3889             COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN);
3890             return FALSE;
3891         }
3892         pagesetup_change_printer(def, data);
3893         HeapFree(GetProcessHeap(), 0, def);
3894     }
3895 
3896     if (pagesetup_get_flags(data) & PSD_RETURNDEFAULT)
3897     {
3898         pagesetup_update_papersize(data);
3899         return TRUE;
3900     }
3901 
3902     tmpl = pagesetup_get_template(data);
3903 
3904     ret = DialogBoxIndirectParamW(data->u.dlgw->hInstance, tmpl,
3905                                   data->u.dlgw->hwndOwner,
3906                                   pagesetup_dlg_proc, (LPARAM)data) > 0;
3907     return ret;
3908 }
3909 
3910 /***********************************************************************
3911  *            PageSetupDlgA  (COMDLG32.@)
3912  *
3913  *  Displays the PAGE SETUP dialog box, which enables the user to specify
3914  *  specific properties of a printed page such as
3915  *  size, source, orientation and the width of the page margins.
3916  *
3917  * PARAMS
3918  *  setupdlg [IO] PAGESETUPDLGA struct
3919  *
3920  * RETURNS
3921  *  TRUE    if the user pressed the OK button
3922  *  FALSE   if the user cancelled the window or an error occurred
3923  *
3924  * NOTES
3925  *    The values of hDevMode and hDevNames are filled on output and can be
3926  *    changed in PAGESETUPDLG when they are passed in PageSetupDlg.
3927  *
3928  */
3929 BOOL WINAPI PageSetupDlgA(LPPAGESETUPDLGA setupdlg)
3930 {
3931     pagesetup_data data;
3932 
3933     data.unicode = FALSE;
3934     data.u.dlga  = setupdlg;
3935 
3936     return pagesetup_common(&data);
3937 }
3938 
3939 /***********************************************************************
3940  *            PageSetupDlgW  (COMDLG32.@)
3941  *
3942  * See PageSetupDlgA.
3943  */
3944 BOOL WINAPI PageSetupDlgW(LPPAGESETUPDLGW setupdlg)
3945 {
3946     pagesetup_data data;
3947 
3948     data.unicode = TRUE;
3949     data.u.dlgw  = setupdlg;
3950 
3951     return pagesetup_common(&data);
3952 }
3953 
3954 static void pdlgex_to_pdlg(const PRINTDLGEXW *pdlgex, PRINTDLGW *pdlg)
3955 {
3956     pdlg->lStructSize = sizeof(*pdlg);
3957     pdlg->hwndOwner = pdlgex->hwndOwner;
3958     pdlg->hDevMode = pdlgex->hDevMode;
3959     pdlg->hDevNames = pdlgex->hDevNames;
3960     pdlg->hDC = pdlgex->hDC;
3961     pdlg->Flags = pdlgex->Flags;
3962     if ((pdlgex->Flags & PD_NOPAGENUMS) || !pdlgex->nPageRanges || !pdlgex->lpPageRanges)
3963     {
3964         pdlg->nFromPage = 0;
3965         pdlg->nToPage = 65534;
3966     }
3967     else
3968     {
3969         pdlg->nFromPage = pdlgex->lpPageRanges[0].nFromPage;
3970         pdlg->nToPage = pdlgex->lpPageRanges[0].nToPage;
3971     }
3972     pdlg->nMinPage = pdlgex->nMinPage;
3973     pdlg->nMaxPage = pdlgex->nMaxPage;
3974     pdlg->nCopies = pdlgex->nCopies;
3975     pdlg->hInstance = pdlgex->hInstance;
3976     pdlg->lCustData = 0;
3977     pdlg->lpfnPrintHook = NULL;
3978     pdlg->lpfnSetupHook = NULL;
3979     pdlg->lpPrintTemplateName = pdlgex->lpPrintTemplateName;
3980     pdlg->lpSetupTemplateName = NULL;
3981     pdlg->hPrintTemplate = NULL;
3982     pdlg->hSetupTemplate = NULL;
3983 }
3984 
3985 /* Only copy fields that are supposed to be changed. */
3986 static void pdlg_to_pdlgex(const PRINTDLGW *pdlg, PRINTDLGEXW *pdlgex)
3987 {
3988     pdlgex->hDevMode = pdlg->hDevMode;
3989     pdlgex->hDevNames = pdlg->hDevNames;
3990     pdlgex->hDC = pdlg->hDC;
3991     if (!(pdlgex->Flags & PD_NOPAGENUMS) && pdlgex->nPageRanges && pdlgex->lpPageRanges)
3992     {
3993         pdlgex->lpPageRanges[0].nFromPage = pdlg->nFromPage;
3994         pdlgex->lpPageRanges[0].nToPage = pdlg->nToPage;
3995     }
3996     pdlgex->nMinPage = pdlg->nMinPage;
3997     pdlgex->nMaxPage = pdlg->nMaxPage;
3998     pdlgex->nCopies = pdlg->nCopies;
3999 }
4000 
4001 struct callback_data
4002 {
4003     IPrintDialogCallback *callback;
4004     IObjectWithSite *object;
4005 };
4006 
4007 static UINT_PTR CALLBACK pdlgex_hook_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
4008 {
4009     if (msg == WM_INITDIALOG)
4010     {
4011         PRINTDLGW *pd = (PRINTDLGW *)lp;
4012         struct callback_data *cb = (struct callback_data *)pd->lCustData;
4013 
4014         if (cb->callback)
4015         {
4016             cb->callback->lpVtbl->SelectionChange(cb->callback);
4017             cb->callback->lpVtbl->InitDone(cb->callback);
4018         }
4019     }
4020     else
4021     {
4022 /* FIXME: store interface pointer somewhere in window properties and call it
4023         HRESULT hres;
4024         cb->callback->lpVtbl->HandleMessage(cb->callback, hwnd, msg, wp, lp, &hres);
4025 */
4026     }
4027 
4028     return 0;
4029 }
4030 
4031 /***********************************************************************
4032  * PrintDlgExA (COMDLG32.@)
4033  *
4034  * See PrintDlgExW.
4035  *
4036  * BUGS
4037  *   Only a Stub
4038  *
4039  */
4040 HRESULT WINAPI PrintDlgExA(LPPRINTDLGEXA lppd)
4041 {
4042     PRINTER_INFO_2A *pbuf;
4043     DRIVER_INFO_3A *dbuf;
4044     DEVMODEA *dm;
4045     HRESULT hr = S_OK;
4046     HANDLE hprn;
4047 
4048     if ((lppd == NULL) || (lppd->lStructSize != sizeof(PRINTDLGEXA)))
4049         return E_INVALIDARG;
4050 
4051     if (!IsWindow(lppd->hwndOwner))
4052         return E_HANDLE;
4053 
4054     if (lppd->nStartPage != START_PAGE_GENERAL)
4055     {
4056         if (!lppd->nPropertyPages)
4057             return E_INVALIDARG;
4058 
4059         FIXME("custom property sheets (%d at %p) not supported\n", lppd->nPropertyPages, lppd->lphPropertyPages);
4060     }
4061 
4062     /* Use PD_NOPAGENUMS or set nMaxPageRanges and lpPageRanges */
4063     if (!(lppd->Flags & PD_NOPAGENUMS) && (!lppd->nMaxPageRanges || !lppd->lpPageRanges))
4064     {
4065         return E_INVALIDARG;
4066     }
4067 
4068     if (lppd->Flags & PD_RETURNDEFAULT)
4069     {
4070         if (lppd->hDevMode || lppd->hDevNames)
4071         {
4072             WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
4073             COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE);
4074             return E_INVALIDARG;
4075         }
4076         if (!PRINTDLG_OpenDefaultPrinter(&hprn))
4077         {
4078             WARN("Can't find default printer\n");
4079             COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN);
4080             return E_FAIL;
4081         }
4082 
4083         pbuf = get_printer_infoA(hprn);
4084         if (!pbuf)
4085         {
4086             ClosePrinter(hprn);
4087             return E_FAIL;
4088         }
4089 
4090         dbuf = get_driver_infoA(hprn);
4091         if (!dbuf)
4092         {
4093             HeapFree(GetProcessHeap(), 0, pbuf);
4094             COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE);
4095             ClosePrinter(hprn);
4096             return E_FAIL;
4097         }
4098         dm = pbuf->pDevMode;
4099     }
4100     else
4101     {
4102         PRINTDLGA pdlg;
4103         struct callback_data cb_data = { 0 };
4104 
4105         FIXME("(%p) semi-stub\n", lppd);
4106 
4107         if (lppd->lpCallback)
4108         {
4109             IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IPrintDialogCallback, (void **)&cb_data.callback);
4110             IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IObjectWithSite, (void **)&cb_data.object);
4111         }
4112 
4113         /*
4114          * PRINTDLGEXA/W and PRINTDLGA/W layout is the same for A and W variants.
4115          */
4116         pdlgex_to_pdlg((const PRINTDLGEXW *)lppd, (PRINTDLGW *)&pdlg);
4117         pdlg.Flags |= PD_ENABLEPRINTHOOK;
4118         pdlg.lpfnPrintHook = pdlgex_hook_proc;
4119         pdlg.lCustData = (LPARAM)&cb_data;
4120 
4121         if (PrintDlgA(&pdlg))
4122         {
4123             pdlg_to_pdlgex((const PRINTDLGW *)&pdlg, (PRINTDLGEXW *)lppd);
4124             lppd->dwResultAction = PD_RESULT_PRINT;
4125         }
4126         else
4127             lppd->dwResultAction = PD_RESULT_CANCEL;
4128 
4129         if (cb_data.callback)
4130             cb_data.callback->lpVtbl->Release(cb_data.callback);
4131         if (cb_data.object)
4132             cb_data.object->lpVtbl->Release(cb_data.object);
4133 
4134         return S_OK;
4135     }
4136 
4137     ClosePrinter(hprn);
4138 
4139     PRINTDLG_CreateDevNames(&(lppd->hDevNames), dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName);
4140     if (!lppd->hDevNames)
4141         hr = E_FAIL;
4142 
4143     lppd->hDevMode = update_devmode_handleA(lppd->hDevMode, dm);
4144     if (hr == S_OK && lppd->hDevMode) {
4145         if (lppd->Flags & PD_RETURNDC) {
4146             lppd->hDC = CreateDCA(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, dm);
4147             if (!lppd->hDC)
4148                 hr = E_FAIL;
4149         }
4150         else if (lppd->Flags & PD_RETURNIC) {
4151             lppd->hDC = CreateICA(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, dm);
4152             if (!lppd->hDC)
4153                 hr = E_FAIL;
4154         }
4155     }
4156     else
4157         hr = E_FAIL;
4158 
4159     HeapFree(GetProcessHeap(), 0, pbuf);
4160     HeapFree(GetProcessHeap(), 0, dbuf);
4161 
4162     return hr;
4163 }
4164 
4165 /***********************************************************************
4166  * PrintDlgExW (COMDLG32.@)
4167  *
4168  * Display the property sheet style PRINT dialog box
4169  *
4170  * PARAMS
4171  *  lppd  [IO] ptr to PRINTDLGEX struct
4172  *
4173  * RETURNS
4174  *  Success: S_OK
4175  *  Failure: One of the following COM error codes:
4176  *    E_OUTOFMEMORY Insufficient memory.
4177  *    E_INVALIDARG  One or more arguments are invalid.
4178  *    E_POINTER     Invalid pointer.
4179  *    E_HANDLE      Invalid handle.
4180  *    E_FAIL        Unspecified error.
4181  *
4182  * NOTES
4183  * This Dialog enables the user to specify specific properties of the print job.
4184  * The property sheet can also have additional application-specific and
4185  * driver-specific property pages.
4186  *
4187  * BUGS
4188  *   Not fully implemented
4189  *
4190  */
4191 HRESULT WINAPI PrintDlgExW(LPPRINTDLGEXW lppd)
4192 {
4193     PRINTER_INFO_2W *pbuf;
4194     DRIVER_INFO_3W *dbuf;
4195     DEVMODEW *dm;
4196     HRESULT hr = S_OK;
4197     HANDLE hprn;
4198 
4199     if ((lppd == NULL) || (lppd->lStructSize != sizeof(PRINTDLGEXW))) {
4200         return E_INVALIDARG;
4201     }
4202 
4203     if (!IsWindow(lppd->hwndOwner)) {
4204         return E_HANDLE;
4205     }
4206 
4207     if (lppd->nStartPage != START_PAGE_GENERAL)
4208     {
4209         if (!lppd->nPropertyPages)
4210             return E_INVALIDARG;
4211 
4212         FIXME("custom property sheets (%d at %p) not supported\n", lppd->nPropertyPages, lppd->lphPropertyPages);
4213     }
4214 
4215     /* Use PD_NOPAGENUMS or set nMaxPageRanges and lpPageRanges */
4216     if (!(lppd->Flags & PD_NOPAGENUMS) && (!lppd->nMaxPageRanges || !lppd->lpPageRanges))
4217     {
4218         return E_INVALIDARG;
4219     }
4220 
4221     if (lppd->Flags & PD_RETURNDEFAULT) {
4222 
4223         if (lppd->hDevMode || lppd->hDevNames) {
4224             WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
4225             COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE);
4226             return E_INVALIDARG;
4227         }
4228         if (!PRINTDLG_OpenDefaultPrinter(&hprn)) {
4229             WARN("Can't find default printer\n");
4230             COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN);
4231             return E_FAIL;
4232         }
4233 
4234         pbuf = get_printer_infoW(hprn);
4235         if (!pbuf)
4236         {
4237             ClosePrinter(hprn);
4238             return E_FAIL;
4239         }
4240 
4241         dbuf = get_driver_infoW(hprn);
4242         if (!dbuf)
4243         {
4244             HeapFree(GetProcessHeap(), 0, pbuf);
4245             COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE);
4246             ClosePrinter(hprn);
4247             return E_FAIL;
4248         }
4249         dm = pbuf->pDevMode;
4250     }
4251     else
4252     {
4253         PRINTDLGW pdlg;
4254         struct callback_data cb_data = { 0 };
4255 
4256         FIXME("(%p) semi-stub\n", lppd);
4257 
4258         if (lppd->lpCallback)
4259         {
4260             IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IPrintDialogCallback, (void **)&cb_data.callback);
4261             IUnknown_QueryInterface((IUnknown *)lppd->lpCallback, &IID_IObjectWithSite, (void **)&cb_data.object);
4262         }
4263 
4264         pdlgex_to_pdlg(lppd, &pdlg);
4265         pdlg.Flags |= PD_ENABLEPRINTHOOK;
4266         pdlg.lpfnPrintHook = pdlgex_hook_proc;
4267         pdlg.lCustData = (LPARAM)&cb_data;
4268 
4269         if (PrintDlgW(&pdlg))
4270         {
4271             pdlg_to_pdlgex(&pdlg, lppd);
4272             lppd->dwResultAction = PD_RESULT_PRINT;
4273         }
4274         else
4275             lppd->dwResultAction = PD_RESULT_CANCEL;
4276 
4277         if (cb_data.callback)
4278             cb_data.callback->lpVtbl->Release(cb_data.callback);
4279         if (cb_data.object)
4280             cb_data.object->lpVtbl->Release(cb_data.object);
4281 
4282         return S_OK;
4283     }
4284 
4285     ClosePrinter(hprn);
4286 
4287     PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName);
4288     if (!lppd->hDevNames)
4289         hr = E_FAIL;
4290 
4291     lppd->hDevMode = update_devmode_handleW(lppd->hDevMode, dm);
4292     if (hr == S_OK && lppd->hDevMode) {
4293         if (lppd->Flags & PD_RETURNDC) {
4294             lppd->hDC = CreateDCW(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, dm);
4295             if (!lppd->hDC)
4296                 hr = E_FAIL;
4297         }
4298         else if (lppd->Flags & PD_RETURNIC) {
4299             lppd->hDC = CreateICW(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, dm);
4300             if (!lppd->hDC)
4301                 hr = E_FAIL;
4302         }
4303     }
4304     else
4305         hr = E_FAIL;
4306 
4307     HeapFree(GetProcessHeap(), 0, pbuf);
4308     HeapFree(GetProcessHeap(), 0, dbuf);
4309 
4310     return hr;
4311 }
4312