1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
// $Id: dwuninst.cpp 8037 2007-06-10 01:51:33Z alexcher $
31
#define chdir(x) _chdir(x)
32
#define mkdir(x) _mkdir(x)
34
#define DELAY_STEP 500
37
#define UNINSTALLKEY TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
46
char szSection[] = "////////////////////////////////";
48
BOOL gError = FALSE; // set TRUE if an uninstall was not successful
52
char szLogFile[MAXSTR];
56
void do_message(void);
58
BOOL registry_delete(void);
59
BOOL registry_import(void);
65
#define DLGRETURN INT_PTR
67
#define DLGRETURN BOOL
70
// #define gs_addmess(str) fputs(str, stdout) // for debug
71
#define gs_addmess(str)
73
int message_box(LPCTSTR message, LPCTSTR title, int nType)
77
return MessageBox(HWND_DESKTOP, message, title, nType);
80
// linked list for deleting registry entries in reverse order
81
typedef struct tagKEY {
83
struct tagKEY *previous;
88
// read a line from the log, removing trailing new line character
95
err = (fgets(szLine, sizeof(szLine)-1, fLog) == NULL);
96
i = strlen(szLine) - 1;
97
if ( (szLine[0] != '\0') && (szLine[i] == '\n'))
104
return (strncmp(szLine, szSection, strlen(szSection)) == 0);
121
BOOL ReadSection(void)
127
if (strlen(szLine) == 0) {
131
else if (strcmp(szLine, "FileNew")==0) {
132
SetWindowText(hText1, "Removing Files");
137
SetWindowText(hText1, "");
140
else if (strcmp(szLine, "RegistryNew")==0) {
141
SetWindowText(hText1, "Removing Registry entries");
144
if (!registry_delete())
146
SetWindowText(hText1, "");
149
else if (strcmp(szLine, "RegistryOld")==0) {
150
SetWindowText(hText1, "Restoring Registry entries");
153
if (!registry_import())
155
SetWindowText(hText1, "");
158
else if (strcmp(szLine, "ShellNew")==0) {
159
SetWindowText(hText1, "Removing Start Menu items");
164
SetWindowText(hText1, "");
167
else if (strcmp(szLine, "ShellOld")==0) {
168
SetWindowText(hText1, "Restoring Start Menu items");
173
SetWindowText(hText1, "");
188
SetWindowText(hText2, "");
191
if (szLine[0] != '\0') {
192
SetWindowText(hText2, szLine);
195
gs_addmess("Deleting File: ");
210
PostMessage(hDlgModeless, WM_COMMAND, IDC_DONE, 0L);
217
registry_delete_key(void)
219
char keyname[MAXSTR];
220
HKEY hkey = HKEY_CLASSES_ROOT;
221
HKEY hrkey = HKEY_CLASSES_ROOT;
227
if ((szLine[0] == '\0') || (szLine[0] == '\r') || (szLine[0] == '\n'))
229
if (szLine[0] == '[') {
231
rkey = strtok(szLine+1, "\\]\n\r");
232
if (rkey == (char *)NULL)
234
skey = strtok(NULL, "]\n\r");
235
if (strcmp(rkey, "HKEY_CLASSES_ROOT")==0)
236
hrkey = HKEY_CLASSES_ROOT;
237
else if (strcmp(rkey, "HKEY_CURRENT_USER")==0)
238
hrkey = HKEY_CURRENT_USER;
239
else if (strcmp(rkey, "HKEY_LOCAL_MACHINE")==0)
240
hrkey = HKEY_LOCAL_MACHINE;
241
else if (strcmp(rkey, "HKEY_USERS")==0)
245
if (skey == (char *)NULL)
247
gs_addmess("Opening registry key\n ");
252
if (RegCreateKeyEx(hrkey, skey, 0, "", 0, KEY_ALL_ACCESS,
253
NULL, &hkey, &dwResult)
256
strcpy(keyname, skey);
258
else if (szLine[0] == '@') {
260
RegDeleteValue(hkey, NULL);
261
gs_addmess("Deleting registry default value\n");
263
else if (szLine[0] == '\042') {
265
name = strtok(szLine+1, "\042\r\n");
266
RegDeleteValue(hkey, name);
267
gs_addmess("Deleting registry named value\n ");
273
// Find out if key has subkeys or values
274
TCHAR szClass[MAXSTR];
280
DWORD cchMaxValueName;
281
DWORD cbMaxValueData;
282
DWORD cbSecurityDescriptor;
283
FILETIME ftLastWriteTime;
284
cchClass = sizeof(szClass) / sizeof(TCHAR);
287
RegQueryInfoKey(hkey, szClass, &cchClass, NULL,
288
&cSubKeys, &cchMaxSubKey, &cchMaxClass,
289
&cValues, &cchMaxValueName, &cbMaxValueData,
290
&cbSecurityDescriptor, &ftLastWriteTime);
293
if (hkey != HKEY_CLASSES_ROOT)
296
if ((cSubKeys != 0) || (cValues != 0)) {
297
gs_addmess("Not deleting non empty registry key\n ");
301
else if (strlen(keyname)) {
302
gs_addmess("Deleting registry key\n ");
305
RegOpenKeyEx(hrkey, NULL, 0, 0, &hkey);
306
RegDeleteKey(hkey, keyname);
319
// so we can remove keys in reverse order
321
while (GetLine() && !IsSection()) {
323
if (szLine[0] == '[') {
324
if ((key = (KEY *)malloc(sizeof(KEY)))
326
key->previous = last_key;
327
key->index = logindex;
331
logindex = ftell(fLog);
335
for (key = last_key; key != NULL; key = key->previous) {
338
fseek(fLog, key->index, SEEK_SET);
339
registry_delete_key();
344
fseek(fLog, logindex, SEEK_SET);
352
registry_unquote(char *line)
389
HKEY hkey = HKEY_CLASSES_ROOT;
396
if (strncmp(szLine, "REGEDIT4", 8) != 0)
402
if ((szLine[0] == '\0') || (szLine[0] == '\r') || (szLine[0] == '\n'))
404
if (szLine[0] == '[') {
406
if (hkey != HKEY_CLASSES_ROOT) {
408
hkey = HKEY_CLASSES_ROOT;
410
rkey = strtok(szLine+1, "\\]\n\r");
411
if (rkey == (char *)NULL)
413
skey = strtok(NULL, "]\n\r");
414
if (strcmp(rkey, "HKEY_CLASSES_ROOT")==0)
415
hrkey = HKEY_CLASSES_ROOT;
416
else if (strcmp(rkey, "HKEY_CURRENT_USER")==0)
417
hrkey = HKEY_CURRENT_USER;
418
else if (strcmp(rkey, "HKEY_LOCAL_MACHINE")==0)
419
hrkey = HKEY_LOCAL_MACHINE;
420
else if (strcmp(rkey, "HKEY_USERS")==0)
424
if (skey == (char *)NULL)
426
gs_addmess("Creating registry key\n ");
431
if (RegCreateKeyEx(hrkey, skey, 0, "", 0, KEY_ALL_ACCESS,
432
NULL, &hkey, &dwResult)
436
else if (szLine[0] == '@') {
438
if (strlen(szLine) < 4)
440
value = strtok(szLine+3, "\042\r\n");
442
registry_unquote(value);
443
gs_addmess("Setting registry key value\n ");
446
if (RegSetValueEx(hkey, NULL, 0, REG_SZ,
447
(CONST BYTE *)value, strlen(value)+1)
452
else if (szLine[0] == '\042') {
454
name = strtok(szLine+1, "\042\r\n");
455
strtok(NULL, "\042\r\n");
456
value = strtok(NULL, "\042\r\n");
457
registry_unquote(value);
458
gs_addmess("Setting registry key value\n ");
463
if (RegSetValueEx(hkey, name, 0, REG_SZ, (CONST BYTE *)value,
464
strlen(value)+1) != ERROR_SUCCESS)
468
if (hkey != HKEY_CLASSES_ROOT)
474
// requires a full path to be specified, so ignores root \
475
// apart from root \, must not contain trailing \
477
// c:\ (OK, but useless)
479
// c:\gstools\ (incorrect)
480
// c:gstools (incorrect)
481
// gstools (incorrect)
482
// The following UNC names should work,
483
// but didn't under Win3.1 because gs_chdir wouldn't accept UNC names
484
// Needs to be tested under Windows 95.
485
// \\server\sharename\gstools (OK)
486
// \\server\sharename\ (OK, but useless)
489
BOOL MakeDir(char *dirname)
493
if (strlen(dirname) < 3)
496
gs_addmess("Making Directory\n ");
499
if (isalpha(dirname[0]) && dirname[1]==':' && dirname[2]=='\\') {
503
else if (dirname[1]=='\\' && dirname[1]=='\\') {
505
p = strchr(dirname+2, '\\'); // skip servername
509
p = strchr(p, '\\'); // skip sharename
514
// not full path so error
519
strncpy(newdir, dirname, (int)(p-dirname));
520
newdir[(int)(p-dirname)] = '\0';
526
if (p >= dirname + strlen(dirname))
530
p = dirname + strlen(dirname);
533
return SetCurrentDirectory(dirname);
542
// remove shell items added by Ghostscript
543
// We can only delete one group with this code
547
if (strlen(group) != 0) {
548
gs_addmess("Removing shell folder\n ");
551
RemoveDirectory(group);
555
p = strtok(szLine, "=");
556
q = strtok(NULL, "");
560
else if (strcmp(p, "Group")==0) {
562
strncpy(group, q, sizeof(group)-1);
563
// defer this until we have remove contents
565
else if (strcmp(p, "Name") == 0) {
567
gs_addmess("Removing shell link\n ");
579
BOOL CreateShellLink(LPCSTR name, LPCSTR description, LPCSTR program,
580
LPCSTR arguments, LPCSTR directory, LPCSTR icon, int nIconIndex)
585
// Ensure string is UNICODE.
587
MultiByteToWideChar(CP_ACP, 0, name, -1, wsz, MAX_PATH);
589
// Save new shell link
591
// Get a pointer to the IShellLink interface.
592
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
593
IID_IShellLink, (void **)&psl);
594
if (SUCCEEDED(hres)) {
596
// Query IShellLink for the IPersistFile interface for
597
// saving the shell link in persistent storage.
598
hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
599
if (SUCCEEDED(hres)) {
600
gs_addmess("Adding shell link\n ");
604
// Set the path to the shell link target.
605
hres = psl->SetPath(program);
606
if (!SUCCEEDED(hres)) {
607
gs_addmess("SetPath failed!");
610
// Set the description of the shell link.
611
hres = psl->SetDescription(description);
612
if (!SUCCEEDED(hres)) {
613
gs_addmess("SetDescription failed!");
616
if ((arguments != (LPCSTR)NULL) && *arguments) {
617
// Set the arguments of the shell link target.
618
hres = psl->SetArguments(arguments);
619
if (!SUCCEEDED(hres)) {
620
gs_addmess("SetArguments failed!");
624
if ((directory != (LPCSTR)NULL) && *directory) {
625
// Set the arguments of the shell link target.
626
hres = psl->SetWorkingDirectory(directory);
627
if (!SUCCEEDED(hres)) {
628
gs_addmess("SetWorkingDirectory failed!");
632
if ((icon != (LPCSTR)NULL) && *icon) {
633
// Set the arguments of the shell link target.
634
hres = psl->SetIconLocation(icon, nIconIndex);
635
if (!SUCCEEDED(hres)) {
636
gs_addmess("SetIconLocation failed!");
641
// Save the link via the IPersistFile::Save method.
642
hres = ppf->Save(wsz, TRUE);
643
// Release pointer to IPersistFile.
646
// Release pointer to IShellLink.
657
// Add shell items removed by Ghostscript
660
char description[MAXSTR];
661
char program[MAXSTR];
662
char arguments[MAXSTR];
663
char directory[MAXSTR];
666
// Remove shell items added by Ghostscript
667
name[0] = description[0] = program[0] = arguments[0]
668
= directory[0] = icon[0] = '\0';
674
p = strtok(szLine, "=");
675
q = strtok(NULL, "");
676
if (strlen(szLine) == 0) {
677
if (name[0] != '\0') {
678
// add start menu item
679
CreateShellLink(name, description, program, arguments,
680
directory, icon, nIconIndex);
682
name[0] = description[0] = program[0] = arguments[0]
683
= directory[0] = icon[0] = '\0';
687
else if (p == (char *)NULL) {
690
else if (strcmp(p, "Group")==0) {
693
else if (strcmp(p, "Name") == 0)
694
strncpy(name, q, sizeof(name)-1);
695
else if (strcmp(p, "Description") == 0)
696
strncpy(description, q, sizeof(description)-1);
697
else if (strcmp(p, "Program") == 0)
698
strncpy(program, q, sizeof(program)-1);
699
else if (strcmp(p, "Arguments") == 0)
700
strncpy(arguments, q, sizeof(arguments)-1);
701
else if (strcmp(p, "Directory") == 0)
702
strncpy(directory, q, sizeof(directory)-1);
703
else if (strcmp(p, "IconLocation") == 0)
704
strncpy(icon, q, sizeof(icon)-1);
705
else if (strcmp(p, "IconIndex") == 0)
706
nIconIndex = atoi(q);
717
DLGRETURN CALLBACK _export
718
RemoveDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
722
SetWindowText(hwnd, szTitle);
724
PostMessage(hwnd, WM_COMMAND, IDOK, 0);
727
switch(LOWORD(wParam)) {
729
// delete registry entries for uninstall
732
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
733
UNINSTALLKEY, 0, KEY_ALL_ACCESS, &hkey)
735
RegDeleteKey(hkey, szTitle);
740
SetWindowText(hText1, "Uninstall successful");
741
SetWindowText(hText2, "");
742
EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
743
EnableWindow(GetDlgItem(hwnd, IDCANCEL), TRUE);
744
SetDlgItemText(hwnd, IDCANCEL, "Exit");
745
SetFocus(GetDlgItem(hwnd, IDCANCEL));
747
PostMessage(hwnd, WM_COMMAND, IDCANCEL, 0);
751
EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
752
EnableWindow(GetDlgItem(hwnd, IDC_PRESSOK), FALSE);
755
if (!ReadSection()) {
756
SetWindowText(hText1, "Uninstall FAILED");
757
SetWindowText(hText2, "");
758
EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
759
EnableWindow(GetDlgItem(hwnd, IDCANCEL), TRUE);
760
SetDlgItemText(hwnd, IDCANCEL, "Exit");
761
SetFocus(GetDlgItem(hwnd, IDCANCEL));
784
while (hDlgModeless && PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE)) {
785
if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
786
TranslateMessage(&msg);
787
DispatchMessage(&msg);
797
DWORD version = GetVersion();
800
BOOL inquote = FALSE;
801
// get location of uninstall log from command line as argv[1]
802
p = GetCommandLine();
805
// skip over program name
807
while (*s && *s!='\042')
812
else if (*s != ' ') {
813
// skip over program name
815
while (*s && *s!=' ')
820
while (*s && *s==' ')
828
while (*s && (*s != '\042'))
832
while (*s && (*s != ' '))
836
strncpy(szLogFile, p, min(len, (int)sizeof(szLogFile)-1));
837
szLogFile[len] = '\0';
838
if (inquote && (*s == '\042')) {
843
if (strlen(szLogFile) == 0) {
844
message_box("Usage: uninstgs logfile.txt [-q]",
845
"GPL Ghostscript Uninstall", MB_OK);
849
while (*s && *s==' ')
851
if (strncmp(s, "-q", 2) == 0)
854
// read first few lines of file to get title
855
fLog = fopen(szLogFile, "r");
856
if (fLog == (FILE *)NULL) {
857
message_box(szLogFile, "Can't find file", MB_OK);
862
message_box(szLogFile, "Not valid uninstall log", MB_OK);
866
if (strcmp(szLine, "UninstallName") != 0) {
867
message_box(szLogFile, "Not valid uninstall log", MB_OK);
871
strcpy(szTitle, szLine);
875
if (LOBYTE(LOWORD(version)) >= 4)
884
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
888
phInstance = hInstance;
895
hDlgModeless = CreateDialogParam(hInstance,
896
MAKEINTRESOURCE(IDD_UNSET),
897
HWND_DESKTOP, RemoveDlgProc, (LPARAM)NULL);
898
hText1 = GetDlgItem(hDlgModeless, IDC_T1);
899
hText2 = GetDlgItem(hDlgModeless, IDC_T2);
901
SetWindowPos(hDlgModeless, HWND_TOP, 0, 0, 0, 0,
902
(bSilent ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) | SWP_NOMOVE | SWP_NOSIZE);
904
while (hDlgModeless && GetMessage(&msg, (HWND)NULL, 0, 0)) {
905
if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
906
TranslateMessage(&msg);
907
DispatchMessage(&msg);