blob: 99cdc679cc08ba97be84b7a7ceb8a3ab00edb3ac [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * uninstal.c: Minimalistic uninstall program for Vim on MS-Windows
12 * Removes:
13 * - the "Edit with Vim" popup menu entry
14 * - the Vim "Open With..." popup menu entry
15 * - any Vim Batch files in the path
16 * - icons for Vim on the Desktop
17 * - the Vim entry in the Start Menu
18 */
19
20/* Include common code for dosinst.c and uninstal.c. */
21#include "dosinst.h"
22
23/*
24 * Return TRUE if the user types a 'y' or 'Y', FALSE otherwise.
25 */
26 static int
27confirm(void)
28{
29 char answer[10];
30
31 fflush(stdout);
32 return (scanf(" %c", answer) == 1 && toupper(answer[0]) == 'Y');
33}
34
35#ifdef WIN3264
Bram Moolenaarbf650512010-08-02 23:06:46 +020036
37 static int
38reg_delete_key(HKEY hRootKey, const char *key)
39{
40 static int did_load = FALSE;
41 static HANDLE advapi_lib = NULL;
42 static LONG (WINAPI *delete_key_ex)(HKEY, LPCTSTR, REGSAM, DWORD) = NULL;
43
44 if (!did_load)
45 {
46 /* The RegDeleteKeyEx() function is only available on new systems. It
47 * is required for 64-bit registry access. For other systems fall
48 * back to RegDeleteKey(). */
49 did_load = TRUE;
50 advapi_lib = LoadLibrary("ADVAPI32.DLL");
51 if (advapi_lib != NULL)
52 delete_key_ex = (LONG (WINAPI *)(HKEY, LPCTSTR, REGSAM, DWORD))GetProcAddress(advapi_lib, "RegDeleteKeyExA");
53 }
54 if (delete_key_ex != NULL) {
55 return (*delete_key_ex)(hRootKey, key, KEY_WOW64_64KEY, 0);
56 }
57 return RegDeleteKey(hRootKey, key);
58}
59
Bram Moolenaar071d4272004-06-13 20:20:40 +000060/*
61 * Check if the popup menu entry exists and what gvim it refers to.
62 * Returns non-zero when it's found.
63 */
64 static int
65popup_gvim_path(char *buf)
66{
67 HKEY key_handle;
68 DWORD value_type;
69 DWORD bufsize = BUFSIZE;
70 int r;
71
72 /* Open the key where the path to gvim.exe is stored. */
Bram Moolenaar760d14a2010-07-31 22:03:44 +020073 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
74 KEY_WOW64_64KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +000075 return 0;
76
77 /* get the DisplayName out of it to show the user */
78 r = RegQueryValueEx(key_handle, "path", 0,
79 &value_type, (LPBYTE)buf, &bufsize);
80 RegCloseKey(key_handle);
81
82 return (r == ERROR_SUCCESS);
83}
84
85/*
86 * Check if the "Open With..." menu entry exists and what gvim it refers to.
87 * Returns non-zero when it's found.
88 */
89 static int
90openwith_gvim_path(char *buf)
91{
92 HKEY key_handle;
93 DWORD value_type;
94 DWORD bufsize = BUFSIZE;
95 int r;
96
97 /* Open the key where the path to gvim.exe is stored. */
98 if (RegOpenKeyEx(HKEY_CLASSES_ROOT,
Bram Moolenaar760d14a2010-07-31 22:03:44 +020099 "Applications\\gvim.exe\\shell\\edit\\command", 0,
100 KEY_WOW64_64KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101 return 0;
102
103 /* get the DisplayName out of it to show the user */
104 r = RegQueryValueEx(key_handle, "", 0, &value_type, (LPBYTE)buf, &bufsize);
105 RegCloseKey(key_handle);
106
107 return (r == ERROR_SUCCESS);
108}
109
110 static void
111remove_popup(void)
112{
113 int fail = 0;
114 HKEY kh;
115
Bram Moolenaarbf650512010-08-02 23:06:46 +0200116 if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\\InProcServer32") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000117 ++fail;
Bram Moolenaarbf650512010-08-02 23:06:46 +0200118 if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119 ++fail;
Bram Moolenaarbf650512010-08-02 23:06:46 +0200120 if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\shellex\\ContextMenuHandlers\\gvim") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000121 ++fail;
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200122 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 0,
123 KEY_WOW64_64KEY | KEY_ALL_ACCESS, &kh) != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000124 ++fail;
125 else
126 {
127 if (RegDeleteValue(kh, "{51EEE242-AD87-11d3-9C1E-0090278BBD99}") != ERROR_SUCCESS)
128 ++fail;
129 RegCloseKey(kh);
130 }
Bram Moolenaarbf650512010-08-02 23:06:46 +0200131 if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000132 ++fail;
Bram Moolenaarbf650512010-08-02 23:06:46 +0200133 if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134 ++fail;
135
136 if (fail == 6)
137 printf("No Vim popup registry entries could be removed\n");
138 else if (fail > 0)
139 printf("Some Vim popup registry entries could not be removed\n");
140 else
141 printf("The Vim popup registry entries have been removed\n");
142}
143
144 static void
145remove_openwith(void)
146{
147 int fail = 0;
148
Bram Moolenaarbf650512010-08-02 23:06:46 +0200149 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit\\command") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150 ++fail;
Bram Moolenaarbf650512010-08-02 23:06:46 +0200151 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152 ++fail;
Bram Moolenaarbf650512010-08-02 23:06:46 +0200153 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154 ++fail;
Bram Moolenaarbf650512010-08-02 23:06:46 +0200155 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000156 ++fail;
Bram Moolenaarbf650512010-08-02 23:06:46 +0200157 if (reg_delete_key(HKEY_CLASSES_ROOT, ".htm\\OpenWithList\\gvim.exe") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000158 ++fail;
Bram Moolenaarbf650512010-08-02 23:06:46 +0200159 if (reg_delete_key(HKEY_CLASSES_ROOT, ".vim\\OpenWithList\\gvim.exe") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160 ++fail;
Bram Moolenaarbf650512010-08-02 23:06:46 +0200161 if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\OpenWithList\\gvim.exe") != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162 ++fail;
163
164 if (fail == 7)
165 printf("No Vim open-with registry entries could be removed\n");
166 else if (fail > 0)
167 printf("Some Vim open-with registry entries could not be removed\n");
168 else
169 printf("The Vim open-with registry entries have been removed\n");
170}
171#endif
172
173/*
174 * Check if a batch file is really for the current version. Don't delete a
175 * batch file that was written for another (possibly newer) version.
176 */
177 static int
178batfile_thisversion(char *path)
179{
180 FILE *fd;
181 char line[BUFSIZE];
182 char *p;
183 int ver_len = strlen(VIM_VERSION_NODOT);
184 int found = FALSE;
185
186 fd = fopen(path, "r");
187 if (fd != NULL)
188 {
189 while (fgets(line, BUFSIZE, fd) != NULL)
190 {
191 for (p = line; *p != 0; ++p)
192 /* don't accept "vim60an" when looking for "vim60". */
193 if (strnicmp(p, VIM_VERSION_NODOT, ver_len) == 0
194 && !isdigit(p[ver_len])
195 && !isalpha(p[ver_len]))
196 {
197 found = TRUE;
198 break;
199 }
200 if (found)
201 break;
202 }
203 fclose(fd);
204 }
205 return found;
206}
207
208 static int
209remove_batfiles(int doit)
210{
211 char *batfile_path;
212 int i;
213 int found = 0;
214
215 for (i = 1; i < TARGET_COUNT; ++i)
216 {
217 batfile_path = searchpath_save(targets[i].batname);
218 if (batfile_path != NULL && batfile_thisversion(batfile_path))
219 {
220 ++found;
221 if (doit)
222 {
223 printf("removing %s\n", batfile_path);
224 remove(batfile_path);
225 }
226 else
227 printf(" - the batch file %s\n", batfile_path);
228 free(batfile_path);
229 }
230 }
231 return found;
232}
233
234#ifdef WIN3264
235 static void
236remove_if_exists(char *path, char *filename)
237{
238 char buf[BUFSIZE];
239 FILE *fd;
240
241 sprintf(buf, "%s\\%s", path, filename);
242
243 fd = fopen(buf, "r");
244 if (fd != NULL)
245 {
246 fclose(fd);
247 printf("removing %s\n", buf);
248 remove(buf);
249 }
250}
251
252 static void
253remove_icons(void)
254{
255 char path[BUFSIZE];
256 int i;
257
258 if (get_shell_folder_path(path, "desktop"))
259 for (i = 0; i < ICON_COUNT; ++i)
260 remove_if_exists(path, icon_link_names[i]);
261}
262
263 static void
264remove_start_menu(void)
265{
266 char path[BUFSIZE];
267 int i;
268 struct stat st;
269
270 if (get_shell_folder_path(path, VIM_STARTMENU))
271 {
272 for (i = 1; i < TARGET_COUNT; ++i)
273 remove_if_exists(path, targets[i].lnkname);
274 remove_if_exists(path, "uninstall.lnk");
275 remove_if_exists(path, "Help.lnk");
276 /* Win95 uses .pif, WinNT uses .lnk */
277 remove_if_exists(path, "Vim tutor.pif");
278 remove_if_exists(path, "Vim tutor.lnk");
279 remove_if_exists(path, "Vim online.url");
280 if (stat(path, &st) == 0)
281 {
282 printf("removing %s\n", path);
283 rmdir(path);
284 }
285 }
286}
287#endif
288
289#if 0 /* currently not used */
290/*
291 * Return TRUE when we're on Windows 95/98/ME.
292 */
293 static int
294win95(void)
295{
296 static int done = FALSE;
297 static DWORD PlatformId;
298
299 if (!done)
300 {
301 OSVERSIONINFO ovi;
302
303 ovi.dwOSVersionInfoSize = sizeof(ovi);
304 GetVersionEx(&ovi);
305 PlatformId = ovi.dwPlatformId;
306 done = TRUE;
307 }
308 /* Win NT/2000/XP is VER_PLATFORM_WIN32_NT */
309 return PlatformId == VER_PLATFORM_WIN32_WINDOWS;
310}
311#endif
312
313 static void
314delete_uninstall_key(void)
315{
316#ifdef WIN3264
Bram Moolenaarbf650512010-08-02 23:06:46 +0200317 reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000318#else
319 FILE *fd;
320 char buf[BUFSIZE];
321
322 /*
323 * On DJGPP we delete registry entries by creating a .inf file and
324 * installing it.
325 */
326 fd = fopen("vim.inf", "w");
327 if (fd != NULL)
328 {
329 fprintf(fd, "[version]\n");
330 fprintf(fd, "signature=\"$CHICAGO$\"\n\n");
331 fprintf(fd, "[DefaultInstall]\n");
332 fprintf(fd, "DelReg=DeleteMe\n\n");
333 fprintf(fd, "[DeleteMe]\n");
334 fprintf(fd, "HKLM,\"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT "\"\n");
335 fclose(fd);
336
337 /* Don't know how to detect Win NT with DJGPP. Hack: Just try the Win
338 * 95/98/ME method, since the DJGPP version can't use long filenames
339 * on Win NT anyway. */
340 sprintf(buf, "rundll setupx.dll,InstallHinfSection DefaultInstall 132 %s\\vim.inf", installdir);
341 run_command(buf);
342#if 0
343 /* Windows NT method (untested). */
344 sprintf(buf, "rundll32 syssetup,SetupInfObjectInstallAction DefaultInstall 128 %s\\vim.inf", installdir);
345 run_command(buf);
346#endif
347
348 remove("vim.inf");
349 }
350#endif
351}
352
353 int
354main(int argc, char *argv[])
355{
356 int found = 0;
357 FILE *fd;
358#ifdef WIN3264
359 int i;
360 struct stat st;
361 char icon[BUFSIZE];
362 char path[BUFSIZE];
363 char popup_path[BUFSIZE];
364
365 /* The nsis uninstaller calls us with a "-nsis" argument. */
366 if (argc == 2 && stricmp(argv[1], "-nsis") == 0)
367 interactive = FALSE;
368 else
369#endif
370 interactive = TRUE;
371
372 /* Initialize this program. */
373 do_inits(argv);
374
375 printf("This program will remove the following items:\n");
376
377#ifdef WIN3264
378 if (popup_gvim_path(popup_path))
379 {
380 printf(" - the \"Edit with Vim\" entry in the popup menu\n");
381 printf(" which uses \"%s\"\n", popup_path);
Bram Moolenaar442b4222010-05-24 21:34:22 +0200382 if (interactive)
383 printf("\nRemove it (y/n)? ");
384 if (!interactive || confirm())
Bram Moolenaar071d4272004-06-13 20:20:40 +0000385 {
386 remove_popup();
387 /* Assume the "Open With" entry can be removed as well, don't
388 * bother the user with asking him again. */
389 remove_openwith();
390 }
391 }
392 else if (openwith_gvim_path(popup_path))
393 {
394 printf(" - the Vim \"Open With...\" entry in the popup menu\n");
395 printf(" which uses \"%s\"\n", popup_path);
396 printf("\nRemove it (y/n)? ");
397 if (confirm())
398 remove_openwith();
399 }
400
401 if (get_shell_folder_path(path, "desktop"))
402 {
403 printf("\n");
404 for (i = 0; i < ICON_COUNT; ++i)
405 {
406 sprintf(icon, "%s\\%s", path, icon_link_names[i]);
407 if (stat(icon, &st) == 0)
408 {
409 printf(" - the \"%s\" icon on the desktop\n", icon_names[i]);
410 ++found;
411 }
412 }
413 if (found > 0)
414 {
415 if (interactive)
416 printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
417 if (!interactive || confirm())
418 remove_icons();
419 }
420 }
421
422 if (get_shell_folder_path(path, VIM_STARTMENU)
423 && stat(path, &st) == 0)
424 {
425 printf("\n - the \"%s\" entry in the Start Menu\n", VIM_STARTMENU);
426 if (interactive)
427 printf("\nRemove it (y/n)? ");
428 if (!interactive || confirm())
429 remove_start_menu();
430 }
431#endif
432
433 printf("\n");
434 found = remove_batfiles(0);
435 if (found > 0)
436 {
437 if (interactive)
438 printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
439 if (!interactive || confirm())
440 remove_batfiles(1);
441 }
442
443 fd = fopen("gvim.exe", "r");
444 if (fd != NULL)
445 {
446 fclose(fd);
447 printf("gvim.exe detected. Attempting to unregister gvim with OLE\n");
448 system("gvim.exe -silent -unregister");
449 }
450
451 delete_uninstall_key();
452
453 if (interactive)
454 {
455 printf("\nYou may now want to delete the Vim executables and runtime files.\n");
456 printf("(They are still where you unpacked them.)\n");
457 }
458
Bram Moolenaar442b4222010-05-24 21:34:22 +0200459 if (interactive)
460 {
461 rewind(stdin);
462 printf("\nPress Enter to exit...");
463 (void)getchar();
464 }
465 else
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200466 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000467
468 return 0;
469}