comdlg32: Fix incorrect scaling.
[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 {
2393     LPPAGESETUPDLGA     dlga; /* Handler to user defined struct */
2394     HWND                hDlg; /* Page Setup dialog handler */
2395     RECT                rtDrawRect; /* Drawing rect for page */
2396 } pagesetup_data;
2397
2398 typedef struct {
2399     LPPAGESETUPDLGW     dlgw;
2400     PRINTDLGW           pdlg;
2401     PAGESETUPDLGW       curdlg; /* Current dialog state */
2402 } PageSetupDataW;
2403
2404
2405 static HGLOBAL PRINTDLG_GetPGSTemplateA(const PAGESETUPDLGA *lppd)
2406 {
2407     HRSRC hResInfo;
2408     HGLOBAL hDlgTmpl;
2409         
2410     if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATEHANDLE) {
2411         hDlgTmpl = lppd->hPageSetupTemplate;
2412     } else if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATE) {
2413         hResInfo = FindResourceA(lppd->hInstance,
2414                                  lppd->lpPageSetupTemplateName, (LPSTR)RT_DIALOG);
2415         hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2416     } else {
2417         hResInfo = FindResourceA(COMDLG32_hInstance,(LPCSTR)PAGESETUPDLGORD,(LPSTR)RT_DIALOG);
2418         hDlgTmpl = LoadResource(COMDLG32_hInstance,hResInfo);
2419     }
2420     return hDlgTmpl;
2421 }
2422
2423 static HGLOBAL PRINTDLG_GetPGSTemplateW(const PAGESETUPDLGW *lppd)
2424 {
2425     HRSRC hResInfo;
2426     HGLOBAL hDlgTmpl;
2427
2428     if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATEHANDLE) {
2429         hDlgTmpl = lppd->hPageSetupTemplate;
2430     } else if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATE) {
2431         hResInfo = FindResourceW(lppd->hInstance,
2432                                  lppd->lpPageSetupTemplateName, (LPWSTR)RT_DIALOG);
2433         hDlgTmpl = LoadResource(lppd->hInstance, hResInfo);
2434     } else {
2435         hResInfo = FindResourceW(COMDLG32_hInstance,(LPCWSTR)PAGESETUPDLGORD,(LPWSTR)RT_DIALOG);
2436         hDlgTmpl = LoadResource(COMDLG32_hInstance,hResInfo);
2437     }
2438     return hDlgTmpl;
2439 }
2440
2441 static inline DWORD pagesetup_get_flags(const pagesetup_data *data)
2442 {
2443     return data->dlga->Flags;
2444 }
2445
2446 static inline BOOL is_metric(const pagesetup_data *data)
2447 {
2448     return pagesetup_get_flags(data) & PSD_INHUNDREDTHSOFMILLIMETERS;
2449 }
2450
2451 static inline LONG tenths_mm_to_size(pagesetup_data *data, LONG size)
2452 {
2453     if (is_metric(data))
2454         return 10 * size;
2455     else
2456         return 10 * size * 100 / 254;
2457 }
2458
2459 static inline LONG thousandths_inch_to_size(pagesetup_data *data, LONG size)
2460 {
2461     if (is_metric(data))
2462         return size * 254 / 100;
2463     else
2464         return size;
2465 }
2466
2467 static DWORD
2468 _c_10mm2size(PAGESETUPDLGW *dlga,DWORD size) {
2469     if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES)
2470         return 10*size*100/254;
2471     return 10*size;
2472 }
2473
2474
2475 static DWORD
2476 _c_inch2size(PAGESETUPDLGW *dlga,DWORD size) {
2477     if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES)
2478         return size;
2479     else
2480         return (size*254)/100;
2481 }
2482
2483 static WCHAR get_decimal_sep(void)
2484 {
2485     static WCHAR sep;
2486
2487     if(!sep)
2488     {
2489         WCHAR buf[2] = {'.',0};
2490         GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buf, sizeof(buf) / sizeof(buf[0]));
2491         sep = buf[0];
2492     }
2493     return sep;
2494 }
2495
2496 static void size2str(const pagesetup_data *data, DWORD size, LPWSTR strout)
2497 {
2498     WCHAR integer_fmt[] = {'%','d',0};
2499     WCHAR hundredths_fmt[] = {'%','d','%','c','%','0','2','d',0};
2500     WCHAR thousandths_fmt[] = {'%','d','%','c','%','0','3','d',0};
2501
2502     /* FIXME use LOCALE_SDECIMAL when the edit parsing code can cope */
2503
2504     if (is_metric(data))
2505     {
2506         if(size % 100)
2507             wsprintfW(strout, hundredths_fmt, size / 100, get_decimal_sep(), size % 100);
2508         else
2509             wsprintfW(strout, integer_fmt, size / 100);
2510     }
2511     else
2512     {
2513         if(size % 1000)
2514             wsprintfW(strout, thousandths_fmt, size / 1000, get_decimal_sep(), size % 1000);
2515         else
2516             wsprintfW(strout, integer_fmt, size / 1000);
2517
2518     }
2519 }
2520
2521 static void
2522 _c_size2strW(PageSetupDataW *pdw,DWORD size,LPWSTR strout) {
2523     static const char mm_fmt[] = "%.2f mm";
2524     static const char in_fmt[] = "%.2f in";
2525     char buf[20];
2526     if (pdw->dlgw->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) {
2527         sprintf(buf, mm_fmt, (size * 1.0) / 100.0);
2528     } else if (pdw->dlgw->Flags & PSD_INTHOUSANDTHSOFINCHES) {
2529         sprintf(buf, in_fmt, (size * 1.0) / 1000.0);
2530     } else {
2531         pdw->dlgw->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS;
2532         sprintf(buf, mm_fmt, (size * 1.0) / 100.0);
2533     }
2534
2535     MultiByteToWideChar(CP_ACP, 0, buf, -1, strout, 20);
2536 }
2537
2538 static DWORD
2539 _c_str2sizeA(const PAGESETUPDLGA *dlga, LPCSTR strin) {
2540     float       val;
2541     char        rest[200];
2542
2543     rest[0]='\0';
2544     if (!sscanf(strin,"%f%s",&val,rest))
2545         return 0;
2546
2547     if (!strcmp(rest,"in") || !strcmp(rest,"inch")) {
2548         if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES)
2549             return 1000*val;
2550         else
2551             return val*25.4*100;
2552     }
2553     if (!strcmp(rest,"cm")) { rest[0]='m'; val = val*10.0; }
2554     if (!strcmp(rest,"m")) { strcpy(rest,"mm"); val = val*1000.0; }
2555
2556     if (!strcmp(rest,"mm")) {
2557         if (dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS)
2558             return 100*val;
2559         else
2560             return 1000.0*val/25.4;
2561     }
2562     if (rest[0]=='\0') {
2563         /* use application supplied default */
2564         if (dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) {
2565             /* 100*mm */
2566             return 100.0*val;
2567         }
2568         if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) {
2569             /* 1000*inch */
2570             return 1000.0*val;
2571         }
2572     }
2573     ERR("Did not find a conversion for type '%s'!\n",rest);
2574     return 0;
2575 }
2576
2577
2578 static DWORD
2579 _c_str2sizeW(const PAGESETUPDLGW *dlga, LPCWSTR strin) {
2580     char        buf[200];
2581
2582     /* this W -> A transition is OK */
2583     /* we need a unicode version of sscanf to avoid it */
2584     WideCharToMultiByte(CP_ACP, 0, strin, -1, buf, sizeof(buf), NULL, NULL);
2585     return _c_str2sizeA((const PAGESETUPDLGA *)dlga, buf);
2586 }
2587
2588 static inline BOOL is_default_metric(void)
2589 {
2590     DWORD system;
2591     GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER,
2592                    (LPWSTR)&system, sizeof(system));
2593     return system == 0;
2594 }
2595
2596 /**********************************************
2597  *           rotate_rect
2598  * Cyclically permute the four members of rc
2599  * If sense is TRUE l -> t -> r -> b
2600  * otherwise        l <- t <- r <- b
2601  */
2602 static inline void rotate_rect(RECT *rc, BOOL sense)
2603 {
2604     INT tmp;
2605     if(sense)
2606     {
2607         tmp        = rc->bottom;
2608         rc->bottom = rc->right;
2609         rc->right  = rc->top;
2610         rc->top    = rc->left;
2611         rc->left   = tmp;
2612     }
2613     else
2614     {
2615         tmp        = rc->left;
2616         rc->left   = rc->top;
2617         rc->top    = rc->right;
2618         rc->right  = rc->bottom;
2619         rc->bottom = tmp;
2620     }
2621 }
2622
2623 static void pagesetup_set_orientation(pagesetup_data *data, WORD orient)
2624 {
2625     DEVMODEA *dm = GlobalLock(data->dlga->hDevMode);
2626
2627     assert(orient == DMORIENT_PORTRAIT || orient == DMORIENT_LANDSCAPE);
2628
2629     dm->u1.s1.dmOrientation = orient;
2630     GlobalUnlock(data->dlga->hDevMode);
2631 }
2632
2633 static WORD pagesetup_get_orientation(const pagesetup_data *data)
2634 {
2635     DEVMODEA *dm = GlobalLock(data->dlga->hDevMode);
2636     WORD orient = dm->u1.s1.dmOrientation;
2637     GlobalUnlock(data->dlga->hDevMode);
2638     return orient;
2639 }
2640
2641 static void pagesetup_set_papersize(pagesetup_data *data, WORD paper)
2642 {
2643     DEVMODEA *dm = GlobalLock(data->dlga->hDevMode);
2644     dm->u1.s1.dmPaperSize = paper;
2645     GlobalUnlock(data->dlga->hDevMode);
2646 }
2647
2648 static WORD pagesetup_get_papersize(const pagesetup_data *data)
2649 {
2650     DEVMODEA *dm = GlobalLock(data->dlga->hDevMode);
2651     WORD paper = dm->u1.s1.dmPaperSize;
2652     GlobalUnlock(data->dlga->hDevMode);
2653     return paper;
2654 }
2655
2656 static void pagesetup_set_defaultsource(pagesetup_data *data, WORD source)
2657 {
2658     DEVMODEA *dm = GlobalLock(data->dlga->hDevMode);
2659     dm->u1.s1.dmDefaultSource = source;
2660     GlobalUnlock(data->dlga->hDevMode);
2661 }
2662
2663 static WCHAR *pagesetup_get_drvname(const pagesetup_data *data)
2664 {
2665     DEVNAMES *dn;
2666     int len;
2667     WCHAR *name;
2668
2669     dn = GlobalLock(data->dlga->hDevNames);
2670     len = MultiByteToWideChar(CP_ACP, 0, (char*)dn + dn->wDriverOffset, -1, NULL, 0);
2671     name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2672     MultiByteToWideChar(CP_ACP, 0, (char*)dn + dn->wDriverOffset, -1, name, len);
2673     GlobalUnlock(data->dlga->hDevNames);
2674     return name;
2675 }
2676
2677 static void pagesetup_release_drvname(const pagesetup_data *data, WCHAR *name)
2678 {
2679     HeapFree(GetProcessHeap(), 0, name);
2680 }
2681
2682 static WCHAR *pagesetup_get_devname(const pagesetup_data *data)
2683 {
2684     DEVNAMES *dn;
2685     int len;
2686     WCHAR *name;
2687
2688     dn = GlobalLock(data->dlga->hDevNames);
2689     len = MultiByteToWideChar(CP_ACP, 0, (char*)dn + dn->wDeviceOffset, -1, NULL, 0);
2690     name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2691     MultiByteToWideChar(CP_ACP, 0, (char*)dn + dn->wDeviceOffset, -1, name, len);
2692     GlobalUnlock(data->dlga->hDevNames);
2693     return name;
2694 }
2695
2696 static void pagesetup_release_devname(const pagesetup_data *data, WCHAR *name)
2697 {
2698     HeapFree(GetProcessHeap(), 0, name);
2699 }
2700
2701 static WCHAR *pagesetup_get_portname(const pagesetup_data *data)
2702 {
2703     DEVNAMES *dn;
2704     int len;
2705     WCHAR *name;
2706
2707     dn = GlobalLock(data->dlga->hDevNames);
2708     len = MultiByteToWideChar(CP_ACP, 0, (char*)dn + dn->wOutputOffset, -1, NULL, 0);
2709     name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2710     MultiByteToWideChar(CP_ACP, 0, (char*)dn + dn->wOutputOffset, -1, name, len);
2711     GlobalUnlock(data->dlga->hDevNames);
2712     return name;
2713 }
2714
2715 static void pagesetup_release_portname(const pagesetup_data *data, WCHAR *name)
2716 {
2717     HeapFree(GetProcessHeap(), 0, name);
2718 }
2719
2720 static void pagesetup_set_devnames(pagesetup_data *data, LPCWSTR drv, LPCWSTR devname, LPCWSTR port)
2721 {
2722     DEVNAMES *dn;
2723     char *ptr;
2724     WCHAR def[256];
2725     DWORD len = sizeof(DEVNAMES), drv_len, dev_len, port_len;
2726     drv_len = WideCharToMultiByte(CP_ACP, 0, drv, -1, NULL, 0, NULL, NULL);
2727     dev_len = WideCharToMultiByte(CP_ACP, 0, devname, -1, NULL, 0, NULL, NULL);
2728     port_len = WideCharToMultiByte(CP_ACP, 0, port, -1, NULL, 0, NULL, NULL);
2729
2730     len += drv_len + dev_len + port_len;
2731
2732     data->dlga->hDevNames = GlobalReAlloc(data->dlga->hDevNames, len, GMEM_MOVEABLE);
2733     dn = GlobalLock(data->dlga->hDevNames);
2734
2735     ptr = (char *)(dn + 1);
2736     len = sizeof(DEVNAMES);
2737     dn->wDriverOffset = len;
2738     WideCharToMultiByte(CP_ACP, 0, drv, -1, ptr, drv_len, NULL, NULL);
2739     ptr += drv_len;
2740     len += drv_len;
2741     dn->wDeviceOffset = len;
2742     WideCharToMultiByte(CP_ACP, 0, devname, -1, ptr, dev_len, NULL, NULL);
2743     ptr += dev_len;
2744     len += dev_len;
2745     dn->wOutputOffset = len;
2746     WideCharToMultiByte(CP_ACP, 0, port, -1, ptr, port_len, NULL, NULL);
2747
2748     dn->wDefault = 0;
2749     len = sizeof(def) / sizeof(def[0]);
2750     GetDefaultPrinterW(def, &len);
2751     if(!lstrcmpW(def, devname))
2752         dn->wDefault = 1;
2753
2754     GlobalUnlock(data->dlga->hDevNames);
2755 }
2756
2757 static DEVMODEW *pagesetup_get_devmode(const pagesetup_data *data)
2758 {
2759     DEVMODEA *dm;
2760     DEVMODEW *dmW;
2761
2762     dm = GlobalLock(data->dlga->hDevMode);
2763     dmW = GdiConvertToDevmodeW(dm);
2764     GlobalUnlock(data->dlga->hDevMode);
2765     return dmW;
2766 }
2767
2768 static void pagesetup_release_devmode(const pagesetup_data *data, DEVMODEW *dm)
2769 {
2770     HeapFree(GetProcessHeap(), 0, dm);
2771 }
2772
2773 static void pagesetup_set_devmode(pagesetup_data *data, DEVMODEW *dm)
2774 {
2775     DEVMODEA *dmA, *tmp_dm;
2776
2777     tmp_dm = convert_to_devmodeA(dm);
2778     data->dlga->hDevMode = GlobalReAlloc(data->dlga->hDevMode,
2779                                          tmp_dm->dmSize + tmp_dm->dmDriverExtra,
2780                                          GMEM_MOVEABLE);
2781     dmA = GlobalLock(data->dlga->hDevMode);
2782     memcpy(dmA, tmp_dm, tmp_dm->dmSize + tmp_dm->dmDriverExtra);
2783     GlobalUnlock(data->dlga->hDevMode);
2784     HeapFree(GetProcessHeap(), 0, tmp_dm);
2785 }
2786
2787 static inline POINT *pagesetup_get_papersize_pt(const pagesetup_data *data)
2788 {
2789     return &data->dlga->ptPaperSize;
2790 }
2791
2792 static inline RECT *pagesetup_get_margin_rect(const pagesetup_data *data)
2793 {
2794     return &data->dlga->rtMargin;
2795 }
2796
2797 static inline void swap_point(POINT *pt)
2798 {
2799     LONG tmp = pt->x;
2800     pt->x = pt->y;
2801     pt->y = tmp;
2802 }
2803
2804 static BOOL pagesetup_update_papersize(pagesetup_data *data)
2805 {
2806     DEVMODEW *dm;
2807     LPWSTR devname, portname;
2808     int i, num;
2809     WORD *words = NULL, paperword;
2810     POINT *points = NULL;
2811     BOOL retval = FALSE;
2812
2813     dm       = pagesetup_get_devmode(data);
2814     devname  = pagesetup_get_devname(data);
2815     portname = pagesetup_get_portname(data);
2816
2817     num = DeviceCapabilitiesW(devname, portname, DC_PAPERS, NULL, dm);
2818     if (num <= 0)
2819     {
2820         FIXME("No papernames found for %s/%s\n", debugstr_w(devname), debugstr_w(portname));
2821         goto end;
2822     }
2823
2824     words = HeapAlloc(GetProcessHeap(), 0, num * sizeof(WORD));
2825     points = HeapAlloc(GetProcessHeap(), 0, num * sizeof(POINT));
2826
2827     if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERS, (LPWSTR)words, dm))
2828     {
2829         FIXME("Number of returned words is not %d\n", num);
2830         goto end;
2831     }
2832
2833     if (num != DeviceCapabilitiesW(devname, portname, DC_PAPERSIZE, (LPWSTR)points, dm))
2834     {
2835         FIXME("Number of returned sizes is not %d\n", num);
2836         goto end;
2837     }
2838
2839     paperword = pagesetup_get_papersize(data);
2840
2841     for (i = 0; i < num; i++)
2842         if (words[i] == paperword)
2843             break;
2844
2845     if (i == num)
2846     {
2847         FIXME("Papersize %d not found in list?\n", paperword);
2848         goto end;
2849     }
2850
2851     /* this is _10ths_ of a millimeter */
2852     pagesetup_get_papersize_pt(data)->x = tenths_mm_to_size(data, points[i].x);
2853     pagesetup_get_papersize_pt(data)->y = tenths_mm_to_size(data, points[i].y);
2854
2855     if(pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE)
2856         swap_point(pagesetup_get_papersize_pt(data));
2857
2858     retval = TRUE;
2859
2860 end:
2861     HeapFree(GetProcessHeap(), 0, words);
2862     HeapFree(GetProcessHeap(), 0, points);
2863     pagesetup_release_portname(data, portname);
2864     pagesetup_release_devname(data, devname);
2865     pagesetup_release_devmode(data, dm);
2866
2867     return retval;
2868 }
2869
2870 static BOOL
2871 PRINTDLG_PS_UpdateDlgStructW(HWND hDlg, PageSetupDataW *pdw) {
2872     DEVNAMES    *dn;
2873     DEVMODEW    *dm;
2874     LPWSTR      devname,portname;
2875     WCHAR       papername[64];
2876     WCHAR       buf[200];
2877
2878     dn = GlobalLock(pdw->pdlg.hDevNames);
2879     dm = GlobalLock(pdw->pdlg.hDevMode);
2880     devname     = ((WCHAR*)dn)+dn->wDeviceOffset;
2881     portname    = ((WCHAR*)dn)+dn->wOutputOffset;
2882
2883     /* Save paper size into device context */
2884     PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb2,devname,portname,dm);
2885     /* Save paper source into device context */
2886     PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb3,devname,portname,dm);
2887
2888     if (GetDlgItemTextW(hDlg,cmb2,papername,sizeof(papername)/sizeof(papername[0]))>0) {
2889         PRINTDLG_PaperSizeW(&(pdw->pdlg),papername,&(pdw->dlgw->ptPaperSize));
2890         pdw->dlgw->ptPaperSize.x = _c_10mm2size(pdw->dlgw,pdw->dlgw->ptPaperSize.x);
2891         pdw->dlgw->ptPaperSize.y = _c_10mm2size(pdw->dlgw,pdw->dlgw->ptPaperSize.y);
2892     } else
2893         FIXME("could not get dialog text for papersize cmbbox?\n");
2894 #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); }
2895     GETVAL(edt4,pdw->dlgw->rtMargin.left);
2896     GETVAL(edt5,pdw->dlgw->rtMargin.top);
2897     GETVAL(edt6,pdw->dlgw->rtMargin.right);
2898     GETVAL(edt7,pdw->dlgw->rtMargin.bottom);
2899 #undef GETVAL
2900
2901     /* If we are in landscape, swap x and y of page size */
2902     if (IsDlgButtonChecked(hDlg, rad2)) {
2903         DWORD tmp;
2904         tmp = pdw->dlgw->ptPaperSize.x;
2905         pdw->dlgw->ptPaperSize.x = pdw->dlgw->ptPaperSize.y;
2906         pdw->dlgw->ptPaperSize.y = tmp;
2907     }
2908
2909     /* Save orientation */
2910     if (pdw->dlgw->ptPaperSize.x > pdw->dlgw->ptPaperSize.y)
2911         dm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
2912     else
2913         dm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2914
2915     GlobalUnlock(pdw->pdlg.hDevNames);
2916     GlobalUnlock(pdw->pdlg.hDevMode);
2917     return TRUE;
2918 }
2919
2920 /**********************************************************************************************
2921  * pagesetup_change_printer
2922  *
2923  * Redefines hDevMode and hDevNames HANDLES and initialises it.
2924  * 
2925  */
2926 static BOOL pagesetup_change_printer(LPWSTR name, pagesetup_data *data)
2927 {
2928     HANDLE hprn;
2929     DWORD needed;
2930     PRINTER_INFO_2W *prn_info = NULL;
2931     DRIVER_INFO_3W *drv_info = NULL;
2932     DEVMODEW *dm = NULL;
2933     BOOL retval = FALSE;
2934
2935     if(!OpenPrinterW(name, &hprn, NULL))
2936     {
2937         ERR("Can't open printer %s\n", debugstr_w(name));
2938         goto end;
2939     }
2940
2941     GetPrinterW(hprn, 2, NULL, 0, &needed);
2942     prn_info = HeapAlloc(GetProcessHeap(), 0, needed);
2943     GetPrinterW(hprn, 2, (LPBYTE)prn_info, needed, &needed);
2944     GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed);
2945     drv_info = HeapAlloc(GetProcessHeap(), 0, needed);
2946     if(!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)drv_info, needed, &needed))
2947     {
2948         ERR("GetPrinterDriverA failed for %s, fix your config!\n", debugstr_w(prn_info->pPrinterName));
2949         goto end;
2950     }
2951     ClosePrinter(hprn);
2952
2953     needed = DocumentPropertiesW(0, 0, name, NULL, NULL, 0);
2954     if(needed == -1)
2955     {
2956         ERR("DocumentProperties fails on %s\n", debugstr_w(name));
2957         goto end;
2958     }
2959
2960     dm = HeapAlloc(GetProcessHeap(), 0, needed);
2961     DocumentPropertiesW(0, 0, name, dm, NULL, DM_OUT_BUFFER);
2962
2963     pagesetup_set_devmode(data, dm);
2964     pagesetup_set_devnames(data, drv_info->pDriverPath, prn_info->pPrinterName,
2965                            prn_info->pPortName);
2966
2967     retval = TRUE;
2968 end:
2969     HeapFree(GetProcessHeap(), 0, dm);
2970     HeapFree(GetProcessHeap(), 0, prn_info);
2971     HeapFree(GetProcessHeap(), 0, drv_info);
2972     return retval;
2973 }
2974
2975 /****************************************************************************************
2976  *  pagesetup_init_combos
2977  *
2978  *  Fills Printers, Paper and Source combos
2979  *
2980  */
2981 static void pagesetup_init_combos(HWND hDlg, pagesetup_data *data)
2982 {
2983     DEVMODEW *dm;
2984     LPWSTR devname, portname;
2985
2986     dm       = pagesetup_get_devmode(data);
2987     devname  = pagesetup_get_devname(data);
2988     portname = pagesetup_get_portname(data);
2989
2990     PRINTDLG_SetUpPrinterListComboW(hDlg, cmb1, devname);
2991     PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2, devname, portname, dm);
2992     PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3, devname, portname, dm);
2993
2994     pagesetup_release_portname(data, portname);
2995     pagesetup_release_devname(data, devname);
2996     pagesetup_release_devmode(data, dm);
2997 }
2998
2999
3000 /****************************************************************************************
3001  *  pagesetup_change_printer_dialog
3002  *
3003  *  Pops up another dialog that lets the user pick another printer.
3004  *
3005  *  For now we display the PrintDlg, this should display a striped down version of it.
3006  */
3007 static void pagesetup_change_printer_dialog(HWND hDlg, pagesetup_data *data)
3008 {
3009     PRINTDLGW prnt;
3010     LPWSTR drvname, devname, portname;
3011     DEVMODEW *tmp_dm, *dm;
3012
3013     memset(&prnt, 0, sizeof(prnt));
3014     prnt.lStructSize = sizeof(prnt);
3015     prnt.Flags     = 0;
3016     prnt.hwndOwner = hDlg;
3017
3018     drvname = pagesetup_get_drvname(data);
3019     devname = pagesetup_get_devname(data);
3020     portname = pagesetup_get_portname(data);
3021     prnt.hDevNames = 0;
3022     PRINTDLG_CreateDevNamesW(&prnt.hDevNames, drvname, devname, portname);
3023     pagesetup_release_portname(data, portname);
3024     pagesetup_release_devname(data, devname);
3025     pagesetup_release_drvname(data, drvname);
3026
3027     tmp_dm = pagesetup_get_devmode(data);
3028     prnt.hDevMode = GlobalAlloc(GMEM_MOVEABLE, tmp_dm->dmSize + tmp_dm->dmDriverExtra);
3029     dm = GlobalLock(prnt.hDevMode);
3030     memcpy(dm, tmp_dm, tmp_dm->dmSize + tmp_dm->dmDriverExtra);
3031     GlobalUnlock(prnt.hDevMode);
3032     pagesetup_release_devmode(data, tmp_dm);
3033
3034     if (PrintDlgW(&prnt))
3035     {
3036         DEVMODEW *dm = GlobalLock(prnt.hDevMode);
3037         DEVNAMES *dn = GlobalLock(prnt.hDevNames);
3038
3039         pagesetup_set_devnames(data, (WCHAR*)dn + dn->wDriverOffset,
3040                                (WCHAR*)dn + dn->wDeviceOffset, (WCHAR *)dn + dn->wOutputOffset);
3041         pagesetup_set_devmode(data, dm);
3042         GlobalUnlock(prnt.hDevNames);
3043         GlobalUnlock(prnt.hDevMode);
3044         pagesetup_init_combos(hDlg, data);
3045     }
3046
3047     GlobalFree(prnt.hDevMode);
3048     GlobalFree(prnt.hDevNames);
3049
3050 }
3051
3052 static void PRINTDLG_PS_SetOrientationW(HWND hDlg, PageSetupDataW* pdw)
3053 {
3054     WCHAR PaperName[64];
3055
3056     GetDlgItemTextW(hDlg, cmb2, PaperName, sizeof(PaperName)/sizeof(WCHAR));
3057     PRINTDLG_PaperSizeW(&pdw->pdlg, PaperName, &pdw->curdlg.ptPaperSize);
3058     pdw->curdlg.ptPaperSize.x = _c_10mm2size(pdw->dlgw, pdw->curdlg.ptPaperSize.x);
3059     pdw->curdlg.ptPaperSize.y = _c_10mm2size(pdw->dlgw, pdw->curdlg.ptPaperSize.y);
3060
3061     if(IsDlgButtonChecked(hDlg, rad2))
3062     {
3063         DWORD tmp = pdw->curdlg.ptPaperSize.x;
3064         pdw->curdlg.ptPaperSize.x = pdw->curdlg.ptPaperSize.y;
3065         pdw->curdlg.ptPaperSize.y = tmp;
3066     }
3067 }
3068
3069 static void PRINTDLG_PS_UpdatePrintDlgW(PageSetupDataW* pdw, HWND hDlg)
3070 {
3071     DEVMODEW* dm;
3072     DWORD sel;
3073
3074     dm = GlobalLock(pdw->pdlg.hDevMode);
3075
3076     if(!dm)
3077         return;
3078
3079     if(pdw->curdlg.ptPaperSize.y > pdw->curdlg.ptPaperSize.x)
3080         dm->u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3081     else
3082         dm->u1.s1.dmOrientation = DMORIENT_LANDSCAPE;
3083
3084     sel = SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0);
3085
3086     if(sel != CB_ERR)
3087         dm->u1.s1.dmPaperSize = SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, sel, 0);
3088
3089     GlobalUnlock(pdw->pdlg.hDevMode);
3090 }
3091
3092 static BOOL
3093 PRINTDLG_PS_ChangePrinterW(HWND hDlg, PageSetupDataW *pdw) {
3094     DEVNAMES    *dn;
3095     DEVMODEW    *dm;
3096     LPWSTR      devname,portname;
3097
3098     dn = GlobalLock(pdw->pdlg.hDevNames);
3099     dm = GlobalLock(pdw->pdlg.hDevMode);
3100     devname     = ((WCHAR*)dn)+dn->wDeviceOffset;
3101     portname    = ((WCHAR*)dn)+dn->wOutputOffset;
3102     PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb2,devname,portname,dm);
3103     PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb3,devname,portname,dm);
3104
3105     /* Landscape orientation */
3106     if (dm->u1.s1.dmOrientation == DMORIENT_LANDSCAPE)
3107         CheckRadioButton(hDlg, rad1, rad2, rad2);
3108     else /* this is default if papersize is not set */
3109         CheckRadioButton(hDlg, rad1, rad2, rad1);
3110
3111     GlobalUnlock(pdw->pdlg.hDevNames);
3112     GlobalUnlock(pdw->pdlg.hDevMode);
3113
3114     PRINTDLG_PS_SetOrientationW(hDlg, pdw);
3115
3116     return TRUE;
3117 }
3118
3119 /******************************************************************************************
3120  * pagesetup_change_preview
3121  *
3122  * Changes paper preview size / position
3123  *
3124  */
3125 static void pagesetup_change_preview(const pagesetup_data *data)
3126 {
3127     LONG width, height, x, y;
3128     RECT tmp;
3129     const int shadow = 4;
3130
3131     if(pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE)
3132     {
3133         width  = data->rtDrawRect.right - data->rtDrawRect.left;
3134         height = pagesetup_get_papersize_pt(data)->y * width / pagesetup_get_papersize_pt(data)->x;
3135     }
3136     else
3137     {
3138         height = data->rtDrawRect.bottom - data->rtDrawRect.top;
3139         width  = pagesetup_get_papersize_pt(data)->x * height / pagesetup_get_papersize_pt(data)->y;
3140     }
3141     x = (data->rtDrawRect.right + data->rtDrawRect.left - width) / 2;
3142     y = (data->rtDrawRect.bottom + data->rtDrawRect.top - height) / 2;
3143     TRACE("draw rect %s x=%d, y=%d, w=%d, h=%d\n",
3144           wine_dbgstr_rect(&data->rtDrawRect), x, y, width, height);
3145
3146     MoveWindow(GetDlgItem(data->hDlg, rct2), x + width, y + shadow, shadow, height, FALSE);
3147     MoveWindow(GetDlgItem(data->hDlg, rct3), x + shadow, y + height, width, shadow, FALSE);
3148     MoveWindow(GetDlgItem(data->hDlg, rct1), x, y, width, height, FALSE);
3149
3150     tmp = data->rtDrawRect;
3151     tmp.right  += shadow;
3152     tmp.bottom += shadow;
3153     InvalidateRect(data->hDlg, &tmp, TRUE);
3154 }
3155
3156 static inline LONG *element_from_margin_id(RECT *rc, WORD id)
3157 {
3158     switch(id)
3159     {
3160     case edt4: return &rc->left;
3161     case edt5: return &rc->top;
3162     case edt6: return &rc->right;
3163     case edt7: return &rc->bottom;
3164     }
3165     return NULL;
3166 }
3167
3168 static void update_margin_edits(HWND hDlg, const pagesetup_data *data, WORD id)
3169 {
3170     WCHAR str[100];
3171     WORD idx;
3172
3173     for(idx = edt4; idx <= edt7; idx++)
3174     {
3175         if(id == 0 || id == idx)
3176         {
3177             size2str(data, *element_from_margin_id(pagesetup_get_margin_rect(data), idx), str);
3178             SetDlgItemTextW(hDlg, idx, str);
3179         }
3180     }
3181 }
3182
3183 static void margin_edit_notification(HWND hDlg, pagesetup_data *data, WORD msg, WORD id)
3184 {
3185     switch (msg)
3186     {
3187     case EN_CHANGE:
3188       {
3189         WCHAR buf[10];
3190         LONG val = 0;
3191         LONG *value = element_from_margin_id(pagesetup_get_margin_rect(data), id);
3192
3193         if (GetDlgItemTextW(hDlg, id, buf, sizeof(buf) / sizeof(buf[0])) != 0)
3194         {
3195             WCHAR *end;
3196             WCHAR decimal = get_decimal_sep();
3197
3198             val = strtolW(buf, &end, 10);
3199             if(end != buf || *end == decimal)
3200             {
3201                 int mult = is_metric(data) ? 100 : 1000;
3202                 val *= mult;
3203                 if(*end == decimal)
3204                 {
3205                     while(mult > 1)
3206                     {
3207                         end++;
3208                         mult /= 10;
3209                         if(isdigitW(*end))
3210                             val += (*end - '0') * mult;
3211                         else
3212                             break;
3213                     }
3214                 }
3215             }
3216         }
3217         *value = val;
3218         return;
3219       }
3220
3221     case EN_KILLFOCUS:
3222         update_margin_edits(hDlg, data, id);
3223         return;
3224     }
3225 }
3226
3227 static void set_margin_groupbox_title(HWND hDlg, const pagesetup_data *data)
3228 {
3229     WCHAR title[256];
3230
3231     if(LoadStringW(COMDLG32_hInstance, is_metric(data) ? PD32_MARGINS_IN_MILLIMETERS : PD32_MARGINS_IN_INCHES,
3232                    title, sizeof(title)/sizeof(title[0])))
3233         SetDlgItemTextW(hDlg, grp4, title);
3234 }
3235
3236 static void pagesetup_update_orientation_buttons(HWND hDlg, const pagesetup_data *data)
3237 {
3238     if (pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE)
3239         CheckRadioButton(hDlg, rad1, rad2, rad2);
3240     else
3241         CheckRadioButton(hDlg, rad1, rad2, rad1);
3242 }
3243
3244 /****************************************************************************************
3245  *  pagesetup_printer_properties
3246  *
3247  *  Handle invocation of the 'Properties' button (not present in the default template).
3248  */
3249 static void pagesetup_printer_properties(HWND hDlg, pagesetup_data *data)
3250 {
3251     HANDLE hprn;
3252     LPWSTR devname;
3253     DEVMODEW *dm;
3254     LRESULT count;
3255     int i;
3256
3257     devname = pagesetup_get_devname(data);
3258
3259     if (!OpenPrinterW(devname, &hprn, NULL))
3260     {
3261         FIXME("Call to OpenPrinter did not succeed!\n");
3262         pagesetup_release_devname(data, devname);
3263         return;
3264     }
3265
3266     dm = pagesetup_get_devmode(data);
3267     DocumentPropertiesW(hDlg, hprn, devname, dm, dm, DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT);
3268     pagesetup_set_devmode(data, dm);
3269     pagesetup_release_devmode(data, dm);
3270     pagesetup_release_devname(data, devname);
3271     ClosePrinter(hprn);
3272
3273     /* Changing paper */
3274     pagesetup_update_papersize(data);
3275     pagesetup_update_orientation_buttons(hDlg, data);
3276
3277     /* Changing paper preview */
3278     pagesetup_change_preview(data);
3279
3280     /* Selecting paper in combo */
3281     count = SendDlgItemMessageW(hDlg, cmb2, CB_GETCOUNT, 0, 0);
3282     if(count != CB_ERR)
3283     {
3284         WORD paperword = pagesetup_get_papersize(data);
3285         for(i = 0; i < count; i++)
3286         {
3287             if(SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, i, 0) == paperword) {
3288                 SendDlgItemMessageW(hDlg, cmb2, CB_SETCURSEL, i, 0);
3289                 break;
3290             }
3291         }
3292     }
3293 }
3294
3295 /********************************************************************************
3296  * PRINTDLG_PS_WMCommandA
3297  * process WM_COMMAND message for PageSetupDlgA
3298  *
3299  * PARAMS
3300  *  hDlg        [in]    Main dialog HANDLE 
3301  *  wParam      [in]    WM_COMMAND wParam
3302  *  lParam      [in]    WM_COMMAND lParam
3303  *  pda         [in/out] ptr to PageSetupDataA
3304  */
3305
3306 static BOOL PRINTDLG_PS_WMCommandA(HWND hDlg, WPARAM wParam, LPARAM lParam, pagesetup_data *data)
3307 {
3308     WORD msg = HIWORD(wParam);
3309     WORD id  = LOWORD(wParam);
3310
3311     TRACE("loword (lparam) %d, wparam 0x%lx, lparam %08lx\n",
3312             LOWORD(lParam),wParam,lParam);
3313     switch (id)  {
3314     case IDOK:
3315         EndDialog(hDlg, TRUE);
3316         return TRUE ;
3317
3318     case IDCANCEL:
3319         EndDialog(hDlg, FALSE);
3320         return FALSE ;
3321
3322     case psh3: /* Printer... */
3323         pagesetup_change_printer_dialog(hDlg, data);
3324         return TRUE;
3325
3326     case rad1: /* Portrait */
3327     case rad2: /* Landscape */
3328         if((id == rad1 && pagesetup_get_orientation(data) == DMORIENT_LANDSCAPE) ||
3329            (id == rad2 && pagesetup_get_orientation(data) == DMORIENT_PORTRAIT))
3330         {
3331             pagesetup_set_orientation(data, (id == rad1) ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE);
3332             pagesetup_update_papersize(data);
3333             rotate_rect(pagesetup_get_margin_rect(data), (id == rad2));
3334             update_margin_edits(hDlg, data, 0);
3335             pagesetup_change_preview(data);
3336         }
3337         break;
3338     case cmb1: /* Printer combo */
3339         if(msg == CBN_SELCHANGE)
3340         {
3341             WCHAR name[256];
3342             GetDlgItemTextW(hDlg, id, name, sizeof(name) / sizeof(name[0]));
3343             pagesetup_change_printer(name, data);
3344             pagesetup_init_combos(hDlg, data);
3345         }
3346         break;
3347     case cmb2: /* Paper combo */
3348         if(msg == CBN_SELCHANGE)
3349         {
3350             DWORD paperword = SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA,
3351                                                   SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0), 0);
3352             if (paperword != CB_ERR)
3353             {
3354                 pagesetup_set_papersize(data, paperword);
3355                 pagesetup_update_papersize(data);
3356                 pagesetup_change_preview(data);
3357             } else
3358                 FIXME("could not get dialog text for papersize cmbbox?\n");
3359         }
3360         break;
3361     case cmb3: /* Paper Source */
3362         if(msg == CBN_SELCHANGE)
3363         {
3364             WORD source = SendDlgItemMessageW(hDlg, cmb3, CB_GETITEMDATA,
3365                                               SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0), 0);
3366             pagesetup_set_defaultsource(data, source);
3367         }
3368         break;
3369     case psh2: /* Printer Properties button */
3370         pagesetup_printer_properties(hDlg, data);
3371         break;
3372     case edt4:
3373     case edt5:
3374     case edt6:
3375     case edt7:
3376         margin_edit_notification(hDlg, data, msg, id);
3377         break;
3378     }
3379     InvalidateRect(GetDlgItem(hDlg, rct1), NULL, TRUE);
3380     return FALSE;
3381 }
3382
3383 static BOOL
3384 PRINTDLG_PS_WMCommandW(
3385     HWND hDlg, WPARAM wParam, LPARAM lParam, PageSetupDataW *pdw
3386 ) {
3387     TRACE("loword (lparam) %d, wparam 0x%lx, lparam %08lx\n",
3388             LOWORD(lParam),wParam,lParam);
3389     switch (LOWORD(wParam))  {
3390     case IDOK:
3391         if (!PRINTDLG_PS_UpdateDlgStructW(hDlg, pdw))
3392             return(FALSE);
3393         EndDialog(hDlg, TRUE);
3394         return TRUE ;
3395
3396     case IDCANCEL:
3397         EndDialog(hDlg, FALSE);
3398         return FALSE ;
3399
3400     case rad1:
3401     case rad2:
3402         if((LOWORD(wParam) == rad1 && pdw->curdlg.ptPaperSize.x > pdw->curdlg.ptPaperSize.y) ||
3403            (LOWORD(wParam) == rad2 && pdw->curdlg.ptPaperSize.y > pdw->curdlg.ptPaperSize.x))
3404         {
3405             WCHAR tmpText[25];
3406             WCHAR tmpText2[25];
3407             DWORD tmp = pdw->curdlg.ptPaperSize.y;
3408
3409             pdw->curdlg.ptPaperSize.y = pdw->curdlg.ptPaperSize.x;
3410             pdw->curdlg.ptPaperSize.x = tmp;
3411
3412             GetDlgItemTextW(hDlg, edt4, tmpText, sizeof(tmpText)/sizeof(WCHAR));
3413             GetDlgItemTextW(hDlg, edt5, tmpText2, sizeof(tmpText2)/sizeof(WCHAR));
3414             SetDlgItemTextW(hDlg, edt5, tmpText);
3415             SetDlgItemTextW(hDlg, edt4, tmpText2);
3416
3417             GetDlgItemTextW(hDlg, edt6, tmpText, sizeof(tmpText)/sizeof(WCHAR));
3418             GetDlgItemTextW(hDlg, edt7, tmpText2, sizeof(tmpText2)/sizeof(WCHAR));
3419             SetDlgItemTextW(hDlg, edt7, tmpText);
3420             SetDlgItemTextW(hDlg, edt6, tmpText2);
3421         }
3422         break;
3423
3424     case psh3: {
3425         pdw->pdlg.Flags         = 0;
3426         pdw->pdlg.hwndOwner     = hDlg;
3427         PRINTDLG_PS_UpdatePrintDlgW(pdw, hDlg);
3428         if (PrintDlgW(&(pdw->pdlg)))
3429             PRINTDLG_PS_ChangePrinterW(hDlg,pdw);
3430         return TRUE;
3431     }
3432     }
3433     return FALSE;
3434 }
3435
3436
3437 /***********************************************************************
3438  *           DefaultPagePaintHook
3439  * Default hook paint procedure that receives WM_PSD_* messages from the dialog box 
3440  * whenever the sample page is redrawn.
3441 */
3442
3443 static UINT_PTR
3444 PRINTDLG_DefaultPagePaintHook(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam,
3445                               const pagesetup_data *data)
3446 {
3447     LPRECT lprc = (LPRECT) lParam;
3448     HDC hdc = (HDC) wParam;
3449     HPEN hpen, holdpen;
3450     LOGFONTW lf;
3451     HFONT hfont, holdfont;
3452     INT oldbkmode;
3453     TRACE("uMsg: WM_USER+%d\n",uMsg-WM_USER);
3454     /* Call user paint hook if enable */
3455     if (pagesetup_get_flags(data) & PSD_ENABLEPAGEPAINTHOOK)
3456         if (data->dlga->lpfnPagePaintHook(hwndDlg, uMsg, wParam, lParam))
3457             return TRUE;
3458
3459     switch (uMsg) {
3460        /* LPPAGESETUPDLG in lParam */
3461        case WM_PSD_PAGESETUPDLG:
3462        /* Inform about the sample page rectangle */
3463        case WM_PSD_FULLPAGERECT:
3464        /* Inform about the margin rectangle */
3465        case WM_PSD_MINMARGINRECT:
3466             return FALSE;
3467
3468         /* Draw dashed rectangle showing margins */
3469         case WM_PSD_MARGINRECT:
3470             hpen = CreatePen(PS_DASH, 1, GetSysColor(COLOR_3DSHADOW));
3471             holdpen = SelectObject(hdc, hpen);
3472             Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom);
3473             DeleteObject(SelectObject(hdc, holdpen));
3474             return TRUE;
3475         /* Draw the fake document */
3476         case WM_PSD_GREEKTEXTRECT:
3477             /* select a nice scalable font, because we want the text really small */
3478             SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0);
3479             lf.lfHeight = 6; /* value chosen based on visual effect */
3480             hfont = CreateFontIndirectW(&lf);
3481             holdfont = SelectObject(hdc, hfont);
3482
3483             /* if text not loaded, then do so now */
3484             if (wszFakeDocumentText[0] == '\0')
3485                  LoadStringW(COMDLG32_hInstance,
3486                         IDS_FAKEDOCTEXT,
3487                         wszFakeDocumentText,
3488                         sizeof(wszFakeDocumentText)/sizeof(wszFakeDocumentText[0]));
3489
3490             oldbkmode = SetBkMode(hdc, TRANSPARENT);
3491             DrawTextW(hdc, wszFakeDocumentText, -1, lprc, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_WORDBREAK);
3492             SetBkMode(hdc, oldbkmode);
3493
3494             DeleteObject(SelectObject(hdc, holdfont));
3495             return TRUE;
3496
3497         /* Envelope stamp */
3498         case WM_PSD_ENVSTAMPRECT:
3499         /* Return address */
3500         case WM_PSD_YAFULLPAGERECT:
3501             FIXME("envelope/stamp is not implemented\n");
3502             return FALSE;
3503         default:
3504             FIXME("Unknown message %x\n",uMsg);
3505             return FALSE;
3506     }
3507     return TRUE;
3508 }
3509
3510 /***********************************************************************
3511  *           PagePaintProc
3512  * The main paint procedure for the PageSetupDlg function.
3513  * The Page Setup dialog box includes an image of a sample page that shows how
3514  * the user's selections affect the appearance of the printed output.
3515  * The image consists of a rectangle that represents the selected paper
3516  * or envelope type, with a dotted-line rectangle representing
3517  * the current margins, and partial (Greek text) characters
3518  * to show how text looks on the printed page. 
3519  *
3520  * The following messages in the order sends to user hook procedure:
3521  *   WM_PSD_PAGESETUPDLG    Draw the contents of the sample page
3522  *   WM_PSD_FULLPAGERECT    Inform about the bounding rectangle
3523  *   WM_PSD_MINMARGINRECT   Inform about the margin rectangle (min margin?)
3524  *   WM_PSD_MARGINRECT      Draw the margin rectangle
3525  *   WM_PSD_GREEKTEXTRECT   Draw the Greek text inside the margin rectangle
3526  * If any of first three messages returns TRUE, painting done.
3527  *
3528  * PARAMS:
3529  *   hWnd   [in] Handle to the Page Setup dialog box
3530  *   uMsg   [in] Received message
3531  *
3532  * TODO:
3533  *   WM_PSD_ENVSTAMPRECT    Draw in the envelope-stamp rectangle (for envelopes only)
3534  *   WM_PSD_YAFULLPAGERECT  Draw the return address portion (for envelopes and other paper sizes)
3535  *
3536  * RETURNS:
3537  *   FALSE if all done correctly
3538  *
3539  */
3540
3541
3542 static LRESULT CALLBACK
3543 PRINTDLG_PagePaintProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3544 {
3545     PAINTSTRUCT ps;
3546     RECT rcClient, rcMargin;
3547     HPEN hpen, holdpen;
3548     HDC hdc;
3549     HBRUSH hbrush, holdbrush;
3550     pagesetup_data *data;
3551     int papersize=0, orientation=0; /* FIXME: set this values for user paint hook */
3552     double scalx, scaly;
3553 #define CALLPAINTHOOK(msg,lprc) PRINTDLG_DefaultPagePaintHook( hWnd, msg, (WPARAM)hdc, (LPARAM)lprc, data)
3554
3555     if (uMsg != WM_PAINT)
3556         return CallWindowProcA(lpfnStaticWndProc, hWnd, uMsg, wParam, lParam);
3557
3558     /* Processing WM_PAINT message */
3559     data = GetPropW(hWnd, pagesetupdlg_prop);
3560     if (!data) {
3561         WARN("__WINE_PAGESETUPDLGDATA prop not set?\n");
3562         return FALSE;
3563     }
3564     if (PRINTDLG_DefaultPagePaintHook(hWnd, WM_PSD_PAGESETUPDLG, MAKELONG(papersize, orientation), (LPARAM)data->dlga, data))
3565         return FALSE;
3566
3567     hdc = BeginPaint(hWnd, &ps);
3568     GetClientRect(hWnd, &rcClient);
3569     
3570     scalx = rcClient.right  / (double)pagesetup_get_papersize_pt(data)->x;
3571     scaly = rcClient.bottom / (double)pagesetup_get_papersize_pt(data)->y;
3572     rcMargin = rcClient;
3573
3574     rcMargin.left   += pagesetup_get_margin_rect(data)->left   * scalx;
3575     rcMargin.top    += pagesetup_get_margin_rect(data)->top    * scaly;
3576     rcMargin.right  -= pagesetup_get_margin_rect(data)->right  * scalx;
3577     rcMargin.bottom -= pagesetup_get_margin_rect(data)->bottom * scaly;
3578
3579     /* if the space is too small then we make sure to not draw anything */
3580     rcMargin.left = min(rcMargin.left, rcMargin.right);
3581     rcMargin.top = min(rcMargin.top, rcMargin.bottom);
3582
3583     if (!CALLPAINTHOOK(WM_PSD_FULLPAGERECT, &rcClient) &&
3584         !CALLPAINTHOOK(WM_PSD_MINMARGINRECT, &rcMargin) )
3585     {
3586         /* fill background */
3587         hbrush = GetSysColorBrush(COLOR_3DHIGHLIGHT);
3588         FillRect(hdc, &rcClient, hbrush);
3589         holdbrush = SelectObject(hdc, hbrush);
3590
3591         hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
3592         holdpen = SelectObject(hdc, hpen);
3593         
3594         /* paint left edge */
3595         MoveToEx(hdc, rcClient.left, rcClient.top, NULL);
3596         LineTo(hdc, rcClient.left, rcClient.bottom-1);
3597
3598         /* paint top edge */
3599         MoveToEx(hdc, rcClient.left, rcClient.top, NULL);
3600         LineTo(hdc, rcClient.right, rcClient.top);
3601
3602         hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DDKSHADOW));
3603         DeleteObject(SelectObject(hdc, hpen));
3604
3605         /* paint right edge */
3606         MoveToEx(hdc, rcClient.right-1, rcClient.top, NULL);
3607         LineTo(hdc, rcClient.right-1, rcClient.bottom);
3608
3609         /* paint bottom edge */
3610         MoveToEx(hdc, rcClient.left, rcClient.bottom-1, NULL);
3611         LineTo(hdc, rcClient.right, rcClient.bottom-1);
3612
3613         DeleteObject(SelectObject(hdc, holdpen));
3614         DeleteObject(SelectObject(hdc, holdbrush));
3615
3616         CALLPAINTHOOK(WM_PSD_MARGINRECT, &rcMargin);
3617
3618         /* give text a bit of a space from the frame */
3619         rcMargin.left += 2;
3620         rcMargin.top += 2;
3621         rcMargin.right -= 2;
3622         rcMargin.bottom -= 2;
3623         
3624         /* if the space is too small then we make sure to not draw anything */
3625         rcMargin.left = min(rcMargin.left, rcMargin.right);
3626         rcMargin.top = min(rcMargin.top, rcMargin.bottom);
3627
3628         CALLPAINTHOOK(WM_PSD_GREEKTEXTRECT, &rcMargin);
3629     }
3630
3631     EndPaint(hWnd, &ps);
3632     return FALSE;
3633 #undef CALLPAINTHOOK
3634 }
3635
3636 /*******************************************************
3637  * The margin edit controls are subclassed to filter
3638  * anything other than numbers and the decimal separator.
3639  */
3640 static LRESULT CALLBACK pagesetup_margin_editproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
3641 {
3642     switch(msg)
3643     case WM_CHAR:
3644     {
3645         WCHAR decimal = get_decimal_sep();
3646         WCHAR wc = (WCHAR)wparam;
3647         if(!isdigitW(wc) && wc != decimal && wc != VK_BACK) return 0;
3648     }
3649     return CallWindowProcW(edit_wndproc, hwnd, msg, wparam, lparam);
3650 }
3651
3652 static void subclass_margin_edits(HWND hDlg)
3653 {
3654     int id;
3655     WNDPROC old_proc;
3656
3657     for(id = edt4; id <= edt7; id++)
3658     {
3659         old_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hDlg, id),
3660                                               GWLP_WNDPROC,
3661                                               (ULONG_PTR)pagesetup_margin_editproc);
3662         InterlockedCompareExchangePointer((void**)&edit_wndproc, old_proc, NULL);
3663     }
3664 }
3665
3666 /***********************************************************************
3667  *           PRINTDLG_PageDlgProcA
3668  * Message handler for PageSetupDlgA
3669  */
3670 static INT_PTR CALLBACK
3671 PRINTDLG_PageDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
3672 {
3673     pagesetup_data *data;
3674     INT_PTR             res = FALSE;
3675     HWND                hDrawWnd;
3676
3677     if (uMsg == WM_INITDIALOG) { /*Init dialog*/
3678         data = (pagesetup_data *)lParam;
3679         data->hDlg = hDlg;
3680
3681         hDrawWnd = GetDlgItem(hDlg, rct1); 
3682         TRACE("set property to %p\n", data);
3683         SetPropW(hDlg, pagesetupdlg_prop, data);
3684         SetPropW(hDrawWnd, pagesetupdlg_prop, data);
3685         GetWindowRect(hDrawWnd, &data->rtDrawRect); /* Calculating rect in client coordinates where paper draws */
3686         ScreenToClient(hDlg, (LPPOINT)&data->rtDrawRect);
3687         ScreenToClient(hDlg, (LPPOINT)(&data->rtDrawRect.right));
3688         lpfnStaticWndProc = (WNDPROC)SetWindowLongPtrW(
3689             hDrawWnd,
3690             GWLP_WNDPROC,
3691             (ULONG_PTR)PRINTDLG_PagePaintProc);
3692         
3693         /* FIXME: Paint hook. Must it be at begin of initialization or at end? */
3694         res = TRUE;
3695         if (pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPHOOK)
3696         {
3697             if (!data->dlga->lpfnPageSetupHook(hDlg,uMsg,wParam,(LPARAM)data->dlga))
3698                 FIXME("Setup page hook failed?\n");
3699         }
3700
3701         /* if printer button disabled */
3702         if (pagesetup_get_flags(data) & PSD_DISABLEPRINTER)
3703             EnableWindow(GetDlgItem(hDlg, psh3), FALSE);
3704         /* if margin edit boxes disabled */
3705         if (pagesetup_get_flags(data) & PSD_DISABLEMARGINS)
3706         {
3707             EnableWindow(GetDlgItem(hDlg, edt4), FALSE);
3708             EnableWindow(GetDlgItem(hDlg, edt5), FALSE);
3709             EnableWindow(GetDlgItem(hDlg, edt6), FALSE);
3710             EnableWindow(GetDlgItem(hDlg, edt7), FALSE);
3711         }
3712
3713         /* Set orientation radiobuttons properly */
3714         pagesetup_update_orientation_buttons(hDlg, data);
3715
3716         /* if orientation disabled */
3717         if (pagesetup_get_flags(data) & PSD_DISABLEORIENTATION)
3718         {
3719             EnableWindow(GetDlgItem(hDlg,rad1),FALSE);
3720             EnableWindow(GetDlgItem(hDlg,rad2),FALSE);
3721         }
3722
3723         /* We fill them out enabled or not */
3724         if (!(pagesetup_get_flags(data) & PSD_MARGINS))
3725         {
3726             /* default is 1 inch */
3727             LONG size = thousandths_inch_to_size(data, 1000);
3728             SetRect(pagesetup_get_margin_rect(data), size, size, size, size);
3729         }
3730         update_margin_edits(hDlg, data, 0);
3731         subclass_margin_edits(hDlg);
3732         set_margin_groupbox_title(hDlg, data);
3733
3734         /* if paper disabled */
3735         if (pagesetup_get_flags(data) & PSD_DISABLEPAPER)
3736         {
3737             EnableWindow(GetDlgItem(hDlg,cmb2),FALSE);
3738             EnableWindow(GetDlgItem(hDlg,cmb3),FALSE);
3739         }
3740
3741         /* filling combos: printer, paper, source. selecting current printer (from DEVMODEA) */
3742         pagesetup_init_combos(hDlg, data);
3743         pagesetup_update_papersize(data);
3744         pagesetup_set_defaultsource(data, DMBIN_FORMSOURCE); /* FIXME: This is the auto select bin. Is this correct? */
3745
3746         /* Drawing paper prev */
3747         pagesetup_change_preview(data);
3748         return TRUE;
3749     } else {
3750         data = GetPropW(hDlg, pagesetupdlg_prop);
3751         if (!data)
3752         {
3753             WARN("__WINE_PAGESETUPDLGDATA prop not set?\n");
3754             return FALSE;
3755         }
3756         if (pagesetup_get_flags(data) & PSD_ENABLEPAGESETUPHOOK)
3757         {
3758             res = data->dlga->lpfnPageSetupHook(hDlg, uMsg, wParam, lParam);
3759             if (res) return res;
3760         }
3761     }
3762     switch (uMsg) {
3763     case WM_COMMAND:
3764         return PRINTDLG_PS_WMCommandA(hDlg, wParam, lParam, data);
3765     }
3766     return FALSE;
3767 }
3768
3769 static INT_PTR CALLBACK
3770 PageDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
3771 {
3772     PageSetupDataW      *pdw;
3773     BOOL                res = FALSE;
3774
3775     if (uMsg==WM_INITDIALOG) {
3776         res = TRUE;
3777         pdw = (PageSetupDataW*)lParam;
3778         pdw->curdlg = *pdw->dlgw;
3779         SetPropW(hDlg, pagesetupdlg_prop, pdw);
3780         if (pdw->dlgw->Flags & PSD_ENABLEPAGESETUPHOOK) {
3781             res = pdw->dlgw->lpfnPageSetupHook(hDlg,uMsg,wParam,(LPARAM)pdw->dlgw);
3782             if (!res) {
3783                 FIXME("Setup page hook failed?\n");
3784                 res = TRUE;
3785             }
3786         }
3787
3788         if (pdw->dlgw->Flags & PSD_ENABLEPAGEPAINTHOOK) {
3789             FIXME("PagePaintHook not yet implemented!\n");
3790         }
3791         if (pdw->dlgw->Flags & PSD_DISABLEPRINTER)
3792             EnableWindow(GetDlgItem(hDlg, psh3), FALSE);
3793         if (pdw->dlgw->Flags & PSD_DISABLEMARGINS) {
3794             EnableWindow(GetDlgItem(hDlg, edt4), FALSE);
3795             EnableWindow(GetDlgItem(hDlg, edt5), FALSE);
3796             EnableWindow(GetDlgItem(hDlg, edt6), FALSE);
3797             EnableWindow(GetDlgItem(hDlg, edt7), FALSE);
3798         }
3799
3800         PRINTDLG_PS_ChangePrinterW(hDlg,pdw);
3801
3802         if (pdw->dlgw->Flags & PSD_DISABLEORIENTATION) {
3803             EnableWindow(GetDlgItem(hDlg,rad1),FALSE);
3804             EnableWindow(GetDlgItem(hDlg,rad2),FALSE);
3805         }
3806         /* We fill them out enabled or not */
3807         if (pdw->dlgw->Flags & PSD_MARGINS) {
3808             WCHAR str[100];
3809             _c_size2strW(pdw,pdw->dlgw->rtMargin.left,str);
3810             SetDlgItemTextW(hDlg,edt4,str);
3811             _c_size2strW(pdw,pdw->dlgw->rtMargin.top,str);
3812             SetDlgItemTextW(hDlg,edt5,str);
3813             _c_size2strW(pdw,pdw->dlgw->rtMargin.right,str);
3814             SetDlgItemTextW(hDlg,edt6,str);
3815             _c_size2strW(pdw,pdw->dlgw->rtMargin.bottom,str);
3816             SetDlgItemTextW(hDlg,edt7,str);
3817         } else {
3818             /* default is 1 inch */
3819             DWORD size = _c_inch2size(pdw->dlgw,1000);
3820             WCHAR       str[20];
3821             _c_size2strW(pdw,size,str);
3822             SetDlgItemTextW(hDlg,edt4,str);
3823             SetDlgItemTextW(hDlg,edt5,str);
3824             SetDlgItemTextW(hDlg,edt6,str);
3825             SetDlgItemTextW(hDlg,edt7,str);
3826         }
3827
3828         if (pdw->dlgw->Flags & PSD_DISABLEPAPER) {
3829             EnableWindow(GetDlgItem(hDlg,cmb2),FALSE);
3830             EnableWindow(GetDlgItem(hDlg,cmb3),FALSE);
3831         }
3832
3833         return TRUE;
3834     } else {
3835         pdw = GetPropW(hDlg, pagesetupdlg_prop);
3836         if (!pdw) {
3837             WARN("__WINE_PAGESETUPDLGDATA prop not set?\n");
3838             return FALSE;
3839         }
3840         if (pdw->dlgw->Flags & PSD_ENABLEPAGESETUPHOOK) {
3841             res = pdw->dlgw->lpfnPageSetupHook(hDlg,uMsg,wParam,lParam);
3842             if (res) return res;
3843         }
3844     }
3845     switch (uMsg) {
3846     case WM_COMMAND:
3847         return PRINTDLG_PS_WMCommandW(hDlg, wParam, lParam, pdw);
3848     }
3849     return FALSE;
3850 }
3851
3852 /***********************************************************************
3853  *            PageSetupDlgA  (COMDLG32.@)
3854  *
3855  *  Displays the PAGE SETUP dialog box, which enables the user to specify
3856  *  specific properties of a printed page such as
3857  *  size, source, orientation and the width of the page margins.
3858  *
3859  * PARAMS
3860  *  setupdlg [IO] PAGESETUPDLGA struct
3861  *
3862  * RETURNS
3863  *  TRUE    if the user pressed the OK button
3864  *  FALSE   if the user cancelled the window or an error occurred
3865  *
3866  * NOTES
3867  *    The values of hDevMode and hDevNames are filled on output and can be
3868  *    changed in PAGESETUPDLG when they are passed in PageSetupDlg.
3869  * 
3870  */
3871
3872 BOOL WINAPI PageSetupDlgA(LPPAGESETUPDLGA setupdlg) {
3873     HGLOBAL             hDlgTmpl;
3874     LPVOID              ptr;
3875     BOOL                bRet;
3876     pagesetup_data *data;
3877
3878     if (setupdlg == NULL) {
3879            COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION);
3880            return FALSE;
3881     }
3882
3883     /* TRACE */
3884     if(TRACE_ON(commdlg)) {
3885         char flagstr[1000] = "";
3886         const struct pd_flags *pflag = psd_flags;
3887         for( ; pflag->name; pflag++) {
3888             if(setupdlg->Flags & pflag->flag) {
3889                 strcat(flagstr, pflag->name);
3890                 strcat(flagstr, "|");
3891             }
3892         }
3893         TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
3894               "hinst %p, flags %08x (%s)\n",
3895               setupdlg, setupdlg->hwndOwner, setupdlg->hDevMode,
3896               setupdlg->hDevNames,
3897               setupdlg->hInstance, setupdlg->Flags, flagstr);
3898     }
3899
3900     /* Checking setupdlg structure */
3901     if(setupdlg->lStructSize != sizeof(PAGESETUPDLGA)) {
3902            COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE);
3903            return FALSE;
3904     }
3905     if ((setupdlg->Flags & PSD_ENABLEPAGEPAINTHOOK) &&
3906         (setupdlg->lpfnPagePaintHook == NULL)) {
3907             COMDLG32_SetCommDlgExtendedError(CDERR_NOHOOK);
3908             return FALSE;
3909         }
3910
3911     if(!(setupdlg->Flags & (PSD_INTHOUSANDTHSOFINCHES | PSD_INHUNDREDTHSOFMILLIMETERS)))
3912         setupdlg->Flags |= is_default_metric() ?
3913             PSD_INHUNDREDTHSOFMILLIMETERS : PSD_INTHOUSANDTHSOFINCHES;
3914
3915     /* Initialize default printer struct. If no printer device info is specified
3916        retrieve the default printer data. */
3917     if (!setupdlg->hDevMode || !setupdlg->hDevNames)
3918     {
3919         PRINTDLGA pdlg;
3920         memset(&pdlg, 0, sizeof(pdlg));
3921         pdlg.lStructSize = sizeof(pdlg);
3922         pdlg.Flags = PD_RETURNDEFAULT;
3923         bRet = PrintDlgA(&pdlg);
3924         if (!bRet)
3925         {
3926             if (!(setupdlg->Flags & PSD_NOWARNING)) {
3927                 WCHAR errstr[256];
3928                 LoadStringW(COMDLG32_hInstance, PD32_NO_DEFAULT_PRINTER, errstr, 255);
3929                 MessageBoxW(setupdlg->hwndOwner, errstr, 0, MB_OK | MB_ICONERROR);
3930             }
3931             return FALSE;
3932         }
3933         setupdlg->hDevMode  = pdlg.hDevMode;
3934         setupdlg->hDevNames = pdlg.hDevNames;
3935     }
3936
3937     data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
3938     data->dlga = setupdlg;
3939
3940     /* short cut exit, just return default values */
3941     if (setupdlg->Flags & PSD_RETURNDEFAULT) {
3942         pagesetup_update_papersize(data);
3943         HeapFree(GetProcessHeap(), 0, data);
3944         return TRUE;
3945     }
3946
3947     /* get dialog template */
3948     hDlgTmpl = PRINTDLG_GetPGSTemplateA(setupdlg);
3949     if (!hDlgTmpl) {
3950         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3951         return FALSE;
3952     }
3953     ptr = LockResource( hDlgTmpl );
3954     if (!ptr) {
3955         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3956         return FALSE;
3957     }
3958
3959     bRet = (0<DialogBoxIndirectParamW(
3960                 setupdlg->hInstance,
3961                 ptr,
3962                 setupdlg->hwndOwner,
3963                 PRINTDLG_PageDlgProcA,
3964                 (LPARAM)data)
3965     );
3966
3967     HeapFree(GetProcessHeap(), 0, data);
3968     return bRet;
3969 }
3970 /***********************************************************************
3971  *            PageSetupDlgW  (COMDLG32.@)
3972  *
3973  * See PageSetupDlgA.
3974  */
3975 BOOL WINAPI PageSetupDlgW(LPPAGESETUPDLGW setupdlg) {
3976     HGLOBAL             hDlgTmpl;
3977     LPVOID              ptr;
3978     BOOL                bRet;
3979     PageSetupDataW      *pdw;
3980     PRINTDLGW           pdlg;
3981
3982     FIXME("Unicode implementation is not done yet\n");
3983
3984     if (setupdlg == NULL) {
3985            COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION);
3986            return FALSE;
3987     }
3988
3989     if(TRACE_ON(commdlg)) {
3990         char flagstr[1000] = "";
3991         const struct pd_flags *pflag = psd_flags;
3992         for( ; pflag->name; pflag++) {
3993             if(setupdlg->Flags & pflag->flag) {
3994                 strcat(flagstr, pflag->name);
3995                 strcat(flagstr, "|");
3996             }
3997         }
3998         TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n"
3999               "hinst %p, flags %08x (%s)\n",
4000               setupdlg, setupdlg->hwndOwner, setupdlg->hDevMode,
4001               setupdlg->hDevNames,
4002               setupdlg->hInstance, setupdlg->Flags, flagstr);
4003     }
4004
4005     /* Initialize default printer struct. If no printer device info is specified
4006        retrieve the default printer data. */
4007     memset(&pdlg,0,sizeof(pdlg));
4008     pdlg.lStructSize    = sizeof(pdlg);
4009     if (setupdlg->hDevMode && setupdlg->hDevNames) {
4010         pdlg.hDevMode = setupdlg->hDevMode;
4011         pdlg.hDevNames = setupdlg->hDevNames;
4012     } else {
4013         pdlg.Flags = PD_RETURNDEFAULT;
4014         bRet = PrintDlgW(&pdlg);
4015         if (!bRet){
4016             if (!(setupdlg->Flags & PSD_NOWARNING)) {
4017                 WCHAR errstr[256];
4018                 LoadStringW(COMDLG32_hInstance, PD32_NO_DEFAULT_PRINTER, errstr, 255);
4019                 MessageBoxW(setupdlg->hwndOwner, errstr, 0, MB_OK | MB_ICONERROR);
4020             }
4021             return FALSE;
4022         }
4023     }
4024
4025     /* short cut exit, just return default values */
4026     if (setupdlg->Flags & PSD_RETURNDEFAULT) {
4027         static const WCHAR a4[] = {'A','4',0};
4028         setupdlg->hDevMode      = pdlg.hDevMode;
4029         setupdlg->hDevNames     = pdlg.hDevNames;
4030         /* FIXME: Just return "A4" for now. */
4031         PRINTDLG_PaperSizeW(&pdlg,a4,&setupdlg->ptPaperSize);
4032         setupdlg->ptPaperSize.x=_c_10mm2size(setupdlg,setupdlg->ptPaperSize.x);
4033         setupdlg->ptPaperSize.y=_c_10mm2size(setupdlg,setupdlg->ptPaperSize.y);
4034         return TRUE;
4035     }
4036     hDlgTmpl = PRINTDLG_GetPGSTemplateW(setupdlg);
4037     if (!hDlgTmpl) {
4038         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4039         return FALSE;
4040     }
4041     ptr = LockResource( hDlgTmpl );
4042     if (!ptr) {
4043         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
4044         return FALSE;
4045     }
4046     pdw = HeapAlloc(GetProcessHeap(),0,sizeof(*pdw));
4047     pdw->dlgw = setupdlg;
4048     pdw->pdlg = pdlg;
4049
4050     bRet = (0<DialogBoxIndirectParamW(
4051                 setupdlg->hInstance,
4052                 ptr,
4053                 setupdlg->hwndOwner,
4054                 PageDlgProcW,
4055                 (LPARAM)pdw)
4056     );
4057     return bRet;
4058 }
4059
4060 /***********************************************************************
4061  * PrintDlgExA (COMDLG32.@)
4062  *
4063  * See PrintDlgExW.
4064  *
4065  * BUGS
4066  *   Only a Stub
4067  *
4068  */
4069 HRESULT WINAPI PrintDlgExA(LPPRINTDLGEXA lppd)
4070 {
4071
4072     FIXME("(%p) stub\n", lppd);
4073     if ((lppd == NULL) || (lppd->lStructSize != sizeof(PRINTDLGEXA))) {
4074         return E_INVALIDARG;
4075     }
4076
4077     if (!IsWindow(lppd->hwndOwner)) {
4078         return E_HANDLE;
4079     }
4080
4081     return E_NOTIMPL;
4082 }
4083
4084 /***********************************************************************
4085  * PrintDlgExW (COMDLG32.@)
4086  *
4087  * Display the property sheet style PRINT dialog box
4088  *  
4089  * PARAMS
4090  *  lppd  [IO] ptr to PRINTDLGEX struct
4091  * 
4092  * RETURNS
4093  *  Success: S_OK
4094  *  Failure: One of the following COM error codes:
4095  *    E_OUTOFMEMORY Insufficient memory.
4096  *    E_INVALIDARG  One or more arguments are invalid.
4097  *    E_POINTER     Invalid pointer.
4098  *    E_HANDLE      Invalid handle.
4099  *    E_FAIL        Unspecified error.
4100  *  
4101  * NOTES
4102  * This Dialog enables the user to specify specific properties of the print job.
4103  * The property sheet can also have additional application-specific and
4104  * driver-specific property pages.
4105  *
4106  * BUGS
4107  *   Not fully implemented
4108  *
4109  */
4110 HRESULT WINAPI PrintDlgExW(LPPRINTDLGEXW lppd)
4111 {
4112     DWORD     ret = E_FAIL;
4113     LPVOID    ptr;
4114
4115     FIXME("(%p) not fully implemented\n", lppd);
4116
4117     if ((lppd == NULL) || (lppd->lStructSize != sizeof(PRINTDLGEXW))) {
4118         return E_INVALIDARG;
4119     }
4120
4121     if (!IsWindow(lppd->hwndOwner)) {
4122         return E_HANDLE;
4123     }
4124
4125     if (lppd->Flags & PD_RETURNDEFAULT) {
4126         PRINTER_INFO_2W *pbuf;
4127         DRIVER_INFO_2W  *dbuf;
4128         HANDLE hprn;
4129         DWORD needed = 1024;
4130         BOOL bRet;
4131
4132         if (lppd->hDevMode || lppd->hDevNames) {
4133             WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n");
4134             COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE);
4135             return E_INVALIDARG;
4136         }
4137         if (!PRINTDLG_OpenDefaultPrinter(&hprn)) {
4138             WARN("Can't find default printer\n");
4139             COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN);
4140             return E_FAIL;
4141         }
4142
4143         pbuf = HeapAlloc(GetProcessHeap(), 0, needed);
4144         bRet = GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed);
4145         if (!bRet && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4146             HeapFree(GetProcessHeap(), 0, pbuf);
4147             pbuf = HeapAlloc(GetProcessHeap(), 0, needed);
4148             bRet = GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed);
4149         }
4150         if (!bRet) {
4151             HeapFree(GetProcessHeap(), 0, pbuf);
4152             ClosePrinter(hprn);
4153             return E_FAIL;
4154         }
4155
4156         needed = 1024;
4157         dbuf = HeapAlloc(GetProcessHeap(), 0, needed);
4158         bRet = GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed);
4159         if (!bRet && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4160             HeapFree(GetProcessHeap(), 0, dbuf);
4161             dbuf = HeapAlloc(GetProcessHeap(), 0, needed);
4162             bRet = GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed);
4163         }
4164         if (!bRet) {
4165             ERR("GetPrinterDriverW failed, last error %d, fix your config for printer %s!\n",
4166                 GetLastError(), debugstr_w(pbuf->pPrinterName));
4167             HeapFree(GetProcessHeap(), 0, dbuf);
4168             HeapFree(GetProcessHeap(), 0, pbuf);
4169             COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE);
4170             ClosePrinter(hprn);
4171             return E_FAIL;
4172         }
4173         ClosePrinter(hprn);
4174
4175         PRINTDLG_CreateDevNamesW(&(lppd->hDevNames),
4176                       dbuf->pDriverPath,
4177                       pbuf->pPrinterName,
4178                       pbuf->pPortName);
4179         lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize +
4180                          pbuf->pDevMode->dmDriverExtra);
4181         if (lppd->hDevMode) {
4182             ptr = GlobalLock(lppd->hDevMode);
4183             if (ptr) {
4184                 memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize +
4185                     pbuf->pDevMode->dmDriverExtra);
4186                 GlobalUnlock(lppd->hDevMode);
4187                 ret = S_OK;
4188             }
4189         }
4190         HeapFree(GetProcessHeap(), 0, pbuf);
4191         HeapFree(GetProcessHeap(), 0, dbuf);
4192
4193         return ret;
4194     }
4195
4196     return E_NOTIMPL;
4197 }