1 /* Copyright (C) 1989, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevwpr2.c,v 1.18 2004/08/05 17:02:36 stefan Exp $ */
18 /*
19 * Microsoft Windows 3.n printer driver for Ghostscript.
20 * Original version by Russell Lang and
21 * L. Peter Deutsch, Aladdin Enterprises.
22 * Modified by rjl 1995-03-29 to use BMP printer code
23 * Modified by Pierre Arnaud 1999-02-18 (see description below)
24 * Modified by lpd 1999-04-03 for compatibility with Borland C++ 4.5.
25 * Modified by Pierre Arnaud 1999-10-03 (accept b&w printing on color printers).
26 * Modified by Pierre Arnaud 1999-11-20 (accept lower resolution)
27 * Bug fixed by Pierre Arnaud 2000-03-09 (win_pr2_put_params error when is_open)
28 * Bug fixed by Pierre Arnaud 2000-03-20 (win_pr2_set_bpp did not set anti_alias)
29 * Bug fixed by Pierre Arnaud 2000-03-22 (win_pr2_set_bpp depth was wrong)
30 * Modified by Pierre Arnaud 2000-12-12 (mainly added support for Tumble)
31 * Bug fixed by Pierre Arnaud 2000-12-18 (-dQueryUser now works from cmd line)
32 */
33
34 /* This driver uses the printer default size and resolution and
35 * ignores page size and resolution set using -gWIDTHxHEIGHT and
36 * -rXxY. You must still set the correct PageSize to get the
37 * correct clipping path.
38 * The code in win_pr2_getdc() does try to set the printer page
39 * size from the PostScript PageSize, but it isn't working
40 * reliably at the moment.
41 *
42 * This driver doesn't work with some Windows printer drivers.
43 * The reason is unknown. All printers to which I have access
44 * work.
45 *
46 * rjl 1997-11-20
47 */
48
49 /* Additions by Pierre Arnaud (Pierre.Arnaud@opac.ch)
50 *
51 * The driver has been extended in order to provide some run-time
52 * feed-back about the default Windows printer and to give the user
53 * the opportunity to select the printer's properties before the
54 * device gets opened (and any spooling starts).
55 *
56 * The driver returns an additional property named "UserSettings".
57 * This is a dictionary which contens are valid only after setting
58 * the QueryUser property (see below). The UserSettings dict contains
59 * the following keys:
60 *
61 * DocumentRange [begin end] (int array, can be set)
62 * Defines the range of pages in the document; [1 10] would
63 * describe a document starting at page 1 and ending at page 10.
64 *
65 * SelectedRange [begin end] (int array, can be set)
66 * Defines the pages the user wants to print.
67 *
68 * MediaSize [width height] (float array, read only)
69 * Current printer's media size.
70 *
71 * Copies n (integer, can be set)
72 * User selected number of copies.
73 *
74 * PrintCopies n (integer, read only)
75 * Number of copies which must be printed by Ghostscript itself.
76 * This is still experimental.
77 *
78 * DocumentName name (string, can be set)
79 * Name to be associated with the print job.
80 *
81 * UserChangedSettings (bool, read only)
82 * Set to 'true' if the last QueryUser operation succeeded.
83 *
84 * Paper n (integer, can be set)
85 * Windows paper selection (0 = automatic).
86 *
87 * Orient n (integer, can be set)
88 * Windows paper orientation (0 = automatic).
89 *
90 * Color n (integer, can be set)
91 * Windows color (0 = automatic, 1 = monochrome, 2 = color).
92 *
93 * MaxResolution n (integer, can be set)
94 * Maximum resolution in pixels pet inch (0 = no maximum). If
95 * the printer has a higher resolution than the maximum, trim
96 * the used resolution to the best one (dpi_chosen <= dpi_max,
97 * with dpi_chosen = dpi_printer / ratio).
98 */
99
100 /* Supported printer parameters are :
101 *
102 * -dBitsPerPixel=n
103 * Override what the Window printer driver returns.
104 *
105 * -dNoCancel
106 * Don't display cancel dialog box. Useful for unattended or
107 * console EXE operation.
108 *
109 * -dQueryUser=n
110 * Query user interactively for the destination printer, before
111 * the device gets opened. This fills in the UserSettings dict
112 * and the OutputFile name properties. The following values are
113 * supported for n:
114 * 1 => show standard Print dialog
115 * 2 => show Print Setup dialog instead
116 * 3 => select default printer
117 * other, does nothing
118 *
119 * The /Duplex & /Tumble keys of the setpagedevice dict are supported
120 * if the Windows printer supports duplex printing.
121 */
122
123 #include "gdevprn.h"
124 #include "gdevpccm.h"
125
126 #include "windows_.h"
127 #include <shellapi.h>
128 #include "gp_mswin.h"
129
130 #include "gp.h"
131 #include "gpcheck.h"
132 #include "commdlg.h"
133
134
135 /* Make sure we cast to the correct structure type. */
136 typedef struct gx_device_win_pr2_s gx_device_win_pr2;
137
138 #undef wdev
139 #define wdev ((gx_device_win_pr2 *)dev)
140
141 /* Device procedures */
142
143 /* See gxdevice.h for the definitions of the procedures. */
144 private dev_proc_open_device(win_pr2_open);
145 private dev_proc_close_device(win_pr2_close);
146 private dev_proc_print_page(win_pr2_print_page);
147 private dev_proc_map_rgb_color(win_pr2_map_rgb_color);
148 private dev_proc_map_color_rgb(win_pr2_map_color_rgb);
149 private dev_proc_get_params(win_pr2_get_params);
150 private dev_proc_put_params(win_pr2_put_params);
151
152 private void win_pr2_set_bpp(gx_device * dev, int depth);
153
154 private const gx_device_procs win_pr2_procs =
155 prn_color_params_procs(win_pr2_open, gdev_prn_output_page, win_pr2_close,
156 win_pr2_map_rgb_color, win_pr2_map_color_rgb,
157 win_pr2_get_params, win_pr2_put_params);
158
159 #define PARENT_WINDOW HWND_DESKTOP
160 BOOL CALLBACK CancelDlgProc(HWND, UINT, WPARAM, LPARAM);
161 BOOL CALLBACK AbortProc2(HDC, int);
162
163
164 /* The device descriptor */
165 typedef struct gx_device_win_pr2_s gx_device_win_pr2;
166 struct gx_device_win_pr2_s {
167 gx_device_common;
168 gx_prn_device_common;
169 HDC hdcprn;
170 bool nocancel;
171
172 int doc_page_begin; /* first page number in document */
173 int doc_page_end; /* last page number in document */
174 int user_page_begin; /* user's choice: first page to print */
175 int user_page_end; /* user's choice: last page to print */
176 int user_copies; /* user's choice: number of copies */
177 int print_copies; /* number of times GS should print each page */
178 float user_media_size[2]; /* width/height of media selected by user */
179 char doc_name[200]; /* name of document for the spooler */
180 char paper_name[64]; /* name of selected paper format */
181 bool user_changed_settings; /* true if user validated dialog */
182 int user_paper; /* user's choice: paper format */
183 int user_orient; /* user's choice: paper orientation */
184 int user_color; /* user's choice: color format */
185 int max_dpi; /* maximum resolution in DPI */
186 int ratio; /* stretch ratio when printing */
187 int selected_bpp; /* selected bpp, memorised by win_pr2_set_bpp */
188 bool tumble; /* tumble setting (with duplex) */
189 int query_user; /* query user (-dQueryUser) */
190
191 HANDLE win32_hdevmode; /* handle to device mode information */
192 HANDLE win32_hdevnames; /* handle to device names information */
193
194 DLGPROC lpfnAbortProc;
195 DLGPROC lpfnCancelProc;
196 HWND hDlgModeless;
197
198 bool use_old_spool_name; /* user prefers old \\spool\ name */
199 gx_device_win_pr2* original_device; /* used to detect copies */
200 };
201
202 gx_device_win_pr2 far_data gs_mswinpr2_device =
203 {
204 prn_device_std_body(gx_device_win_pr2, win_pr2_procs, "mswinpr2",
205 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72.0, 72.0,
206 0, 0, 0, 0,
207 0, win_pr2_print_page), /* depth = 0 */
208 0, /* hdcprn */
209 0, /* nocancel */
210 0, /* doc_page_begin */
211 0, /* doc_page_end */
212 0, /* user_page_begin */
213 0, /* user_page_end */
214 1, /* user_copies */
215 1, /* print_copies */
216 { 0.0, 0.0 }, /* user_media_size */
217 { 0 }, /* doc_name */
218 { 0 }, /* paper_name */
219 0, /* user_changed_settings */
220 0, /* user_paper */
221 0, /* user_orient */
222 0, /* user_color */
223 0, /* max_dpi */
224 0, /* ratio */
225 0, /* selected_bpp */
226 false, /* tumble */
227 -1, /* query_user */
228 NULL, /* win32_hdevmode */
229 NULL, /* win32_hdevnames */
230 NULL, /* lpfnAbortProc */
231 NULL, /* lpfnCancelProc */
232 NULL, /* hDlgModeless */
233 false, /* use_old_spool_name */
234 NULL /* original_device */
235 };
236
237 /********************************************************************************/
238
239 private int win_pr2_getdc(gx_device_win_pr2 * dev);
240 private int win_pr2_update_dev(gx_device_win_pr2 * dev, LPDEVMODE pdevmode);
241 private int win_pr2_update_win(gx_device_win_pr2 * dev, LPDEVMODE pdevmode);
242 private int win_pr2_print_setup_interaction(gx_device_win_pr2 * dev, int mode);
243 private int win_pr2_write_user_settings(gx_device_win_pr2 * dev, gs_param_list * plist);
244 private int win_pr2_read_user_settings(gx_device_win_pr2 * dev, gs_param_list * plist);
245 private void win_pr2_copy_check(gx_device_win_pr2 * dev);
246
247 /********************************************************************************/
248
249 /* Open the win_pr2 driver */
250 private int
win_pr2_open(gx_device * dev)251 win_pr2_open(gx_device * dev)
252 {
253 int code;
254 int depth;
255 PRINTDLG pd;
256 POINT offset;
257 POINT size;
258 float m[4];
259 FILE *pfile;
260 DOCINFO docinfo;
261 float ratio = 1.0;
262
263 win_pr2_copy_check(wdev);
264
265 /* get a HDC for the printer */
266 if ((wdev->win32_hdevmode) &&
267 (wdev->win32_hdevnames)) {
268 /* The user has already had the opportunity to choose the output */
269 /* file interactively. Just use the specified parameters. */
270
271 LPDEVMODE devmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
272 LPDEVNAMES devnames = (LPDEVNAMES) GlobalLock(wdev->win32_hdevnames);
273
274 const char* driver = (char*)(devnames)+(devnames->wDriverOffset);
275 const char* device = (char*)(devnames)+(devnames->wDeviceOffset);
276 const char* output = (char*)(devnames)+(devnames->wOutputOffset);
277
278 wdev->hdcprn = CreateDC(driver, device, output, devmode);
279
280 GlobalUnlock(wdev->win32_hdevmode);
281 GlobalUnlock(wdev->win32_hdevnames);
282
283 if (wdev->hdcprn == NULL) {
284 return gs_error_Fatal;
285 }
286
287 } else if (!win_pr2_getdc(wdev)) {
288 /* couldn't get a printer from -sOutputFile= */
289 /* Prompt with dialog box */
290
291 LPDEVMODE devmode = NULL;
292 memset(&pd, 0, sizeof(pd));
293
294 pd.lStructSize = sizeof(pd);
295 pd.hwndOwner = PARENT_WINDOW;
296 pd.Flags = PD_RETURNDC;
297 pd.nMinPage = wdev->doc_page_begin;
298 pd.nMaxPage = wdev->doc_page_end;
299 pd.nFromPage = wdev->user_page_begin;
300 pd.nToPage = wdev->user_page_end;
301 pd.nCopies = wdev->user_copies;
302
303 if (!PrintDlg(&pd)) {
304 /* device not opened - exit ghostscript */
305 return gs_error_Fatal; /* exit Ghostscript cleanly */
306 }
307
308 devmode = GlobalLock(pd.hDevMode);
309 win_pr2_update_dev(wdev,devmode);
310 GlobalUnlock(pd.hDevMode);
311
312 if (wdev->win32_hdevmode)
313 GlobalFree(wdev->win32_hdevmode);
314 if (wdev->win32_hdevnames)
315 GlobalFree(wdev->win32_hdevnames);
316
317 wdev->hdcprn = pd.hDC;
318 wdev->win32_hdevmode = pd.hDevMode;
319 wdev->win32_hdevnames = pd.hDevNames;
320
321 pd.hDevMode = NULL;
322 pd.hDevNames = NULL;
323 }
324 if (!(GetDeviceCaps(wdev->hdcprn, RASTERCAPS) != RC_DIBTODEV)) {
325 errprintf( "Windows printer does not have RC_DIBTODEV\n");
326 DeleteDC(wdev->hdcprn);
327 return gs_error_limitcheck;
328 }
329 /* initialise printer, install abort proc */
330 wdev->lpfnAbortProc = (DLGPROC) AbortProc2;
331 SetAbortProc(wdev->hdcprn, (ABORTPROC) wdev->lpfnAbortProc);
332
333 /*
334 * Some versions of the Windows headers include lpszDatatype and fwType,
335 * and some don't. Since we want to set these fields to zero anyway,
336 * we just start by zeroing the whole structure.
337 */
338 memset(&docinfo, 0, sizeof(docinfo));
339 docinfo.cbSize = sizeof(docinfo);
340 docinfo.lpszDocName = wdev->doc_name;
341 /*docinfo.lpszOutput = NULL;*/
342 /*docinfo.lpszDatatype = NULL;*/
343 /*docinfo.fwType = 0;*/
344
345 if (docinfo.lpszDocName[0] == 0) {
346 docinfo.lpszDocName = "Ghostscript output";
347 }
348
349 if (StartDoc(wdev->hdcprn, &docinfo) <= 0) {
350 errprintf("Printer StartDoc failed (error %08x)\n", GetLastError());
351 DeleteDC(wdev->hdcprn);
352 return gs_error_limitcheck;
353 }
354
355 dev->x_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSX);
356 dev->y_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSY);
357
358 wdev->ratio = 1;
359
360 if (wdev->max_dpi > 50) {
361
362 float dpi_x = dev->x_pixels_per_inch;
363 float dpi_y = dev->y_pixels_per_inch;
364
365 while ((dev->x_pixels_per_inch > wdev->max_dpi)
366 || (dev->y_pixels_per_inch > wdev->max_dpi)) {
367 ratio += 1.0;
368 wdev->ratio ++;
369 dev->x_pixels_per_inch = dpi_x / ratio;
370 dev->y_pixels_per_inch = dpi_y / ratio;
371 }
372 }
373
374 size.x = GetDeviceCaps(wdev->hdcprn, PHYSICALWIDTH);
375 size.y = GetDeviceCaps(wdev->hdcprn, PHYSICALHEIGHT);
376 gx_device_set_width_height(dev, (int)(size.x / ratio), (int)(size.y / ratio));
377 offset.x = GetDeviceCaps(wdev->hdcprn, PHYSICALOFFSETX);
378 offset.y = GetDeviceCaps(wdev->hdcprn, PHYSICALOFFSETY);
379
380 /* m[] gives margins in inches */
381 m[0] /*left */ = offset.x / dev->x_pixels_per_inch / ratio;
382 m[3] /*top */ = offset.y / dev->y_pixels_per_inch / ratio;
383 m[2] /*right */ = (size.x - offset.x - GetDeviceCaps(wdev->hdcprn, HORZRES)) / dev->x_pixels_per_inch / ratio;
384 m[1] /*bottom */ = (size.y - offset.y - GetDeviceCaps(wdev->hdcprn, VERTRES)) / dev->y_pixels_per_inch / ratio;
385 gx_device_set_margins(dev, m, true);
386
387 depth = dev->color_info.depth;
388 if (depth == 0) {
389 /* Set parameters that were unknown before opening device */
390 /* Find out if the device supports color */
391 /* We recognize 1, 4 (but use only 3), 8 and 24 bit color devices */
392 depth = GetDeviceCaps(wdev->hdcprn, PLANES) * GetDeviceCaps(wdev->hdcprn, BITSPIXEL);
393 }
394 win_pr2_set_bpp(dev, depth);
395
396 /* gdev_prn_open opens a temporary file which we don't want */
397 /* so we specify the name now so we can delete it later */
398 pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
399 wdev->fname, "wb");
400 fclose(pfile);
401 code = gdev_prn_open(dev);
402 /* delete unwanted temporary file */
403 unlink(wdev->fname);
404
405 if (!wdev->nocancel) {
406 /* inform user of progress with dialog box and allow cancel */
407 wdev->lpfnCancelProc = (DLGPROC) CancelDlgProc;
408 wdev->hDlgModeless = CreateDialog(phInstance, "CancelDlgBox",
409 PARENT_WINDOW, wdev->lpfnCancelProc);
410 ShowWindow(wdev->hDlgModeless, SW_HIDE);
411 }
412 return code;
413 };
414
415 /* Close the win_pr2 driver */
416 private int
win_pr2_close(gx_device * dev)417 win_pr2_close(gx_device * dev)
418 {
419 int code;
420 int aborted = FALSE;
421
422 win_pr2_copy_check(wdev);
423
424 /* Free resources */
425
426 if (!wdev->nocancel) {
427 if (!wdev->hDlgModeless)
428 aborted = TRUE;
429 else
430 DestroyWindow(wdev->hDlgModeless);
431 wdev->hDlgModeless = 0;
432 }
433 if (aborted)
434 AbortDoc(wdev->hdcprn);
435 else
436 EndDoc(wdev->hdcprn);
437
438 DeleteDC(wdev->hdcprn);
439
440 if (wdev->win32_hdevmode != NULL) {
441 GlobalFree(wdev->win32_hdevmode);
442 wdev->win32_hdevmode = NULL;
443 }
444 if (wdev->win32_hdevnames != NULL) {
445 GlobalFree(wdev->win32_hdevnames);
446 wdev->win32_hdevnames = NULL;
447 }
448
449 code = gdev_prn_close(dev);
450 return code;
451 }
452
453
454 /* ------ Internal routines ------ */
455
456 #undef wdev
457 #define wdev ((gx_device_win_pr2 *)pdev)
458
459 /********************************************************************************/
460
461 /* ------ Private definitions ------ */
462
463
464 /* new win_pr2_print_page routine */
465
466 /* Write BMP header to memory, then send bitmap to printer */
467 /* one scan line at a time */
468 private int
win_pr2_print_page(gx_device_printer * pdev,FILE * file)469 win_pr2_print_page(gx_device_printer * pdev, FILE * file)
470 {
471 int raster = gdev_prn_raster(pdev);
472
473 /* BMP scan lines are padded to 32 bits. */
474 ulong bmp_raster = raster + (-raster & 3);
475 ulong bmp_raster_multi;
476 int scan_lines, yslice, lines, i;
477 int width;
478 int depth = pdev->color_info.depth;
479 byte *row;
480 int y;
481 int code = 0; /* return code */
482 MSG msg;
483 char dlgtext[32];
484 HGLOBAL hrow;
485 int ratio = ((gx_device_win_pr2 *)pdev)->ratio;
486
487 struct bmi_s {
488 BITMAPINFOHEADER h;
489 RGBQUAD pal[256];
490 } bmi;
491
492 scan_lines = dev_print_scan_lines(pdev);
493 width = (int)(pdev->width - ((dev_l_margin(pdev) + dev_r_margin(pdev) -
494 dev_x_offset(pdev)) * pdev->x_pixels_per_inch));
495
496 yslice = 65535 / bmp_raster; /* max lines in 64k */
497 bmp_raster_multi = bmp_raster * yslice;
498 hrow = GlobalAlloc(0, bmp_raster_multi);
499 row = GlobalLock(hrow);
500 if (row == 0) /* can't allocate row buffer */
501 return_error(gs_error_VMerror);
502
503 /* Write the info header. */
504
505 bmi.h.biSize = sizeof(bmi.h);
506 bmi.h.biWidth = pdev->width; /* wdev->mdev.width; */
507 bmi.h.biHeight = yslice;
508 bmi.h.biPlanes = 1;
509 bmi.h.biBitCount = pdev->color_info.depth;
510 bmi.h.biCompression = 0;
511 bmi.h.biSizeImage = 0; /* default */
512 bmi.h.biXPelsPerMeter = 0; /* default */
513 bmi.h.biYPelsPerMeter = 0; /* default */
514
515 StartPage(wdev->hdcprn);
516
517 /* Write the palette. */
518
519 if (depth <= 8) {
520 int i;
521 gx_color_value rgb[3];
522 LPRGBQUAD pq;
523
524 bmi.h.biClrUsed = 1 << depth;
525 bmi.h.biClrImportant = 1 << depth;
526 for (i = 0; i != 1 << depth; i++) {
527 (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
528 (gx_color_index) i, rgb);
529 pq = &bmi.pal[i];
530 pq->rgbRed = gx_color_value_to_byte(rgb[0]);
531 pq->rgbGreen = gx_color_value_to_byte(rgb[1]);
532 pq->rgbBlue = gx_color_value_to_byte(rgb[2]);
533 pq->rgbReserved = 0;
534 }
535 } else {
536 bmi.h.biClrUsed = 0;
537 bmi.h.biClrImportant = 0;
538 }
539
540 if (!wdev->nocancel) {
541 sprintf(dlgtext, "Printing page %d", (int)(pdev->PageCount) + 1);
542 SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PRINTING), dlgtext);
543 ShowWindow(wdev->hDlgModeless, SW_SHOW);
544 }
545 for (y = 0; y < scan_lines;) {
546 /* copy slice to row buffer */
547 if (y > scan_lines - yslice)
548 lines = scan_lines - y;
549 else
550 lines = yslice;
551 for (i = 0; i < lines; i++)
552 gdev_prn_copy_scan_lines(pdev, y + i,
553 row + (bmp_raster * (lines - 1 - i)), raster);
554
555 if (ratio > 1) {
556 StretchDIBits(wdev->hdcprn, 0, y*ratio, pdev->width*ratio, lines*ratio,
557 0, 0, pdev->width, lines,
558 row,
559 (BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS, SRCCOPY);
560 } else {
561 SetDIBitsToDevice(wdev->hdcprn, 0, y, pdev->width, lines,
562 0, 0, 0, lines,
563 row,
564 (BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS);
565 }
566 y += lines;
567
568 if (!wdev->nocancel) {
569 /* inform user of progress */
570 sprintf(dlgtext, "%d%% done", (int)(y * 100L / scan_lines));
571 SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PCDONE), dlgtext);
572 }
573 /* process message loop */
574 while (PeekMessage(&msg, wdev->hDlgModeless, 0, 0, PM_REMOVE)) {
575 if ((wdev->hDlgModeless == 0) || !IsDialogMessage(wdev->hDlgModeless, &msg)) {
576 TranslateMessage(&msg);
577 DispatchMessage(&msg);
578 }
579 }
580 if ((!wdev->nocancel) && (wdev->hDlgModeless == 0)) {
581 /* user pressed cancel button */
582 break;
583 }
584 }
585
586 if ((!wdev->nocancel) && (wdev->hDlgModeless == 0))
587 code = gs_error_Fatal; /* exit Ghostscript cleanly */
588 else {
589 /* push out the page */
590 if (!wdev->nocancel)
591 SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PCDONE),
592 "Ejecting page...");
593 EndPage(wdev->hdcprn);
594 if (!wdev->nocancel)
595 ShowWindow(wdev->hDlgModeless, SW_HIDE);
596 }
597
598 GlobalUnlock(hrow);
599 GlobalFree(hrow);
600
601 return code;
602 }
603
604 /* combined color mappers */
605
606 /* 24-bit color mappers (taken from gdevmem2.c). */
607 /* Note that Windows expects RGB values in the order B,G,R. */
608
609 /* Map a r-g-b color to a color index. */
610 private gx_color_index
win_pr2_map_rgb_color(gx_device * dev,const gx_color_value cv[])611 win_pr2_map_rgb_color(gx_device * dev, const gx_color_value cv[])
612 {
613 gx_color_value r = cv[0];
614 gx_color_value g = cv[1];
615 gx_color_value b = cv[2];
616 switch (dev->color_info.depth) {
617 case 1:
618 return gdev_prn_map_rgb_color(dev, cv);
619 case 4:
620 /* use only 8 colors */
621 return (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
622 (g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
623 (b > (gx_max_color_value / 2 + 1) ? 1 : 0);
624 case 8:
625 return pc_8bit_map_rgb_color(dev, cv);
626 case 24:
627 return gx_color_value_to_byte(r) +
628 ((uint) gx_color_value_to_byte(g) << 8) +
629 ((ulong) gx_color_value_to_byte(b) << 16);
630 }
631 return 0; /* error */
632 }
633
634 /* Map a color index to a r-g-b color. */
635 private int
win_pr2_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])636 win_pr2_map_color_rgb(gx_device * dev, gx_color_index color,
637 gx_color_value prgb[3])
638 {
639 switch (dev->color_info.depth) {
640 case 1:
641 gdev_prn_map_color_rgb(dev, color, prgb);
642 break;
643 case 4:
644 /* use only 8 colors */
645 prgb[0] = (color & 4) ? gx_max_color_value : 0;
646 prgb[1] = (color & 2) ? gx_max_color_value : 0;
647 prgb[2] = (color & 1) ? gx_max_color_value : 0;
648 break;
649 case 8:
650 pc_8bit_map_color_rgb(dev, color, prgb);
651 break;
652 case 24:
653 prgb[2] = gx_color_value_from_byte(color >> 16);
654 prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
655 prgb[0] = gx_color_value_from_byte(color & 0xff);
656 break;
657 }
658 return 0;
659 }
660
661 void
win_pr2_set_bpp(gx_device * dev,int depth)662 win_pr2_set_bpp(gx_device * dev, int depth)
663 {
664 if (depth > 8) {
665 static const gx_device_color_info win_pr2_24color = dci_std_color(24);
666
667 dev->color_info = win_pr2_24color;
668 depth = 24;
669 } else if (depth >= 8) {
670 /* 8-bit (SuperVGA-style) color. */
671 /* (Uses a fixed palette of 3,3,2 bits.) */
672 static const gx_device_color_info win_pr2_8color = dci_pc_8bit;
673
674 dev->color_info = win_pr2_8color;
675 depth = 8;
676 } else if (depth >= 3) {
677 /* 3 plane printer */
678 /* suitable for impact dot matrix CMYK printers */
679 /* create 4-bit bitmap, but only use 8 colors */
680 static const gx_device_color_info win_pr2_4color = dci_values(3, 4, 1, 1, 2, 2);
681
682 dev->color_info = win_pr2_4color;
683 depth = 4;
684 } else { /* default is black_and_white */
685 static const gx_device_color_info win_pr2_1color = dci_std_color(1);
686
687 dev->color_info = win_pr2_1color;
688 depth = 1;
689 }
690
691 ((gx_device_win_pr2 *)dev)->selected_bpp = depth;
692
693 /* copy encode/decode procedures */
694 dev->procs.encode_color = dev->procs.map_rgb_color;
695 dev->procs.decode_color = dev->procs.map_color_rgb;
696 if (depth == 1) {
697 dev->procs.get_color_mapping_procs =
698 gx_default_DevGray_get_color_mapping_procs;
699 dev->procs.get_color_comp_index =
700 gx_default_DevGray_get_color_comp_index;
701 }
702 else {
703 dev->procs.get_color_mapping_procs =
704 gx_default_DevRGB_get_color_mapping_procs;
705 dev->procs.get_color_comp_index =
706 gx_default_DevRGB_get_color_comp_index;
707 }
708 }
709
710 /********************************************************************************/
711
712 /* Get device parameters */
713 int
win_pr2_get_params(gx_device * pdev,gs_param_list * plist)714 win_pr2_get_params(gx_device * pdev, gs_param_list * plist)
715 {
716 int code = gdev_prn_get_params(pdev, plist);
717
718 win_pr2_copy_check(wdev);
719
720 if (code >= 0)
721 code = param_write_bool(plist, "NoCancel",
722 &(wdev->nocancel));
723 if (code >= 0)
724 code = param_write_int(plist, "QueryUser",
725 &(wdev->query_user));
726 if (code >= 0)
727 code = win_pr2_write_user_settings(wdev, plist);
728
729 if ((code >= 0) && (wdev->Duplex_set > 0))
730 code = param_write_bool(plist, "Tumble",
731 &(wdev->tumble));
732
733 return code;
734 }
735
736
737 /* We implement this ourselves so that we can change BitsPerPixel */
738 /* before the device is opened */
739 int
win_pr2_put_params(gx_device * pdev,gs_param_list * plist)740 win_pr2_put_params(gx_device * pdev, gs_param_list * plist)
741 {
742 int ecode = 0, code;
743 int old_bpp = pdev->color_info.depth;
744 int bpp = old_bpp;
745 bool tumble = wdev->tumble;
746 bool nocancel = wdev->nocancel;
747 int queryuser = 0;
748 bool old_duplex = wdev->Duplex;
749 bool old_tumble = wdev->tumble;
750 int old_orient = wdev->user_orient;
751 int old_color = wdev->user_color;
752 int old_paper = wdev->user_paper;
753 int old_mx_dpi = wdev->max_dpi;
754
755 if (wdev->Duplex_set < 0) {
756 wdev->Duplex_set = 0;
757 wdev->Duplex = false;
758 wdev->tumble = false;
759 }
760
761 win_pr2_copy_check(wdev);
762
763 code = win_pr2_read_user_settings(wdev, plist);
764
765 switch (code = param_read_int(plist, "BitsPerPixel", &bpp)) {
766 case 0:
767 if (pdev->is_open) {
768 if (wdev->selected_bpp == bpp) {
769 break;
770 }
771 ecode = gs_error_rangecheck;
772 } else { /* change dev->color_info is valid before device is opened */
773 win_pr2_set_bpp(pdev, bpp);
774 break;
775 }
776 goto bppe;
777 default:
778 ecode = code;
779 bppe:param_signal_error(plist, "BitsPerPixel", ecode);
780 case 1:
781 break;
782 }
783
784 switch (code = param_read_bool(plist, "NoCancel", &nocancel)) {
785 case 0:
786 if (pdev->is_open) {
787 if (wdev->nocancel == nocancel) {
788 break;
789 }
790 ecode = gs_error_rangecheck;
791 } else {
792 wdev->nocancel = nocancel;
793 break;
794 }
795 goto nocancele;
796 default:
797 ecode = code;
798 nocancele:param_signal_error(plist, "NoCancel", ecode);
799 case 1:
800 break;
801 }
802
803 switch (code = param_read_bool(plist, "Tumble", &tumble)) {
804 case 0:
805 wdev->tumble = tumble;
806 break;
807 default:
808 ecode = code;
809 param_signal_error(plist, "Tumble", ecode);
810 case 1:
811 break;
812 }
813
814 switch (code = param_read_int(plist, "QueryUser", &queryuser)) {
815 case 0:
816 if ((queryuser > 0) &&
817 (queryuser < 4)) {
818 win_pr2_print_setup_interaction(wdev, queryuser);
819 }
820 break;
821 default:
822 ecode = code;
823 param_signal_error(plist, "QueryUser", ecode);
824 case 1:
825 break;
826 }
827
828 if (ecode >= 0)
829 ecode = gdev_prn_put_params(pdev, plist);
830
831 if (wdev->win32_hdevmode && wdev->hdcprn) {
832 if ( (old_duplex != wdev->Duplex)
833 || (old_tumble != wdev->tumble)
834 || (old_orient != wdev->user_orient)
835 || (old_color != wdev->user_color)
836 || (old_paper != wdev->user_paper)
837 || (old_mx_dpi != wdev->max_dpi) ) {
838
839 LPDEVMODE pdevmode = GlobalLock(wdev->win32_hdevmode);
840
841 if (pdevmode) {
842 win_pr2_update_win(wdev, pdevmode);
843 ResetDC(wdev->hdcprn, pdevmode);
844 GlobalUnlock(pdevmode);
845 }
846 }
847 }
848
849 return ecode;
850 }
851
852 #undef wdev
853
854 /********************************************************************************/
855
856
857 /* Get Device Context for printer */
858 private int
win_pr2_getdc(gx_device_win_pr2 * wdev)859 win_pr2_getdc(gx_device_win_pr2 * wdev)
860 {
861 char *device;
862 char *devices;
863 char *p;
864 char driverbuf[512];
865 char *driver;
866 char *output;
867 char *devcap;
868 int devcapsize;
869 int size;
870
871 int i, n;
872 POINT *pp;
873 int paperindex;
874 int paperwidth, paperheight;
875 int orientation;
876 int papersize;
877 char papername[64];
878 char drvname[32];
879 HINSTANCE hlib;
880 LPFNDEVMODE pfnExtDeviceMode;
881 LPFNDEVCAPS pfnDeviceCapabilities;
882 LPDEVMODE podevmode, pidevmode;
883
884 HANDLE hprinter;
885
886 /* first try to derive the printer name from -sOutputFile= */
887 /* is printer if name prefixed by \\spool\ or by %printer% */
888 if (is_spool(wdev->fname)) {
889 device = wdev->fname + 8; /* skip over \\spool\ */
890 wdev->use_old_spool_name = true;
891 } else if (strncmp("%printer%",wdev->fname,9) == 0) {
892 device = wdev->fname + 9; /* skip over %printer% */
893 wdev->use_old_spool_name = false;
894 } else {
895 return FALSE;
896 }
897
898 /* now try to match the printer name against the [Devices] section */
899 if ((devices = gs_malloc(wdev->memory, 4096, 1, "win_pr2_getdc")) == (char *)NULL)
900 return FALSE;
901 GetProfileString("Devices", NULL, "", devices, 4096);
902 p = devices;
903 while (*p) {
904 if (stricmp(p, device) == 0)
905 break;
906 p += strlen(p) + 1;
907 }
908 if (*p == '\0')
909 p = NULL;
910 gs_free(wdev->memory, devices, 4096, 1, "win_pr2_getdc");
911 if (p == NULL)
912 return FALSE; /* doesn't match an available printer */
913
914 /* the printer exists, get the remaining information from win.ini */
915 GetProfileString("Devices", device, "", driverbuf, sizeof(driverbuf));
916 driver = strtok(driverbuf, ",");
917 output = strtok(NULL, ",");
918 if (is_win32s)
919 {
920 strcpy(drvname, driver);
921 strcat(drvname, ".drv");
922 driver = drvname;
923 }
924
925 if (!is_win32s) { /* Win32 */
926 if (!OpenPrinter(device, &hprinter, NULL))
927 return FALSE;
928 size = DocumentProperties(NULL, hprinter, device, NULL, NULL, 0);
929 if ((podevmode = gs_malloc(wdev->memory, size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
930 ClosePrinter(hprinter);
931 return FALSE;
932 }
933 if ((pidevmode = gs_malloc(wdev->memory, size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
934 gs_free(wdev->memory, podevmode, size, 1, "win_pr2_getdc");
935 ClosePrinter(hprinter);
936 return FALSE;
937 }
938 DocumentProperties(NULL, hprinter, device, podevmode, NULL, DM_OUT_BUFFER);
939 pfnDeviceCapabilities = (LPFNDEVCAPS) DeviceCapabilities;
940 } else
941 { /* Win16 and Win32s */
942 /* now load the printer driver */
943 hlib = LoadLibrary(driver);
944 if (hlib < (HINSTANCE) HINSTANCE_ERROR)
945 return FALSE;
946
947 /* call ExtDeviceMode() to get default parameters */
948 pfnExtDeviceMode = (LPFNDEVMODE) GetProcAddress(hlib, "ExtDeviceMode");
949 if (pfnExtDeviceMode == (LPFNDEVMODE) NULL) {
950 FreeLibrary(hlib);
951 return FALSE;
952 }
953 pfnDeviceCapabilities = (LPFNDEVCAPS) GetProcAddress(hlib, "DeviceCapabilities");
954 if (pfnDeviceCapabilities == (LPFNDEVCAPS) NULL) {
955 FreeLibrary(hlib);
956 return FALSE;
957 }
958 size = pfnExtDeviceMode(NULL, hlib, NULL, device, output, NULL, NULL, 0);
959 if ((podevmode = gs_malloc(wdev->memory, size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
960 FreeLibrary(hlib);
961 return FALSE;
962 }
963 if ((pidevmode = gs_malloc(wdev->memory, size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
964 gs_free(wdev->memory, podevmode, size, 1, "win_pr2_getdc");
965 FreeLibrary(hlib);
966 return FALSE;
967 }
968 pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
969 NULL, NULL, DM_OUT_BUFFER);
970 }
971
972 /* now find out what paper sizes are available */
973 devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, NULL, NULL);
974 devcapsize *= sizeof(POINT);
975 if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
976 return FALSE;
977 n = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, devcap, NULL);
978 paperwidth = (int)(wdev->MediaSize[0] * 254 / 72);
979 paperheight = (int)(wdev->MediaSize[1] * 254 / 72);
980 papername[0] = '\0';
981 papersize = 0;
982 paperindex = -1;
983 orientation = 0;
984 pp = (POINT *) devcap;
985 for (i = 0; i < n; i++, pp++) {
986 if ((pp->x < paperwidth + 20) && (pp->x > paperwidth - 20) &&
987 (pp->y < paperheight + 20) && (pp->y > paperheight - 20)) {
988 paperindex = i;
989 paperwidth = pp->x;
990 paperheight = pp->y;
991 orientation = DMORIENT_PORTRAIT;
992 break;
993 }
994 }
995 if (paperindex < 0) {
996 /* try again in landscape */
997 pp = (POINT *) devcap;
998 for (i = 0; i < n; i++, pp++) {
999 if ((pp->x < paperheight + 20) && (pp->x > paperheight - 20) &&
1000 (pp->y < paperwidth + 20) && (pp->y > paperwidth - 20)) {
1001 paperindex = i;
1002 paperwidth = pp->x;
1003 paperheight = pp->y;
1004 orientation = DMORIENT_LANDSCAPE;
1005 break;
1006 }
1007 }
1008 }
1009 gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
1010
1011 /* get the dmPaperSize */
1012 devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERS, NULL, NULL);
1013 devcapsize *= sizeof(WORD);
1014 if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
1015 return FALSE;
1016 n = pfnDeviceCapabilities(device, output, DC_PAPERS, devcap, NULL);
1017 if ((paperindex >= 0) && (paperindex < n))
1018 papersize = ((WORD *) devcap)[paperindex];
1019 gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
1020
1021 /* get the paper name */
1022 devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, NULL, NULL);
1023 devcapsize *= 64;
1024 if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
1025 return FALSE;
1026 n = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, devcap, NULL);
1027 if ((paperindex >= 0) && (paperindex < n))
1028 strcpy(papername, devcap + paperindex * 64);
1029 gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
1030
1031 memcpy(pidevmode, podevmode, size);
1032
1033 pidevmode->dmFields = 0;
1034
1035 wdev->paper_name[0] = 0;
1036
1037 if ( (wdev->user_paper)
1038 && (wdev->user_paper != papersize) ) {
1039 papersize = wdev->user_paper;
1040 paperheight = 0;
1041 paperwidth = 0;
1042 papername[0] = 0;
1043 }
1044 if (wdev->user_orient) {
1045 orientation = wdev->user_orient;
1046 }
1047
1048 pidevmode->dmFields &= ~(DM_PAPERSIZE | DM_ORIENTATION | DM_COLOR | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_DUPLEX);
1049 pidevmode->dmFields |= DM_DEFAULTSOURCE;
1050 pidevmode->dmDefaultSource = 0;
1051
1052 if (orientation) {
1053 wdev->user_orient = orientation;
1054 }
1055 if (papersize) {
1056 wdev->user_paper = papersize;
1057 strcpy (wdev->paper_name, papername);
1058 }
1059
1060 if (paperheight && paperwidth) {
1061 pidevmode->dmFields |= (DM_PAPERLENGTH | DM_PAPERWIDTH);
1062 pidevmode->dmPaperWidth = paperwidth;
1063 pidevmode->dmPaperLength = paperheight;
1064 wdev->user_media_size[0] = paperwidth / 254.0 * 72.0;
1065 wdev->user_media_size[1] = paperheight / 254.0 * 72.0;
1066 }
1067
1068 if (DeviceCapabilities(device, output, DC_DUPLEX, NULL, NULL)) {
1069 wdev->Duplex_set = 1;
1070 }
1071
1072 win_pr2_update_win(wdev, pidevmode);
1073
1074 if (!is_win32s) {
1075
1076 /* merge the entries */
1077 DocumentProperties(NULL, hprinter, device, podevmode, pidevmode, DM_IN_BUFFER | DM_OUT_BUFFER);
1078 ClosePrinter(hprinter);
1079
1080 /* now get a DC */
1081 wdev->hdcprn = CreateDC(driver, device, NULL, podevmode);
1082 } else
1083 { /* Win16 and Win32s */
1084 pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
1085 pidevmode, NULL, DM_IN_BUFFER | DM_OUT_BUFFER);
1086 /* release the printer driver */
1087 FreeLibrary(hlib);
1088 /* now get a DC */
1089 if (is_win32s)
1090 strtok(driver, "."); /* remove .drv */
1091 wdev->hdcprn = CreateDC(driver, device, output, podevmode);
1092 }
1093
1094 if (wdev->win32_hdevmode == NULL) {
1095 wdev->win32_hdevmode = GlobalAlloc(0, sizeof(DEVMODE));
1096 }
1097
1098 if (wdev->win32_hdevmode) {
1099 LPDEVMODE pdevmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
1100 if (pdevmode) {
1101 memcpy(pdevmode, podevmode, sizeof(DEVMODE));
1102 GlobalUnlock(wdev->win32_hdevmode);
1103 }
1104 }
1105
1106 gs_free(wdev->memory, pidevmode, size, 1, "win_pr2_getdc");
1107 gs_free(wdev->memory, podevmode, size, 1, "win_pr2_getdc");
1108
1109 if (wdev->hdcprn != (HDC) NULL)
1110 return TRUE; /* success */
1111
1112 /* fall back to prompting user */
1113 return FALSE;
1114 }
1115
1116
1117 /*
1118 * Minimalist update of the wdev parameters (mainly for the
1119 * UserSettings parameters).
1120 */
1121
1122 private int
win_pr2_update_dev(gx_device_win_pr2 * dev,LPDEVMODE pdevmode)1123 win_pr2_update_dev(gx_device_win_pr2 * dev, LPDEVMODE pdevmode)
1124 {
1125 if (pdevmode == 0)
1126 return FALSE;
1127
1128 if (pdevmode->dmFields & DM_COLOR) {
1129 dev->user_color = pdevmode->dmColor;
1130 }
1131 if (pdevmode->dmFields & DM_ORIENTATION) {
1132 dev->user_orient = pdevmode->dmOrientation;
1133 }
1134 if (pdevmode->dmFields & DM_PAPERSIZE) {
1135 dev->user_paper = pdevmode->dmPaperSize;
1136 dev->user_media_size[0] = pdevmode->dmPaperWidth / 254.0 * 72.0;
1137 dev->user_media_size[1] = pdevmode->dmPaperLength / 254.0 * 72.0;
1138 dev->paper_name[0] = 0; /* unknown paper size */
1139 }
1140 if (pdevmode->dmFields & DM_DUPLEX) {
1141 dev->Duplex_set = 1;
1142 dev->Duplex = pdevmode->dmDuplex == DMDUP_SIMPLEX ? false : true;
1143 dev->tumble = pdevmode->dmDuplex == DMDUP_HORIZONTAL ? true : false;
1144 }
1145
1146 return TRUE;
1147 }
1148
1149 private int
win_pr2_update_win(gx_device_win_pr2 * dev,LPDEVMODE pdevmode)1150 win_pr2_update_win(gx_device_win_pr2 * dev, LPDEVMODE pdevmode)
1151 {
1152 if (dev->Duplex_set > 0) {
1153 pdevmode->dmFields |= DM_DUPLEX;
1154 pdevmode->dmDuplex = DMDUP_SIMPLEX;
1155 if (dev->Duplex) {
1156 if (dev->tumble == false) {
1157 pdevmode->dmDuplex = DMDUP_VERTICAL;
1158 } else {
1159 pdevmode->dmDuplex = DMDUP_HORIZONTAL;
1160 }
1161 }
1162 }
1163
1164 if (dev->user_color) {
1165 pdevmode->dmColor = dev->user_color;
1166 pdevmode->dmFields |= DM_COLOR;
1167 }
1168
1169 if (dev->user_orient) {
1170 pdevmode->dmFields |= DM_ORIENTATION;
1171 pdevmode->dmOrientation = dev->user_orient;
1172 }
1173
1174 if (dev->user_paper) {
1175 pdevmode->dmFields |= DM_PAPERSIZE;
1176 pdevmode->dmPaperSize = dev->user_paper;
1177 }
1178 return 0;
1179 }
1180
1181 /********************************************************************************/
1182
1183 #define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
1184 switch ( code = pread(dict.list, (param_name = pname), &(pa)) )\
1185 {\
1186 case 0:\
1187 if ( (pa).size != psize )\
1188 ecode = gs_note_error(gs_error_rangecheck);\
1189 else {
1190 /* The body of the processing code goes here. */
1191 /* If it succeeds, it should do a 'break'; */
1192 /* if it fails, it should set ecode and fall through. */
1193 #define END_ARRAY_PARAM(pa, e)\
1194 }\
1195 goto e;\
1196 default:\
1197 ecode = code;\
1198 e: param_signal_error(dict.list, param_name, ecode);\
1199 case 1:\
1200 (pa).data = 0; /* mark as not filled */\
1201 }
1202
1203
1204 /* Put the user params from UserSettings into our */
1205 /* internal variables. */
1206 private int
win_pr2_read_user_settings(gx_device_win_pr2 * wdev,gs_param_list * plist)1207 win_pr2_read_user_settings(gx_device_win_pr2 * wdev, gs_param_list * plist)
1208 {
1209 gs_param_dict dict;
1210 gs_param_string docn = { 0 };
1211 const char* dict_name = "UserSettings";
1212 const char* param_name = "";
1213 int code = 0;
1214 int ecode = 0;
1215
1216 switch (code = param_begin_read_dict(plist, dict_name, &dict, false)) {
1217 default:
1218 param_signal_error(plist, dict_name, code);
1219 return code;
1220 case 1:
1221 break;
1222 case 0:
1223 {
1224 gs_param_int_array ia;
1225
1226 BEGIN_ARRAY_PARAM(param_read_int_array, "DocumentRange", ia, 2, ia)
1227 if ((ia.data[0] < 0) ||
1228 (ia.data[1] < 0) ||
1229 (ia.data[0] > ia.data[1]))
1230 ecode = gs_note_error(gs_error_rangecheck);
1231 wdev->doc_page_begin = ia.data[0];
1232 wdev->doc_page_end = ia.data[1];
1233 END_ARRAY_PARAM(ia, doc_range_error)
1234
1235 BEGIN_ARRAY_PARAM(param_read_int_array, "SelectedRange", ia, 2, ia)
1236 if ((ia.data[0] < 0) ||
1237 (ia.data[1] < 0) ||
1238 (ia.data[0] > ia.data[1]))
1239 ecode = gs_note_error(gs_error_rangecheck);
1240 wdev->user_page_begin = ia.data[0];
1241 wdev->user_page_end = ia.data[1];
1242 END_ARRAY_PARAM(ia, sel_range_error)
1243
1244 param_read_int(dict.list, "Copies", &wdev->user_copies);
1245 param_read_int(dict.list, "Paper", &wdev->user_paper);
1246 param_read_int(dict.list, "Orientation", &wdev->user_orient);
1247 param_read_int(dict.list, "Color", &wdev->user_color);
1248 param_read_int(dict.list, "MaxResolution", &wdev->max_dpi);
1249
1250 switch (code = param_read_string(dict.list, (param_name = "DocumentName"), &docn)) {
1251 case 0:
1252 if (docn.size < sizeof(wdev->doc_name))
1253 break;
1254 code = gs_error_rangecheck;
1255 /* fall through */
1256 default:
1257 ecode = code;
1258 param_signal_error(plist, param_name, ecode);
1259 /* fall through */
1260 case 1:
1261 docn.data = 0;
1262 break;
1263 }
1264
1265 param_end_read_dict(plist, dict_name, &dict);
1266
1267 if (docn.data) {
1268 memcpy(wdev->doc_name, docn.data, docn.size);
1269 wdev->doc_name[docn.size] = 0;
1270 }
1271
1272 wdev->print_copies = 1;
1273
1274 if (wdev->win32_hdevmode) {
1275 LPDEVMODE devmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
1276 if (devmode) {
1277 devmode->dmCopies = wdev->user_copies;
1278 devmode->dmPaperSize = wdev->user_paper;
1279 devmode->dmOrientation = wdev->user_orient;
1280 devmode->dmColor = wdev->user_color;
1281 GlobalUnlock(wdev->win32_hdevmode);
1282 }
1283 }
1284 }
1285 break;
1286 }
1287
1288 return code;
1289 }
1290
1291
1292 private int
win_pr2_write_user_settings(gx_device_win_pr2 * wdev,gs_param_list * plist)1293 win_pr2_write_user_settings(gx_device_win_pr2 * wdev, gs_param_list * plist)
1294 {
1295 gs_param_dict dict;
1296 gs_param_int_array range;
1297 gs_param_float_array box;
1298 gs_param_string docn;
1299 gs_param_string papn;
1300 int array[2];
1301 const char* pname = "UserSettings";
1302 int code;
1303
1304 dict.size = 12;
1305 code = param_begin_write_dict(plist, pname, &dict, false);
1306 if (code < 0) return code;
1307
1308 array[0] = wdev->doc_page_begin;
1309 array[1] = wdev->doc_page_end;
1310 range.data = array;
1311 range.size = 2;
1312 range.persistent = false;
1313 code = param_write_int_array(dict.list, "DocumentRange", &range);
1314 if (code < 0) goto error;
1315
1316 array[0] = wdev->user_page_begin;
1317 array[1] = wdev->user_page_end;
1318 range.data = array;
1319 range.size = 2;
1320 range.persistent = false;
1321 code = param_write_int_array(dict.list, "SelectedRange", &range);
1322 if (code < 0) goto error;
1323
1324 box.data = wdev->user_media_size;
1325 box.size = 2;
1326 box.persistent = false;
1327 code = param_write_float_array(dict.list, "MediaSize", &box);
1328 if (code < 0) goto error;
1329
1330 code = param_write_int(dict.list, "Copies", &wdev->user_copies);
1331 if (code < 0) goto error;
1332
1333 code = param_write_int(dict.list, "Paper", &wdev->user_paper);
1334 if (code < 0) goto error;
1335
1336 code = param_write_int(dict.list, "Orientation", &wdev->user_orient);
1337 if (code < 0) goto error;
1338
1339 code = param_write_int(dict.list, "Color", &wdev->user_color);
1340 if (code < 0) goto error;
1341
1342 code = param_write_int(dict.list, "MaxResolution", &wdev->max_dpi);
1343 if (code < 0) goto error;
1344
1345 code = param_write_int(dict.list, "PrintCopies", &wdev->print_copies);
1346 if (code < 0) goto error;
1347
1348 docn.data = (const byte*)wdev->doc_name;
1349 docn.size = strlen(wdev->doc_name);
1350 docn.persistent = false;
1351
1352 code = param_write_string(dict.list, "DocumentName", &docn);
1353 if (code < 0) goto error;
1354
1355 papn.data = (const byte*)wdev->paper_name;
1356 papn.size = strlen(wdev->paper_name);
1357 papn.persistent = false;
1358
1359 code = param_write_string(dict.list, "PaperName", &papn);
1360 if (code < 0) goto error;
1361
1362 code = param_write_bool(dict.list, "UserChangedSettings", &wdev->user_changed_settings);
1363
1364 error:
1365 param_end_write_dict(plist, pname, &dict);
1366 return code;
1367 }
1368
1369 /********************************************************************************/
1370
1371 /* Show up a dialog for the user to choose a printer and a paper size.
1372 * If mode == 3, then automatically select the default Windows printer
1373 * instead of asking the user.
1374 */
1375
1376 private int
win_pr2_print_setup_interaction(gx_device_win_pr2 * wdev,int mode)1377 win_pr2_print_setup_interaction(gx_device_win_pr2 * wdev, int mode)
1378 {
1379 PRINTDLG pd;
1380 LPDEVMODE devmode;
1381 LPDEVNAMES devnames;
1382
1383 wdev->user_changed_settings = FALSE;
1384 wdev->query_user = mode;
1385
1386 memset(&pd, 0, sizeof(pd));
1387 pd.lStructSize = sizeof(pd);
1388 pd.hwndOwner = PARENT_WINDOW;
1389
1390 switch (mode) {
1391 case 2: pd.Flags = PD_PRINTSETUP; break;
1392 case 3: pd.Flags = PD_RETURNDEFAULT; break;
1393 default: pd.Flags = 0; break;
1394 }
1395
1396 pd.Flags |= PD_USEDEVMODECOPIES;
1397
1398 pd.nMinPage = wdev->doc_page_begin;
1399 pd.nMaxPage = wdev->doc_page_end;
1400 pd.nFromPage = wdev->user_page_begin;
1401 pd.nToPage = wdev->user_page_end;
1402 pd.nCopies = wdev->user_copies;
1403
1404 /* Show the Print Setup dialog and let the user choose a printer
1405 * and a paper size/orientation.
1406 */
1407
1408 if (!PrintDlg(&pd)) return FALSE;
1409
1410 devmode = (LPDEVMODE) GlobalLock(pd.hDevMode);
1411 devnames = (LPDEVNAMES) GlobalLock(pd.hDevNames);
1412
1413 wdev->user_changed_settings = TRUE;
1414 if (wdev->use_old_spool_name) {
1415 sprintf(wdev->fname, "\\\\spool\\%s", (char*)(devnames)+(devnames->wDeviceOffset));
1416 } else {
1417 sprintf(wdev->fname, "%%printer%%%s", (char*)(devnames)+(devnames->wDeviceOffset));
1418 }
1419
1420 if (mode == 3) {
1421 devmode->dmCopies = wdev->user_copies * wdev->print_copies;
1422 pd.nCopies = 1;
1423 }
1424
1425 wdev->user_page_begin = pd.nFromPage;
1426 wdev->user_page_end = pd.nToPage;
1427 wdev->user_copies = devmode->dmCopies;
1428 wdev->print_copies = pd.nCopies;
1429 wdev->user_media_size[0] = devmode->dmPaperWidth / 254.0 * 72.0;
1430 wdev->user_media_size[1] = devmode->dmPaperLength / 254.0 * 72.0;
1431 wdev->user_paper = devmode->dmPaperSize;
1432 wdev->user_orient = devmode->dmOrientation;
1433 wdev->user_color = devmode->dmColor;
1434
1435 if (devmode->dmFields & DM_DUPLEX) {
1436 wdev->Duplex_set = 1;
1437 wdev->Duplex = devmode->dmDuplex == DMDUP_SIMPLEX ? false : true;
1438 wdev->tumble = devmode->dmDuplex == DMDUP_HORIZONTAL ? true : false;
1439 }
1440
1441 {
1442 float xppinch = 0;
1443 float yppinch = 0;
1444 const char* driver = (char*)(devnames)+(devnames->wDriverOffset);
1445 const char* device = (char*)(devnames)+(devnames->wDeviceOffset);
1446 const char* output = (char*)(devnames)+(devnames->wOutputOffset);
1447
1448 HDC hic = CreateIC(driver, device, output, devmode);
1449
1450 if (hic) {
1451 xppinch = (float)GetDeviceCaps(hic, LOGPIXELSX);
1452 yppinch = (float)GetDeviceCaps(hic, LOGPIXELSY);
1453 wdev->user_media_size[0] = GetDeviceCaps(hic, PHYSICALWIDTH) * 72.0 / xppinch;
1454 wdev->user_media_size[1] = GetDeviceCaps(hic, PHYSICALHEIGHT) * 72.0 / yppinch;
1455 DeleteDC(hic);
1456 }
1457 }
1458
1459 devmode = NULL;
1460 devnames = NULL;
1461
1462 GlobalUnlock(pd.hDevMode);
1463 GlobalUnlock(pd.hDevNames);
1464
1465 if (wdev->win32_hdevmode != NULL) {
1466 GlobalFree(wdev->win32_hdevmode);
1467 }
1468 if (wdev->win32_hdevnames != NULL) {
1469 GlobalFree(wdev->win32_hdevnames);
1470 }
1471
1472 wdev->win32_hdevmode = pd.hDevMode;
1473 wdev->win32_hdevnames = pd.hDevNames;
1474
1475 return TRUE;
1476 }
1477
1478 /* Check that we are dealing with an original device. If this
1479 * happens to be a copy made by "copydevice", we will have to
1480 * copy the original's handles to the associated Win32 params.
1481 */
1482
1483 private void
win_pr2_copy_check(gx_device_win_pr2 * wdev)1484 win_pr2_copy_check(gx_device_win_pr2 * wdev)
1485 {
1486 HGLOBAL hdevmode = wdev->win32_hdevmode;
1487 HGLOBAL hdevnames = wdev->win32_hdevnames;
1488 DWORD devmode_len = (hdevmode) ? GlobalSize(hdevmode) : 0;
1489 DWORD devnames_len = (hdevnames) ? GlobalSize(hdevnames) : 0;
1490
1491 if (wdev->original_device == wdev)
1492 return;
1493
1494 wdev->hdcprn = NULL;
1495 wdev->win32_hdevmode = NULL;
1496 wdev->win32_hdevnames = NULL;
1497
1498 wdev->original_device = wdev;
1499
1500 if (devmode_len) {
1501 wdev->win32_hdevmode = GlobalAlloc(0, devmode_len);
1502 if (wdev->win32_hdevmode) {
1503 memcpy(GlobalLock(wdev->win32_hdevmode), GlobalLock(hdevmode), devmode_len);
1504 GlobalUnlock(wdev->win32_hdevmode);
1505 GlobalUnlock(hdevmode);
1506 }
1507 }
1508
1509 if (devnames_len) {
1510 wdev->win32_hdevnames = GlobalAlloc(0, devnames_len);
1511 if (wdev->win32_hdevnames) {
1512 memcpy(GlobalLock(wdev->win32_hdevnames), GlobalLock(hdevnames), devnames_len);
1513 GlobalUnlock(wdev->win32_hdevnames);
1514 GlobalUnlock(hdevnames);
1515 }
1516 }
1517 }
1518
1519
1520 /* Modeless dialog box - Cancel printing */
1521 BOOL CALLBACK
CancelDlgProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)1522 CancelDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1523 {
1524 switch (message) {
1525 case WM_INITDIALOG:
1526 SetWindowText(hDlg, szAppName);
1527 return TRUE;
1528 case WM_COMMAND:
1529 switch (LOWORD(wParam)) {
1530 case IDCANCEL:
1531 DestroyWindow(hDlg);
1532 EndDialog(hDlg, 0);
1533 return TRUE;
1534 }
1535 }
1536 return FALSE;
1537 }
1538
1539
1540 BOOL CALLBACK
AbortProc2(HDC hdcPrn,int code)1541 AbortProc2(HDC hdcPrn, int code)
1542 {
1543 process_interrupts(NULL);
1544 if (code == SP_OUTOFDISK)
1545 return (FALSE); /* cancel job */
1546 return (TRUE);
1547 }
1548
1549