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