blob: 11b6c629ad195029840382cb60e7af76c7351916 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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
Bram Moolenaarbf650512010-08-02 23:06:46 +020035 static int
Bram Moolenaar6199d432017-10-14 19:05:44 +020036reg_delete_key(HKEY hRootKey, const char *key, DWORD flag)
Bram Moolenaarbf650512010-08-02 23:06:46 +020037{
38 static int did_load = FALSE;
39 static HANDLE advapi_lib = NULL;
40 static LONG (WINAPI *delete_key_ex)(HKEY, LPCTSTR, REGSAM, DWORD) = NULL;
41
42 if (!did_load)
43 {
44 /* The RegDeleteKeyEx() function is only available on new systems. It
45 * is required for 64-bit registry access. For other systems fall
46 * back to RegDeleteKey(). */
47 did_load = TRUE;
48 advapi_lib = LoadLibrary("ADVAPI32.DLL");
49 if (advapi_lib != NULL)
50 delete_key_ex = (LONG (WINAPI *)(HKEY, LPCTSTR, REGSAM, DWORD))GetProcAddress(advapi_lib, "RegDeleteKeyExA");
51 }
52 if (delete_key_ex != NULL) {
Bram Moolenaar6199d432017-10-14 19:05:44 +020053 return (*delete_key_ex)(hRootKey, key, flag, 0);
Bram Moolenaarbf650512010-08-02 23:06:46 +020054 }
55 return RegDeleteKey(hRootKey, key);
56}
57
Bram Moolenaar071d4272004-06-13 20:20:40 +000058/*
59 * Check if the popup menu entry exists and what gvim it refers to.
60 * Returns non-zero when it's found.
61 */
62 static int
63popup_gvim_path(char *buf)
64{
65 HKEY key_handle;
66 DWORD value_type;
67 DWORD bufsize = BUFSIZE;
68 int r;
69
70 /* Open the key where the path to gvim.exe is stored. */
Bram Moolenaar760d14a2010-07-31 22:03:44 +020071 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
72 KEY_WOW64_64KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
Bram Moolenaar6199d432017-10-14 19:05:44 +020073 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
74 KEY_WOW64_32KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
75 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000076
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;
Bram Moolenaar6199d432017-10-14 19:05:44 +0200114 int i;
115 int loop = is_64bit_os() ? 2 : 1;
116 int maxfail = loop * 6;
117 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000118 HKEY kh;
119
Bram Moolenaar6199d432017-10-14 19:05:44 +0200120 for (i = 0; i < loop; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000121 {
Bram Moolenaar6199d432017-10-14 19:05:44 +0200122 if (i == 0)
123 flag = KEY_WOW64_32KEY;
124 else
125 flag = KEY_WOW64_64KEY;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000126
Bram Moolenaar6199d432017-10-14 19:05:44 +0200127 if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\\InProcServer32", flag) != ERROR_SUCCESS)
128 ++fail;
129 if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}", flag) != ERROR_SUCCESS)
130 ++fail;
131 if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\shellex\\ContextMenuHandlers\\gvim", flag) != ERROR_SUCCESS)
132 ++fail;
133 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 0,
134 flag | KEY_ALL_ACCESS, &kh) != ERROR_SUCCESS)
135 ++fail;
136 else
137 {
138 if (RegDeleteValue(kh, "{51EEE242-AD87-11d3-9C1E-0090278BBD99}") != ERROR_SUCCESS)
139 ++fail;
140 RegCloseKey(kh);
141 }
142 if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", flag) != ERROR_SUCCESS)
143 ++fail;
144 if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim", flag) != ERROR_SUCCESS)
145 ++fail;
146 }
147
148 if (fail == maxfail)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149 printf("No Vim popup registry entries could be removed\n");
150 else if (fail > 0)
151 printf("Some Vim popup registry entries could not be removed\n");
152 else
153 printf("The Vim popup registry entries have been removed\n");
154}
155
156 static void
157remove_openwith(void)
158{
159 int fail = 0;
Bram Moolenaar6199d432017-10-14 19:05:44 +0200160 int i;
161 int loop = is_64bit_os() ? 2 : 1;
162 int maxfail = loop * 7;
163 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164
Bram Moolenaar6199d432017-10-14 19:05:44 +0200165 for (i = 0; i < loop; i++)
166 {
167 if (i == 0)
168 flag = KEY_WOW64_32KEY;
169 else
170 flag = KEY_WOW64_64KEY;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171
Bram Moolenaar6199d432017-10-14 19:05:44 +0200172 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit\\command", flag) != ERROR_SUCCESS)
173 ++fail;
174 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit", flag) != ERROR_SUCCESS)
175 ++fail;
176 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell", flag) != ERROR_SUCCESS)
177 ++fail;
178 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe", flag) != ERROR_SUCCESS)
179 ++fail;
180 if (reg_delete_key(HKEY_CLASSES_ROOT, ".htm\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
181 ++fail;
182 if (reg_delete_key(HKEY_CLASSES_ROOT, ".vim\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
183 ++fail;
184 if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
185 ++fail;
186 }
187
188 if (fail == maxfail)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000189 printf("No Vim open-with registry entries could be removed\n");
190 else if (fail > 0)
191 printf("Some Vim open-with registry entries could not be removed\n");
192 else
193 printf("The Vim open-with registry entries have been removed\n");
194}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000195
196/*
197 * Check if a batch file is really for the current version. Don't delete a
198 * batch file that was written for another (possibly newer) version.
199 */
200 static int
201batfile_thisversion(char *path)
202{
203 FILE *fd;
204 char line[BUFSIZE];
205 char *p;
206 int ver_len = strlen(VIM_VERSION_NODOT);
207 int found = FALSE;
208
209 fd = fopen(path, "r");
210 if (fd != NULL)
211 {
212 while (fgets(line, BUFSIZE, fd) != NULL)
213 {
214 for (p = line; *p != 0; ++p)
215 /* don't accept "vim60an" when looking for "vim60". */
216 if (strnicmp(p, VIM_VERSION_NODOT, ver_len) == 0
217 && !isdigit(p[ver_len])
218 && !isalpha(p[ver_len]))
219 {
220 found = TRUE;
221 break;
222 }
223 if (found)
224 break;
225 }
226 fclose(fd);
227 }
228 return found;
229}
230
231 static int
232remove_batfiles(int doit)
233{
234 char *batfile_path;
235 int i;
236 int found = 0;
237
238 for (i = 1; i < TARGET_COUNT; ++i)
239 {
240 batfile_path = searchpath_save(targets[i].batname);
241 if (batfile_path != NULL && batfile_thisversion(batfile_path))
242 {
243 ++found;
244 if (doit)
245 {
246 printf("removing %s\n", batfile_path);
247 remove(batfile_path);
248 }
249 else
250 printf(" - the batch file %s\n", batfile_path);
251 free(batfile_path);
252 }
253 }
254 return found;
255}
256
Bram Moolenaar071d4272004-06-13 20:20:40 +0000257 static void
258remove_if_exists(char *path, char *filename)
259{
260 char buf[BUFSIZE];
261 FILE *fd;
262
263 sprintf(buf, "%s\\%s", path, filename);
264
265 fd = fopen(buf, "r");
266 if (fd != NULL)
267 {
268 fclose(fd);
269 printf("removing %s\n", buf);
270 remove(buf);
271 }
272}
273
274 static void
275remove_icons(void)
276{
277 char path[BUFSIZE];
278 int i;
279
280 if (get_shell_folder_path(path, "desktop"))
281 for (i = 0; i < ICON_COUNT; ++i)
282 remove_if_exists(path, icon_link_names[i]);
283}
284
285 static void
286remove_start_menu(void)
287{
288 char path[BUFSIZE];
289 int i;
290 struct stat st;
291
292 if (get_shell_folder_path(path, VIM_STARTMENU))
293 {
294 for (i = 1; i < TARGET_COUNT; ++i)
295 remove_if_exists(path, targets[i].lnkname);
296 remove_if_exists(path, "uninstall.lnk");
297 remove_if_exists(path, "Help.lnk");
298 /* Win95 uses .pif, WinNT uses .lnk */
299 remove_if_exists(path, "Vim tutor.pif");
300 remove_if_exists(path, "Vim tutor.lnk");
301 remove_if_exists(path, "Vim online.url");
302 if (stat(path, &st) == 0)
303 {
304 printf("removing %s\n", path);
305 rmdir(path);
306 }
307 }
308}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000309
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 static void
311delete_uninstall_key(void)
312{
Bram Moolenaar6199d432017-10-14 19:05:44 +0200313 reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT, KEY_WOW64_64KEY);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000314}
315
316 int
317main(int argc, char *argv[])
318{
319 int found = 0;
320 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000321 int i;
322 struct stat st;
323 char icon[BUFSIZE];
324 char path[BUFSIZE];
325 char popup_path[BUFSIZE];
326
327 /* The nsis uninstaller calls us with a "-nsis" argument. */
328 if (argc == 2 && stricmp(argv[1], "-nsis") == 0)
329 interactive = FALSE;
330 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000331 interactive = TRUE;
332
333 /* Initialize this program. */
334 do_inits(argv);
335
336 printf("This program will remove the following items:\n");
337
Bram Moolenaar071d4272004-06-13 20:20:40 +0000338 if (popup_gvim_path(popup_path))
339 {
340 printf(" - the \"Edit with Vim\" entry in the popup menu\n");
341 printf(" which uses \"%s\"\n", popup_path);
Bram Moolenaar442b4222010-05-24 21:34:22 +0200342 if (interactive)
343 printf("\nRemove it (y/n)? ");
344 if (!interactive || confirm())
Bram Moolenaar071d4272004-06-13 20:20:40 +0000345 {
346 remove_popup();
347 /* Assume the "Open With" entry can be removed as well, don't
348 * bother the user with asking him again. */
349 remove_openwith();
350 }
351 }
352 else if (openwith_gvim_path(popup_path))
353 {
354 printf(" - the Vim \"Open With...\" entry in the popup menu\n");
355 printf(" which uses \"%s\"\n", popup_path);
356 printf("\nRemove it (y/n)? ");
357 if (confirm())
358 remove_openwith();
359 }
360
361 if (get_shell_folder_path(path, "desktop"))
362 {
363 printf("\n");
364 for (i = 0; i < ICON_COUNT; ++i)
365 {
366 sprintf(icon, "%s\\%s", path, icon_link_names[i]);
367 if (stat(icon, &st) == 0)
368 {
369 printf(" - the \"%s\" icon on the desktop\n", icon_names[i]);
370 ++found;
371 }
372 }
373 if (found > 0)
374 {
375 if (interactive)
376 printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
377 if (!interactive || confirm())
378 remove_icons();
379 }
380 }
381
382 if (get_shell_folder_path(path, VIM_STARTMENU)
383 && stat(path, &st) == 0)
384 {
385 printf("\n - the \"%s\" entry in the Start Menu\n", VIM_STARTMENU);
386 if (interactive)
387 printf("\nRemove it (y/n)? ");
388 if (!interactive || confirm())
389 remove_start_menu();
390 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000391
392 printf("\n");
393 found = remove_batfiles(0);
394 if (found > 0)
395 {
396 if (interactive)
397 printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
398 if (!interactive || confirm())
399 remove_batfiles(1);
400 }
401
402 fd = fopen("gvim.exe", "r");
403 if (fd != NULL)
404 {
405 fclose(fd);
406 printf("gvim.exe detected. Attempting to unregister gvim with OLE\n");
407 system("gvim.exe -silent -unregister");
408 }
409
410 delete_uninstall_key();
411
412 if (interactive)
413 {
414 printf("\nYou may now want to delete the Vim executables and runtime files.\n");
415 printf("(They are still where you unpacked them.)\n");
416 }
417
Bram Moolenaar442b4222010-05-24 21:34:22 +0200418 if (interactive)
419 {
420 rewind(stdin);
421 printf("\nPress Enter to exit...");
422 (void)getchar();
423 }
424 else
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200425 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000426
427 return 0;
428}