1 /* Copyright (C) 1996-2001 Ghostgum Software Pty Ltd. 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: dwmain.c,v 1.21 2004/09/15 19:41:01 ray Exp $ */
18 /* Ghostscript DLL loader for Windows */
19
20 #include "windows_.h"
21 #include <shellapi.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include "gscdefs.h"
26 #define GSREVISION gs_revision
27 #include "ierrors.h"
28 #include "iapi.h"
29 #include "vdtrace.h"
30
31 #include "dwmain.h"
32 #include "dwdll.h"
33 #include "dwtext.h"
34 #include "dwimg.h"
35 #include "dwtrace.h"
36 #include "dwreg.h"
37 #include "gdevdsp.h"
38
39 /* public handles */
40 HINSTANCE ghInstance;
41
42 /* redirected stdio */
43 TW *tw;
44
45 static const LPSTR szAppName = "Ghostscript";
46
47 const LPSTR szIniName = "gswin32.ini";
48 const char *szDllName = "gsdll32.dll";
49 const LPSTR szIniSection = "Text";
50
51
52 GSDLL gsdll;
53 void *instance;
54 HWND hwndtext;
55
56 char start_string[] = "systemdict /start get exec\n";
57
poll(void)58 static int poll(void)
59 {
60 MSG msg;
61 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
62 TranslateMessage(&msg);
63 DispatchMessage(&msg);
64 }
65 /* If text window closing then abort Ghostscript */
66 if (tw->quitnow)
67 return e_Fatal;
68 return 0;
69 }
70
71 /*********************************************************************/
72 /* stdio functions */
73 static int GSDLLCALL
gsdll_stdin(void * instance,char * buf,int len)74 gsdll_stdin(void *instance, char *buf, int len)
75 {
76 return text_read_line(tw, buf, len);
77 }
78
79 static int GSDLLCALL
gsdll_stdout(void * instance,const char * str,int len)80 gsdll_stdout(void *instance, const char *str, int len)
81 {
82 text_write_buf(tw, str, len);
83 return len;
84 }
85
86 static int GSDLLCALL
gsdll_stderr(void * instance,const char * str,int len)87 gsdll_stderr(void *instance, const char *str, int len)
88 {
89 text_write_buf(tw, str, len);
90 return len;
91 }
92
93 /* Poll the caller for cooperative multitasking. */
94 /* If this function is NULL, polling is not needed */
gsdll_poll(void * handle)95 static int GSDLLCALL gsdll_poll(void *handle)
96 {
97 return poll();
98 }
99 /*********************************************************************/
100
101 /* new dll display device */
102 /*
103 #define DISPLAY_DEBUG
104 */
105
106 /* New device has been opened */
107 /* This is the first event from this device. */
display_open(void * handle,void * device)108 static int display_open(void *handle, void *device)
109 {
110 IMAGE *img;
111 #ifdef DISPLAY_DEBUG
112 char buf[256];
113 sprintf(buf, "display_open(0x%x, 0x%x)\n", handle, device);
114 text_puts(tw, buf);
115 #endif
116 img = image_new(handle, device); /* create and add to list */
117 if (img)
118 image_open(img);
119 return 0;
120 }
121
122 /* Device is about to be closed. */
123 /* Device will not be closed until this function returns. */
display_preclose(void * handle,void * device)124 static int display_preclose(void *handle, void *device)
125 {
126 #ifdef DISPLAY_DEBUG
127 char buf[256];
128 sprintf(buf, "display_preclose(0x%x, 0x$x)\n", handle, device);
129 text_puts(tw, buf);
130 #endif
131 /* do nothing - no thread synchonisation needed */
132 return 0;
133 }
134
135 /* Device has been closed. */
136 /* This is the last event from this device. */
display_close(void * handle,void * device)137 static int display_close(void *handle, void *device)
138 {
139 IMAGE *img;
140 #ifdef DISPLAY_DEBUG
141 char buf[256];
142 sprintf(buf, "display_close(0x%x, 0x$x)\n", handle, device);
143 text_puts(tw, buf);
144 #endif
145 img = image_find(handle, device);
146 if (img) {
147 image_delete(img); /* remove from list but don't free */
148 image_close(img);
149 }
150 return 0;
151 }
152
153 /* Device is about to be resized. */
154 /* Resize will only occur if this function returns 0. */
display_presize(void * handle,void * device,int width,int height,int raster,unsigned int format)155 static int display_presize(void *handle, void *device, int width, int height,
156 int raster, unsigned int format)
157 {
158 #ifdef DISPLAY_DEBUG
159 char buf[256];
160 sprintf(buf, "display_presize(0x%x, 0x%x, width=%d height=%d raster=%d\n\
161 format=%d)\n",
162 handle, device, width, height, raster, format);
163 text_puts(tw, buf);
164 #endif
165 return 0;
166 }
167
168 /* Device has been resized. */
169 /* New pointer to raster returned in pimage */
display_size(void * handle,void * device,int width,int height,int raster,unsigned int format,unsigned char * pimage)170 static int display_size(void *handle, void *device, int width, int height,
171 int raster, unsigned int format, unsigned char *pimage)
172 {
173 IMAGE *img;
174 #ifdef DISPLAY_DEBUG
175 char buf[256];
176 sprintf(buf, "display_size(0x%x, 0x%x, width=%d height=%d raster=%d\n\
177 format=%d image=0x%x)\n",
178 handle, device, width, height, raster, format, pimage);
179 text_puts(tw, buf);
180 #endif
181 img = image_find(handle, device);
182 image_size(img, width, height, raster, format, pimage);
183 image_updatesize(img);
184 return 0;
185 }
186
187 /* flushpage */
display_sync(void * handle,void * device)188 static int display_sync(void *handle, void *device)
189 {
190 IMAGE *img;
191 #ifdef DISPLAY_DEBUG
192 char buf[256];
193 sprintf(buf, "display_sync(0x%x, 0x%x)\n", handle, device);
194 text_puts(tw, buf);
195 #endif
196 img = image_find(handle, device);
197 image_sync(img);
198 return 0;
199 }
200
201 /* showpage */
202 /* If you want to pause on showpage, then don't return immediately */
display_page(void * handle,void * device,int copies,int flush)203 static int display_page(void *handle, void *device, int copies, int flush)
204 {
205 IMAGE *img;
206 #ifdef DISPLAY_DEBUG
207 char buf[256];
208 sprintf(buf, "display_page(0x%x, 0x%x, copies=%d flush=%d)\n",
209 handle, device, copies, flush);
210 text_puts(tw, buf);
211 #endif
212 img = image_find(handle, device);
213 image_page(img);
214 return 0;
215 }
216
217 /* Poll the caller for cooperative multitasking. */
218 /* If this function is NULL, polling is not needed */
display_update(void * handle,void * device,int x,int y,int w,int h)219 static int display_update(void *handle, void *device,
220 int x, int y, int w, int h)
221 {
222 IMAGE *img;
223 img = image_find(handle, device);
224 image_poll(img); /* redraw the window periodically */
225 return poll();
226 }
227
display_separation(void * handle,void * device,int comp_num,const char * name,unsigned short c,unsigned short m,unsigned short y,unsigned short k)228 int display_separation(void *handle, void *device,
229 int comp_num, const char *name,
230 unsigned short c, unsigned short m,
231 unsigned short y, unsigned short k)
232 {
233 IMAGE *img;
234 #ifdef DISPLAY_DEBUG
235 fprintf(stdout, "display_separation(0x%x, 0x%x, %d '%s' %d,%d,%d,%d)\n",
236 handle, device, comp_num, name, (int)c, (int)m, (int)y, (int)k);
237 #endif
238 img = image_find(handle, device);
239 if (img)
240 image_separation(img, comp_num, name, c, m, y, k);
241 return 0;
242 }
243
244 display_callback display = {
245 sizeof(display_callback),
246 DISPLAY_VERSION_MAJOR,
247 DISPLAY_VERSION_MINOR,
248 display_open,
249 display_preclose,
250 display_close,
251 display_presize,
252 display_size,
253 display_sync,
254 display_page,
255 display_update,
256 NULL, /* memalloc */
257 NULL, /* memfree */
258 display_separation
259 };
260
261
262 /*********************************************************************/
263
264 /* program really starts at WinMain */
new_main(int argc,char * argv[])265 int new_main(int argc, char *argv[])
266 {
267 int code, code1;
268 int exit_status;
269 int exit_code;
270 int nargc;
271 char **nargv;
272 char dformat[64];
273 char ddpi[64];
274 char buf[256];
275
276 memset(buf, 0, sizeof(buf));
277 if (load_dll(&gsdll, buf, sizeof(buf))) {
278 text_puts(tw, "Can't load Ghostscript DLL\n");
279 text_puts(tw, buf);
280 text_puts(tw, "\n");
281 return 1;
282 }
283
284 if (gsdll.new_instance(&instance, NULL) < 0) {
285 text_puts(tw, "Can't create Ghostscript instance\n");
286 return 1;
287 }
288
289 #ifdef DEBUG
290 visual_tracer_init();
291 gsdll.set_visual_tracer(&visual_tracer);
292 #endif
293
294 gsdll.set_stdio(instance, gsdll_stdin, gsdll_stdout, gsdll_stderr);
295 gsdll.set_poll(instance, gsdll_poll);
296 gsdll.set_display_callback(instance, &display);
297
298 /* insert display device defaults as first arguments */
299 { int format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
300 DISPLAY_DEPTH_1 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
301 HDC hdc = GetDC(NULL); /* get hdc for desktop */
302 int depth = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
303 sprintf(ddpi, "-dDisplayResolution=%d", GetDeviceCaps(hdc, LOGPIXELSY));
304 ReleaseDC(NULL, hdc);
305 if (depth == 32)
306 format = DISPLAY_COLORS_RGB | DISPLAY_UNUSED_LAST |
307 DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
308 else if (depth == 16)
309 format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
310 DISPLAY_DEPTH_16 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST |
311 DISPLAY_NATIVE_555;
312 else if (depth > 8)
313 format = DISPLAY_COLORS_RGB | DISPLAY_ALPHA_NONE |
314 DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
315 else if (depth >= 8)
316 format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
317 DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
318 else if (depth >= 4)
319 format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
320 DISPLAY_DEPTH_4 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
321 sprintf(dformat, "-dDisplayFormat=%d", format);
322 }
323 nargc = argc + 2;
324 nargv = (char **)malloc((nargc + 1) * sizeof(char *));
325 nargv[0] = argv[0];
326 nargv[1] = dformat;
327 nargv[2] = ddpi;
328 memcpy(&nargv[3], &argv[1], argc * sizeof(char *));
329
330 #if defined(_MSC_VER) || defined(__BORLANDC__)
331 __try {
332 #endif
333 code = gsdll.init_with_args(instance, nargc, nargv);
334 if (code == 0)
335 code = gsdll.run_string(instance, start_string, 0, &exit_code);
336 code1 = gsdll.exit(instance);
337 if (code == 0 || (code == e_Quit && code1 != 0))
338 code = code1;
339 #if defined(_MSC_VER) || defined(__BORLANDC__)
340 } __except(exception_code() == EXCEPTION_STACK_OVERFLOW) {
341 code = e_Fatal;
342 text_puts(tw, "*** C stack overflow. Quiting...\n");
343 }
344 #endif
345
346 gsdll.delete_instance(instance);
347
348 #ifdef DEBUG
349 visual_tracer_close();
350 #endif
351
352 unload_dll(&gsdll);
353
354 free(nargv);
355
356 exit_status = 0;
357 switch (code) {
358 case 0:
359 case e_Quit:
360 break;
361 case e_Fatal:
362 exit_status = 1;
363 break;
364 case e_Info:
365 default:
366 exit_status = 255;
367 }
368
369 return exit_status;
370 }
371
372
373
374 void
set_font(void)375 set_font(void)
376 {
377 int fontsize;
378 char fontname[256];
379 char buf[32];
380
381 /* read ini file */
382 GetPrivateProfileString(szIniSection, "FontName", "Courier New", fontname, sizeof(fontname), szIniName);
383 fontsize = GetPrivateProfileInt(szIniSection, "FontSize", 10, szIniName);
384
385 /* set font */
386 text_font(tw, fontname, fontsize);
387
388 /* write ini file */
389 WritePrivateProfileString(szIniSection, "FontName", fontname, szIniName);
390 sprintf(buf, "%d", fontsize);
391 WritePrivateProfileString(szIniSection, "FontSize", buf, szIniName);
392 }
393
394 int PASCAL
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int cmdShow)395 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
396 {
397 int dll_exit_status;
398 #define MAXCMDTOKENS 128
399 /* BC++ 4.5 will give us _argc and _argv[], but they will be */
400 /* incorrect if there is a space in the program name. */
401 /* Provide our own parsing code to create argc and argv[]. */
402 int argc;
403 LPSTR argv[MAXCMDTOKENS];
404 LPSTR p;
405 char command[256];
406 char *args;
407 char *d, *e;
408 char winposbuf[256];
409 int len = sizeof(winposbuf);
410 int x, y, cx, cy;
411
412 /* copy the hInstance into a variable so it can be used */
413 ghInstance = hInstance;
414
415 if (hPrevInstance) {
416 MessageBox((HWND)NULL,"Can't run twice", szAppName,
417 MB_ICONHAND | MB_OK);
418 return FALSE;
419 }
420
421 /* If called with "gswin32c.exe arg1 arg2"
422 * lpszCmdLine returns:
423 * "arg1 arg2" if called with CreateProcess(NULL, command, ...)
424 * "arg2" if called with CreateProcess(command, args, ...)
425 * GetCommandLine() returns
426 * ""gswin32c.exe" arg1 arg2"
427 * if called with CreateProcess(NULL, command, ...)
428 * " arg1 arg2"
429 * if called with CreateProcess(command, args, ...)
430 * Consequently we must use GetCommandLine()
431 */
432 p = GetCommandLine();
433
434 argc = 0;
435 args = (char *)malloc(lstrlen(p)+1);
436 if (args == (char *)NULL) {
437 fprintf(stdout, "Insufficient memory in WinMain()\n");
438 return 1;
439 }
440
441 /* Parse command line handling quotes. */
442 d = args;
443 while (*p) {
444 /* for each argument */
445
446 if (argc >= MAXCMDTOKENS - 1)
447 break;
448
449 e = d;
450 while ((*p) && (*p != ' ')) {
451 if (*p == '\042') {
452 /* Remove quotes, skipping over embedded spaces. */
453 /* Doesn't handle embedded quotes. */
454 p++;
455 while ((*p) && (*p != '\042'))
456 *d++ =*p++;
457 }
458 else
459 *d++ = *p;
460 if (*p)
461 p++;
462 }
463 *d++ = '\0';
464 argv[argc++] = e;
465
466 while ((*p) && (*p == ' '))
467 p++; /* Skip over trailing spaces */
468 }
469 argv[argc] = NULL;
470
471 if (strlen(argv[0]) == 0) {
472 GetModuleFileName(hInstance, command, sizeof(command)-1);
473 argv[0] = command;
474 }
475
476
477 tw = text_new();
478 if (tw == NULL) {
479 MessageBox((HWND)NULL, "Can't create text window",
480 szAppName, MB_OK | MB_ICONSTOP);
481 return 1;
482 }
483
484 /* start up the text window */
485 if (!hPrevInstance) {
486 HICON hicon = LoadIcon(hInstance, (LPSTR)MAKEINTRESOURCE(GSTEXT_ICON));
487 text_register_class(tw, hicon);
488 }
489 set_font();
490 text_size(tw, 80, 80);
491 text_drag(tw, "(", ") run\r");
492 if (win_get_reg_value("Text", winposbuf, &len) == 0) {
493 if (sscanf(winposbuf, "%d %d %d %d", &x, &y, &cx, &cy) == 4)
494 text_setpos(tw, x, y, cx, cy);
495 }
496
497 /* create the text window */
498 if (text_create(tw, szAppName, cmdShow))
499 exit(1);
500
501 hwndtext = text_get_handle(tw);
502
503 dll_exit_status = new_main(argc, argv);
504
505 if (dll_exit_status && !tw->quitnow) {
506 /* display error message in text window */
507 MSG msg;
508 text_puts(tw, "\nClose this window with the close button on the title bar or the system menu.\n");
509 if (IsIconic(text_get_handle(tw)))
510 ShowWindow(text_get_handle(tw), SW_SHOWNORMAL);
511 BringWindowToTop(text_get_handle(tw)); /* make text window visible */
512 FlashWindow(text_get_handle(tw), TRUE);
513 /* Wait until error message is read */
514 while (!tw->quitnow && GetMessage(&msg, (HWND)NULL, 0, 0)) {
515 TranslateMessage(&msg);
516 DispatchMessage(&msg);
517 }
518 }
519
520 /* Save the text window size */
521 if (text_getpos(tw, &x, &y, &cx, &cy) == 0) {
522 sprintf(winposbuf, "%d %d %d %d", x, y, cx, cy);
523 win_set_reg_value("Text", winposbuf);
524 }
525
526 text_destroy(tw);
527 tw = NULL;
528
529 return dll_exit_status;
530 }
531
532
533
534