blob: e9a9aac3272cce72563781ad2fed35a431a9ed2d [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);
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 {
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 }
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
Bram Moolenaare4963c52019-02-22 19:41:08 +010063popup_gvim_path(char *buf, DWORD bufsize)
Bram Moolenaar071d4272004-06-13 20:20:40 +000064{
65 HKEY key_handle;
66 DWORD value_type;
Bram Moolenaar071d4272004-06-13 20:20:40 +000067 int r;
68
Bram Moolenaare38eab22019-12-05 21:50:01 +010069 // Open the key where the path to gvim.exe is stored.
Bram Moolenaar760d14a2010-07-31 22:03:44 +020070 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
71 KEY_WOW64_64KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
Bram Moolenaar6199d432017-10-14 19:05:44 +020072 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
73 KEY_WOW64_32KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
74 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000075
Bram Moolenaare38eab22019-12-05 21:50:01 +010076 // get the DisplayName out of it to show the user
Bram Moolenaar071d4272004-06-13 20:20:40 +000077 r = RegQueryValueEx(key_handle, "path", 0,
78 &value_type, (LPBYTE)buf, &bufsize);
79 RegCloseKey(key_handle);
80
81 return (r == ERROR_SUCCESS);
82}
83
84/*
85 * Check if the "Open With..." menu entry exists and what gvim it refers to.
86 * Returns non-zero when it's found.
87 */
88 static int
Bram Moolenaare4963c52019-02-22 19:41:08 +010089openwith_gvim_path(char *buf, DWORD bufsize)
Bram Moolenaar071d4272004-06-13 20:20:40 +000090{
91 HKEY key_handle;
92 DWORD value_type;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 int r;
94
Bram Moolenaare38eab22019-12-05 21:50:01 +010095 // Open the key where the path to gvim.exe is stored.
Bram Moolenaar071d4272004-06-13 20:20:40 +000096 if (RegOpenKeyEx(HKEY_CLASSES_ROOT,
Bram Moolenaar760d14a2010-07-31 22:03:44 +020097 "Applications\\gvim.exe\\shell\\edit\\command", 0,
98 KEY_WOW64_64KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
Bram Moolenaar071d4272004-06-13 20:20:40 +000099 return 0;
100
Bram Moolenaare38eab22019-12-05 21:50:01 +0100101 // get the DisplayName out of it to show the user
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102 r = RegQueryValueEx(key_handle, "", 0, &value_type, (LPBYTE)buf, &bufsize);
103 RegCloseKey(key_handle);
104
105 return (r == ERROR_SUCCESS);
106}
107
108 static void
109remove_popup(void)
110{
111 int fail = 0;
Bram Moolenaar6199d432017-10-14 19:05:44 +0200112 int i;
113 int loop = is_64bit_os() ? 2 : 1;
114 int maxfail = loop * 6;
115 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116 HKEY kh;
117
Bram Moolenaar6199d432017-10-14 19:05:44 +0200118 for (i = 0; i < loop; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119 {
Bram Moolenaar6199d432017-10-14 19:05:44 +0200120 if (i == 0)
121 flag = KEY_WOW64_32KEY;
122 else
123 flag = KEY_WOW64_64KEY;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000124
Bram Moolenaar6199d432017-10-14 19:05:44 +0200125 if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\\InProcServer32", flag) != ERROR_SUCCESS)
126 ++fail;
127 if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}", flag) != ERROR_SUCCESS)
128 ++fail;
129 if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\shellex\\ContextMenuHandlers\\gvim", flag) != ERROR_SUCCESS)
130 ++fail;
131 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 0,
132 flag | KEY_ALL_ACCESS, &kh) != ERROR_SUCCESS)
133 ++fail;
134 else
135 {
136 if (RegDeleteValue(kh, "{51EEE242-AD87-11d3-9C1E-0090278BBD99}") != ERROR_SUCCESS)
137 ++fail;
138 RegCloseKey(kh);
139 }
140 if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", flag) != ERROR_SUCCESS)
141 ++fail;
142 if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim", flag) != ERROR_SUCCESS)
143 ++fail;
144 }
145
146 if (fail == maxfail)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147 printf("No Vim popup registry entries could be removed\n");
148 else if (fail > 0)
149 printf("Some Vim popup registry entries could not be removed\n");
150 else
151 printf("The Vim popup registry entries have been removed\n");
152}
153
154 static void
155remove_openwith(void)
156{
157 int fail = 0;
Bram Moolenaar6199d432017-10-14 19:05:44 +0200158 int i;
159 int loop = is_64bit_os() ? 2 : 1;
160 int maxfail = loop * 7;
161 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162
Bram Moolenaar6199d432017-10-14 19:05:44 +0200163 for (i = 0; i < loop; i++)
164 {
165 if (i == 0)
166 flag = KEY_WOW64_32KEY;
167 else
168 flag = KEY_WOW64_64KEY;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169
Bram Moolenaar6199d432017-10-14 19:05:44 +0200170 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit\\command", flag) != ERROR_SUCCESS)
171 ++fail;
172 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit", flag) != ERROR_SUCCESS)
173 ++fail;
174 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell", flag) != ERROR_SUCCESS)
175 ++fail;
176 if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe", flag) != ERROR_SUCCESS)
177 ++fail;
178 if (reg_delete_key(HKEY_CLASSES_ROOT, ".htm\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
179 ++fail;
180 if (reg_delete_key(HKEY_CLASSES_ROOT, ".vim\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
181 ++fail;
182 if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
183 ++fail;
184 }
185
186 if (fail == maxfail)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187 printf("No Vim open-with registry entries could be removed\n");
188 else if (fail > 0)
189 printf("Some Vim open-with registry entries could not be removed\n");
190 else
191 printf("The Vim open-with registry entries have been removed\n");
192}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000193
194/*
195 * Check if a batch file is really for the current version. Don't delete a
196 * batch file that was written for another (possibly newer) version.
197 */
198 static int
199batfile_thisversion(char *path)
200{
201 FILE *fd;
202 char line[BUFSIZE];
Bram Moolenaar1fa8d2c2020-02-17 22:53:14 +0100203 int key_len = strlen(VIMBAT_UNINSTKEY);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000204 int found = FALSE;
205
206 fd = fopen(path, "r");
207 if (fd != NULL)
208 {
Bram Moolenaare4963c52019-02-22 19:41:08 +0100209 while (fgets(line, sizeof(line), fd) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210 {
Bram Moolenaar1fa8d2c2020-02-17 22:53:14 +0100211 if (strncmp(line, VIMBAT_UNINSTKEY, key_len) == 0)
212 {
213 found = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000214 break;
Bram Moolenaar1fa8d2c2020-02-17 22:53:14 +0100215 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000216 }
217 fclose(fd);
218 }
219 return found;
220}
221
222 static int
223remove_batfiles(int doit)
224{
225 char *batfile_path;
226 int i;
227 int found = 0;
228
Bram Moolenaar57ea2922020-02-09 14:27:20 +0100229 // avoid looking in the "installdir" by chdir to system root
230 mch_chdir(sysdrive);
231 mch_chdir("\\");
232
Bram Moolenaar071d4272004-06-13 20:20:40 +0000233 for (i = 1; i < TARGET_COUNT; ++i)
234 {
235 batfile_path = searchpath_save(targets[i].batname);
236 if (batfile_path != NULL && batfile_thisversion(batfile_path))
237 {
238 ++found;
239 if (doit)
240 {
241 printf("removing %s\n", batfile_path);
242 remove(batfile_path);
243 }
244 else
245 printf(" - the batch file %s\n", batfile_path);
246 free(batfile_path);
247 }
248 }
Bram Moolenaar57ea2922020-02-09 14:27:20 +0100249
250 mch_chdir(installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000251 return found;
252}
253
Bram Moolenaar071d4272004-06-13 20:20:40 +0000254 static void
255remove_if_exists(char *path, char *filename)
256{
257 char buf[BUFSIZE];
258 FILE *fd;
259
260 sprintf(buf, "%s\\%s", path, filename);
261
262 fd = fopen(buf, "r");
263 if (fd != NULL)
264 {
265 fclose(fd);
266 printf("removing %s\n", buf);
267 remove(buf);
268 }
269}
270
271 static void
272remove_icons(void)
273{
274 char path[BUFSIZE];
275 int i;
276
277 if (get_shell_folder_path(path, "desktop"))
278 for (i = 0; i < ICON_COUNT; ++i)
279 remove_if_exists(path, icon_link_names[i]);
280}
281
282 static void
283remove_start_menu(void)
284{
285 char path[BUFSIZE];
286 int i;
287 struct stat st;
288
289 if (get_shell_folder_path(path, VIM_STARTMENU))
290 {
291 for (i = 1; i < TARGET_COUNT; ++i)
292 remove_if_exists(path, targets[i].lnkname);
293 remove_if_exists(path, "uninstall.lnk");
294 remove_if_exists(path, "Help.lnk");
Bram Moolenaare38eab22019-12-05 21:50:01 +0100295 // Win95 uses .pif, WinNT uses .lnk
Bram Moolenaar071d4272004-06-13 20:20:40 +0000296 remove_if_exists(path, "Vim tutor.pif");
297 remove_if_exists(path, "Vim tutor.lnk");
298 remove_if_exists(path, "Vim online.url");
299 if (stat(path, &st) == 0)
300 {
301 printf("removing %s\n", path);
302 rmdir(path);
303 }
304 }
305}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307 static void
308delete_uninstall_key(void)
309{
Bram Moolenaar6199d432017-10-14 19:05:44 +0200310 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 +0000311}
312
313 int
314main(int argc, char *argv[])
315{
316 int found = 0;
317 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000318 int i;
319 struct stat st;
320 char icon[BUFSIZE];
Bram Moolenaarbbd854d2019-02-18 22:19:33 +0100321 char path[MAX_PATH];
322 char popup_path[MAX_PATH];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000323
Bram Moolenaare38eab22019-12-05 21:50:01 +0100324 // The nsis uninstaller calls us with a "-nsis" argument.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000325 if (argc == 2 && stricmp(argv[1], "-nsis") == 0)
326 interactive = FALSE;
327 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000328 interactive = TRUE;
329
Bram Moolenaare38eab22019-12-05 21:50:01 +0100330 // Initialize this program.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000331 do_inits(argv);
332
333 printf("This program will remove the following items:\n");
334
Bram Moolenaare4963c52019-02-22 19:41:08 +0100335 if (popup_gvim_path(popup_path, sizeof(popup_path)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000336 {
337 printf(" - the \"Edit with Vim\" entry in the popup menu\n");
338 printf(" which uses \"%s\"\n", popup_path);
Bram Moolenaar442b4222010-05-24 21:34:22 +0200339 if (interactive)
340 printf("\nRemove it (y/n)? ");
341 if (!interactive || confirm())
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 {
343 remove_popup();
Bram Moolenaare38eab22019-12-05 21:50:01 +0100344 // Assume the "Open With" entry can be removed as well, don't
345 // bother the user with asking him again.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000346 remove_openwith();
347 }
348 }
Bram Moolenaare4963c52019-02-22 19:41:08 +0100349 else if (openwith_gvim_path(popup_path, sizeof(popup_path)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 {
351 printf(" - the Vim \"Open With...\" entry in the popup menu\n");
352 printf(" which uses \"%s\"\n", popup_path);
353 printf("\nRemove it (y/n)? ");
354 if (confirm())
355 remove_openwith();
356 }
357
358 if (get_shell_folder_path(path, "desktop"))
359 {
360 printf("\n");
361 for (i = 0; i < ICON_COUNT; ++i)
362 {
363 sprintf(icon, "%s\\%s", path, icon_link_names[i]);
364 if (stat(icon, &st) == 0)
365 {
366 printf(" - the \"%s\" icon on the desktop\n", icon_names[i]);
367 ++found;
368 }
369 }
370 if (found > 0)
371 {
372 if (interactive)
373 printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
374 if (!interactive || confirm())
375 remove_icons();
376 }
377 }
378
379 if (get_shell_folder_path(path, VIM_STARTMENU)
380 && stat(path, &st) == 0)
381 {
382 printf("\n - the \"%s\" entry in the Start Menu\n", VIM_STARTMENU);
383 if (interactive)
384 printf("\nRemove it (y/n)? ");
385 if (!interactive || confirm())
386 remove_start_menu();
387 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000388
389 printf("\n");
390 found = remove_batfiles(0);
391 if (found > 0)
392 {
393 if (interactive)
394 printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
395 if (!interactive || confirm())
396 remove_batfiles(1);
397 }
398
399 fd = fopen("gvim.exe", "r");
400 if (fd != NULL)
401 {
402 fclose(fd);
403 printf("gvim.exe detected. Attempting to unregister gvim with OLE\n");
404 system("gvim.exe -silent -unregister");
405 }
406
407 delete_uninstall_key();
408
409 if (interactive)
410 {
411 printf("\nYou may now want to delete the Vim executables and runtime files.\n");
412 printf("(They are still where you unpacked them.)\n");
413 }
414
Bram Moolenaar442b4222010-05-24 21:34:22 +0200415 if (interactive)
416 {
417 rewind(stdin);
418 printf("\nPress Enter to exit...");
419 (void)getchar();
420 }
421 else
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200422 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423
424 return 0;
425}