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