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