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