blob: 907ed3797644a3df1704eb0924c5fa22bd7614d7 [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/*
Bram Moolenaar30e8e732019-09-27 13:08:36 +020011 * uninstall.c: Minimalistic uninstall program for Vim on MS-Windows
Bram Moolenaar071d4272004-06-13 20:20:40 +000012 * 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
Bram Moolenaare38eab22019-12-05 21:50:01 +010020// Include common code for dosinst.c and uninstall.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +000021#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);
Keith Thompson184f71c2024-01-04 21:19:04 +010032 return (scanf(" %c", answer) == 1 && toupper((unsigned char)answer[0]) == 'Y');
Bram Moolenaar071d4272004-06-13 20:20:40 +000033}
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 {
Bram Moolenaare38eab22019-12-05 21:50:01 +010044 // 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().
Bram Moolenaarbf650512010-08-02 23:06:46 +020047 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 }
Bram Moolenaarebfec1c2023-01-22 21:14:53 +000052 if (delete_key_ex != NULL)
53 {
Bram Moolenaar6199d432017-10-14 19:05:44 +020054 return (*delete_key_ex)(hRootKey, key, flag, 0);
Bram Moolenaarbf650512010-08-02 23:06:46 +020055 }
56 return RegDeleteKey(hRootKey, key);
57}
58
Bram Moolenaar071d4272004-06-13 20:20:40 +000059/*
60 * Check if the popup menu entry exists and what gvim it refers to.
61 * Returns non-zero when it's found.
62 */
63 static int
Bram Moolenaare4963c52019-02-22 19:41:08 +010064popup_gvim_path(char *buf, DWORD bufsize)
Bram Moolenaar071d4272004-06-13 20:20:40 +000065{
66 HKEY key_handle;
67 DWORD value_type;
Bram Moolenaar071d4272004-06-13 20:20:40 +000068 int r;
69
Bram Moolenaare38eab22019-12-05 21:50:01 +010070 // 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
Bram Moolenaare38eab22019-12-05 21:50:01 +010077 // get the DisplayName out of it to show the user
Bram Moolenaar071d4272004-06-13 20:20:40 +000078 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
Bram Moolenaare4963c52019-02-22 19:41:08 +010090openwith_gvim_path(char *buf, DWORD bufsize)
Bram Moolenaar071d4272004-06-13 20:20:40 +000091{
92 HKEY key_handle;
93 DWORD value_type;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 int r;
95
Bram Moolenaare38eab22019-12-05 21:50:01 +010096 // Open the key where the path to gvim.exe is stored.
Bram Moolenaar071d4272004-06-13 20:20:40 +000097 if (RegOpenKeyEx(HKEY_CLASSES_ROOT,
Bram Moolenaar760d14a2010-07-31 22:03:44 +020098 "Applications\\gvim.exe\\shell\\edit\\command", 0,
99 KEY_WOW64_64KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000100 return 0;
101
Bram Moolenaare38eab22019-12-05 21:50:01 +0100102 // get the DisplayName out of it to show the user
Bram Moolenaar071d4272004-06-13 20:20:40 +0000103 r = RegQueryValueEx(key_handle, "", 0, &value_type, (LPBYTE)buf, &bufsize);
104 RegCloseKey(key_handle);
105
106 return (r == ERROR_SUCCESS);
107}
108
109 static void
110remove_popup(void)
111{
112 int fail = 0;
Bram Moolenaar6199d432017-10-14 19:05:44 +0200113 int i;
114 int loop = is_64bit_os() ? 2 : 1;
115 int maxfail = loop * 6;
116 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000117 HKEY kh;
118
Bram Moolenaar6199d432017-10-14 19:05:44 +0200119 for (i = 0; i < loop; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000120 {
Bram Moolenaar6199d432017-10-14 19:05:44 +0200121 if (i == 0)
122 flag = KEY_WOW64_32KEY;
123 else
124 flag = KEY_WOW64_64KEY;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125
Bram Moolenaar6199d432017-10-14 19:05:44 +0200126 if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\\InProcServer32", flag) != ERROR_SUCCESS)
127 ++fail;
128 if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}", flag) != ERROR_SUCCESS)
129 ++fail;
130 if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\shellex\\ContextMenuHandlers\\gvim", flag) != ERROR_SUCCESS)
131 ++fail;
132 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 0,
133 flag | KEY_ALL_ACCESS, &kh) != ERROR_SUCCESS)
134 ++fail;
135 else
136 {
137 if (RegDeleteValue(kh, "{51EEE242-AD87-11d3-9C1E-0090278BBD99}") != ERROR_SUCCESS)
138 ++fail;
139 RegCloseKey(kh);
140 }
141 if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", flag) != ERROR_SUCCESS)
142 ++fail;
143 if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim", flag) != ERROR_SUCCESS)
144 ++fail;
145 }
146
147 if (fail == maxfail)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148 printf("No Vim popup registry entries could be removed\n");
149 else if (fail > 0)
150 printf("Some Vim popup registry entries could not be removed\n");
151 else
152 printf("The Vim popup registry entries have been removed\n");
153}
154
155 static void
156remove_openwith(void)
157{
158 int fail = 0;
Bram Moolenaar6199d432017-10-14 19:05:44 +0200159 int i;
160 int loop = is_64bit_os() ? 2 : 1;
161 int maxfail = loop * 7;
162 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163
Bram Moolenaar6199d432017-10-14 19:05:44 +0200164 for (i = 0; i < loop; i++)
165 {
166 if (i == 0)
167 flag = KEY_WOW64_32KEY;
168 else
169 flag = KEY_WOW64_64KEY;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
Bram Moolenaar6199d432017-10-14 19:05:44 +0200171 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit\\command", flag) != ERROR_SUCCESS)
172 ++fail;
173 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit", flag) != ERROR_SUCCESS)
174 ++fail;
175 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell", flag) != ERROR_SUCCESS)
176 ++fail;
177 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe", flag) != ERROR_SUCCESS)
178 ++fail;
179 if (reg_delete_key(HKEY_CLASSES_ROOT, ".htm\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
180 ++fail;
181 if (reg_delete_key(HKEY_CLASSES_ROOT, ".vim\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
182 ++fail;
183 if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
184 ++fail;
185 }
186
187 if (fail == maxfail)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000188 printf("No Vim open-with registry entries could be removed\n");
189 else if (fail > 0)
190 printf("Some Vim open-with registry entries could not be removed\n");
191 else
192 printf("The Vim open-with registry entries have been removed\n");
193}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194
195/*
196 * Check if a batch file is really for the current version. Don't delete a
197 * batch file that was written for another (possibly newer) version.
198 */
199 static int
200batfile_thisversion(char *path)
201{
202 FILE *fd;
203 char line[BUFSIZE];
Bram Moolenaar1fa8d2c2020-02-17 22:53:14 +0100204 int key_len = strlen(VIMBAT_UNINSTKEY);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000205 int found = FALSE;
206
207 fd = fopen(path, "r");
Yegappan Lakshmanan142ed772023-01-26 12:00:00 +0000208 if (fd == NULL)
209 return FALSE;
210
211 while (fgets(line, sizeof(line), fd) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000212 {
Yegappan Lakshmanan142ed772023-01-26 12:00:00 +0000213 if (strncmp(line, VIMBAT_UNINSTKEY, key_len) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000214 {
Yegappan Lakshmanan142ed772023-01-26 12:00:00 +0000215 found = TRUE;
216 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218 }
Yegappan Lakshmanan142ed772023-01-26 12:00:00 +0000219 fclose(fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 return found;
221}
222
223 static int
224remove_batfiles(int doit)
225{
226 char *batfile_path;
227 int i;
228 int found = 0;
229
Bram Moolenaar57ea2922020-02-09 14:27:20 +0100230 // avoid looking in the "installdir" by chdir to system root
231 mch_chdir(sysdrive);
232 mch_chdir("\\");
233
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234 for (i = 1; i < TARGET_COUNT; ++i)
235 {
236 batfile_path = searchpath_save(targets[i].batname);
237 if (batfile_path != NULL && batfile_thisversion(batfile_path))
238 {
239 ++found;
240 if (doit)
241 {
242 printf("removing %s\n", batfile_path);
243 remove(batfile_path);
244 }
245 else
246 printf(" - the batch file %s\n", batfile_path);
247 free(batfile_path);
248 }
249 }
Bram Moolenaar57ea2922020-02-09 14:27:20 +0100250
251 mch_chdir(installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000252 return found;
253}
254
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255 static void
256remove_if_exists(char *path, char *filename)
257{
258 char buf[BUFSIZE];
259 FILE *fd;
260
261 sprintf(buf, "%s\\%s", path, filename);
262
263 fd = fopen(buf, "r");
Yegappan Lakshmanan142ed772023-01-26 12:00:00 +0000264 if (fd == NULL)
265 return;
266
267 fclose(fd);
268 printf("removing %s\n", buf);
269 remove(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000270}
271
272 static void
273remove_icons(void)
274{
275 char path[BUFSIZE];
276 int i;
277
278 if (get_shell_folder_path(path, "desktop"))
279 for (i = 0; i < ICON_COUNT; ++i)
280 remove_if_exists(path, icon_link_names[i]);
281}
282
283 static void
284remove_start_menu(void)
285{
286 char path[BUFSIZE];
287 int i;
288 struct stat st;
289
Yegappan Lakshmanan142ed772023-01-26 12:00:00 +0000290 if (get_shell_folder_path(path, VIM_STARTMENU) == FAIL)
291 return;
292
293 for (i = 1; i < TARGET_COUNT; ++i)
294 remove_if_exists(path, targets[i].lnkname);
295 remove_if_exists(path, "uninstall.lnk");
296 remove_if_exists(path, "Help.lnk");
297 // Win95 uses .pif, WinNT uses .lnk
298 remove_if_exists(path, "Vim tutor.pif");
299 remove_if_exists(path, "Vim tutor.lnk");
300 remove_if_exists(path, "Vim online.url");
301 if (stat(path, &st) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000302 {
Yegappan Lakshmanan142ed772023-01-26 12:00:00 +0000303 printf("removing %s\n", path);
304 rmdir(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 }
306}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308 static void
309delete_uninstall_key(void)
310{
Bram Moolenaar6199d432017-10-14 19:05:44 +0200311 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 +0000312}
313
314 int
315main(int argc, char *argv[])
316{
317 int found = 0;
318 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319 int i;
320 struct stat st;
321 char icon[BUFSIZE];
Bram Moolenaarbbd854d2019-02-18 22:19:33 +0100322 char path[MAX_PATH];
323 char popup_path[MAX_PATH];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000324
Bram Moolenaare38eab22019-12-05 21:50:01 +0100325 // The nsis uninstaller calls us with a "-nsis" argument.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000326 if (argc == 2 && stricmp(argv[1], "-nsis") == 0)
327 interactive = FALSE;
328 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000329 interactive = TRUE;
330
Bram Moolenaare38eab22019-12-05 21:50:01 +0100331 // Initialize this program.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000332 do_inits(argv);
333
334 printf("This program will remove the following items:\n");
335
Bram Moolenaare4963c52019-02-22 19:41:08 +0100336 if (popup_gvim_path(popup_path, sizeof(popup_path)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000337 {
338 printf(" - the \"Edit with Vim\" entry in the popup menu\n");
339 printf(" which uses \"%s\"\n", popup_path);
Bram Moolenaar442b4222010-05-24 21:34:22 +0200340 if (interactive)
341 printf("\nRemove it (y/n)? ");
342 if (!interactive || confirm())
Bram Moolenaar071d4272004-06-13 20:20:40 +0000343 {
344 remove_popup();
Bram Moolenaare38eab22019-12-05 21:50:01 +0100345 // Assume the "Open With" entry can be removed as well, don't
346 // bother the user with asking him again.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 remove_openwith();
348 }
349 }
Bram Moolenaare4963c52019-02-22 19:41:08 +0100350 else if (openwith_gvim_path(popup_path, sizeof(popup_path)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000351 {
352 printf(" - the Vim \"Open With...\" entry in the popup menu\n");
353 printf(" which uses \"%s\"\n", popup_path);
354 printf("\nRemove it (y/n)? ");
355 if (confirm())
356 remove_openwith();
357 }
358
359 if (get_shell_folder_path(path, "desktop"))
360 {
361 printf("\n");
362 for (i = 0; i < ICON_COUNT; ++i)
363 {
364 sprintf(icon, "%s\\%s", path, icon_link_names[i]);
365 if (stat(icon, &st) == 0)
366 {
367 printf(" - the \"%s\" icon on the desktop\n", icon_names[i]);
368 ++found;
369 }
370 }
371 if (found > 0)
372 {
373 if (interactive)
374 printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
375 if (!interactive || confirm())
376 remove_icons();
377 }
378 }
379
380 if (get_shell_folder_path(path, VIM_STARTMENU)
381 && stat(path, &st) == 0)
382 {
383 printf("\n - the \"%s\" entry in the Start Menu\n", VIM_STARTMENU);
384 if (interactive)
385 printf("\nRemove it (y/n)? ");
386 if (!interactive || confirm())
387 remove_start_menu();
388 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389
390 printf("\n");
391 found = remove_batfiles(0);
392 if (found > 0)
393 {
394 if (interactive)
395 printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
396 if (!interactive || confirm())
397 remove_batfiles(1);
398 }
399
400 fd = fopen("gvim.exe", "r");
401 if (fd != NULL)
402 {
403 fclose(fd);
404 printf("gvim.exe detected. Attempting to unregister gvim with OLE\n");
405 system("gvim.exe -silent -unregister");
406 }
407
408 delete_uninstall_key();
409
410 if (interactive)
411 {
412 printf("\nYou may now want to delete the Vim executables and runtime files.\n");
413 printf("(They are still where you unpacked them.)\n");
414 }
415
Bram Moolenaar442b4222010-05-24 21:34:22 +0200416 if (interactive)
417 {
418 rewind(stdin);
419 printf("\nPress Enter to exit...");
420 (void)getchar();
421 }
422 else
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200423 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424
425 return 0;
426}