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 |
|