File: uninstallation_via_os_settings.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (168 lines) | stat: -rw-r--r-- 6,011 bytes parent folder | download | duplicates (7)
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;
}