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
This commit is contained in:
Robert Müller 2022-12-29 16:47:17 +01:00
parent 8a3a8974d0
commit 3b73107100
2 changed files with 44 additions and 1 deletions

View file

@ -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 <windows.h>
#include <winsock2.h>
@ -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);

View file

@ -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.
*