diff options
Diffstat (limited to 'src/uninstal.c')
-rw-r--r-- | src/uninstal.c | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/src/uninstal.c b/src/uninstal.c new file mode 100644 index 0000000..11b6c62 --- /dev/null +++ b/src/uninstal.c @@ -0,0 +1,428 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * uninstal.c: Minimalistic uninstall program for Vim on MS-Windows + * Removes: + * - the "Edit with Vim" popup menu entry + * - the Vim "Open With..." popup menu entry + * - any Vim Batch files in the path + * - icons for Vim on the Desktop + * - the Vim entry in the Start Menu + */ + +/* Include common code for dosinst.c and uninstal.c. */ +#include "dosinst.h" + +/* + * Return TRUE if the user types a 'y' or 'Y', FALSE otherwise. + */ + static int +confirm(void) +{ + char answer[10]; + + fflush(stdout); + return (scanf(" %c", answer) == 1 && toupper(answer[0]) == 'Y'); +} + + static int +reg_delete_key(HKEY hRootKey, const char *key, DWORD flag) +{ + static int did_load = FALSE; + static HANDLE advapi_lib = NULL; + static LONG (WINAPI *delete_key_ex)(HKEY, LPCTSTR, REGSAM, DWORD) = NULL; + + if (!did_load) + { + /* The RegDeleteKeyEx() function is only available on new systems. It + * is required for 64-bit registry access. For other systems fall + * back to RegDeleteKey(). */ + did_load = TRUE; + advapi_lib = LoadLibrary("ADVAPI32.DLL"); + if (advapi_lib != NULL) + delete_key_ex = (LONG (WINAPI *)(HKEY, LPCTSTR, REGSAM, DWORD))GetProcAddress(advapi_lib, "RegDeleteKeyExA"); + } + if (delete_key_ex != NULL) { + return (*delete_key_ex)(hRootKey, key, flag, 0); + } + return RegDeleteKey(hRootKey, key); +} + +/* + * Check if the popup menu entry exists and what gvim it refers to. + * Returns non-zero when it's found. + */ + static int +popup_gvim_path(char *buf) +{ + HKEY key_handle; + DWORD value_type; + DWORD bufsize = BUFSIZE; + int r; + + /* Open the key where the path to gvim.exe is stored. */ + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0, + KEY_WOW64_64KEY | KEY_READ, &key_handle) != ERROR_SUCCESS) + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0, + KEY_WOW64_32KEY | KEY_READ, &key_handle) != ERROR_SUCCESS) + return 0; + + /* get the DisplayName out of it to show the user */ + r = RegQueryValueEx(key_handle, "path", 0, + &value_type, (LPBYTE)buf, &bufsize); + RegCloseKey(key_handle); + + return (r == ERROR_SUCCESS); +} + +/* + * Check if the "Open With..." menu entry exists and what gvim it refers to. + * Returns non-zero when it's found. + */ + static int +openwith_gvim_path(char *buf) +{ + HKEY key_handle; + DWORD value_type; + DWORD bufsize = BUFSIZE; + int r; + + /* Open the key where the path to gvim.exe is stored. */ + if (RegOpenKeyEx(HKEY_CLASSES_ROOT, + "Applications\\gvim.exe\\shell\\edit\\command", 0, + KEY_WOW64_64KEY | KEY_READ, &key_handle) != ERROR_SUCCESS) + return 0; + + /* get the DisplayName out of it to show the user */ + r = RegQueryValueEx(key_handle, "", 0, &value_type, (LPBYTE)buf, &bufsize); + RegCloseKey(key_handle); + + return (r == ERROR_SUCCESS); +} + + static void +remove_popup(void) +{ + int fail = 0; + int i; + int loop = is_64bit_os() ? 2 : 1; + int maxfail = loop * 6; + DWORD flag; + HKEY kh; + + for (i = 0; i < loop; i++) + { + if (i == 0) + flag = KEY_WOW64_32KEY; + else + flag = KEY_WOW64_64KEY; + + if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\\InProcServer32", flag) != ERROR_SUCCESS) + ++fail; + if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}", flag) != ERROR_SUCCESS) + ++fail; + if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\shellex\\ContextMenuHandlers\\gvim", flag) != ERROR_SUCCESS) + ++fail; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 0, + flag | KEY_ALL_ACCESS, &kh) != ERROR_SUCCESS) + ++fail; + else + { + if (RegDeleteValue(kh, "{51EEE242-AD87-11d3-9C1E-0090278BBD99}") != ERROR_SUCCESS) + ++fail; + RegCloseKey(kh); + } + if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", flag) != ERROR_SUCCESS) + ++fail; + if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim", flag) != ERROR_SUCCESS) + ++fail; + } + + if (fail == maxfail) + printf("No Vim popup registry entries could be removed\n"); + else if (fail > 0) + printf("Some Vim popup registry entries could not be removed\n"); + else + printf("The Vim popup registry entries have been removed\n"); +} + + static void +remove_openwith(void) +{ + int fail = 0; + int i; + int loop = is_64bit_os() ? 2 : 1; + int maxfail = loop * 7; + DWORD flag; + + for (i = 0; i < loop; i++) + { + if (i == 0) + flag = KEY_WOW64_32KEY; + else + flag = KEY_WOW64_64KEY; + + if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit\\command", flag) != ERROR_SUCCESS) + ++fail; + if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit", flag) != ERROR_SUCCESS) + ++fail; + if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell", flag) != ERROR_SUCCESS) + ++fail; + if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe", flag) != ERROR_SUCCESS) + ++fail; + if (reg_delete_key(HKEY_CLASSES_ROOT, ".htm\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS) + ++fail; + if (reg_delete_key(HKEY_CLASSES_ROOT, ".vim\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS) + ++fail; + if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS) + ++fail; + } + + if (fail == maxfail) + printf("No Vim open-with registry entries could be removed\n"); + else if (fail > 0) + printf("Some Vim open-with registry entries could not be removed\n"); + else + printf("The Vim open-with registry entries have been removed\n"); +} + +/* + * Check if a batch file is really for the current version. Don't delete a + * batch file that was written for another (possibly newer) version. + */ + static int +batfile_thisversion(char *path) +{ + FILE *fd; + char line[BUFSIZE]; + char *p; + int ver_len = strlen(VIM_VERSION_NODOT); + int found = FALSE; + + fd = fopen(path, "r"); + if (fd != NULL) + { + while (fgets(line, BUFSIZE, fd) != NULL) + { + for (p = line; *p != 0; ++p) + /* don't accept "vim60an" when looking for "vim60". */ + if (strnicmp(p, VIM_VERSION_NODOT, ver_len) == 0 + && !isdigit(p[ver_len]) + && !isalpha(p[ver_len])) + { + found = TRUE; + break; + } + if (found) + break; + } + fclose(fd); + } + return found; +} + + static int +remove_batfiles(int doit) +{ + char *batfile_path; + int i; + int found = 0; + + for (i = 1; i < TARGET_COUNT; ++i) + { + batfile_path = searchpath_save(targets[i].batname); + if (batfile_path != NULL && batfile_thisversion(batfile_path)) + { + ++found; + if (doit) + { + printf("removing %s\n", batfile_path); + remove(batfile_path); + } + else + printf(" - the batch file %s\n", batfile_path); + free(batfile_path); + } + } + return found; +} + + static void +remove_if_exists(char *path, char *filename) +{ + char buf[BUFSIZE]; + FILE *fd; + + sprintf(buf, "%s\\%s", path, filename); + + fd = fopen(buf, "r"); + if (fd != NULL) + { + fclose(fd); + printf("removing %s\n", buf); + remove(buf); + } +} + + static void +remove_icons(void) +{ + char path[BUFSIZE]; + int i; + + if (get_shell_folder_path(path, "desktop")) + for (i = 0; i < ICON_COUNT; ++i) + remove_if_exists(path, icon_link_names[i]); +} + + static void +remove_start_menu(void) +{ + char path[BUFSIZE]; + int i; + struct stat st; + + if (get_shell_folder_path(path, VIM_STARTMENU)) + { + for (i = 1; i < TARGET_COUNT; ++i) + remove_if_exists(path, targets[i].lnkname); + remove_if_exists(path, "uninstall.lnk"); + remove_if_exists(path, "Help.lnk"); + /* Win95 uses .pif, WinNT uses .lnk */ + remove_if_exists(path, "Vim tutor.pif"); + remove_if_exists(path, "Vim tutor.lnk"); + remove_if_exists(path, "Vim online.url"); + if (stat(path, &st) == 0) + { + printf("removing %s\n", path); + rmdir(path); + } + } +} + + static void +delete_uninstall_key(void) +{ + reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT, KEY_WOW64_64KEY); +} + + int +main(int argc, char *argv[]) +{ + int found = 0; + FILE *fd; + int i; + struct stat st; + char icon[BUFSIZE]; + char path[BUFSIZE]; + char popup_path[BUFSIZE]; + + /* The nsis uninstaller calls us with a "-nsis" argument. */ + if (argc == 2 && stricmp(argv[1], "-nsis") == 0) + interactive = FALSE; + else + interactive = TRUE; + + /* Initialize this program. */ + do_inits(argv); + + printf("This program will remove the following items:\n"); + + if (popup_gvim_path(popup_path)) + { + printf(" - the \"Edit with Vim\" entry in the popup menu\n"); + printf(" which uses \"%s\"\n", popup_path); + if (interactive) + printf("\nRemove it (y/n)? "); + if (!interactive || confirm()) + { + remove_popup(); + /* Assume the "Open With" entry can be removed as well, don't + * bother the user with asking him again. */ + remove_openwith(); + } + } + else if (openwith_gvim_path(popup_path)) + { + printf(" - the Vim \"Open With...\" entry in the popup menu\n"); + printf(" which uses \"%s\"\n", popup_path); + printf("\nRemove it (y/n)? "); + if (confirm()) + remove_openwith(); + } + + if (get_shell_folder_path(path, "desktop")) + { + printf("\n"); + for (i = 0; i < ICON_COUNT; ++i) + { + sprintf(icon, "%s\\%s", path, icon_link_names[i]); + if (stat(icon, &st) == 0) + { + printf(" - the \"%s\" icon on the desktop\n", icon_names[i]); + ++found; + } + } + if (found > 0) + { + if (interactive) + printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it"); + if (!interactive || confirm()) + remove_icons(); + } + } + + if (get_shell_folder_path(path, VIM_STARTMENU) + && stat(path, &st) == 0) + { + printf("\n - the \"%s\" entry in the Start Menu\n", VIM_STARTMENU); + if (interactive) + printf("\nRemove it (y/n)? "); + if (!interactive || confirm()) + remove_start_menu(); + } + + printf("\n"); + found = remove_batfiles(0); + if (found > 0) + { + if (interactive) + printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it"); + if (!interactive || confirm()) + remove_batfiles(1); + } + + fd = fopen("gvim.exe", "r"); + if (fd != NULL) + { + fclose(fd); + printf("gvim.exe detected. Attempting to unregister gvim with OLE\n"); + system("gvim.exe -silent -unregister"); + } + + delete_uninstall_key(); + + if (interactive) + { + printf("\nYou may now want to delete the Vim executables and runtime files.\n"); + printf("(They are still where you unpacked them.)\n"); + } + + if (interactive) + { + rewind(stdin); + printf("\nPress Enter to exit..."); + (void)getchar(); + } + else + sleep(3); + + return 0; +} |