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