blob: 79f6ef69a6aec18cca3163262ef423579d3abaef [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
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289 static void
290delete_uninstall_key(void)
291{
Bram Moolenaarbf650512010-08-02 23:06:46 +0200292 reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000293}
294
295 int
296main(int argc, char *argv[])
297{
298 int found = 0;
299 FILE *fd;
300#ifdef WIN3264
301 int i;
302 struct stat st;
303 char icon[BUFSIZE];
304 char path[BUFSIZE];
305 char popup_path[BUFSIZE];
306
307 /* The nsis uninstaller calls us with a "-nsis" argument. */
308 if (argc == 2 && stricmp(argv[1], "-nsis") == 0)
309 interactive = FALSE;
310 else
311#endif
312 interactive = TRUE;
313
314 /* Initialize this program. */
315 do_inits(argv);
316
317 printf("This program will remove the following items:\n");
318
319#ifdef WIN3264
320 if (popup_gvim_path(popup_path))
321 {
322 printf(" - the \"Edit with Vim\" entry in the popup menu\n");
323 printf(" which uses \"%s\"\n", popup_path);
Bram Moolenaar442b4222010-05-24 21:34:22 +0200324 if (interactive)
325 printf("\nRemove it (y/n)? ");
326 if (!interactive || confirm())
Bram Moolenaar071d4272004-06-13 20:20:40 +0000327 {
328 remove_popup();
329 /* Assume the "Open With" entry can be removed as well, don't
330 * bother the user with asking him again. */
331 remove_openwith();
332 }
333 }
334 else if (openwith_gvim_path(popup_path))
335 {
336 printf(" - the Vim \"Open With...\" entry in the popup menu\n");
337 printf(" which uses \"%s\"\n", popup_path);
338 printf("\nRemove it (y/n)? ");
339 if (confirm())
340 remove_openwith();
341 }
342
343 if (get_shell_folder_path(path, "desktop"))
344 {
345 printf("\n");
346 for (i = 0; i < ICON_COUNT; ++i)
347 {
348 sprintf(icon, "%s\\%s", path, icon_link_names[i]);
349 if (stat(icon, &st) == 0)
350 {
351 printf(" - the \"%s\" icon on the desktop\n", icon_names[i]);
352 ++found;
353 }
354 }
355 if (found > 0)
356 {
357 if (interactive)
358 printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
359 if (!interactive || confirm())
360 remove_icons();
361 }
362 }
363
364 if (get_shell_folder_path(path, VIM_STARTMENU)
365 && stat(path, &st) == 0)
366 {
367 printf("\n - the \"%s\" entry in the Start Menu\n", VIM_STARTMENU);
368 if (interactive)
369 printf("\nRemove it (y/n)? ");
370 if (!interactive || confirm())
371 remove_start_menu();
372 }
373#endif
374
375 printf("\n");
376 found = remove_batfiles(0);
377 if (found > 0)
378 {
379 if (interactive)
380 printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
381 if (!interactive || confirm())
382 remove_batfiles(1);
383 }
384
385 fd = fopen("gvim.exe", "r");
386 if (fd != NULL)
387 {
388 fclose(fd);
389 printf("gvim.exe detected. Attempting to unregister gvim with OLE\n");
390 system("gvim.exe -silent -unregister");
391 }
392
393 delete_uninstall_key();
394
395 if (interactive)
396 {
397 printf("\nYou may now want to delete the Vim executables and runtime files.\n");
398 printf("(They are still where you unpacked them.)\n");
399 }
400
Bram Moolenaar442b4222010-05-24 21:34:22 +0200401 if (interactive)
402 {
403 rewind(stdin);
404 printf("\nPress Enter to exit...");
405 (void)getchar();
406 }
407 else
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200408 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000409
410 return 0;
411}