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