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