1 /*
2 * COMMDLG - Print Dialog
3 *
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1999 Klaas van Gend
7 * Copyright 2000 Huw D M Davies
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winspool.h"
36 #include "winerror.h"
37
38 #include "wine/debug.h"
39
40 #include "commdlg.h"
41 #include "dlgs.h"
42 #include "cderr.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
45
46 #include "cdlg.h"
47 #include "printdlg.h"
48
49 /* Yes these constants are the same, but we're just copying win98 */
50 #define UPDOWN_ID 0x270f
51 #define MAX_COPIES 9999
52
53 /* Debugging info */
54 static const struct pd_flags psd_flags[] = {
55 {PSD_MINMARGINS,"PSD_MINMARGINS"},
56 {PSD_MARGINS,"PSD_MARGINS"},
57 {PSD_INTHOUSANDTHSOFINCHES,"PSD_INTHOUSANDTHSOFINCHES"},
58 {PSD_INHUNDREDTHSOFMILLIMETERS,"PSD_INHUNDREDTHSOFMILLIMETERS"},
59 {PSD_DISABLEMARGINS,"PSD_DISABLEMARGINS"},
60 {PSD_DISABLEPRINTER,"PSD_DISABLEPRINTER"},
61 {PSD_NOWARNING,"PSD_NOWARNING"},
62 {PSD_DISABLEORIENTATION,"PSD_DISABLEORIENTATION"},
63 {PSD_RETURNDEFAULT,"PSD_RETURNDEFAULT"},
64 {PSD_DISABLEPAPER,"PSD_DISABLEPAPER"},
65 {PSD_SHOWHELP,"PSD_SHOWHELP"},
66 {PSD_ENABLEPAGESETUPHOOK,"PSD_ENABLEPAGESETUPHOOK"},
67 {PSD_ENABLEPAGESETUPTEMPLATE,"PSD_ENABLEPAGESETUPTEMPLATE"},
68 {PSD_ENABLEPAGESETUPTEMPLATEHANDLE,"PSD_ENABLEPAGESETUPTEMPLATEHANDLE"},
69 {PSD_ENABLEPAGEPAINTHOOK,"PSD_ENABLEPAGEPAINTHOOK"},
70 {PSD_DISABLEPAGEPAINTING,"PSD_DISABLEPAGEPAINTING"},
71 {-1, NULL}
72 };
73
74 /* address of wndproc for subclassed Static control */
75 static WNDPROC lpfnStaticWndProc;
76 /* the text of the fake document to render for the Page Setup dialog */
77 static WCHAR wszFakeDocumentText[1024];
78
79 /***********************************************************************
80 * PRINTDLG_OpenDefaultPrinter
81 *
82 * Returns a winspool printer handle to the default printer in *hprn
83 * Caller must call ClosePrinter on the handle
84 *
85 * Returns TRUE on success else FALSE
86 */
87 BOOL PRINTDLG_OpenDefaultPrinter(HANDLE *hprn)
88 {
89 WCHAR buf[260];
90 DWORD dwBufLen = sizeof(buf) / sizeof(buf[0]);
91 BOOL res;
92 if(!GetDefaultPrinterW(buf, &dwBufLen))
93 return FALSE;
94 res = OpenPrinterW(buf, hprn, NULL);
95 if (!res)
96 WARN("Could not open printer %s\n", debugstr_w(buf));
97 return res;
98 }
99
100 /***********************************************************************
101 * PRINTDLG_SetUpPrinterListCombo
102 *
103 * Initializes printer list combox.
104 * hDlg: HWND of dialog
105 * id: Control id of combo
106 * name: Name of printer to select
107 *
108 * Initializes combo with list of available printers. Selects printer 'name'
109 * If name is NULL or does not exist select the default printer.
110 *
111 * Returns number of printers added to list.
112 */
113 INT PRINTDLG_SetUpPrinterListComboA(HWND hDlg, UINT id, LPCSTR name)
114 {
115 DWORD needed, num;
116 INT i;
117 LPPRINTER_INFO_2A pi;
118 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
119 pi = HeapAlloc(GetProcessHeap(), 0, needed);
120 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed,
121 &num);
122
123 SendDlgItemMessageA(hDlg, id, CB_RESETCONTENT, 0, 0);
124
125 for(i = 0; i < num; i++) {
126 SendDlgItemMessageA(hDlg, id, CB_ADDSTRING, 0,
127 (LPARAM)pi[i].pPrinterName );
128 }
129 HeapFree(GetProcessHeap(), 0, pi);
130 if(!name ||
131 (i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1,
132 (LPARAM)name)) == CB_ERR) {
133
134 char buf[260];
135 DWORD dwBufLen = sizeof(buf);
136 if (name != NULL)
137 WARN("Can't find %s in printer list so trying to find default\n",
138 debugstr_a(name));
139 if(!GetDefaultPrinterA(buf, &dwBufLen))
140 return num;
141 i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf);
142 if(i == CB_ERR)
143 FIXME("Can't find default printer in printer list\n");
144 }
145 SendDlgItemMessageA(hDlg, id, CB_SETCURSEL, i, 0);
146 return num;
147 }
148
149 static INT PRINTDLG_SetUpPrinterListComboW(HWND hDlg, UINT id, LPCWSTR name)
150 {
151 DWORD needed, num;
152 INT i;
153 LPPRINTER_INFO_2W pi;
154 EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num);
155 pi = HeapAlloc(GetProcessHeap(), 0, needed);
156 EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed,
157 &num);
158
159 for(i = 0; i < num; i++) {
160 SendDlgItemMessageW(hDlg, id, CB_ADDSTRING, 0,
161 (LPARAM)pi[i].pPrinterName );
162 }
163 HeapFree(GetProcessHeap(), 0, pi);
164 if(!name ||
165 (i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1,
166 (LPARAM)name)) == CB_ERR) {
167 WCHAR buf[260];
168 DWORD dwBufLen = sizeof(buf)/sizeof(buf[0]);
169 if (name != NULL)
170 WARN("Can't find %s in printer list so trying to find default\n",
171 debugstr_w(name));
172 if(!GetDefaultPrinterW(buf, &dwBufLen))
173 return num;
174 i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf);
175 if(i == CB_ERR)
176 TRACE("Can't find default printer in printer list\n");
177 }
178 SendDlgItemMessageW(hDlg, id, CB_SETCURSEL, i, 0);
179 return num;
180 }
181
182 /***********************************************************************
183 * PRINTDLG_CreateDevNames [internal]
184 *
185 *
186 * creates a DevNames structure.
187 *
188 * (NB. when we handle unicode the offsets will be in wchars).
189 */
190 static BOOL PRINTDLG_CreateDevNames(HGLOBAL *hmem, const char* DeviceDriverName,
191 const char* DeviceName, const char* OutputPort)
192 {
193 long size;
194 char* pDevNamesSpace;
195 char* pTempPtr;
196 LPDEVNAMES lpDevNames;
197 char buf[260];
198 DWORD dwBufLen = sizeof(buf);
199
200 size = strlen(DeviceDriverName) + 1
201 + strlen(DeviceName) + 1
202 + strlen(OutputPort) + 1
203 + sizeof(DEVNAMES);
204
205 if(*hmem)
206 *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
207 else
208 *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
209 if (*hmem == 0)
210 return FALSE;
211
212 pDevNamesSpace = GlobalLock(*hmem);
213 lpDevNames = (LPDEVNAMES) pDevNamesSpace;
214
215 pTempPtr = pDevNamesSpace + sizeof(DEVNAMES);
216 strcpy(pTempPtr, DeviceDriverName);
217 lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
218
219 pTempPtr += strlen(DeviceDriverName) + 1;
220 strcpy(pTempPtr, DeviceName);
221 lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
222
223 pTempPtr += strlen(DeviceName) + 1;
224 strcpy(pTempPtr, OutputPort);
225 lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
226
227 GetDefaultPrinterA(buf, &dwBufLen);
228 lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0;
229 GlobalUnlock(*hmem);
230 return TRUE;
231 }
232
233 static BOOL PRINTDLG_CreateDevNamesW(HGLOBAL *hmem, LPCWSTR DeviceDriverName,
234 LPCWSTR DeviceName, LPCWSTR OutputPort)
235 {
236 long size;
237 LPWSTR pDevNamesSpace;
238 LPWSTR pTempPtr;
239 LPDEVNAMES lpDevNames;
240 WCHAR bufW[260];
241 DWORD dwBufLen = sizeof(bufW) / sizeof(WCHAR);
242
243 size = sizeof(WCHAR)*lstrlenW(DeviceDriverName) + 2
244 + sizeof(WCHAR)*lstrlenW(DeviceName) + 2
245 + sizeof(WCHAR)*lstrlenW(OutputPort) + 2
246 + sizeof(DEVNAMES);
247
248 if(*hmem)
249 *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE);
250 else
251 *hmem = GlobalAlloc(GMEM_MOVEABLE, size);
252 if (*hmem == 0)
253 return FALSE;
254
255 pDevNamesSpace = GlobalLock(*hmem);
256 lpDevNames = (LPDEVNAMES) pDevNamesSpace;
257
258 pTempPtr = (LPWSTR)((LPDEVNAMES)pDevNamesSpace + 1);
259 lstrcpyW(pTempPtr, DeviceDriverName);
260 lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
261
262 pTempPtr += lstrlenW(DeviceDriverName) + 1;
263 lstrcpyW(pTempPtr, DeviceName);
264 lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
265
266 pTempPtr += lstrlenW(DeviceName) + 1;
267 lstrcpyW(pTempPtr, OutputPort);
268 lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
269
270 GetDefaultPrinterW(bufW, &dwBufLen);
271 lpDevNames->wDefault = (lstrcmpW(bufW, DeviceName) == 0) ? 1 : 0;
272 GlobalUnlock(*hmem);
273 return TRUE;
274 }
275
276 /***********************************************************************
277 * PRINTDLG_UpdatePrintDlg [internal]
278 *
279 *
280 * updates the PrintDlg structure for return values.
281 *
282 * RETURNS
283 * FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values)
284 * TRUE if successful.
285 */
286 static BOOL PRINTDLG_UpdatePrintDlgA(HWND hDlg,
287 PRINT_PTRA* PrintStructures)
288 {
289 LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
290 PDEVMODEA lpdm = PrintStructures->lpDevMode;
291 LPPRINTER_INFO_2A pi = PrintStructures->lpPrinterInfo;
292
293
294 if(!lpdm) {
295 FIXME("No lpdm ptr?\n");
296 return FALSE;
297 }
298
299
300 if(!(lppd->Flags & PD_PRINTSETUP)) {
301 /* check whether nFromPage and nToPage are within range defined by
302 * nMinPage and nMaxPage
303 */
304 if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
305 WORD nToPage;
306 WORD nFromPage;
307 nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
308 nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
309 if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
310 nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
311 WCHAR resourcestr[256];
312 WCHAR resultstr[256];
313 LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, resourcestr, 255);
314 wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage);
315 LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, resourcestr, 255);
316 MessageBoxW(hDlg, resultstr, resourcestr, MB_OK | MB_ICONWARNING);
317 return FALSE;
318 }
319 lppd->nFromPage = nFromPage;
320 lppd->nToPage = nToPage;
321 lppd->Flags |= PD_PAGENUMS;
322 }
323 else
324 lppd->Flags &= ~PD_PAGENUMS;
325
326 if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */
327 lppd->Flags |= PD_SELECTION;
328 else
329 lppd->Flags &= ~PD_SELECTION;
330
331 if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
332 static char file[] = "FILE:";
333 lppd->Flags |= PD_PRINTTOFILE;
334 pi->pPortName = file;
335 }
336
337 if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
338 FIXME("Collate lppd not yet implemented as output\n");
339 }
340
341 /* set PD_Collate and nCopies */
342 if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
343 /* The application doesn't support multiple copies or collate...
344 */
345 lppd->Flags &= ~PD_COLLATE;
346 lppd->nCopies = 1;
347 /* if the printer driver supports it... store info there
348 * otherwise no collate & multiple copies !
349 */
350 if (lpdm->dmFields & DM_COLLATE)
351 lpdm->dmCollate =
352 (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
353 if (lpdm->dmFields & DM_COPIES)
354 lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
355 } else {
356 /* Application is responsible for multiple copies */
357 if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
358 lppd->Flags |= PD_COLLATE;
359 else
360 lppd->Flags &= ~PD_COLLATE;
361 lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
362 /* multiple copies already included in the document. Driver must print only one copy */
363 lpdm->u1.s1.dmCopies = 1;
364 }
365
366 /* Print quality, PrintDlg16 */
367 if(GetDlgItem(hDlg, cmb1))
368 {
369 HWND hQuality = GetDlgItem(hDlg, cmb1);
370 int Sel = SendMessageA(hQuality, CB_GETCURSEL, 0, 0);
371
372 if(Sel != CB_ERR)
373 {
374 LONG dpi = SendMessageA(hQuality, CB_GETITEMDATA, Sel, 0);
375 lpdm->dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION;
376 lpdm->u1.s1.dmPrintQuality = LOWORD(dpi);
377 lpdm->dmYResolution = HIWORD(dpi);
378 }
379 }
380 }
381 return TRUE;
382 }
383
384 static BOOL PRINTDLG_UpdatePrintDlgW(HWND hDlg,
385 PRINT_PTRW* PrintStructures)
386 {
387 LPPRINTDLGW lppd = PrintStructures->lpPrintDlg;
388 PDEVMODEW lpdm = PrintStructures->lpDevMode;
389 LPPRINTER_INFO_2W pi = PrintStructures->lpPrinterInfo;
390
391
392 if(!lpdm) {
393 FIXME("No lpdm ptr?\n");
394 return FALSE;
395 }
396
397
398 if(!(lppd->Flags & PD_PRINTSETUP)) {
399 /* check whether nFromPage and nToPage are within range defined by
400 * nMinPage and nMaxPage
401 */
402 if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */
403 WORD nToPage;
404 WORD nFromPage;
405 nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE);
406 nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE);
407 if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage ||
408 nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) {
409 WCHAR resourcestr[256];
410 WCHAR resultstr[256];
411 LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE,
412 resourcestr, 255);
413 wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage);
414 LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE,
415 resourcestr, 255);
416 MessageBoxW(hDlg, resultstr, resourcestr,
417 MB_OK | MB_ICONWARNING);
418 return FALSE;
419 }
420 lppd->nFromPage = nFromPage;
421 lppd->nToPage = nToPage;
422 lppd->Flags |= PD_PAGENUMS;
423 }
424 else
425 lppd->Flags &= ~PD_PAGENUMS;
426
427 if (IsDlgButtonChecked(hDlg, rad2) == BST_CHECKED) /* Selection */
428 lppd->Flags |= PD_SELECTION;
429 else
430 lppd->Flags &= ~PD_SELECTION;
431
432 if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */
433 static WCHAR file[] = {'F','I','L','E',':',0};
434 lppd->Flags |= PD_PRINTTOFILE;
435 pi->pPortName = file;
436 }
437
438 if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */
439 FIXME("Collate lppd not yet implemented as output\n");
440 }
441
442 /* set PD_Collate and nCopies */
443 if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) {
444 /* The application doesn't support multiple copies or collate...
445 */
446 lppd->Flags &= ~PD_COLLATE;
447 lppd->nCopies = 1;
448 /* if the printer driver supports it... store info there
449 * otherwise no collate & multiple copies !
450 */
451 if (lpdm->dmFields & DM_COLLATE)
452 lpdm->dmCollate =
453 (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED);
454 if (lpdm->dmFields & DM_COPIES)
455 lpdm->u1.s1.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
456 } else {
457 if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
458 lppd->Flags |= PD_COLLATE;
459 else
460 lppd->Flags &= ~PD_COLLATE;
461 lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
462 }
463 }
464 return TRUE;
465 }
466
467 static BOOL PRINTDLG_PaperSizeA(
468 PRINTDLGA *pdlga,const WORD PaperSize,LPPOINT size
469 ) {
470 DEVNAMES *dn;
471 DEVMODEA *dm;
472 LPSTR devname,portname;
473 int i;
474 INT NrOfEntries,ret;
475 WORD *Words = NULL;
476 POINT *points = NULL;
477 BOOL retval = FALSE;
478
479 dn = GlobalLock(pdlga->hDevNames);
480 dm = GlobalLock(pdlga->hDevMode);
481 devname = ((char*)dn)+dn->wDeviceOffset;
482 portname = ((char*)dn)+dn->wOutputOffset;
483
484
485 NrOfEntries = DeviceCapabilitiesA(devname,portname,DC_PAPERNAMES,NULL,dm);
486 if (!NrOfEntries) {
487 FIXME("No papernames found for %s/%s\n",devname,portname);
488 goto out;
489 }
490 if (NrOfEntries == -1) {
491 ERR("Hmm ? DeviceCapabilities() DC_PAPERNAMES failed, ret -1 !\n");
492 goto out;
493 }
494
495 Words = HeapAlloc(GetProcessHeap(),0,NrOfEntries*sizeof(WORD));
496 if (NrOfEntries != (ret=DeviceCapabilitiesA(devname,portname,DC_PAPERS,(LPSTR)Words,dm))) {
497 FIXME("Number of returned vals %d is not %d\n",NrOfEntries,ret);
498 goto out;
499 }
500 for (i=0;i<NrOfEntries;i++)
501 if (Words[i] == PaperSize)
502 break;
503 if (i == NrOfEntries) {
504 FIXME("Papersize %d not found in list?\n",PaperSize);
505 goto out;
506 }
507 points = HeapAlloc(GetProcessHeap(),0,sizeof(points[0])*NrOfEntries);
508 if (NrOfEntries!=(ret=DeviceCapabilitiesA(devname,portname,DC_PAPERSIZE,(LPSTR)points,dm))) {
509 FIXME("Number of returned sizes %d is not %d?\n",NrOfEntries,ret);
510 goto out;
511 }
512 /* this is _10ths_ of a millimeter */
513 size->x=points[i].x;
514 size->y=points[i].y;
515 retval = TRUE;
516 out:
517 GlobalUnlock(pdlga->hDevNames);
518 GlobalUnlock(pdlga->hDevMode);
519 HeapFree(GetProcessHeap(),0,Words);
520 HeapFree(GetProcessHeap(),0,points);
521 return retval;
522 }
523
524 static BOOL PRINTDLG_PaperSizeW(
525 PRINTDLGW *pdlga,const WCHAR *PaperSize,LPPOINT size
526 ) {
527 DEVNAMES *dn;
528 DEVMODEW *dm;
529 LPWSTR devname,portname;
530 int i;
531 INT NrOfEntries,ret;
532 WCHAR *Names = NULL;
533 POINT *points = NULL;
534 BOOL retval = FALSE;
535
536 dn = GlobalLock(pdlga->hDevNames);
537 dm = GlobalLock(pdlga->hDevMode);
538 devname = ((WCHAR*)dn)+dn->wDeviceOffset;
539 portname = ((WCHAR*)dn)+dn->wOutputOffset;
540
541
542 NrOfEntries = DeviceCapabilitiesW(devname,portname,DC_PAPERNAMES,NULL,dm);
543 if (!NrOfEntries) {
544 FIXME("No papernames found for %s/%s\n",debugstr_w(devname),debugstr_w(portname));
545 goto out;
546 }
547 if (NrOfEntries == -1) {
548 ERR("Hmm ? DeviceCapabilities() DC_PAPERNAMES failed, ret -1 !\n");
549 goto out;
550 }
551
552 Names = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*NrOfEntries*64);
553 if (NrOfEntries != (ret=DeviceCapabilitiesW(devname,portname,DC_PAPERNAMES,Names,dm))) {
554 FIXME("Number of returned vals %d is not %d\n",NrOfEntries,ret);
555 goto out;
556 }
557 for (i=0;i<NrOfEntries;i++)
558 if (!lstrcmpW(PaperSize,Names+(64*i)))
559 break;
560 if (i==NrOfEntries) {
561 FIXME("Papersize %s not found in list?\n",debugstr_w(PaperSize));
562 goto out;
563 }
564 points = HeapAlloc(GetProcessHeap(),0,sizeof(points[0])*NrOfEntries);
565 if (NrOfEntries!=(ret=DeviceCapabilitiesW(devname,portname,DC_PAPERSIZE,(LPWSTR)points,dm))) {
566 FIXME("Number of returned sizes %d is not %d?\n",NrOfEntries,ret);
567 goto out;
568 }
569 /* this is _10ths_ of a millimeter */
570 size->x=points[i].x;
571 size->y=points[i].y;
572 retval = TRUE;
573 out:
574 GlobalUnlock(pdlga->hDevNames);
575 GlobalUnlock(pdlga->hDevMode);
576 HeapFree(GetProcessHeap(),0,Names);
577 HeapFree(GetProcessHeap(),0,points);
578 return retval;
579 }
580
581
582 /************************************************************************
583 * PRINTDLG_SetUpPaperComboBox
584 *
585 * Initialize either the papersize or inputslot combos of the Printer Setup
586 * dialog. We store the associated word (eg DMPAPER_A4) as the item data.
587 * We also try to re-select the old selection.
588 */
589 static BOOL PRINTDLG_SetUpPaperComboBoxA(HWND hDlg,
590 int nIDComboBox,
591 char* PrinterName,
592 char* PortName,
593 LPDEVMODEA dm)
594 {
595 int i;
596 int NrOfEntries;
597 char* Names;
598 WORD* Words;
599 DWORD Sel;
600 WORD oldWord = 0;
601 int NamesSize;
602 int fwCapability_Names;
603 int fwCapability_Words;
604
605 TRACE(" Printer: %s, Port: %s, ComboID: %d\n",PrinterName,PortName,nIDComboBox);
606
607 /* query the dialog box for the current selected value */
608 Sel = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
609 if(Sel != CB_ERR) {
610 /* we enter here only if a different printer is selected after
611 * the Print Setup dialog is opened. The current settings are
612 * stored into the newly selected printer.
613 */
614 oldWord = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA,
615 Sel, 0);
616 if (dm) {
617 if (nIDComboBox == cmb2)
618 dm->u1.s1.dmPaperSize = oldWord;
619 else
620 dm->u1.s1.dmDefaultSource = oldWord;
621 }
622 }
623 else {
624 /* we enter here only when the Print setup dialog is initially
625 * opened. In this case the settings are restored from when
626 * the dialog was last closed.
627 */
628 if (dm) {
629 if (nIDComboBox == cmb2)
630 oldWord = dm->u1.s1.dmPaperSize;
631 else
632 oldWord = dm->u1.s1.dmDefaultSource;
633 }
634 }
635
636 if (nIDComboBox == cmb2) {
637 NamesSize = 64;
638 fwCapability_Names = DC_PAPERNAMES;
639 fwCapability_Words = DC_PAPERS;
640 } else {
641 nIDComboBox = cmb3;
642 NamesSize = 24;
643 fwCapability_Names = DC_BINNAMES;
644 fwCapability_Words = DC_BINS;
645 }
646
647 /* for some printer drivers, DeviceCapabilities calls a VXD to obtain the
648 * paper settings. As Wine doesn't allow VXDs, this results in a crash.
649 */
650 WARN(" if your printer driver uses VXDs, expect a crash now!\n");
651 NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
652 fwCapability_Names, NULL, dm);
653 if (NrOfEntries == 0)
654 WARN("no Name Entries found!\n");
655 else if (NrOfEntries < 0)
656 return FALSE;
657
658 if(DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Words, NULL, dm)
659 != NrOfEntries) {
660 ERR("Number of caps is different\n");
661 NrOfEntries = 0;
662 }
663
664 Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(char)*NamesSize);
665 Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
666 NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
667 fwCapability_Names, Names, dm);
668 NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName,
669 fwCapability_Words, (LPSTR)Words, dm);
670
671 /* reset any current content in the combobox */
672 SendDlgItemMessageA(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
673
674 /* store new content */
675 for (i = 0; i < NrOfEntries; i++) {
676 DWORD pos = SendDlgItemMessageA(hDlg, nIDComboBox, CB_ADDSTRING, 0,
677 (LPARAM)(&Names[i*NamesSize]) );
678 SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETITEMDATA, pos,
679 Words[i]);
680 }
681
682 /* Look for old selection - can't do this is previous loop since
683 item order will change as more items are added */
684 Sel = 0;
685 for (i = 0; i < NrOfEntries; i++) {
686 if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
687 oldWord) {
688 Sel = i;
689 break;
690 }
691 }
692 SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
693
694 HeapFree(GetProcessHeap(),0,Words);
695 HeapFree(GetProcessHeap(),0,Names);
696 return TRUE;
697 }
698
699 static BOOL PRINTDLG_SetUpPaperComboBoxW(HWND hDlg,
700 int nIDComboBox,
701 const WCHAR* PrinterName,
702 const WCHAR* PortName,
703 LPDEVMODEW dm)
704 {
705 int i;
706 int NrOfEntries;
707 WCHAR* Names;
708 WORD* Words;
709 DWORD Sel;
710 WORD oldWord = 0;
711 int NamesSize;
712 int fwCapability_Names;
713 int fwCapability_Words;
714
715 TRACE(" Printer: %s, Port: %s, ComboID: %d\n",debugstr_w(PrinterName),debugstr_w(PortName),nIDComboBox);
716
717 /* query the dialog box for the current selected value */
718 Sel = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0);
719 if(Sel != CB_ERR) {
720 /* we enter here only if a different printer is selected after
721 * the Print Setup dialog is opened. The current settings are
722 * stored into the newly selected printer.
723 */
724 oldWord = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA,
725 Sel, 0);
726 if (dm) {
727 if (nIDComboBox == cmb2)
728 dm->u1.s1.dmPaperSize = oldWord;
729 else
730 dm->u1.s1.dmDefaultSource = oldWord;
731 }
732 }
733 else {
734 /* we enter here only when the Print setup dialog is initially
735 * opened. In this case the settings are restored from when
736 * the dialog was last closed.
737 */
738 if (dm) {
739 if (nIDComboBox == cmb2)
740 oldWord = dm->u1.s1.dmPaperSize;
741 else
742 oldWord = dm->u1.s1.dmDefaultSource;
743 }
744 }
745
746 if (nIDComboBox == cmb2) {
747 NamesSize = 64;
748 fwCapability_Names = DC_PAPERNAMES;
749 fwCapability_Words = DC_PAPERS;
750 } else {
751 nIDComboBox = cmb3;
752 NamesSize = 24;
753 fwCapability_Names = DC_BINNAMES;
754 fwCapability_Words = DC_BINS;
755 }
756
757 /* for some printer drivers, DeviceCapabilities calls a VXD to obtain the
758 * paper settings. As Wine doesn't allow VXDs, this results in a crash.
759 */
760 WARN(" if your printer driver uses VXDs, expect a crash now!\n");
761 NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
762 fwCapability_Names, NULL, dm);
763 if (NrOfEntries == 0)
764 WARN("no Name Entries found!\n");
765 else if (NrOfEntries < 0)
766 return FALSE;
767
768 if(DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Words, NULL, dm)
769 != NrOfEntries) {
770 ERR("Number of caps is different\n");
771 NrOfEntries = 0;
772 }
773
774 Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WCHAR)*NamesSize);
775 Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD));
776 NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
777 fwCapability_Names, Names, dm);
778 NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName,
779 fwCapability_Words, (LPWSTR)Words, dm);
780
781 /* reset any current content in the combobox */
782 SendDlgItemMessageW(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0);
783
784 /* store new content */
785 for (i = 0; i < NrOfEntries; i++) {
786 DWORD pos = SendDlgItemMessageW(hDlg, nIDComboBox, CB_ADDSTRING, 0,
787 (LPARAM)(&Names[i*NamesSize]) );
788 SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETITEMDATA, pos,
789 Words[i]);
790 }
791
792 /* Look for old selection - can't do this is previous loop since
793 item order will change as more items are added */
794 Sel = 0;
795 for (i = 0; i < NrOfEntries; i++) {
796 if(SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) ==
797 oldWord) {
798 Sel = i;
799 break;
800 }
801 }
802 SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0);
803
804 HeapFree(GetProcessHeap(),0,Words);
805 HeapFree(GetProcessHeap(),0,Names);
806 return TRUE;
807 }
808
809
810 /***********************************************************************
811 * PRINTDLG_UpdatePrinterInfoTexts [internal]
812 */
813 static void PRINTDLG_UpdatePrinterInfoTextsA(HWND hDlg, const PRINTER_INFO_2A *pi)
814 {
815 char StatusMsg[256];
816 char ResourceString[256];
817 int i;
818
819 /* Status Message */
820 StatusMsg[0]='\0';
821
822 /* add all status messages */
823 for (i = 0; i < 25; i++) {
824 if (pi->Status & (1<<i)) {
825 LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i,
826 ResourceString, 255);
827 strcat(StatusMsg,ResourceString);
828 }
829 }
830 /* append "ready" */
831 /* FIXME: status==ready must only be appended if really so.
832 but how to detect? */
833 LoadStringA(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY,
834 ResourceString, 255);
835 strcat(StatusMsg,ResourceString);
836 SetDlgItemTextA(hDlg, stc12, StatusMsg);
837
838 /* set all other printer info texts */
839 SetDlgItemTextA(hDlg, stc11, pi->pDriverName);
840
841 if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
842 SetDlgItemTextA(hDlg, stc14, pi->pLocation);
843 else
844 SetDlgItemTextA(hDlg, stc14, pi->pPortName);
845 SetDlgItemTextA(hDlg, stc13, pi->pComment ? pi->pComment : "");
846 return;
847 }
848
849 static void PRINTDLG_UpdatePrinterInfoTextsW(HWND hDlg, const PRINTER_INFO_2W *pi)
850 {
851 WCHAR StatusMsg[256];
852 WCHAR ResourceString[256];
853 static const WCHAR emptyW[] = {0};
854 int i;
855
856 /* Status Message */
857 StatusMsg[0]='\0';
858
859 /* add all status messages */
860 for (i = 0; i < 25; i++) {
861 if (pi->Status & (1<<i)) {
862 LoadStringW(COMDLG32_hInstance, PD32_PRINTER_STATUS_PAUSED+i,
863 ResourceString, 255);
864 lstrcatW(StatusMsg,ResourceString);
865 }
866 }
867 /* append "ready" */
868 /* FIXME: status==ready must only be appended if really so.
869 but how to detect? */
870 LoadStringW(COMDLG32_hInstance, PD32_PRINTER_STATUS_READY,
871 ResourceString, 255);
872 lstrcatW(StatusMsg,ResourceString);
873 SetDlgItemTextW(hDlg, stc12, StatusMsg);
874
875 /* set all other printer info texts */
876 SetDlgItemTextW(hDlg, stc11, pi->pDriverName);
877 if (pi->pLocation != NULL && pi->pLocation[0] != '\0')
878 SetDlgItemTextW(hDlg, stc14, pi->pLocation);
879 else
880 SetDlgItemTextW(hDlg, stc14, pi->pPortName);
881 SetDlgItemTextW(hDlg, stc13, pi->pComment ? pi->pComment : emptyW);
882 }
883
884
885 /*******************************************************************
886 *
887 * PRINTDLG_ChangePrinter
888 *
889 */
890 BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name,
891 PRINT_PTRA *PrintStructures)
892 {
893 LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
894 LPDEVMODEA lpdm = NULL;
895 LONG dmSize;
896 DWORD needed;
897 HANDLE hprn;
898
899 HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo);
900 HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo);
901 if(!OpenPrinterA(name, &hprn, NULL)) {
902 ERR("Can't open printer %s\n", name);
903 return FALSE;
904 }
905 GetPrinterA(hprn, 2, NULL, 0, &needed);
906 PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed);
907