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