1 /* Copyright (C) 1992, 2000-2003 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_mswin.c,v 1.25 2005/03/04 21:58:55 ghostgum Exp $ */ 18 /* 19 * Microsoft Windows platform support for Ghostscript. 20 * 21 * Original version by Russell Lang and Maurice Castro with help from 22 * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press; 23 * initially created from gp_dosfb.c and gp_itbc.c 5th June 1992. 24 */ 25 26 /* Modified for Win32 & Microsoft C/C++ 8.0 32-Bit, 26.Okt.1994 */ 27 /* by Friedrich Nowak */ 28 29 /* Original EXE and GSview specific code removed */ 30 /* DLL version must now be used under MS-Windows */ 31 /* Russell Lang 16 March 1996 */ 32 33 #include "stdio_.h" 34 #include "string_.h" 35 #include "memory_.h" 36 #include "pipe_.h" 37 #include <stdlib.h> 38 #include <stdarg.h> 39 #include "ctype_.h" 40 #include <io.h> 41 #include "malloc_.h" 42 #include <fcntl.h> 43 #include <signal.h> 44 #include "gx.h" 45 #include "gp.h" 46 #include "gpcheck.h" 47 #include "gpmisc.h" 48 #include "gserrors.h" 49 #include "gsexit.h" 50 51 #include "windows_.h" 52 #include <shellapi.h> 53 #include <winspool.h> 54 #include "gp_mswin.h" 55 56 /* Library routines not declared in a standard header */ 57 extern char *getenv(const char *); 58 59 /* limits */ 60 #define MAXSTR 255 61 62 /* GLOBAL VARIABLE that needs to be removed */ 63 char win_prntmp[MAXSTR]; /* filename of PRN temporary file */ 64 65 /* GLOBAL VARIABLES - initialised at DLL load time */ 66 HINSTANCE phInstance; 67 BOOL is_win32s = FALSE; 68 69 const LPSTR szAppName = "Ghostscript"; 70 private int is_printer(const char *name); 71 72 73 /* ====== Generic platform procedures ====== */ 74 75 /* ------ Initialization/termination (from gp_itbc.c) ------ */ 76 77 /* Do platform-dependent initialization. */ 78 void 79 gp_init(void) 80 { 81 } 82 83 /* Do platform-dependent cleanup. */ 84 void 85 gp_exit(int exit_status, int code) 86 { 87 } 88 89 /* Exit the program. */ 90 void 91 gp_do_exit(int exit_status) 92 { 93 exit(exit_status); 94 } 95 96 /* ------ Persistent data cache ------*/ 97 98 /* insert a buffer under a (type, key) pair */ 99 int gp_cache_insert(int type, byte *key, int keylen, void *buffer, int buflen) 100 { 101 /* not yet implemented */ 102 return 0; 103 } 104 105 /* look up a (type, key) in the cache */ 106 int gp_cache_query(int type, byte* key, int keylen, void **buffer, 107 gp_cache_alloc alloc, void *userdata) 108 { 109 /* not yet implemented */ 110 return -1; 111 } 112 113 /* ------ Printer accessing ------ */ 114 115 /* Forward references */ 116 private int gp_printfile(const char *, const char *); 117 118 /* Open a connection to a printer. A null file name means use the */ 119 /* standard printer connected to the machine, if any. */ 120 /* Return NULL if the connection could not be opened. */ 121 FILE * 122 gp_open_printer(char fname[gp_file_name_sizeof], int binary_mode) 123 { 124 if (is_printer(fname)) { 125 FILE *pfile; 126 127 /* Open a scratch file, which we will send to the */ 128 /* actual printer in gp_close_printer. */ 129 pfile = gp_open_scratch_file(gp_scratch_file_name_prefix, 130 win_prntmp, "wb"); 131 return pfile; 132 } else if (fname[0] == '|') /* pipe */ 133 return popen(fname + 1, (binary_mode ? "wb" : "w")); 134 else 135 return fopen(fname, (binary_mode ? "wb" : "w")); 136 } 137 138 /* Close the connection to the printer. */ 139 void 140 gp_close_printer(FILE * pfile, const char *fname) 141 { 142 fclose(pfile); 143 if (!is_printer(fname)) 144 return; /* a file, not a printer */ 145 146 gp_printfile(win_prntmp, fname); 147 unlink(win_prntmp); 148 } 149 150 151 /* Dialog box to select printer port */ 152 DLGRETURN CALLBACK 153 SpoolDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 154 { 155 LPSTR entry; 156 157 switch (message) { 158 case WM_INITDIALOG: 159 entry = (LPSTR) lParam; 160 while (*entry) { 161 SendDlgItemMessage(hDlg, SPOOL_PORT, LB_ADDSTRING, 0, (LPARAM) entry); 162 entry += lstrlen(entry) + 1; 163 } 164 SendDlgItemMessage(hDlg, SPOOL_PORT, LB_SETCURSEL, 0, (LPARAM) 0); 165 return TRUE; 166 case WM_COMMAND: 167 switch (LOWORD(wParam)) { 168 case SPOOL_PORT: 169 if (HIWORD(wParam) == LBN_DBLCLK) 170 PostMessage(hDlg, WM_COMMAND, IDOK, 0L); 171 return FALSE; 172 case IDOK: 173 EndDialog(hDlg, 1 + (int)SendDlgItemMessage(hDlg, SPOOL_PORT, LB_GETCURSEL, 0, 0L)); 174 return TRUE; 175 case IDCANCEL: 176 EndDialog(hDlg, 0); 177 return TRUE; 178 } 179 } 180 return FALSE; 181 } 182 183 /* return TRUE if queue looks like a valid printer name */ 184 int 185 is_spool(const char *queue) 186 { 187 char *prefix = "\\\\spool"; /* 7 characters long */ 188 int i; 189 190 for (i = 0; i < 7; i++) { 191 if (prefix[i] == '\\') { 192 if ((*queue != '\\') && (*queue != '/')) 193 return FALSE; 194 } else if (tolower(*queue) != prefix[i]) 195 return FALSE; 196 queue++; 197 } 198 if (*queue && (*queue != '\\') && (*queue != '/')) 199 return FALSE; 200 return TRUE; 201 } 202 203 204 private int 205 is_printer(const char *name) 206 { 207 char buf[128]; 208 209 /* is printer if no name given */ 210 if (strlen(name) == 0) 211 return TRUE; 212 213 /* is printer if name appears in win.ini [ports] section */ 214 GetProfileString("ports", name, "XYZ", buf, sizeof(buf)); 215 if (strlen(name) == 0 || strcmp(buf, "XYZ")) 216 return TRUE; 217 218 /* is printer if name prefixed by \\spool\ */ 219 if (is_spool(name)) 220 return TRUE; 221 222 return FALSE; 223 } 224 225 226 /******************************************************************/ 227 /* Print File to port or queue */ 228 /* port==NULL means prompt for port or queue with dialog box */ 229 230 /* This is messy because Microsoft changed the spooler interface */ 231 /* between Windows 3.1 and Windows 95/NT */ 232 /* and didn't provide the spooler interface in Win32s */ 233 234 /* Win95, WinNT: Use OpenPrinter, WritePrinter etc. */ 235 private int gp_printfile_win32(const char *filename, char *port); 236 237 /* Win32s: Pass to Win16 spooler via gs16spl.exe */ 238 private int gp_printfile_gs16spl(const char *filename, const char *port); 239 240 /* 241 * Valid values for pmport are: 242 * "" 243 * action: WinNT and Win95 use default queue, Win32s prompts for port 244 * "LPT1:" (or other port that appears in win.ini [ports] 245 * action: start gs16spl.exe to print to the port 246 * "\\spool\printer name" 247 * action: send to printer using WritePrinter (WinNT and Win95). 248 * action: translate to port name using win.ini [Devices] 249 * then use gs16spl.exe (Win32s). 250 * "\\spool" 251 * action: prompt for queue name then send to printer using 252 * WritePrinter (WinNT and Win95). 253 * action: prompt for port then use gs16spl.exe (Win32s). 254 */ 255 /* Print File */ 256 private int 257 gp_printfile(const char *filename, const char *pmport) 258 { 259 /* treat WinNT and Win95 differently to Win32s */ 260 if (!is_win32s) { 261 if (strlen(pmport) == 0) { /* get default printer */ 262 char buf[256]; 263 char *p; 264 265 /* WinNT stores default printer in registry and win.ini */ 266 /* Win95 stores default printer in win.ini */ 267 GetProfileString("windows", "device", "", buf, sizeof(buf)); 268 if ((p = strchr(buf, ',')) != NULL) 269 *p = '\0'; 270 return gp_printfile_win32(filename, buf); 271 } else if (is_spool(pmport)) { 272 if (strlen(pmport) >= 8) 273 return gp_printfile_win32(filename, (char *)pmport + 8); 274 else 275 return gp_printfile_win32(filename, (char *)NULL); 276 } else 277 return gp_printfile_gs16spl(filename, pmport); 278 } else { 279 /* Win32s */ 280 if (is_spool(pmport)) { 281 if (strlen(pmport) >= 8) { 282 /* extract port name from win.ini */ 283 char driverbuf[256]; 284 char *output; 285 286 GetProfileString("Devices", pmport + 8, "", driverbuf, sizeof(driverbuf)); 287 strtok(driverbuf, ","); 288 output = strtok(NULL, ","); 289 return gp_printfile_gs16spl(filename, output); 290 } else 291 return gp_printfile_gs16spl(filename, (char *)NULL); 292 } else 293 return gp_printfile_gs16spl(filename, pmport); 294 } 295 } 296 297 #define PRINT_BUF_SIZE 16384u 298 #define PORT_BUF_SIZE 4096 299 300 char * 301 get_queues(void) 302 { 303 int i; 304 DWORD count, needed; 305 PRINTER_INFO_1 *prinfo; 306 char *enumbuffer; 307 char *buffer; 308 char *p; 309 310 /* enumerate all available printers */ 311 EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, NULL, 0, &needed, &count); 312 if (needed == 0) { 313 /* no printers */ 314 enumbuffer = malloc(4); 315 if (enumbuffer == (char *)NULL) 316 return NULL; 317 memset(enumbuffer, 0, 4); 318 return enumbuffer; 319 } 320 enumbuffer = malloc(needed); 321 if (enumbuffer == (char *)NULL) 322 return NULL; 323 if (!EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, (LPBYTE) enumbuffer, needed, &needed, &count)) { 324 char buf[256]; 325 326 free(enumbuffer); 327 sprintf(buf, "EnumPrinters() failed, error code = %d", GetLastError()); 328 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP); 329 return NULL; 330 } 331 prinfo = (PRINTER_INFO_1 *) enumbuffer; 332 if ((buffer = malloc(PORT_BUF_SIZE)) == (char *)NULL) { 333 free(enumbuffer); 334 return NULL; 335 } 336 /* copy printer names to single buffer */ 337 p = buffer; 338 for (i = 0; i < count; i++) { 339 if (strlen(prinfo[i].pName) + 1 < (PORT_BUF_SIZE - (p - buffer))) { 340 strcpy(p, prinfo[i].pName); 341 p += strlen(p) + 1; 342 } 343 } 344 *p = '\0'; /* double null at end */ 345 free(enumbuffer); 346 return buffer; 347 } 348 349 350 char * 351 get_ports(void) 352 { 353 char *buffer; 354 355 if (!is_win32s) 356 return get_queues(); 357 358 if ((buffer = malloc(PORT_BUF_SIZE)) == (char *)NULL) 359 return NULL; 360 GetProfileString("ports", NULL, "", buffer, PORT_BUF_SIZE); 361 return buffer; 362 } 363 364 /* return TRUE if queuename available */ 365 /* return FALSE if cancelled or error */ 366 /* if queue non-NULL, use as suggested queue */ 367 BOOL 368 get_queuename(char *portname, const char *queue) 369 { 370 char *buffer; 371 char *p; 372 int i, iport; 373 374 buffer = get_queues(); 375 if (buffer == NULL) 376 return FALSE; 377 if ((queue == (char *)NULL) || (strlen(queue) == 0)) { 378 /* select a queue */ 379 iport = DialogBoxParam(phInstance, "QueueDlgBox", (HWND) NULL, SpoolDlgProc, (LPARAM) buffer); 380 if (!iport) { 381 free(buffer); 382 return FALSE; 383 } 384 p = buffer; 385 for (i = 1; i < iport && strlen(p) != 0; i++) 386 p += lstrlen(p) + 1; 387 /* prepend \\spool\ which is used by Ghostscript to distinguish */ 388 /* real files from queues */ 389 strcpy(portname, "\\\\spool\\"); 390 strcat(portname, p); 391 } else { 392 strcpy(portname, "\\\\spool\\"); 393 strcat(portname, queue); 394 } 395 396 free(buffer); 397 return TRUE; 398 } 399 400 /* return TRUE if portname available */ 401 /* return FALSE if cancelled or error */ 402 /* if port non-NULL, use as suggested port */ 403 BOOL 404 get_portname(char *portname, const char *port) 405 { 406 char *buffer; 407 char *p; 408 int i, iport; 409 char filename[MAXSTR]; 410 411 buffer = get_ports(); 412 if (buffer == NULL) 413 return FALSE; 414 if ((port == (char *)NULL) || (strlen(port) == 0)) { 415 if (buffer == (char *)NULL) 416 return FALSE; 417 /* select a port */ 418 iport = DialogBoxParam(phInstance, "SpoolDlgBox", (HWND) NULL, SpoolDlgProc, (LPARAM) buffer); 419 if (!iport) { 420 free(buffer); 421 return FALSE; 422 } 423 p = buffer; 424 for (i = 1; i < iport && strlen(p) != 0; i++) 425 p += lstrlen(p) + 1; 426 strcpy(portname, p); 427 } else 428 strcpy(portname, port); 429 430 if (strlen(portname) == 0) 431 return FALSE; 432 if (strcmp(portname, "FILE:") == 0) { 433 OPENFILENAME ofn; 434 435 filename[0] = '\0'; 436 memset(&ofn, 0, sizeof(OPENFILENAME)); 437 ofn.lStructSize = sizeof(OPENFILENAME); 438 ofn.hwndOwner = (HWND) NULL; 439 ofn.lpstrFile = filename; 440 ofn.nMaxFile = sizeof(filename); 441 ofn.Flags = OFN_PATHMUSTEXIST; 442 if (!GetSaveFileName(&ofn)) { 443 free(buffer); 444 return FALSE; 445 } 446 strcpy(portname, filename); 447 } 448 free(buffer); 449 return TRUE; 450 } 451 452 453 /* True Win32 method, using OpenPrinter, WritePrinter etc. */ 454 private int 455 gp_printfile_win32(const char *filename, char *port) 456 { 457 DWORD count; 458 char *buffer; 459 char portname[MAXSTR]; 460 FILE *f; 461 HANDLE printer; 462 DOC_INFO_1 di; 463 DWORD written; 464 465 if (!get_queuename(portname, port)) 466 return FALSE; 467 port = portname + 8; /* skip over \\spool\ */ 468 469 if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL) 470 return FALSE; 471 472 if ((f = fopen(filename, "rb")) == (FILE *) NULL) { 473 free(buffer); 474 return FALSE; 475 } 476 /* open a printer */ 477 if (!OpenPrinter(port, &printer, NULL)) { 478 char buf[256]; 479 480 sprintf(buf, "OpenPrinter() failed for \042%s\042, error code = %d", port, GetLastError()); 481 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP); 482 free(buffer); 483 return FALSE; 484 } 485 /* from here until ClosePrinter, should AbortPrinter on error */ 486 487 di.pDocName = szAppName; 488 di.pOutputFile = NULL; 489 di.pDatatype = "RAW"; /* for available types see EnumPrintProcessorDatatypes */ 490 if (!StartDocPrinter(printer, 1, (LPBYTE) & di)) { 491 char buf[256]; 492 493 sprintf(buf, "StartDocPrinter() failed, error code = %d", GetLastError()); 494 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP); 495 AbortPrinter(printer); 496 free(buffer); 497 return FALSE; 498 } 499 /* copy file to printer */ 500 while ((count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0) { 501 if (!WritePrinter(printer, (LPVOID) buffer, count, &written)) { 502 free(buffer); 503 fclose(f); 504 AbortPrinter(printer); 505 return FALSE; 506 } 507 } 508 fclose(f); 509 free(buffer); 510 511 if (!EndDocPrinter(printer)) { 512 char buf[256]; 513 514 sprintf(buf, "EndDocPrinter() failed, error code = %d", GetLastError()); 515 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP); 516 AbortPrinter(printer); 517 return FALSE; 518 } 519 if (!ClosePrinter(printer)) { 520 char buf[256]; 521 522 sprintf(buf, "ClosePrinter() failed, error code = %d", GetLastError()); 523 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP); 524 return FALSE; 525 } 526 return TRUE; 527 } 528 529 530 /* Start a 16-bit application gs16spl.exe to print a file */ 531 /* Intended for Win32s where 16-bit spooler functions are not available */ 532 /* and Win32 spooler functions are not implemented. */ 533 int 534 gp_printfile_gs16spl(const char *filename, const char *port) 535 { 536 /* Get printer port list from win.ini */ 537 char portname[MAXSTR]; 538 HINSTANCE hinst; 539 char command[MAXSTR]; 540 char *p; 541 HWND hwndspl; 542 543 if (!get_portname(portname, port)) 544 return FALSE; 545 546 /* get path to EXE - same as DLL */ 547 GetModuleFileName(phInstance, command, sizeof(command)); 548 if ((p = strrchr(command, '\\')) != (char *)NULL) 549 p++; 550 else 551 p = command; 552 *p = '\0'; 553 sprintf(command + strlen(command), "gs16spl.exe %s %s", 554 portname, filename); 555 556 hinst = (HINSTANCE) WinExec(command, SW_SHOWNORMAL); 557 if (hinst < (HINSTANCE) HINSTANCE_ERROR) { 558 char buf[MAXSTR]; 559 560 sprintf(buf, "Can't run: %s", command); 561 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP); 562 return FALSE; 563 } 564 hwndspl = FindWindow(NULL, "GS Win32s/Win16 spooler"); 565 566 while (IsWindow(hwndspl)) { 567 gp_check_interrupts(NULL); 568 } 569 570 return 0; 571 } 572 573 574 /******************************************************************/ 575 /* MS Windows has popen and pclose in stdio.h, but under different names. 576 * Unfortunately MSVC5 and 6 have a broken implementation of _popen, 577 * so we use own. Our implementation only supports mode "wb". 578 */ 579 FILE *mswin_popen(const char *cmd, const char *mode) 580 { 581 SECURITY_ATTRIBUTES saAttr; 582 STARTUPINFO siStartInfo; 583 PROCESS_INFORMATION piProcInfo; 584 HANDLE hPipeTemp = INVALID_HANDLE_VALUE; 585 HANDLE hChildStdinRd = INVALID_HANDLE_VALUE; 586 HANDLE hChildStdinWr = INVALID_HANDLE_VALUE; 587 HANDLE hChildStdoutWr = INVALID_HANDLE_VALUE; 588 HANDLE hChildStderrWr = INVALID_HANDLE_VALUE; 589 HANDLE hProcess = GetCurrentProcess(); 590 int handle = 0; 591 char *command = NULL; 592 FILE *pipe = NULL; 593 594 if (strcmp(mode, "wb") != 0) 595 return NULL; 596 597 /* Set the bInheritHandle flag so pipe handles are inherited. */ 598 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 599 saAttr.bInheritHandle = TRUE; 600 saAttr.lpSecurityDescriptor = NULL; 601 602 /* Create anonymous inheritable pipes for STDIN for child. 603 * First create a noninheritable duplicate handle of our end of 604 * the pipe, then close the inheritable handle. 605 */ 606 if (handle == 0) 607 if (!CreatePipe(&hChildStdinRd, &hPipeTemp, &saAttr, 0)) 608 handle = -1; 609 if (handle == 0) { 610 if (!DuplicateHandle(hProcess, hPipeTemp, 611 hProcess, &hChildStdinWr, 0, FALSE /* not inherited */, 612 DUPLICATE_SAME_ACCESS)) 613 handle = -1; 614 CloseHandle(hPipeTemp); 615 } 616 /* Create inheritable duplicate handles for our stdout/err */ 617 if (handle == 0) 618 if (!DuplicateHandle(hProcess, GetStdHandle(STD_OUTPUT_HANDLE), 619 hProcess, &hChildStdoutWr, 0, TRUE /* inherited */, 620 DUPLICATE_SAME_ACCESS)) 621 handle = -1; 622 if (handle == 0) 623 if (!DuplicateHandle(hProcess, GetStdHandle(STD_ERROR_HANDLE), 624 hProcess, &hChildStderrWr, 0, TRUE /* inherited */, 625 DUPLICATE_SAME_ACCESS)) 626 handle = -1; 627 628 /* Set up members of STARTUPINFO structure. */ 629 memset(&siStartInfo, 0, sizeof(STARTUPINFO)); 630 siStartInfo.cb = sizeof(STARTUPINFO); 631 siStartInfo.dwFlags = STARTF_USESTDHANDLES; 632 siStartInfo.hStdInput = hChildStdinRd; 633 siStartInfo.hStdOutput = hChildStdoutWr; 634 siStartInfo.hStdError = hChildStderrWr; 635 636 if (handle == 0) { 637 command = (char *)malloc(strlen(cmd)+1); 638 if (command) 639 strcpy(command, cmd); 640 else 641 handle = -1; 642 } 643 644 if (handle == 0) 645 if (!CreateProcess(NULL, 646 command, /* command line */ 647 NULL, /* process security attributes */ 648 NULL, /* primary thread security attributes */ 649 TRUE, /* handles are inherited */ 650 0, /* creation flags */ 651 NULL, /* environment */ 652 NULL, /* use parent's current directory */ 653 &siStartInfo, /* STARTUPINFO pointer */ 654 &piProcInfo)) /* receives PROCESS_INFORMATION */ 655 { 656 handle = -1; 657 } 658 else { 659 CloseHandle(piProcInfo.hProcess); 660 CloseHandle(piProcInfo.hThread); 661 handle = _open_osfhandle((long)hChildStdinWr, 0); 662 } 663 664 if (hChildStdinRd != INVALID_HANDLE_VALUE) 665 CloseHandle(hChildStdinRd); /* close our copy */ 666 if (hChildStdoutWr != INVALID_HANDLE_VALUE) 667 CloseHandle(hChildStdoutWr); /* close our copy */ 668 if (hChildStderrWr != INVALID_HANDLE_VALUE) 669 CloseHandle(hChildStderrWr); /* close our copy */ 670 if (command) 671 free(command); 672 673 if (handle < 0) { 674 if (hChildStdinWr != INVALID_HANDLE_VALUE) 675 CloseHandle(hChildStdinWr); 676 } 677 else { 678 pipe = _fdopen(handle, "wb"); 679 if (pipe == NULL) 680 _close(handle); 681 } 682 return pipe; 683 } 684 685 686 /* ------ File naming and accessing ------ */ 687 688 /* Create and open a scratch file with a given name prefix. */ 689 /* Write the actual file name at fname. */ 690 FILE * 691 gp_open_scratch_file(const char *prefix, char *fname, const char *mode) 692 { 693 UINT n; 694 DWORD l; 695 HANDLE hfile = INVALID_HANDLE_VALUE; 696 int fd = -1; 697 FILE *f = NULL; 698 char sTempDir[_MAX_PATH]; 699 char sTempFileName[_MAX_PATH]; 700 701 memset(fname, 0, gp_file_name_sizeof); 702 if (!gp_file_name_is_absolute(prefix, strlen(prefix))) { 703 int plen = sizeof(sTempDir); 704 705 if (gp_gettmpdir(sTempDir, &plen) != 0) 706 l = GetTempPath(sizeof(sTempDir), sTempDir); 707 else 708 l = strlen(sTempDir); 709 } else { 710 strncpy(sTempDir, prefix, sizeof(sTempDir)); 711 prefix = ""; 712 l = strlen(sTempDir); 713 } 714 /* Fix the trailing terminator so GetTempFileName doesn't get confused */ 715 if (sTempDir[l-1] == '/') 716 sTempDir[l-1] = '\\'; /* What Windoze prefers */ 717 718 if (l <= sizeof(sTempDir)) { 719 n = GetTempFileName(sTempDir, prefix, 0, sTempFileName); 720 if (n == 0) { 721 /* If 'prefix' is not a directory, it is a path prefix. */ 722 int l = strlen(sTempDir), i; 723 724 for (i = l - 1; i > 0; i--) { 725 uint slen = gs_file_name_check_separator(sTempDir + i, l, sTempDir + l); 726 727 if (slen > 0) { 728 sTempDir[i] = 0; 729 i += slen; 730 break; 731 } 732 } 733 if (i > 0) 734 n = GetTempFileName(sTempDir, sTempDir + i, 0, sTempFileName); 735 } 736 if (n != 0) { 737 hfile = CreateFile(sTempFileName, 738 GENERIC_READ | GENERIC_WRITE | DELETE, 739 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 740 FILE_ATTRIBUTE_NORMAL /* | FILE_FLAG_DELETE_ON_CLOSE */, 741 NULL); 742 /* 743 * Can't apply FILE_FLAG_DELETE_ON_CLOSE due to 744 * the logics of clist_fclose. Also note that 745 * gdev_prn_render_pages requires multiple temporary files 746 * to exist simultaneousely, so that keeping all them opened 747 * may exceed available CRTL file handles. 748 */ 749 } 750 } 751 if (hfile != INVALID_HANDLE_VALUE) { 752 /* Associate a C file handle with an OS file handle. */ 753 fd = _open_osfhandle((long)hfile, 0); 754 if (fd == -1) 755 CloseHandle(hfile); 756 else { 757 /* Associate a C file stream with C file handle. */ 758 f = fdopen(fd, mode); 759 if (f == NULL) 760 _close(fd); 761 } 762 } 763 if (f != NULL) { 764 if ((strlen(sTempFileName) < gp_file_name_sizeof)) 765 strncpy(fname, sTempFileName, gp_file_name_sizeof - 1); 766 else { 767 /* The file name is too long. */ 768 fclose(f); 769 f = NULL; 770 } 771 } 772 if (f == NULL) 773 eprintf1("**** Could not open temporary file '%s'\n", fname); 774 return f; 775 } 776 777 /* Open a file with the given name, as a stream of uninterpreted bytes. */ 778 FILE * 779 gp_fopen(const char *fname, const char *mode) 780 { 781 return fopen(fname, mode); 782 } 783 784 /* ------ Font enumeration ------ */ 785 786 /* This is used to query the native os for a list of font names and 787 * corresponding paths. The general idea is to save the hassle of 788 * building a custom fontmap file. 789 */ 790 791 void *gp_enumerate_fonts_init(gs_memory_t *mem) 792 { 793 return NULL; 794 } 795 796 int gp_enumerate_fonts_next(void *enum_state, char **fontname, char **path) 797 { 798 return 0; 799 } 800 801 void gp_enumerate_fonts_free(void *enum_state) 802 { 803 } 804