xref: /plan9/sys/src/cmd/gs/src/gp_mswin.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 /* Copyright (C) 1992, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2 
3    This file is part of Aladdin Ghostscript.
4 
5    Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
6    or distributor accepts any responsibility for the consequences of using it,
7    or for whether it serves any particular purpose or works at all, unless he
8    or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
9    License (the "License") for full details.
10 
11    Every copy of Aladdin Ghostscript must include a copy of the License,
12    normally in a plain ASCII text file named PUBLIC.  The License grants you
13    the right to copy, modify and redistribute Aladdin Ghostscript, but only
14    under certain conditions described in the License.  Among other things, the
15    License requires that the copyright notice and this notice be preserved on
16    all copies.
17  */
18 
19 /*$Id: gp_mswin.c,v 1.1 2000/03/09 08:40:41 lpd Exp $ */
20 /*
21  * Microsoft Windows 3.n platform support for Ghostscript.
22  *
23  * Original version by Russell Lang and Maurice Castro with help from
24  * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
25  * initially created from gp_dosfb.c and gp_itbc.c 5th June 1992.
26  */
27 
28 /* Modified for Win32 & Microsoft C/C++ 8.0 32-Bit, 26.Okt.1994 */
29 /* by Friedrich Nowak                                           */
30 
31 /* Original EXE and GSview specific code removed */
32 /* DLL version must now be used under MS-Windows */
33 /* Russell Lang 16 March 1996 */
34 
35 #include "stdio_.h"
36 #include "string_.h"
37 #include "memory_.h"
38 #include <stdlib.h>
39 #include <stdarg.h>
40 #include "ctype_.h"
41 #include "dos_.h"
42 #include <io.h>
43 #include "malloc_.h"
44 #include <fcntl.h>
45 #include <signal.h>
46 #include "gx.h"
47 #include "gp.h"
48 #include "gpcheck.h"
49 #include "gserrors.h"
50 #include "gsexit.h"
51 
52 #include "windows_.h"
53 #include <shellapi.h>
54 #ifdef __WIN32__
55 #include <winspool.h>
56 #endif
57 #include "gp_mswin.h"
58 #include "gsdll.h"
59 /* use longjmp instead of exit when using DLL */
60 #include <setjmp.h>
61 extern jmp_buf gsdll_env;
62 
63 /* Library routines not declared in a standard header */
64 extern char *getenv(P1(const char *));
65 
66 /* ------ from gnuplot winmain.c plus new stuff ------ */
67 
68 /* limits */
69 #define MAXSTR 255
70 
71 /* public handles */
72 HINSTANCE phInstance;
73 HWND hwndtext = HWND_DESKTOP;	/* would be better to be a real window */
74 
75 const LPSTR szAppName = "Ghostscript";
76 BOOL is_win32s = FALSE;
77 char FAR win_prntmp[MAXSTR];	/* filename of PRN temporary file */
78 private int is_printer(const char *name);
79 int win_init = 0;		/* flag to know if gp_exit has been called */
80 int win_exit_status;
81 
82 BOOL CALLBACK _export AbortProc(HDC, int);
83 
84 #ifdef __WIN32__
85 /* DLL entry point for Borland C++ */
86 BOOL WINAPI _export
87 DllEntryPoint(HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved)
88 {
89     /* Win32s: HIWORD bit 15 is 1 and bit 14 is 0 */
90     /* Win95:  HIWORD bit 15 is 1 and bit 14 is 1 */
91     /* WinNT:  HIWORD bit 15 is 0 and bit 14 is 0 */
92     /* WinNT Shell Update Release is WinNT && LOBYTE(LOWORD) >= 4 */
93     DWORD version = GetVersion();
94 
95     if (((HIWORD(version) & 0x8000) != 0) && ((HIWORD(version) & 0x4000) == 0))
96 	is_win32s = TRUE;
97 
98     phInstance = hInst;
99     return TRUE;
100 }
101 
102 /* DLL entry point for Microsoft Visual C++ */
103 BOOL WINAPI _export
104 DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved)
105 {
106     return DllEntryPoint(hInst, fdwReason, lpReserved);
107 }
108 
109 
110 #else
111 int WINAPI _export
112 LibMain(HINSTANCE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine)
113 {
114     phInstance = hInstance;
115     return 1;
116 }
117 
118 int WINAPI _export
119 WEP(int nParam)
120 {
121     return 1;
122 }
123 #endif
124 
125 
126 BOOL CALLBACK _export
127 AbortProc(HDC hdcPrn, int code)
128 {
129     process_interrupts();
130     if (code == SP_OUTOFDISK)
131 	return (FALSE);		/* cancel job */
132     return (TRUE);
133 }
134 
135 /* ------ Process message loop ------ */
136 /*
137  * Check messages and interrupts; return true if interrupted.
138  * This is called frequently - it must be quick!
139  */
140 int
141 gp_check_interrupts(void)
142 {
143     return (*pgsdll_callback) (GSDLL_POLL, NULL, 0);
144 }
145 
146 /* ====== Generic platform procedures ====== */
147 
148 /* ------ Initialization/termination (from gp_itbc.c) ------ */
149 
150 /* Do platform-dependent initialization. */
151 void
152 gp_init(void)
153 {
154     win_init = 1;
155 }
156 
157 /* Do platform-dependent cleanup. */
158 void
159 gp_exit(int exit_status, int code)
160 {
161     win_init = 0;
162     win_exit_status = exit_status;
163 }
164 
165 /* Exit the program. */
166 void
167 gp_do_exit(int exit_status)
168 {
169     /* Use longjmp since exit would terminate caller */
170     /* setjmp code will check gs_exit_status */
171     longjmp(gsdll_env, gs_exit_status);
172 }
173 
174 /* ------ Printer accessing ------ */
175 
176 /* Forward references */
177 private int gp_printfile(P2(const char *, const char *));
178 
179 /* Open a connection to a printer.  A null file name means use the */
180 /* standard printer connected to the machine, if any. */
181 /* Return NULL if the connection could not be opened. */
182 FILE *
183 gp_open_printer(char fname[gp_file_name_sizeof], int binary_mode)
184 {
185     if (is_printer(fname)) {
186 	FILE *pfile;
187 
188 	/* Open a scratch file, which we will send to the */
189 	/* actual printer in gp_close_printer. */
190 	pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
191 				     win_prntmp, "wb");
192 	return pfile;
193     } else
194 	return fopen(fname, (binary_mode ? "wb" : "w"));
195 }
196 
197 /* Close the connection to the printer. */
198 void
199 gp_close_printer(FILE * pfile, const char *fname)
200 {
201     fclose(pfile);
202     if (!is_printer(fname))
203 	return;			/* a file, not a printer */
204 
205     gp_printfile(win_prntmp, fname);
206     unlink(win_prntmp);
207 }
208 
209 /* Printer abort procedure and progress/cancel dialog box */
210 /* Used by Win32 and mswinprn device */
211 
212 HWND hDlgModeless;
213 
214 BOOL CALLBACK _export
215 PrintAbortProc(HDC hdcPrn, int code)
216 {
217     MSG msg;
218 
219     while (hDlgModeless && PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
220 	if (hDlgModeless || !IsDialogMessage(hDlgModeless, &msg)) {
221 	    TranslateMessage(&msg);
222 	    DispatchMessage(&msg);
223 	}
224     }
225     return (hDlgModeless != 0);
226 }
227 
228 /* Modeless dialog box - Cancel printing */
229 BOOL CALLBACK _export
230 CancelDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
231 {
232     switch (message) {
233 	case WM_INITDIALOG:
234 	    SetWindowText(hDlg, szAppName);
235 	    return TRUE;
236 	case WM_COMMAND:
237 	    switch (LOWORD(wParam)) {
238 		case IDCANCEL:
239 		    DestroyWindow(hDlg);
240 		    hDlgModeless = 0;
241 		    EndDialog(hDlg, 0);
242 		    return TRUE;
243 	    }
244     }
245     return FALSE;
246 }
247 
248 #ifndef __WIN32__
249 
250 /* Windows does not provide API's in the SDK for writing directly to a */
251 /* printer.  Instead you are supposed to use the Windows printer drivers. */
252 /* Ghostscript has its own printer drivers, so we need to use some API's */
253 /* that are documented only in the Device Driver Adaptation Guide */
254 /* that comes with the DDK.  Prototypes taken from DDK <print.h> */
255 DECLARE_HANDLE(HPJOB);
256 
257 HPJOB WINAPI OpenJob(LPSTR, LPSTR, HPJOB);
258 int WINAPI StartSpoolPage(HPJOB);
259 int WINAPI EndSpoolPage(HPJOB);
260 int WINAPI WriteSpool(HPJOB, LPSTR, int);
261 int WINAPI CloseJob(HPJOB);
262 int WINAPI DeleteJob(HPJOB, int);
263 int WINAPI WriteDialog(HPJOB, LPSTR, int);
264 int WINAPI DeleteSpoolPage(HPJOB);
265 
266 #endif /* WIN32 */
267 
268 /* Dialog box to select printer port */
269 BOOL CALLBACK _export
270 SpoolDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
271 {
272     LPSTR entry;
273 
274     switch (message) {
275 	case WM_INITDIALOG:
276 	    entry = (LPSTR) lParam;
277 	    while (*entry) {
278 		SendDlgItemMessage(hDlg, SPOOL_PORT, LB_ADDSTRING, 0, (LPARAM) entry);
279 		entry += lstrlen(entry) + 1;
280 	    }
281 	    SendDlgItemMessage(hDlg, SPOOL_PORT, LB_SETCURSEL, 0, (LPARAM) 0);
282 	    return TRUE;
283 	case WM_COMMAND:
284 	    switch (LOWORD(wParam)) {
285 		case SPOOL_PORT:
286 #ifdef __WIN32__
287 		    if (HIWORD(wParam)
288 #else
289 		    if (HIWORD(lParam)
290 #endif
291 			== LBN_DBLCLK)
292 			PostMessage(hDlg, WM_COMMAND, IDOK, 0L);
293 		    return FALSE;
294 		case IDOK:
295 		    EndDialog(hDlg, 1 + (int)SendDlgItemMessage(hDlg, SPOOL_PORT, LB_GETCURSEL, 0, 0L));
296 		    return TRUE;
297 		case IDCANCEL:
298 		    EndDialog(hDlg, 0);
299 		    return TRUE;
300 	    }
301     }
302     return FALSE;
303 }
304 
305 /* return TRUE if queue looks like a valid printer name */
306 int
307 is_spool(const char *queue)
308 {
309     char *prefix = "\\\\spool";	/* 7 characters long */
310     int i;
311 
312     for (i = 0; i < 7; i++) {
313 	if (prefix[i] == '\\') {
314 	    if ((*queue != '\\') && (*queue != '/'))
315 		return FALSE;
316 	} else if (tolower(*queue) != prefix[i])
317 	    return FALSE;
318 	queue++;
319     }
320     if (*queue && (*queue != '\\') && (*queue != '/'))
321 	return FALSE;
322     return TRUE;
323 }
324 
325 
326 private int
327 is_printer(const char *name)
328 {
329     char buf[128];
330 
331     /* is printer if no name given */
332     if (strlen(name) == 0)
333 	return TRUE;
334 
335     /*  is printer if name appears in win.ini [ports] section */
336     GetProfileString("ports", name, "XYZ", buf, sizeof(buf));
337     if (strlen(name) == 0 || strcmp(buf, "XYZ"))
338 	return TRUE;
339 
340     /* is printer if name prefixed by \\spool\ */
341     if (is_spool(name))
342 	return TRUE;
343 
344     return FALSE;
345 }
346 
347 #ifdef __WIN32__		/* ******** WIN32 ******** */
348 
349 /******************************************************************/
350 /* Print File to port or queue */
351 /* port==NULL means prompt for port or queue with dialog box */
352 
353 /* This is messy because Microsoft changed the spooler interface */
354 /* between Window 3.1 and Windows 95/NT */
355 /* and didn't provide the spooler interface in Win32s */
356 
357 /* Win95, WinNT: Use OpenPrinter, WritePrinter etc. */
358 private int gp_printfile_win32(const char *filename, char *port);
359 
360 /* Win32s: Pass to Win16 spooler via gs16spl.exe */
361 private int gp_printfile_gs16spl(const char *filename, const char *port);
362 
363 /*
364  * Valid values for pmport are:
365  *   ""
366  *      action: WinNT and Win95 use default queue, Win32s prompts for port
367  *   "LPT1:" (or other port that appears in win.ini [ports]
368  *      action: start gs16spl.exe to print to the port
369  *   "\\spool\printer name"
370  *      action: send to printer using WritePrinter (WinNT and Win95).
371  *      action: translate to port name using win.ini [Devices]
372  *              then use gs16spl.exe (Win32s).
373  *   "\\spool"
374  *      action: prompt for queue name then send to printer using
375  *              WritePrinter (WinNT and Win95).
376  *      action: prompt for port then use gs16spl.exe (Win32s).
377  */
378 /* Print File */
379 private int
380 gp_printfile(const char *filename, const char *pmport)
381 {
382     /* treat WinNT and Win95 differently to Win32s */
383     if (!is_win32s) {
384 	if (strlen(pmport) == 0) {	/* get default printer */
385 	    char buf[256];
386 	    char *p;
387 
388 	    /* WinNT stores default printer in registry and win.ini */
389 	    /* Win95 stores default printer in win.ini */
390 	    GetProfileString("windows", "device", "", buf, sizeof(buf));
391 	    if ((p = strchr(buf, ',')) != NULL)
392 		*p = '\0';
393 	    return gp_printfile_win32(filename, buf);
394 	} else if (is_spool(pmport)) {
395 	    if (strlen(pmport) >= 8)
396 		return gp_printfile_win32(filename, (char *)pmport + 8);
397 	    else
398 		return gp_printfile_win32(filename, (char *)NULL);
399 	} else
400 	    return gp_printfile_gs16spl(filename, pmport);
401     } else {
402 	/* Win32s */
403 	if (is_spool(pmport)) {
404 	    if (strlen(pmport) >= 8) {
405 		/* extract port name from win.ini */
406 		char driverbuf[256];
407 		char *output;
408 
409 		GetProfileString("Devices", pmport + 8, "", driverbuf, sizeof(driverbuf));
410 		strtok(driverbuf, ",");
411 		output = strtok(NULL, ",");
412 		return gp_printfile_gs16spl(filename, output);
413 	    } else
414 		return gp_printfile_gs16spl(filename, (char *)NULL);
415 	} else
416 	    return gp_printfile_gs16spl(filename, pmport);
417     }
418 }
419 
420 #define PRINT_BUF_SIZE 16384u
421 #define PORT_BUF_SIZE 4096
422 
423 char *
424 get_queues(void)
425 {
426     int i;
427     DWORD count, needed;
428     PRINTER_INFO_1 *prinfo;
429     char *enumbuffer;
430     char *buffer;
431     char *p;
432 
433     /* enumerate all available printers */
434     EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, NULL, 0, &needed, &count);
435     if (needed == 0) {
436 	/* no printers */
437 	enumbuffer = malloc(4);
438 	if (enumbuffer == (char *)NULL)
439 	    return NULL;
440 	memset(enumbuffer, 0, 4);
441 	return enumbuffer;
442     }
443     enumbuffer = malloc(needed);
444     if (enumbuffer == (char *)NULL)
445 	return NULL;
446     if (!EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, (LPBYTE) enumbuffer, needed, &needed, &count)) {
447 	char buf[256];
448 
449 	free(enumbuffer);
450 	sprintf(buf, "EnumPrinters() failed, error code = %d", GetLastError());
451 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
452 	return NULL;
453     }
454     prinfo = (PRINTER_INFO_1 *) enumbuffer;
455     if ((buffer = malloc(PORT_BUF_SIZE)) == (char *)NULL) {
456 	free(enumbuffer);
457 	return NULL;
458     }
459     /* copy printer names to single buffer */
460     p = buffer;
461     for (i = 0; i < count; i++) {
462 	if (strlen(prinfo[i].pName) + 1 < (PORT_BUF_SIZE - (p - buffer))) {
463 	    strcpy(p, prinfo[i].pName);
464 	    p += strlen(p) + 1;
465 	}
466     }
467     *p = '\0';			/* double null at end */
468     free(enumbuffer);
469     return buffer;
470 }
471 
472 
473 char *
474 get_ports(void)
475 {
476     char *buffer;
477 
478 #ifdef __WIN32__
479     if (!is_win32s)
480 	return get_queues();
481 #endif
482 
483     if ((buffer = malloc(PORT_BUF_SIZE)) == (char *)NULL)
484 	return NULL;
485     GetProfileString("ports", NULL, "", buffer, PORT_BUF_SIZE);
486     return buffer;
487 }
488 
489 /* return TRUE if queuename available */
490 /* return FALSE if cancelled or error */
491 /* if queue non-NULL, use as suggested queue */
492 BOOL
493 get_queuename(char *portname, const char *queue)
494 {
495     char *buffer;
496     char *p;
497     int i, iport;
498 
499     buffer = get_queues();
500     if (buffer == NULL)
501 	return FALSE;
502     if ((queue == (char *)NULL) || (strlen(queue) == 0)) {
503 	/* select a queue */
504 	iport = DialogBoxParam(phInstance, "QueueDlgBox", (HWND) NULL, SpoolDlgProc, (LPARAM) buffer);
505 	if (!iport) {
506 	    free(buffer);
507 	    return FALSE;
508 	}
509 	p = buffer;
510 	for (i = 1; i < iport && strlen(p) != 0; i++)
511 	    p += lstrlen(p) + 1;
512 	/* prepend \\spool\ which is used by Ghostscript to distinguish */
513 	/* real files from queues */
514 	strcpy(portname, "\\\\spool\\");
515 	strcat(portname, p);
516     } else {
517 	strcpy(portname, "\\\\spool\\");
518 	strcat(portname, queue);
519     }
520 
521     free(buffer);
522     return TRUE;
523 }
524 
525 /* return TRUE if portname available */
526 /* return FALSE if cancelled or error */
527 /* if port non-NULL, use as suggested port */
528 BOOL
529 get_portname(char *portname, const char *port)
530 {
531     char *buffer;
532     char *p;
533     int i, iport;
534     char filename[MAXSTR];
535 
536     buffer = get_ports();
537     if (buffer == NULL)
538 	return FALSE;
539     if ((port == (char *)NULL) || (strlen(port) == 0)) {
540 	if (buffer == (char *)NULL)
541 	    return FALSE;
542 	/* select a port */
543 	iport = DialogBoxParam(phInstance, "SpoolDlgBox", (HWND) NULL, SpoolDlgProc, (LPARAM) buffer);
544 	if (!iport) {
545 	    free(buffer);
546 	    return FALSE;
547 	}
548 	p = buffer;
549 	for (i = 1; i < iport && strlen(p) != 0; i++)
550 	    p += lstrlen(p) + 1;
551 	strcpy(portname, p);
552     } else
553 	strcpy(portname, port);
554 
555     if (strlen(portname) == 0)
556 	return FALSE;
557     if (strcmp(portname, "FILE:") == 0) {
558 	OPENFILENAME ofn;
559 
560 	filename[0] = '\0';
561 	memset(&ofn, 0, sizeof(OPENFILENAME));
562 	ofn.lStructSize = sizeof(OPENFILENAME);
563 	ofn.hwndOwner = (HWND) NULL;
564 	ofn.lpstrFile = filename;
565 	ofn.nMaxFile = sizeof(filename);
566 	ofn.Flags = OFN_PATHMUSTEXIST;
567 	if (!GetSaveFileName(&ofn)) {
568 	    free(buffer);
569 	    return FALSE;
570 	}
571 	strcpy(portname, filename);
572     }
573     free(buffer);
574     return TRUE;
575 }
576 
577 
578 /* True Win32 method, using OpenPrinter, WritePrinter etc. */
579 private int
580 gp_printfile_win32(const char *filename, char *port)
581 {
582     DWORD count;
583     char *buffer;
584     char portname[MAXSTR];
585     FILE *f;
586     HANDLE printer;
587     DOC_INFO_1 di;
588     DWORD written;
589 
590     if (!get_queuename(portname, port))
591 	return FALSE;
592     port = portname + 8;	/* skip over \\spool\ */
593 
594     if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
595 	return FALSE;
596 
597     if ((f = fopen(filename, "rb")) == (FILE *) NULL) {
598 	free(buffer);
599 	return FALSE;
600     }
601     /* open a printer */
602     if (!OpenPrinter(port, &printer, NULL)) {
603 	char buf[256];
604 
605 	sprintf(buf, "OpenPrinter() failed for \042%s\042, error code = %d", port, GetLastError());
606 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
607 	free(buffer);
608 	return FALSE;
609     }
610     /* from here until ClosePrinter, should AbortPrinter on error */
611 
612     di.pDocName = szAppName;
613     di.pOutputFile = NULL;
614     di.pDatatype = "RAW";	/* for available types see EnumPrintProcessorDatatypes */
615     if (!StartDocPrinter(printer, 1, (LPBYTE) & di)) {
616 	char buf[256];
617 
618 	sprintf(buf, "StartDocPrinter() failed, error code = %d", GetLastError());
619 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
620 	AbortPrinter(printer);
621 	free(buffer);
622 	return FALSE;
623     }
624     /* copy file to printer */
625     while ((count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0) {
626 	if (!WritePrinter(printer, (LPVOID) buffer, count, &written)) {
627 	    free(buffer);
628 	    fclose(f);
629 	    AbortPrinter(printer);
630 	    return FALSE;
631 	}
632     }
633     fclose(f);
634     free(buffer);
635 
636     if (!EndDocPrinter(printer)) {
637 	char buf[256];
638 
639 	sprintf(buf, "EndDocPrinter() failed, error code = %d", GetLastError());
640 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
641 	AbortPrinter(printer);
642 	return FALSE;
643     }
644     if (!ClosePrinter(printer)) {
645 	char buf[256];
646 
647 	sprintf(buf, "ClosePrinter() failed, error code = %d", GetLastError());
648 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
649 	return FALSE;
650     }
651     return TRUE;
652 }
653 
654 
655 /* Start a 16-bit application gs16spl.exe to print a file */
656 /* Intended for Win32s where 16-bit spooler functions are not available */
657 /* and Win32 spooler functions are not implemented. */
658 int
659 gp_printfile_gs16spl(const char *filename, const char *port)
660 {
661 /* Get printer port list from win.ini */
662     char portname[MAXSTR];
663     HINSTANCE hinst;
664     char command[MAXSTR];
665     char *p;
666     HWND hwndspl;
667 
668     if (!get_portname(portname, port))
669 	return FALSE;
670 
671     /* get path to EXE - same as DLL */
672     GetModuleFileName(phInstance, command, sizeof(command));
673     if ((p = strrchr(command, '\\')) != (char *)NULL)
674 	p++;
675     else
676 	p = command;
677     *p = '\0';
678     sprintf(command + strlen(command), "gs16spl.exe %s %s",
679 	    portname, filename);
680 
681     hinst = (HINSTANCE) WinExec(command, SW_SHOWNORMAL);
682     if (hinst < (HINSTANCE) HINSTANCE_ERROR) {
683 	char buf[MAXSTR];
684 
685 	sprintf(buf, "Can't run: %s", command);
686 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
687 	return FALSE;
688     }
689     hwndspl = FindWindow(NULL, "GS Win32s/Win16 spooler");
690 
691     while (IsWindow(hwndspl)) {
692 	gp_check_interrupts();
693     }
694 
695     return 0;
696 }
697 
698 
699 
700 #else /* ******** !WIN32 ******** */
701 
702 /* Print File to port */
703 private int
704 gp_printfile(const char *filename, const char *pmport)
705 {
706 #define PRINT_BUF_SIZE 16384u
707     char *buffer;
708     char *portname;
709     int i, port;
710     FILE *f;
711     DLGPROC lpfnSpoolProc;
712     WORD count;
713     DLGPROC lpfnCancelProc;
714     int error = FALSE;
715     long lsize;
716     long ldone;
717     char pcdone[20];
718     MSG msg;
719     HPJOB hJob;
720 
721     if (is_spool(pmport) && (strlen(pmport) >= 8)) {
722 	/* translate from printer name to port name */
723 	char driverbuf[256];
724 
725 	GetProfileString("Devices", pmport + 8, "", driverbuf, sizeof(driverbuf));
726 	strtok(driverbuf, ",");
727 	pmport = strtok(NULL, ",");
728     }
729     /* get list of ports */
730     if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
731 	return FALSE;
732 
733     if ((strlen(pmport) == 0) || (strcmp(pmport, "PRN") == 0)) {
734 	GetProfileString("ports", NULL, "", buffer, PRINT_BUF_SIZE);
735 	/* select a port */
736 #ifdef __WIN32__
737 	lpfnSpoolProc = (DLGPROC) SpoolDlgProc;
738 #else
739 #ifdef __DLL__
740 	lpfnSpoolProc = (DLGPROC) GetProcAddress(phInstance, "SpoolDlgProc");
741 #else
742 	lpfnSpoolProc = (DLGPROC) MakeProcInstance((FARPROC) SpoolDlgProc, phInstance);
743 #endif
744 #endif
745 	port = DialogBoxParam(phInstance, "SpoolDlgBox", (HWND) NULL, lpfnSpoolProc, (LPARAM) buffer);
746 #if !defined(__WIN32__) && !defined(__DLL__)
747 	FreeProcInstance((FARPROC) lpfnSpoolProc);
748 #endif
749 	if (!port) {
750 	    free(buffer);
751 	    return FALSE;
752 	}
753 	portname = buffer;
754 	for (i = 1; i < port && strlen(portname) != 0; i++)
755 	    portname += lstrlen(portname) + 1;
756     } else
757 	portname = (char *)pmport;	/* Print Manager port name already supplied */
758 
759     if ((f = fopen(filename, "rb")) == (FILE *) NULL) {
760 	free(buffer);
761 	return FALSE;
762     }
763     fseek(f, 0L, SEEK_END);
764     lsize = ftell(f);
765     if (lsize <= 0)
766 	lsize = 1;
767     fseek(f, 0L, SEEK_SET);
768 
769     hJob = OpenJob(portname, filename, (HPJOB) NULL);
770     switch ((int)hJob) {
771 	case SP_APPABORT:
772 	case SP_ERROR:
773 	case SP_OUTOFDISK:
774 	case SP_OUTOFMEMORY:
775 	case SP_USERABORT:
776 	    fclose(f);
777 	    free(buffer);
778 	    return FALSE;
779     }
780     if (StartSpoolPage(hJob) < 0)
781 	error = TRUE;
782 
783 #ifdef __WIN32__
784     lpfnCancelProc = (DLGPROC) CancelDlgProc;
785 #else
786 #ifdef __DLL__
787     lpfnCancelProc = (DLGPROC) GetProcAddress(phInstance, "CancelDlgProc");
788 #else
789     lpfnCancelProc = (DLGPROC) MakeProcInstance((FARPROC) CancelDlgProc, phInstance);
790 #endif
791 #endif
792     hDlgModeless = CreateDialog(phInstance, "CancelDlgBox", (HWND) NULL, lpfnCancelProc);
793     ldone = 0;
794 
795     while (!error && hDlgModeless
796 	   && (count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0) {
797 	if (WriteSpool(hJob, buffer, count) < 0)
798 	    error = TRUE;
799 	ldone += count;
800 	sprintf(pcdone, "%d %%done", (int)(ldone * 100 / lsize));
801 	SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), pcdone);
802 	while (PeekMessage(&msg, hDlgModeless, 0, 0, PM_REMOVE)) {
803 	    if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
804 		TranslateMessage(&msg);
805 		DispatchMessage(&msg);
806 	    }
807 	}
808     }
809     free(buffer);
810     fclose(f);
811 
812     if (!hDlgModeless)
813 	error = TRUE;
814     DestroyWindow(hDlgModeless);
815     hDlgModeless = 0;
816 #if !defined(__WIN32__) && !defined(__DLL__)
817     FreeProcInstance((FARPROC) lpfnCancelProc);
818 #endif
819     EndSpoolPage(hJob);
820     if (error)
821 	DeleteJob(hJob, 0);
822     else
823 	CloseJob(hJob);
824     return !error;
825 }
826 
827 #endif /* ******** (!)WIN32 ******** */
828 
829 /* ------ File naming and accessing ------ */
830 
831 /* Create and open a scratch file with a given name prefix. */
832 /* Write the actual file name at fname. */
833 FILE *
834 gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
835 {				/* The -7 is for XXXXXX plus a possible final \. */
836     int len = gp_file_name_sizeof - strlen(prefix) - 7;
837 
838     if (gp_getenv("TEMP", fname, &len) != 0)
839 	*fname = 0;
840     else {
841 	char *temp;
842 
843 	/* Prevent X's in path from being converted by mktemp. */
844 	for (temp = fname; *temp; temp++)
845 	    *temp = tolower(*temp);
846 	if (strlen(fname) && (fname[strlen(fname) - 1] != '\\'))
847 	    strcat(fname, "\\");
848     }
849     strcat(fname, prefix);
850     strcat(fname, "XXXXXX");
851     mktemp(fname);
852     return fopen(fname, mode);
853 }
854 
855 /* Open a file with the given name, as a stream of uninterpreted bytes. */
856 FILE *
857 gp_fopen(const char *fname, const char *mode)
858 {
859     return fopen(fname, mode);
860 }
861