~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to base/gdevwpr2.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

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