Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 2001 artofcode LLC.  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: gp_msprn.c,v 1.4 2004/07/07 09:07:35 ghostgum Exp $ */
18
/* %printer% IODevice */
19
 
20
#include "windows_.h"
21
#include "errno_.h"
22
#include "stdio_.h"
23
#include "string_.h"
24
#include "ctype_.h"
25
#include "fcntl_.h"
26
#include <io.h>
27
#include "gp.h"
28
#include "gscdefs.h"
29
#include "gserrors.h"
30
#include "gserror.h"
31
#include "gstypes.h"
32
#include "gsmemory.h"		/* for gxiodev.h */
33
#include "gxiodev.h"
34
 
35
/* The MS-Windows printer IODevice */
36
 
37
/*
38
 * This allows a MS-Windows printer to be specified as an 
39
 * output using
40
 *  -sOutputFile="%printer%HP DeskJet 500"
41
 *
42
 * To write to a remote printer on another server
43
 *  -sOutputFile="%printer%\\server\printer name"
44
 *
45
 * If you don't supply a printer name you will get
46
 *  Error: /undefinedfilename in --.outputpage-- 
47
 * If the printer name is invalid you will get
48
 *  Error: /invalidfileaccess in --.outputpage-- 
49
 *
50
 * This is implemented by returning the file pointer
51
 * for the write end of a pipe, and starting a thread
52
 * which reads the pipe and writes to a Windows printer.
53
 * This will not work in Win32s.
54
 *
55
 * The old method provided by gp_open_printer()
56
 *  -sOutputFile="\\spool\HP DeskJet 500"
57
 * should not be used except on Win32s.
58
 * The "\\spool\" is not a UNC name and causes confusion.
59
 */
60
 
61
private iodev_proc_init(mswin_printer_init);
62
private iodev_proc_fopen(mswin_printer_fopen);
63
private iodev_proc_fclose(mswin_printer_fclose);
64
const gx_io_device gs_iodev_printer = {
65
    "%printer%", "FileSystem",
66
    {mswin_printer_init, iodev_no_open_device,
67
     NULL /*iodev_os_open_file */ , mswin_printer_fopen, mswin_printer_fclose,
68
     iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,
69
     iodev_no_enumerate_files, NULL, NULL,
70
     iodev_no_get_params, iodev_no_put_params
71
    }
72
};
73
 
74
typedef struct tid_s {
75
    unsigned long tid;
76
} tid_t;
77
 
78
 
79
void mswin_printer_thread(void *arg)
80
{
81
    int fd = (int)arg;
82
    char pname[gp_file_name_sizeof];
83
    char data[4096];
84
    HANDLE hprinter = INVALID_HANDLE_VALUE;
85
    int count;
86
    DWORD written;
87
    DOC_INFO_1 di;
88
 
89
    /* Read from pipe and write to Windows printer.
90
     * First gp_file_name_sizeof bytes are name of the printer.
91
     */
92
    if (read(fd, pname, sizeof(pname)) != sizeof(pname)) {
93
	/* Didn't get the printer name */
94
	close(fd);
95
	return;
96
    }
97
 
98
    while ( (count = read(fd, data, sizeof(data))) > 0 ) {
99
	if (hprinter == INVALID_HANDLE_VALUE) {
100
	    if (!OpenPrinter(pname, &hprinter, NULL)) {
101
		close(fd);
102
		return;
103
	    }
104
	    di.pDocName = (LPTSTR)gs_product;
105
	    di.pOutputFile = NULL;
106
	    di.pDatatype = "RAW";
107
	    if (!StartDocPrinter(hprinter, 1, (LPBYTE) & di)) {
108
		AbortPrinter(hprinter);
109
		close(fd);
110
		return;
111
	    }
112
	}
113
	if (!WritePrinter(hprinter, (LPVOID) data, count, &written)) {
114
	    AbortPrinter(hprinter);
115
	    close(fd);
116
	    return;
117
	}
118
    }
119
    if (hprinter != INVALID_HANDLE_VALUE) {
120
	if (count == 0) {
121
	    /* EOF */
122
	    EndDocPrinter(hprinter);
123
	    ClosePrinter(hprinter);
124
	}
125
	else {
126
	    /* Error */
127
	    AbortPrinter(hprinter);
128
	}
129
    }
130
    close(fd);
131
}
132
 
133
/* The file device procedures */
134
private int
135
mswin_printer_init(gx_io_device * iodev, gs_memory_t * mem)
136
{
137
    /* state -> structure containing thread handle */
138
    iodev->state = gs_alloc_bytes(mem, sizeof(tid_t), "mswin_printer_init");
139
    if (iodev->state == NULL)
140
        return_error(gs_error_VMerror);
141
    ((tid_t *)iodev->state)->tid = -1;
142
    return 0;
143
}
144
 
145
 
146
private int
147
mswin_printer_fopen(gx_io_device * iodev, const char *fname, const char *access,
148
	   FILE ** pfile, char *rfname, uint rnamelen)
149
{
150
    DWORD version = GetVersion();
151
    HANDLE hprinter;
152
    int pipeh[2];
153
    unsigned long tid;
154
    HANDLE hthread;
155
    char pname[gp_file_name_sizeof];
156
    unsigned long *ptid = &((tid_t *)(iodev->state))->tid;
157
 
158
    /* Win32s supports neither pipes nor Win32 printers. */
159
    if (((HIWORD(version) & 0x8000) != 0) && 
160
	((HIWORD(version) & 0x4000) == 0))
161
	return_error(gs_error_invalidfileaccess);
162
 
163
    /* Make sure that printer exists. */
164
    if (!OpenPrinter((LPTSTR)fname, &hprinter, NULL))
165
	return_error(gs_error_invalidfileaccess);
166
    ClosePrinter(hprinter);
167
 
168
    /* Create a pipe to connect a FILE pointer to a Windows printer. */
169
    if (_pipe(pipeh, 4096, _O_BINARY) != 0)
170
	return_error(gs_fopen_errno_to_code(errno));
171
 
172
    *pfile = fdopen(pipeh[1], (char *)access);
173
    if (*pfile == NULL) {
174
	close(pipeh[0]);
175
	close(pipeh[1]);
176
	return_error(gs_fopen_errno_to_code(errno));
177
    }
178
 
179
    /* start a thread to read the pipe */
180
    tid = _beginthread(&mswin_printer_thread, 32768, pipeh[0]);
181
    if (tid == -1) {
182
	fclose(*pfile);
183
	close(pipeh[0]);
184
	return_error(gs_error_invalidfileaccess);
185
    }
186
    /* Duplicate thread handle so we can wait on it
187
     * even if original handle is closed by CRTL
188
     * when the thread finishes.
189
     */
190
    if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)tid,
191
	GetCurrentProcess(), &hthread, 
192
	0, FALSE, DUPLICATE_SAME_ACCESS)) {
193
	fclose(*pfile);
194
	return_error(gs_error_invalidfileaccess);
195
    }
196
    *ptid = (unsigned long)hthread;
197
 
198
    /* Give the name of the printer to the thread by writing
199
     * it to the pipe.  This is avoids elaborate thread 
200
     * synchronisation code.
201
     */
202
    strncpy(pname, fname, sizeof(pname));
203
    fwrite(pname, 1, sizeof(pname), *pfile);
204
 
205
    return 0;
206
}
207
 
208
private int
209
mswin_printer_fclose(gx_io_device * iodev, FILE * file)
210
{
211
    unsigned long *ptid = &((tid_t *)(iodev->state))->tid;
212
    HANDLE hthread;
213
    fclose(file);
214
    if (*ptid != -1) {
215
	/* Wait until the print thread finishes before continuing */
216
	hthread = (HANDLE)*ptid;
217
	WaitForSingleObject(hthread, 60000);
218
	CloseHandle(hthread);
219
	*ptid = -1;
220
    }
221
    return 0;
222
}
223
 
224