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