xref: /plan9/sys/src/cmd/gs/src/dwuninst.cpp (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1999, 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: dwuninst.cpp,v 1.6 2005/03/04 21:58:55 ghostgum Exp $
18 
19 #define STRICT
20 #include <windows.h>
21 #include <objbase.h>
22 #include <shlobj.h>
23 #include <shellapi.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <direct.h>
28 #include "dwuninst.h"
29 
30 
31 #ifdef _MSC_VER
32 #define _export
33 #define chdir(x) _chdir(x)
34 #define mkdir(x) _mkdir(x)
35 #endif
36 #define DELAY_STEP 500
37 #define DELAY_FILE 0
38 #define MAXSTR 256
39 #define UNINSTALLKEY TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
40 
41 #ifdef _WIN64
42 #define DLGRETURN INT_PTR
43 #else
44 #define DLGRETURN BOOL
45 #endif
46 
47 
48 HWND hDlgModeless;
49 HWND hText1;
50 HWND hText2;
51 char path[MAXSTR];
52 int language = 0;
53 BOOL is_win4 = FALSE;
54 HINSTANCE phInstance;
55 char szSection[] = "////////////////////////////////";
56 BOOL bQuit = FALSE;
57 BOOL gError = FALSE;	// set TRUE if an uninstall was not successful
58 
59 char szTitle[MAXSTR];
60 char szLogFile[MAXSTR];
61 char szLine[MAXSTR];
62 FILE *fLog;
63 
64 void do_message(void);
65 BOOL dofiles(void);
66 BOOL registry_delete(void);
67 BOOL registry_import(void);
68 BOOL shell_new(void);
69 BOOL shell_old(void);
70 BOOL doEOF(void);
71 
72 // #define gs_addmess(str) fputs(str, stdout)	// for debug
73 #define gs_addmess(str)
74 
75 
76 // linked list for deleting registry entries in reverse order
77 typedef struct tagKEY {
78     long index;
79     struct tagKEY *previous;
80 } KEY;
81 KEY *last_key = NULL;
82 
83 
84 // read a line from the log, removing trailing new line character
GetLine(void)85 BOOL GetLine(void)
86 {
87     BOOL err = TRUE;
88     int i;
89     szLine[0] = '\0';
90     if (fLog)
91         err = (fgets(szLine, sizeof(szLine)-1, fLog) == NULL);
92     i = strlen(szLine) - 1;
93     if ( (szLine[0] != '\0') && (szLine[i] == '\n'))
94 		szLine[i] = '\0';
95     return !err;
96 }
97 
IsSection(void)98 BOOL IsSection(void)
99 {
100     return (strncmp(szLine, szSection, strlen(szSection)) == 0);
101 }
102 
103 BOOL
NextSection(void)104 NextSection(void)
105 {
106     while (GetLine()) {
107 		do_message();
108 		if (bQuit)
109 			return FALSE;
110 		if (IsSection())
111 			return TRUE;
112 	}
113 
114 	return TRUE;
115 }
116 
ReadSection(void)117 BOOL ReadSection(void)
118 {
119 	do_message();
120 	if (bQuit)
121 		return FALSE;
122 	GetLine();
123 	if (strlen(szLine) == 0) {
124 		doEOF();
125 		return TRUE;
126 	}
127 	else if (strcmp(szLine, "FileNew")==0) {
128 		SetWindowText(hText1, "Removing Files");
129 		Sleep(DELAY_STEP);
130 		if (!dofiles())
131 			return FALSE;
132 		SetWindowText(hText1, "");
133 		return TRUE;
134 	}
135 	else if (strcmp(szLine, "RegistryNew")==0) {
136 		SetWindowText(hText1, "Removing Registry entries");
137 		Sleep(DELAY_STEP);
138 		if (!registry_delete())
139 			return FALSE;
140 		SetWindowText(hText1, "");
141 		return TRUE;
142 	}
143 	else if (strcmp(szLine, "RegistryOld")==0) {
144 		SetWindowText(hText1, "Restoring Registry entries");
145 		Sleep(DELAY_STEP);
146 		if (!registry_import())
147 			return FALSE;
148 		SetWindowText(hText1, "");
149 		return TRUE;
150 	}
151 	else if (strcmp(szLine, "ShellNew")==0) {
152 		SetWindowText(hText1, "Removing Start Menu items");
153 		Sleep(DELAY_STEP);
154 		if (!shell_new())
155 			return FALSE;
156 		SetWindowText(hText1, "");
157 		return TRUE;
158 	}
159 	else if (strcmp(szLine, "ShellOld")==0) {
160 		SetWindowText(hText1, "Restoring Start Menu items");
161 		Sleep(DELAY_STEP);
162 		if (!shell_old())
163 			return FALSE;
164 		SetWindowText(hText1, "");
165 		return TRUE;
166 	}
167 	return FALSE;
168 }
169 
170 
171 BOOL
dofiles(void)172 dofiles(void)
173 {
174     while (GetLine()) {
175 	do_message();
176 	if (bQuit)
177 	    return FALSE;
178 	if (IsSection()) {
179 	    SetWindowText(hText2, "");
180 	    return TRUE;
181 	}
182 	if (szLine[0] != '\0') {
183 	    SetWindowText(hText2, szLine);
184 	    Sleep(DELAY_FILE);
185 	    gs_addmess("Deleting File: ");
186 	    gs_addmess(szLine);
187 	    gs_addmess("\n");
188 	    DeleteFile(szLine);
189 	}
190     }
191     return FALSE;
192 }
193 
194 BOOL
doEOF(void)195 doEOF(void)
196 {
197     fclose(fLog);
198     fLog = NULL;
199     unlink(szLogFile);
200     PostMessage(hDlgModeless, WM_COMMAND, IDC_DONE, 0L);
201 	bQuit = TRUE;
202     return TRUE;
203 }
204 
205 
206 BOOL
registry_delete_key(void)207 registry_delete_key(void)
208 {
209 char keyname[MAXSTR];
210 HKEY hkey = HKEY_CLASSES_ROOT;
211 HKEY hrkey = HKEY_CLASSES_ROOT;
212 char *rkey, *skey;
213 char *name;
214 DWORD dwResult;
215     keyname[0] = '\0';
216     while (GetLine()) {
217 	if ((szLine[0] == '\0') || (szLine[0] == '\r') || (szLine[0] == '\n'))
218 	    break;
219 	if (szLine[0] == '[') {
220 	    // key name
221 	    rkey = strtok(szLine+1, "\\]\n\r");
222 	    if (rkey == (char *)NULL)
223 		return FALSE;
224 	    skey = strtok(NULL, "]\n\r");
225 	    if (strcmp(rkey, "HKEY_CLASSES_ROOT")==0)
226 		hrkey = HKEY_CLASSES_ROOT;
227 	    else if (strcmp(rkey, "HKEY_CURRENT_USER")==0)
228 		hrkey = HKEY_CURRENT_USER;
229 	    else if (strcmp(rkey, "HKEY_LOCAL_MACHINE")==0)
230 		hrkey = HKEY_LOCAL_MACHINE;
231 	    else if (strcmp(rkey, "HKEY_USERS")==0)
232 		hrkey = HKEY_USERS;
233 	    else
234 		return FALSE;
235 	    if (skey == (char *)NULL)
236 		return FALSE;
237 	    gs_addmess("Opening registry key\n   ");
238 	    gs_addmess(rkey);
239 	    gs_addmess("\\");
240 	    gs_addmess(skey);
241 	    gs_addmess("\n");
242 	    if (RegCreateKeyEx(hrkey, skey, 0, "", 0, KEY_ALL_ACCESS,
243 		NULL, &hkey, &dwResult)
244 		!= ERROR_SUCCESS)
245 		return FALSE;
246 	    strcpy(keyname, skey);
247 	}
248 	else if (szLine[0] == '@') {
249 	    // default value
250 	    RegDeleteValue(hkey, NULL);
251 	    gs_addmess("Deleting registry default value\n");
252 	}
253 	else if (szLine[0] == '\042') {
254 	    // named value
255 	    name = strtok(szLine+1, "\042\r\n");
256 	    RegDeleteValue(hkey, name);
257 	    gs_addmess("Deleting registry named value\n   ");
258 	    gs_addmess(name);
259 	    gs_addmess("\n");
260 	}
261     }
262     // close key
263     if (hkey != HKEY_CLASSES_ROOT)
264 	RegCloseKey(hkey);
265     // delete the key
266     if (strlen(keyname)) {
267 	gs_addmess("Deleting registry key\n   ");
268 	gs_addmess(keyname);
269 	gs_addmess("\n");
270 	RegOpenKeyEx(hrkey, NULL, 0, 0, &hkey);
271 	RegDeleteKey(hkey, keyname);
272 	RegCloseKey(hkey);
273     }
274     return TRUE;
275 }
276 
277 BOOL
registry_delete()278 registry_delete()
279 {
280 	long logindex;
281 	KEY *key;
282 
283     // scan log file
284     // so we can remove keys in reverse order
285     logindex = 0;
286     while (GetLine() && !IsSection()) {
287 		KEY *key;
288 		if (szLine[0] == '[') {
289 			if ((key = (KEY *)malloc(sizeof(KEY)))
290 				!= (KEY *)NULL) {
291 				key->previous = last_key;
292 				key->index = logindex;
293 				last_key = key;
294 			}
295 		}
296 		logindex = ftell(fLog);
297     }
298 
299     // Remove keys
300     for (key = last_key; key != NULL;
301 	key = key->previous) {
302 		if (key != last_key)
303 			free(last_key);
304 		fseek(fLog, key->index, SEEK_SET);
305 		registry_delete_key();
306 		last_key = key;
307     }
308     free(last_key);
309 
310     fseek(fLog, logindex, SEEK_SET);
311 	GetLine();
312     return TRUE;
313 }
314 
315 
316 
317 void
registry_unquote(char * line)318 registry_unquote(char *line)
319 {
320 char *s, *d;
321 int value;
322     s = d = line;
323     while (*s) {
324 	if (*s != '\\') {
325 	    *d++ = *s;
326 	}
327 	else {
328 	    s++;
329 	    if (*s == '\\')
330 		*d++ = *s;
331 	    else {
332 		value = 0;
333 		if (*s) {
334 		    value = *s++ - '0';
335 		}
336 		if (*s) {
337 		    value <<= 3;
338 		    value += *s++ - '0';
339 		}
340 		if (*s) {
341 		    value <<= 3;
342 		    value += *s - '0';
343 		}
344 		*d++ = (char)value;
345 	    }
346 	}
347 	s++;
348     }
349     *d = '\0';
350 }
351 
352 BOOL
registry_import()353 registry_import()
354 {
355 	HKEY hkey = HKEY_CLASSES_ROOT;
356 	HKEY hrkey;
357 	char *rkey, *skey;
358 	char *value;
359 	char *name;
360 	DWORD dwResult;
361     GetLine();
362     if (strncmp(szLine, "REGEDIT4", 8) != 0)
363 		return FALSE;
364 
365     while (GetLine()) {
366 		if (IsSection())
367 			break;
368 		if ((szLine[0] == '\0') || (szLine[0] == '\r') || (szLine[0] == '\n'))
369 			continue;
370 		if (szLine[0] == '[') {
371 			// key name
372 			if (hkey != HKEY_CLASSES_ROOT) {
373 				RegCloseKey(hkey);
374 				hkey = HKEY_CLASSES_ROOT;
375 			}
376 			rkey = strtok(szLine+1, "\\]\n\r");
377 			if (rkey == (char *)NULL)
378 				return FALSE;
379 			skey = strtok(NULL, "]\n\r");
380 			if (strcmp(rkey, "HKEY_CLASSES_ROOT")==0)
381 				hrkey = HKEY_CLASSES_ROOT;
382 			else if (strcmp(rkey, "HKEY_CURRENT_USER")==0)
383 				hrkey = HKEY_CURRENT_USER;
384 			else if (strcmp(rkey, "HKEY_LOCAL_MACHINE")==0)
385 				hrkey = HKEY_LOCAL_MACHINE;
386 			else if (strcmp(rkey, "HKEY_USERS")==0)
387 				hrkey = HKEY_USERS;
388 			else
389 				return FALSE;
390 			if (skey == (char *)NULL)
391 				return FALSE;
392 			gs_addmess("Creating registry key\n   ");
393 			gs_addmess(rkey);
394 			gs_addmess("\\");
395 			gs_addmess("skey");
396 			gs_addmess("\n");
397 			if (RegCreateKeyEx(hrkey, skey, 0, "", 0, KEY_ALL_ACCESS,
398 				NULL, &hkey, &dwResult)
399 				!= ERROR_SUCCESS)
400 				return FALSE;
401 		}
402 		else if (szLine[0] == '@') {
403 			// default value
404 			if (strlen(szLine) < 4)
405 				return FALSE;
406 			value = strtok(szLine+3, "\042\r\n");
407 			if (value) {
408 				registry_unquote(value);
409 				gs_addmess("Setting registry key value\n   ");
410 				gs_addmess(value);
411 				gs_addmess("\n");
412 				if (RegSetValueEx(hkey, NULL, 0, REG_SZ,
413 					(CONST BYTE *)value, strlen(value)+1)
414 					!= ERROR_SUCCESS)
415 					return FALSE;
416 			}
417 		}
418 		else if (szLine[0] == '\042') {
419 			// named value
420 			name = strtok(szLine+1, "\042\r\n");
421 			strtok(NULL, "\042\r\n");
422 			value = strtok(NULL, "\042\r\n");
423 			registry_unquote(value);
424 			gs_addmess("Setting registry key value\n   ");
425 			gs_addmess(name);
426 			gs_addmess("=");
427 			gs_addmess(value);
428 			gs_addmess("\n");
429 			if (RegSetValueEx(hkey, name, 0, REG_SZ, (CONST BYTE *)value, strlen(value)+1)
430 				!= ERROR_SUCCESS)
431 				return FALSE;
432 		}
433     }
434     if (hkey != HKEY_CLASSES_ROOT)
435 		RegCloseKey(hkey);
436     return TRUE;
437 }
438 
439 // recursive mkdir
440 // requires a full path to be specified, so ignores root \
441 // apart from root \, must not contain trailing \
442 // Examples:
443 //  c:\          (OK, but useless)
444 //  c:\gstools   (OK)
445 //  c:\gstools\  (incorrect)
446 //  c:gstools    (incorrect)
447 //  gstools      (incorrect)
448 // The following UNC names should work,
449 // but didn't under Win3.1 because gs_chdir wouldn't accept UNC names
450 // Needs to be tested under Windows 95.
451 //  \\server\sharename\gstools    (OK)
452 //  \\server\sharename\           (OK, but useless)
453 //
454 
MakeDir(char * dirname)455 BOOL MakeDir(char *dirname)
456 {
457 char newdir[MAXSTR];
458 char *p;
459     if (strlen(dirname) < 3)
460         return -1;
461 
462     gs_addmess("Making Directory\n  ");
463     gs_addmess(dirname);
464     gs_addmess("\n");
465     if (isalpha(dirname[0]) && dirname[1]==':' && dirname[2]=='\\') {
466         // drive mapped path
467         p = dirname+3;
468     }
469     else if (dirname[1]=='\\' && dirname[1]=='\\') {
470         // UNC path
471         p = strchr(dirname+2, '\\');    // skip servername
472         if (p == NULL)
473             return -1;
474         p++;
475         p = strchr(p, '\\');            // skip sharename
476         if (p == NULL)
477             return -1;
478     }
479     else {
480         // not full path so error
481         return -1;
482     }
483 
484     while (1) {
485         strncpy(newdir, dirname, (int)(p-dirname));
486         newdir[(int)(p-dirname)] = '\0';
487         if (chdir(newdir)) {
488             if (mkdir(newdir))
489                 return -1;
490         }
491         p++;
492         if (p >= dirname + strlen(dirname))
493             break;              // all done
494         p = strchr(p, '\\');
495         if (p == NULL)
496             p = dirname + strlen(dirname);
497     }
498 
499     return SetCurrentDirectory(dirname);
500 }
501 
502 
shell_new(void)503 BOOL shell_new(void)
504 {
505 
506 	char *p, *q;
507 	char group[MAXSTR];
508 	// remove shell items added by Ghostscript
509 	// We can only delete one group with this code
510 	group[0] = '\0';
511 	while (GetLine()) {
512 		if (IsSection()) {
513 			if (strlen(group) != 0) {
514 				gs_addmess("Removing shell folder\n  ");
515 				gs_addmess(group);
516 				gs_addmess("\n");
517 				RemoveDirectory(group);
518 			}
519 			return TRUE;
520 		}
521 		p = strtok(szLine, "=");
522 		q = strtok(NULL, "");
523 		if (p == NULL) {
524 			continue;
525 		}
526 		else if (strcmp(p, "Group")==0) {
527 			if (q)
528 				strncpy(group, q, sizeof(group)-1);
529 			// defer this until we have remove contents
530 		}
531 		else if (strcmp(p, "Name") == 0) {
532 			if (q) {
533 				gs_addmess("Removing shell link\n  ");
534 				gs_addmess(q);
535 				gs_addmess("\n");
536 				DeleteFile(q);
537 			}
538 		}
539 	}
540 
541 	return TRUE;
542 }
543 
544 
CreateShellLink(LPCSTR name,LPCSTR description,LPCSTR program,LPCSTR arguments,LPCSTR directory,LPCSTR icon,int nIconIndex)545 BOOL CreateShellLink(LPCSTR name, LPCSTR description, LPCSTR program,
546 	LPCSTR arguments, LPCSTR directory, LPCSTR icon, int nIconIndex)
547 {
548 	HRESULT hres;
549 	IShellLink* psl;
550 
551 	// Ensure string is UNICODE.
552 	WCHAR wsz[MAX_PATH];
553 	MultiByteToWideChar(CP_ACP, 0, name, -1, wsz, MAX_PATH);
554 
555 	// Save new shell link
556 
557 	// Get a pointer to the IShellLink interface.
558 	hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
559 		IID_IShellLink, (void **)&psl);
560 	if (SUCCEEDED(hres))    {
561 		IPersistFile* ppf;
562 		// Query IShellLink for the IPersistFile interface for
563 		// saving the shell link in persistent storage.
564 		hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
565 		if (SUCCEEDED(hres)) {
566 			gs_addmess("Adding shell link\n  ");
567 			gs_addmess(name);
568 			gs_addmess("\n");
569 
570 			// Set the path to the shell link target.
571 			hres = psl->SetPath(program);
572 			if (!SUCCEEDED(hres)) {
573 				gs_addmess("SetPath failed!");
574 				gError = TRUE;
575 			}
576 			// Set the description of the shell link.
577 			hres = psl->SetDescription(description);
578 			if (!SUCCEEDED(hres)) {
579 				gs_addmess("SetDescription failed!");
580 				gError = TRUE;
581 			}
582 			if ((arguments != (LPCSTR)NULL) && *arguments) {
583 				// Set the arguments of the shell link target.
584 				hres = psl->SetArguments(arguments);
585 				if (!SUCCEEDED(hres)) {
586 					gs_addmess("SetArguments failed!");
587 					gError = TRUE;
588 				}
589 			}
590 			if ((directory != (LPCSTR)NULL) && *directory) {
591 				// Set the arguments of the shell link target.
592 				hres = psl->SetWorkingDirectory(directory);
593 				if (!SUCCEEDED(hres)) {
594 					gs_addmess("SetWorkingDirectory failed!");
595 					gError = TRUE;
596 				}
597 			}
598 			if ((icon != (LPCSTR)NULL) && *icon) {
599 				// Set the arguments of the shell link target.
600 				hres = psl->SetIconLocation(icon, nIconIndex);
601 				if (!SUCCEEDED(hres)) {
602 					gs_addmess("SetIconLocation failed!");
603 					gError = TRUE;
604 				}
605 			}
606 
607 			// Save the link via the IPersistFile::Save method.
608 			hres = ppf->Save(wsz, TRUE);
609 			// Release pointer to IPersistFile.
610 			ppf->Release();
611 		}
612 		// Release pointer to IShellLink.
613 		psl->Release();
614 	}
615 
616 	return (hres == 0);
617 }
618 
619 
620 
shell_old(void)621 BOOL shell_old(void)
622 {
623 	// Add shell items removed by Ghostscript
624 	char *p, *q;
625 	char name[MAXSTR];
626 	char description[MAXSTR];
627 	char program[MAXSTR];
628 	char arguments[MAXSTR];
629 	char directory[MAXSTR];
630 	char icon[MAXSTR];
631 	int nIconIndex;
632 	// Remove shell items added by Ghostscript
633 	name[0] = description[0] = program[0] = arguments[0]
634 		= directory[0] = icon[0] = '\0';
635 	nIconIndex = 0;
636 
637 	while (GetLine()) {
638 		if (IsSection())
639 			return TRUE;
640 		p = strtok(szLine, "=");
641 		q = strtok(NULL, "");
642 		if (strlen(szLine) == 0) {
643 			if (name[0] != '\0') {
644 				// add start menu item
645 				CreateShellLink(name, description, program, arguments,
646 					directory, icon, nIconIndex);
647 			}
648 			name[0] = description[0] = program[0] = arguments[0]
649 				= directory[0] = icon[0] = '\0';
650 			nIconIndex = 0;
651 			continue;
652 		}
653 		else if (p == (char *)NULL) {
654 			continue;
655 		}
656 		else if (strcmp(p, "Group")==0) {
657 			MakeDir(q);
658 		}
659 		else if (strcmp(p, "Name") == 0)
660 			strncpy(name, q, sizeof(name)-1);
661 		else if (strcmp(p, "Description") == 0)
662 			strncpy(description, q, sizeof(description)-1);
663 		else if (strcmp(p, "Program") == 0)
664 			strncpy(program, q, sizeof(program)-1);
665 		else if (strcmp(p, "Arguments") == 0)
666 			strncpy(arguments, q, sizeof(arguments)-1);
667 		else if (strcmp(p, "Directory") == 0)
668 			strncpy(directory, q, sizeof(directory)-1);
669 		else if (strcmp(p, "IconLocation") == 0)
670 			strncpy(icon, q, sizeof(icon)-1);
671 		else if (strcmp(p, "IconIndex") == 0)
672 			nIconIndex = atoi(q);
673 	}
674 
675 	return TRUE;
676 }
677 
678 
679 
680 #ifdef __BORLANDC__
681 #pragma argsused
682 #endif
683 DLGRETURN CALLBACK _export
RemoveDlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)684 RemoveDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
685 {
686   switch(message) {
687     case WM_INITDIALOG:
688 	    SetWindowText(hwnd, szTitle);
689 	    return TRUE;
690 	case WM_COMMAND:
691 	    switch(LOWORD(wParam)) {
692 		case IDC_DONE:
693 		    // delete registry entries for uninstall
694 			if (is_win4) {
695 				HKEY hkey;
696 				if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
697 					UNINSTALLKEY, 0, KEY_ALL_ACCESS, &hkey)
698 					== ERROR_SUCCESS) {
699 					RegDeleteKey(hkey, szTitle);
700 					RegCloseKey(hkey);
701 				}
702 			}
703 
704 		    SetWindowText(hText1, "Uninstall successful");
705 		    SetWindowText(hText2, "");
706 		    EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
707 		    EnableWindow(GetDlgItem(hwnd, IDCANCEL), TRUE);
708 		    SetDlgItemText(hwnd, IDCANCEL, "Exit");
709 		    SetFocus(GetDlgItem(hwnd, IDCANCEL));
710 		    return TRUE;
711 		case IDOK:
712 		    // Start removal
713 		    EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
714 			EnableWindow(GetDlgItem(hwnd, IDC_PRESSOK), FALSE);
715 		    while (!bQuit) {
716 			do_message();
717 			if (!ReadSection()) {
718 			    SetWindowText(hText1, "Uninstall FAILED");
719 			    SetWindowText(hText2, "");
720 			    EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
721 			    EnableWindow(GetDlgItem(hwnd, IDCANCEL), TRUE);
722 			    SetDlgItemText(hwnd, IDCANCEL, "Exit");
723 			    SetFocus(GetDlgItem(hwnd, IDCANCEL));
724 				bQuit = TRUE;
725 			}
726 		    }
727 		    return TRUE;
728 		case IDCANCEL:
729 		    bQuit = TRUE;
730 		    DestroyWindow(hwnd);
731 		    hDlgModeless = 0;
732 		    return TRUE;
733 	    }
734 	case WM_CLOSE:
735 	    DestroyWindow(hwnd);
736 	    hDlgModeless = 0;
737 	    return TRUE;
738     }
739     return FALSE;
740 }
741 
742 void
do_message(void)743 do_message(void)
744 {
745 MSG msg;
746     while (hDlgModeless && PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE)) {
747 	if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
748 	    TranslateMessage(&msg);
749 	    DispatchMessage(&msg);
750 	}
751     }
752 }
753 
754 
755 
756 BOOL
init(void)757 init(void)
758 {
759 	DWORD version = GetVersion();
760 	char *p, *s;
761     // get location of uninstall log from command line as argv[1]
762     p = GetCommandLine();
763 	s = p;
764 	if (*s == '\042') {
765 		// skip over program name
766 		s++;
767 		while (*s && *s!='\042')
768 			s++;
769 		if (*s)
770 			s++;
771 	}
772 	else if (*s != ' ') {
773 		// skip over program name
774 		s++;
775 		while (*s && *s!=' ')
776 			s++;
777 		if (*s)
778 			s++;
779 	}
780 	while (*s && *s==' ')
781 		s++;
782 	if (*s == '\042')
783 		s++;
784 	strncpy(szLogFile, s, sizeof(szLogFile));
785 	s = szLogFile;
786 	while (*s) {
787 		if (*s == '\042') {
788 			*s = '\0';
789 			break;
790 		}
791 		s++;
792 	}
793 	if (strlen(szLogFile) == 0) {
794 		MessageBox(HWND_DESKTOP, "Usage: uninstgs logfile.txt",
795 			"AFPL Ghostscript Uninstall", MB_OK);
796 		return FALSE;
797 	}
798 
799 	// read first few lines of file to get title
800 	fLog = fopen(szLogFile, "r");
801 	if (fLog == (FILE *)NULL) {
802 		MessageBox(HWND_DESKTOP, szLogFile, "Can't find file", MB_OK);
803 		return FALSE;
804 	}
805 	GetLine();
806 	if (!IsSection()) {
807 		MessageBox(HWND_DESKTOP, szLogFile, "Not valid uninstall log",
808 			MB_OK);
809 		return FALSE;
810 	}
811 	GetLine();
812 	if (strcmp(szLine, "UninstallName") != 0) {
813 		MessageBox(HWND_DESKTOP, szLogFile, "Not valid uninstall log",
814 			MB_OK);
815 		return FALSE;
816 	}
817 	GetLine();
818 	strcpy(szTitle, szLine);
819 
820 	NextSection();
821 
822 	if (LOBYTE(LOWORD(version)) >= 4)
823 		is_win4 = TRUE;
824 	return TRUE;
825 }
826 
827 #ifdef __BORLANDC__
828 #pragma argsused
829 #endif
830 int PASCAL
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int cmdShow)831 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
832 {
833 MSG msg;
834 
835     phInstance = hInstance;
836     if (!init())
837 	return 1;
838 
839 
840     CoInitialize(NULL);
841 
842     hDlgModeless = CreateDialogParam(hInstance,
843 	    MAKEINTRESOURCE(IDD_UNSET),
844 	    HWND_DESKTOP, RemoveDlgProc, (LPARAM)NULL);
845     hText1 = GetDlgItem(hDlgModeless, IDC_T1);
846     hText2 = GetDlgItem(hDlgModeless, IDC_T2);
847 
848     SetWindowPos(hDlgModeless, HWND_TOP, 0, 0, 0, 0,
849 	SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
850 
851     while (hDlgModeless && GetMessage(&msg, (HWND)NULL, 0, 0)) {
852 	if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
853 	    TranslateMessage(&msg);
854 	    DispatchMessage(&msg);
855 	}
856     }
857 
858 	if (fLog)
859 		fclose(fLog);
860 
861 	CoUninitialize();
862 
863     return 0;
864 }
865 
866