From 3b73107100dd41e0ae4d518e1956b9a55272be75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Thu, 29 Dec 2022 16:47:17 +0100 Subject: [PATCH] Add `shell_unregister` to delete protocol/file extension handlers This function removes the registry keys that are created with `shell_register_protocol` and `shell_register_extension`. According to the Microsoft documentation, only the keys for the program IDs should be deleted. The keys that associate the file extensions with the program IDs should be kept, as Windows will automatically ignore the value if the program ID does not exist. See: https://learn.microsoft.com/en-us/windows/win32/shell/fa-file-types#deleting-registry-information-during-uninstallation --- src/base/system.cpp | 29 ++++++++++++++++++++++++++++- src/base/system.h | 16 ++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/base/system.cpp b/src/base/system.cpp index bf282fbe4..c6f9c19e2 100644 --- a/src/base/system.cpp +++ b/src/base/system.cpp @@ -59,7 +59,7 @@ #define WIN32_LEAN_AND_MEAN #undef _WIN32_WINNT // 0x0501 (Windows XP) is required for mingw to get getaddrinfo to work -// 0x0600 (Windows Vista) is required to use RegGetValueW +// 0x0600 (Windows Vista) is required to use RegGetValueW and RegDeleteTreeW #define _WIN32_WINNT 0x0600 #include #include @@ -4552,6 +4552,33 @@ bool shell_register_extension(const char *extension, const char *description, co return true; } +bool shell_unregister(const char *shell_class, bool *updated) +{ + const std::wstring class_wide = utf8_to_wstring(shell_class); + + // Open registry key for protocol and file associations of the current user + HKEY handle_subkey_classes; + const LRESULT result_subkey_classes = RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Classes", 0, KEY_ALL_ACCESS, &handle_subkey_classes); + if(result_subkey_classes != ERROR_SUCCESS) + { + windows_print_error("shell_unregister", "Error opening registry key", result_subkey_classes); + return false; + } + + // Delete the registry keys for the shell class (protocol or program ID) + LRESULT result_delete = RegDeleteTreeW(handle_subkey_classes, class_wide.c_str()); + RegCloseKey(handle_subkey_classes); + if(result_delete != ERROR_SUCCESS && result_delete != ERROR_FILE_NOT_FOUND) + { + windows_print_error("shell_unregister", "Error deleting registry key", result_delete); + if(result_delete == ERROR_SUCCESS) + *updated = true; + return false; + } + + return true; +} + void shell_update() { SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); diff --git a/src/base/system.h b/src/base/system.h index 27195e22e..17916a3de 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -2603,6 +2603,22 @@ bool shell_register_protocol(const char *protocol_name, const char *executable, */ bool shell_register_extension(const char *extension, const char *description, const char *executable_name, const char *executable, bool *updated); +/** + * Unregisters a protocol or file extension handler. + * + * @ingroup Shell + * + * @param shell_class The shell class to delete. + * For protocols this is the name of the protocol. + * For file extensions this is the program ID associated with the file extension. + * @param updated Pointer to a variable that will be set to true, iff the shell needs to be updated. + * + * @return true on success, false on failure. + * + * @remark The caller must later call shell_update, iff the shell needs to be updated. + */ +bool shell_unregister(const char *shell_class, bool *updated); + /** * Notifies the system that a protocol or file extension has been changed and the shell needs to be updated. *