1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/win/uninstallation_via_os_settings.h"
#include <windows.h>
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/metrics/histogram_functions.h"
#include "base/win/registry.h"
#include "base/win/windows_types.h"
namespace {
// Win32 App registry entry for uninstallation. System detects the registry
// and show its App for App or Remove Settings.
constexpr wchar_t kUninstallRegistryKey[] =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
// List of registry specific LONG error codes obtained from
// winerror.h in depot_tools/ toolchain as well as
// base/win/windows_types.h.
enum class WinRegistryErrorCode {
kErrorOther = 0,
kErrorSuccess = 1,
kErrorFileNotFound = 2,
kErrorAccessDenied = 3,
kErrorInvalidHandle = 4,
kErrorSharingViolation = 5,
kErrorLockViolation = 6,
kErrorMoreData = 7,
kErrorRegistryRecovered = 8,
kErrorRegistryCorrupt = 9,
kErrorRegistryIOFailed = 10,
kErrorNotRegistryFile = 11,
kErrorRegistryQuotaLimit = 12,
kErrorRegistryHiveRecovered = 13,
kErrorRegistryClusterInvalidFunction = 14,
kMaxValue = kErrorRegistryClusterInvalidFunction
};
void RecordUninstallationRegistrationOSResult(LONG result) {
WinRegistryErrorCode final_code = WinRegistryErrorCode::kErrorOther;
switch (result) {
case ERROR_SUCCESS:
final_code = WinRegistryErrorCode::kErrorSuccess;
break;
case ERROR_FILE_NOT_FOUND:
final_code = WinRegistryErrorCode::kErrorFileNotFound;
break;
case ERROR_ACCESS_DENIED:
final_code = WinRegistryErrorCode::kErrorAccessDenied;
break;
case ERROR_INVALID_HANDLE:
final_code = WinRegistryErrorCode::kErrorInvalidHandle;
break;
case ERROR_SHARING_VIOLATION:
final_code = WinRegistryErrorCode::kErrorSharingViolation;
break;
case ERROR_LOCK_VIOLATION:
final_code = WinRegistryErrorCode::kErrorLockViolation;
break;
case ERROR_MORE_DATA:
final_code = WinRegistryErrorCode::kErrorMoreData;
break;
case ERROR_REGISTRY_RECOVERED:
final_code = WinRegistryErrorCode::kErrorRegistryRecovered;
break;
case ERROR_REGISTRY_CORRUPT:
final_code = WinRegistryErrorCode::kErrorRegistryCorrupt;
break;
case ERROR_REGISTRY_IO_FAILED:
final_code = WinRegistryErrorCode::kErrorRegistryIOFailed;
break;
case ERROR_NOT_REGISTRY_FILE:
final_code = WinRegistryErrorCode::kErrorNotRegistryFile;
break;
case ERROR_REGISTRY_QUOTA_LIMIT:
final_code = WinRegistryErrorCode::kErrorRegistryQuotaLimit;
break;
case ERROR_REGISTRY_HIVE_RECOVERED:
final_code = WinRegistryErrorCode::kErrorRegistryHiveRecovered;
break;
case ERROR_CLUSTER_REGISTRY_INVALID_FUNCTION:
final_code = WinRegistryErrorCode::kErrorRegistryClusterInvalidFunction;
break;
default:
break;
}
base::UmaHistogramEnumeration(
"WebApp.OsSettingsUninstallUnregistration.WinOSResult", final_code);
}
} // namespace
bool RegisterUninstallationViaOsSettings(
const std::wstring& key,
const std::wstring& display_name,
const std::wstring& publisher,
const base::CommandLine& uninstall_command,
const base::FilePath& icon_path) {
DCHECK(!key.empty());
DCHECK(!display_name.empty());
DCHECK(!publisher.empty());
DCHECK(!uninstall_command.GetProgram().empty());
base::win::RegKey uninstall_reg_key;
LONG result = uninstall_reg_key.Open(HKEY_CURRENT_USER, kUninstallRegistryKey,
KEY_CREATE_SUB_KEY);
if (result != ERROR_SUCCESS)
return false;
base::win::RegKey uninstall_reg_entry_key;
DWORD disposition;
result = uninstall_reg_entry_key.CreateWithDisposition(
uninstall_reg_key.Handle(), key.c_str(), &disposition, KEY_WRITE);
if (result != ERROR_SUCCESS)
return false;
if (disposition != REG_CREATED_NEW_KEY)
return false;
// Add Uninstall values. Windows will show the icon at index 0
// if no index is specified in this value.
uninstall_reg_entry_key.WriteValue(L"DisplayIcon", icon_path.value().c_str());
uninstall_reg_entry_key.WriteValue(L"DisplayName", display_name.c_str());
uninstall_reg_entry_key.WriteValue(L"DisplayVersion", L"1.0");
uninstall_reg_entry_key.WriteValue(L"ApplicationVersion", L"1.0");
static constexpr wchar_t kDateFormat[] = L"yyyyyMMdd";
wchar_t date_str[std::size(kDateFormat)] = {};
int len = ::GetDateFormatW(LOCALE_INVARIANT, 0, nullptr, kDateFormat,
date_str, std::size(date_str));
if (len)
uninstall_reg_entry_key.WriteValue(L"InstallDate", date_str);
uninstall_reg_entry_key.WriteValue(L"Publisher", publisher.c_str());
uninstall_reg_entry_key.WriteValue(
L"UninstallString", uninstall_command.GetCommandLineString().c_str());
uninstall_reg_entry_key.WriteValue(L"NoRepair", 1);
uninstall_reg_entry_key.WriteValue(L"NoModify", 1);
return true;
}
bool UnregisterUninstallationViaOsSettings(const std::wstring& name) {
base::win::RegKey uninstall_reg_key;
LONG result = uninstall_reg_key.Open(HKEY_CURRENT_USER, kUninstallRegistryKey,
KEY_QUERY_VALUE);
if (result == ERROR_FILE_NOT_FOUND) {
RecordUninstallationRegistrationOSResult(result);
return true;
} else if (result != ERROR_SUCCESS) {
RecordUninstallationRegistrationOSResult(result);
return false;
}
LONG delete_key_result = uninstall_reg_key.DeleteKey(name.c_str());
RecordUninstallationRegistrationOSResult(delete_key_result);
// DeleteKey and Open work with different security access attributes, so
// ERROR_FILE_NOT_FOUND also needs to be treated as success during deletion.
return delete_key_result == ERROR_SUCCESS ||
delete_key_result == ERROR_FILE_NOT_FOUND;
}
|