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