| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // This file defines functions that integrate Chrome in Windows shell. These | 5 // This file defines functions that integrate Chrome in Windows shell. These |
| 6 // functions can be used by Chrome as well as Chrome installer. All of the | 6 // functions can be used by Chrome as well as Chrome installer. All of the |
| 7 // work is done by the local functions defined in anonymous namespace in | 7 // work is done by the local functions defined in anonymous namespace in |
| 8 // this class. | 8 // this class. |
| 9 | 9 |
| 10 #include "chrome/installer/util/shell_util.h" |
| 11 |
| 10 #include <windows.h> | 12 #include <windows.h> |
| 11 #include <shellapi.h> | |
| 12 #include <shlobj.h> | 13 #include <shlobj.h> |
| 13 | 14 |
| 14 #include "chrome/installer/util/shell_util.h" | |
| 15 | |
| 16 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 17 #include "base/file_path.h" | 16 #include "base/file_path.h" |
| 18 #include "base/file_util.h" | 17 #include "base/file_util.h" |
| 19 #include "base/logging.h" | 18 #include "base/logging.h" |
| 20 #include "base/path_service.h" | |
| 21 #include "base/registry.h" | 19 #include "base/registry.h" |
| 22 #include "base/scoped_ptr.h" | 20 #include "base/scoped_ptr.h" |
| 21 #include "base/stl_util-inl.h" |
| 23 #include "base/string_util.h" | 22 #include "base/string_util.h" |
| 24 #include "base/win_util.h" | 23 #include "base/win_util.h" |
| 25 #include "chrome/common/chrome_constants.h" | 24 #include "chrome/common/chrome_constants.h" |
| 26 #include "chrome/common/chrome_switches.h" | 25 #include "chrome/common/chrome_switches.h" |
| 27 #include "chrome/installer/util/browser_distribution.h" | 26 #include "chrome/installer/util/browser_distribution.h" |
| 28 #include "chrome/installer/util/create_reg_key_work_item.h" | |
| 29 #include "chrome/installer/util/install_util.h" | 27 #include "chrome/installer/util/install_util.h" |
| 30 #include "chrome/installer/util/l10n_string_util.h" | |
| 31 #include "chrome/installer/util/set_reg_value_work_item.h" | |
| 32 #include "chrome/installer/util/util_constants.h" | |
| 33 #include "chrome/installer/util/work_item.h" | |
| 34 | 28 |
| 35 #include "installer_util_strings.h" | 29 #include "installer_util_strings.h" |
| 36 | 30 |
| 37 namespace { | 31 namespace { |
| 38 | 32 |
| 39 // This class represents a single registry entry. The objective is to | 33 // This class represents a single registry entry. The objective is to |
| 40 // encapsulate all the registry entries required for registering Chrome at one | 34 // encapsulate all the registry entries required for registering Chrome at one |
| 41 // place. This class can not be instantiated outside the class and the objects | 35 // place. This class can not be instantiated outside the class and the objects |
| 42 // of this class type can be obtained only by calling a static method of this | 36 // of this class type can be obtained only by calling a static method of this |
| 43 // class. | 37 // class. |
| 44 class RegistryEntry { | 38 class RegistryEntry { |
| 45 public: | 39 public: |
| 46 // This method returns a list of all the registry entries that are needed | 40 // This method returns a list of all the registry entries that |
| 47 // to register Chrome. | 41 // are needed to register Chromium ProgIds. |
| 48 static std::list<RegistryEntry*> GetAllEntries( | 42 static bool GetProgIdEntries(const std::wstring& chrome_exe, |
| 49 const std::wstring& chrome_exe) { | 43 const std::wstring& suffix, |
| 50 std::list<RegistryEntry*> entries; | 44 std::list<RegistryEntry*>* entries) { |
| 51 std::wstring icon_path(chrome_exe); | 45 std::wstring icon_path = ShellUtil::GetChromeIcon(chrome_exe); |
| 52 ShellUtil::GetChromeIcon(icon_path); | |
| 53 std::wstring quoted_exe_path = L"\"" + chrome_exe + L"\""; | |
| 54 std::wstring open_cmd = ShellUtil::GetChromeShellOpenCmd(chrome_exe); | 46 std::wstring open_cmd = ShellUtil::GetChromeShellOpenCmd(chrome_exe); |
| 55 | 47 |
| 48 // File association ProgId |
| 56 std::wstring chrome_html_prog_id(ShellUtil::kRegClasses); | 49 std::wstring chrome_html_prog_id(ShellUtil::kRegClasses); |
| 57 file_util::AppendToPath(&chrome_html_prog_id, ShellUtil::kChromeHTMLProgId); | 50 file_util::AppendToPath(&chrome_html_prog_id, ShellUtil::kChromeHTMLProgId); |
| 58 entries.push_front(new RegistryEntry(chrome_html_prog_id, | 51 chrome_html_prog_id.append(suffix); |
| 59 ShellUtil::kChromeHTMLProgIdDesc)); | 52 entries->push_front(new RegistryEntry( |
| 60 entries.push_front(new RegistryEntry(chrome_html_prog_id, | 53 chrome_html_prog_id, ShellUtil::kChromeHTMLProgIdDesc)); |
| 61 ShellUtil::kRegUrlProtocol, L"")); | 54 entries->push_front(new RegistryEntry( |
| 62 entries.push_front(new RegistryEntry( | 55 chrome_html_prog_id, ShellUtil::kRegUrlProtocol, L"")); |
| 56 entries->push_front(new RegistryEntry( |
| 63 chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); | 57 chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); |
| 64 entries.push_front(new RegistryEntry( | 58 entries->push_front(new RegistryEntry( |
| 65 chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd)); | 59 chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd)); |
| 66 | 60 |
| 67 std::wstring exe_name = file_util::GetFilenameFromPath(chrome_exe); | 61 // Chrome Extension ProgId |
| 68 std::wstring app_key = L"Software\\Classes\\Applications\\" + exe_name + | 62 std::wstring ext_prog_id(ShellUtil::kRegClasses); |
| 69 L"\\shell\\open\\command"; | 63 file_util::AppendToPath(&ext_prog_id, ShellUtil::kChromeExtProgId); |
| 70 entries.push_front(new RegistryEntry(app_key, open_cmd)); | 64 ext_prog_id.append(suffix); |
| 71 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { | 65 entries->push_front(new RegistryEntry( |
| 72 std::wstring open_with_key(L"Software\\Classes\\"); | 66 ext_prog_id, ShellUtil::kChromeExtProgIdDesc)); |
| 73 open_with_key.append(ShellUtil::kFileAssociations[i]); | 67 entries->push_front(new RegistryEntry( |
| 74 open_with_key.append(L"\\OpenWithList\\" + exe_name); | 68 ext_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); |
| 75 entries.push_front(new RegistryEntry(open_with_key, std::wstring())); | |
| 76 } | |
| 77 | |
| 78 // Chrome Extension file handler | |
| 79 std::wstring install_cmd = | 69 std::wstring install_cmd = |
| 80 ShellUtil::GetChromeInstallExtensionCmd(chrome_exe); | 70 ShellUtil::GetChromeInstallExtensionCmd(chrome_exe); |
| 81 std::wstring prog_id = std::wstring(L"Software\\Classes\\") + | 71 entries->push_front(new RegistryEntry( |
| 82 ShellUtil::kChromeExtProgId; | 72 ext_prog_id + ShellUtil::kRegShellOpen, install_cmd)); |
| 83 entries.push_front(new RegistryEntry(prog_id, | 73 |
| 84 ShellUtil::kChromeExtProgIdDesc)); | 74 return true; |
| 85 entries.push_front(new RegistryEntry( | 75 } |
| 86 prog_id + ShellUtil::kRegDefaultIcon, icon_path)); | 76 |
| 87 entries.push_front(new RegistryEntry( | 77 // This method returns a list of all the system level registry entries that |
| 88 prog_id + ShellUtil::kRegShellOpen, install_cmd)); | 78 // are needed to register Chromium on the machine. |
| 79 static bool GetSystemEntries(const std::wstring& chrome_exe, |
| 80 const std::wstring& suffix, |
| 81 std::list<RegistryEntry*>* entries) { |
| 82 std::wstring icon_path = ShellUtil::GetChromeIcon(chrome_exe); |
| 83 std::wstring quoted_exe_path = L"\"" + chrome_exe + L"\""; |
| 89 | 84 |
| 90 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | 85 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| 86 std::wstring app_name = dist->GetApplicationName() + suffix; |
| 91 std::wstring start_menu_entry(ShellUtil::kRegStartMenuInternet); | 87 std::wstring start_menu_entry(ShellUtil::kRegStartMenuInternet); |
| 92 start_menu_entry.append(L"\\" + dist->GetApplicationName()); | 88 start_menu_entry.append(L"\\" + app_name); |
| 93 entries.push_front(new RegistryEntry(start_menu_entry, | 89 entries->push_front(new RegistryEntry(start_menu_entry, app_name)); |
| 94 dist->GetApplicationName())); | 90 entries->push_front(new RegistryEntry( |
| 95 entries.push_front(new RegistryEntry( | |
| 96 start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path)); | 91 start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path)); |
| 97 entries.push_front(new RegistryEntry( | 92 entries->push_front(new RegistryEntry( |
| 98 start_menu_entry + ShellUtil::kRegDefaultIcon, icon_path)); | 93 start_menu_entry + ShellUtil::kRegDefaultIcon, icon_path)); |
| 99 | 94 |
| 100 std::wstring install_info(start_menu_entry + L"\\InstallInfo"); | 95 std::wstring install_info(start_menu_entry + L"\\InstallInfo"); |
| 101 entries.push_front(new RegistryEntry(install_info, L"ReinstallCommand", | 96 entries->push_front(new RegistryEntry(install_info, L"ReinstallCommand", |
| 102 quoted_exe_path + L" --" + switches::kMakeDefaultBrowser)); | 97 quoted_exe_path + L" --" + switches::kMakeDefaultBrowser)); |
| 103 entries.push_front(new RegistryEntry(install_info, L"HideIconsCommand", | 98 entries->push_front(new RegistryEntry(install_info, L"HideIconsCommand", |
| 104 quoted_exe_path + L" --" + switches::kHideIcons)); | 99 quoted_exe_path + L" --" + switches::kHideIcons)); |
| 105 entries.push_front(new RegistryEntry(install_info, L"ShowIconsCommand", | 100 entries->push_front(new RegistryEntry(install_info, L"ShowIconsCommand", |
| 106 quoted_exe_path + L" --" + switches::kShowIcons)); | 101 quoted_exe_path + L" --" + switches::kShowIcons)); |
| 107 entries.push_front(new RegistryEntry(install_info, L"IconsVisible", 1)); | 102 entries->push_front(new RegistryEntry(install_info, L"IconsVisible", 1)); |
| 108 | 103 |
| 109 std::wstring capabilities(start_menu_entry + L"\\Capabilities"); | 104 std::wstring capabilities(start_menu_entry + L"\\Capabilities"); |
| 110 entries.push_front(new RegistryEntry(ShellUtil::kRegRegisteredApplications, | 105 entries->push_front(new RegistryEntry(ShellUtil::kRegRegisteredApplications, |
| 111 dist->GetApplicationName(), | 106 app_name, capabilities)); |
| 112 capabilities)); | 107 entries->push_front(new RegistryEntry( |
| 113 entries.push_front(new RegistryEntry( | |
| 114 capabilities, L"ApplicationDescription", dist->GetApplicationName())); | 108 capabilities, L"ApplicationDescription", dist->GetApplicationName())); |
| 115 entries.push_front(new RegistryEntry( | 109 entries->push_front(new RegistryEntry( |
| 116 capabilities, L"ApplicationIcon", icon_path)); | 110 capabilities, L"ApplicationIcon", icon_path)); |
| 117 entries.push_front(new RegistryEntry( | 111 entries->push_front(new RegistryEntry( |
| 118 capabilities, L"ApplicationName", dist->GetApplicationName())); | 112 capabilities, L"ApplicationName", app_name)); |
| 119 | 113 |
| 120 entries.push_front(new RegistryEntry(capabilities + L"\\StartMenu", | 114 entries->push_front(new RegistryEntry(capabilities + L"\\StartMenu", |
| 121 L"StartMenuInternet", dist->GetApplicationName())); | 115 L"StartMenuInternet", app_name)); |
| 116 |
| 117 std::wstring html_prog_id(ShellUtil::kChromeHTMLProgId); |
| 118 html_prog_id.append(suffix); |
| 122 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { | 119 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { |
| 123 entries.push_front(new RegistryEntry( | 120 entries->push_front(new RegistryEntry( |
| 124 capabilities + L"\\FileAssociations", | 121 capabilities + L"\\FileAssociations", |
| 125 ShellUtil::kFileAssociations[i], ShellUtil::kChromeHTMLProgId)); | 122 ShellUtil::kFileAssociations[i], html_prog_id)); |
| 126 } | 123 } |
| 127 entries.push_front(new RegistryEntry( | 124 for (int i = 0; ShellUtil::kProtocolAssociations[i] != NULL; i++) { |
| 125 entries->push_front(new RegistryEntry( |
| 126 capabilities + L"\\URLAssociations", |
| 127 ShellUtil::kProtocolAssociations[i], html_prog_id)); |
| 128 } |
| 129 std::wstring ext_prog_id(ShellUtil::kChromeExtProgId); |
| 130 ext_prog_id.append(suffix); |
| 131 entries->push_front(new RegistryEntry( |
| 128 capabilities + L"\\FileAssociations", | 132 capabilities + L"\\FileAssociations", |
| 129 chrome::kExtensionFileExtension, ShellUtil::kChromeExtProgId)); | 133 chrome::kExtensionFileExtension, ext_prog_id)); |
| 134 |
| 135 FilePath chrome_path(chrome_exe); |
| 136 std::wstring app_path_key(ShellUtil::kAppPathsRegistryKey); |
| 137 file_util::AppendToPath(&app_path_key, chrome_path.BaseName().value()); |
| 138 entries->push_front(new RegistryEntry(app_path_key, chrome_exe)); |
| 139 entries->push_front(new RegistryEntry(app_path_key, |
| 140 ShellUtil::kAppPathsRegistryPathName, chrome_path.DirName().value())); |
| 141 |
| 142 // TODO: add chrome to open with list (Bug 16726). |
| 143 return true; |
| 144 } |
| 145 |
| 146 // This method returns a list of all the user level registry entries that |
| 147 // are needed to make Chromium default browser. |
| 148 static bool GetUserEntries(const std::wstring& chrome_exe, |
| 149 const std::wstring& suffix, |
| 150 std::list<RegistryEntry*>* entries) { |
| 151 // File extension associations. |
| 152 std::wstring html_prog_id(ShellUtil::kChromeHTMLProgId); |
| 153 html_prog_id.append(suffix); |
| 154 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { |
| 155 std::wstring ext_key(ShellUtil::kRegClasses); |
| 156 file_util::AppendToPath(&ext_key, ShellUtil::kFileAssociations[i]); |
| 157 entries->push_front(new RegistryEntry(ext_key, html_prog_id)); |
| 158 } |
| 159 |
| 160 // .crx file type extension. |
| 161 std::wstring ext_key(ShellUtil::kRegClasses); |
| 162 ext_key.append(L"."); |
| 163 ext_key.append(chrome::kExtensionFileExtension); |
| 164 std::wstring ext_prog_id(ShellUtil::kChromeExtProgId); |
| 165 ext_prog_id.append(suffix); |
| 166 entries->push_front(new RegistryEntry(ext_key, ext_prog_id)); |
| 167 |
| 168 // Protocols associations. |
| 169 std::wstring chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); |
| 170 std::wstring chrome_icon = ShellUtil::GetChromeIcon(chrome_exe); |
| 130 for (int i = 0; ShellUtil::kProtocolAssociations[i] != NULL; i++) { | 171 for (int i = 0; ShellUtil::kProtocolAssociations[i] != NULL; i++) { |
| 131 entries.push_front(new RegistryEntry( | 172 std::wstring url_key(ShellUtil::kRegClasses); |
| 132 capabilities + L"\\URLAssociations", | 173 file_util::AppendToPath(&url_key, ShellUtil::kProtocolAssociations[i]); |
| 133 ShellUtil::kProtocolAssociations[i], ShellUtil::kChromeHTMLProgId)); | 174 |
| 175 // <root hkey>\Software\Classes\<protocol>\DefaultIcon |
| 176 std::wstring icon_key = url_key + ShellUtil::kRegDefaultIcon; |
| 177 entries->push_front(new RegistryEntry(icon_key, chrome_icon)); |
| 178 |
| 179 // <root hkey>\Software\Classes\<protocol>\shell\open\command |
| 180 std::wstring shell_key = url_key + ShellUtil::kRegShellOpen; |
| 181 entries->push_front(new RegistryEntry(shell_key, chrome_open)); |
| 182 |
| 183 // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec |
| 184 std::wstring dde_key = url_key + L"\\shell\\open\\ddeexec"; |
| 185 entries->push_front(new RegistryEntry(dde_key, L"")); |
| 186 |
| 187 // <root hkey>\Software\Classes\<protocol>\shell\@ |
| 188 std::wstring protocol_shell_key = url_key + ShellUtil::kRegShellPath; |
| 189 entries->push_front(new RegistryEntry(protocol_shell_key, L"open")); |
| 134 } | 190 } |
| 135 return entries; | 191 |
| 192 // start->Internet shortcut. |
| 193 std::wstring start_menu(ShellUtil::kRegStartMenuInternet); |
| 194 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| 195 entries->push_front(new RegistryEntry(start_menu, |
| 196 dist->GetApplicationName())); |
| 197 return true; |
| 136 } | 198 } |
| 137 | 199 |
| 138 // Generate work_item tasks required to create current registry entry and | 200 // Generate work_item tasks required to create current registry entry and |
| 139 // add them to the given work item list. | 201 // add them to the given work item list. |
| 140 void AddToWorkItemList(HKEY root, WorkItemList *items) { | 202 void AddToWorkItemList(HKEY root, WorkItemList *items) const { |
| 141 items->AddCreateRegKeyWorkItem(root, _key_path); | 203 items->AddCreateRegKeyWorkItem(root, _key_path); |
| 142 if (_is_string) { | 204 if (_is_string) { |
| 143 items->AddSetRegValueWorkItem(root, _key_path, _name, _value, true); | 205 items->AddSetRegValueWorkItem(root, _key_path, _name, _value, true); |
| 144 } else { | 206 } else { |
| 145 items->AddSetRegValueWorkItem(root, _key_path, _name, _int_value, true); | 207 items->AddSetRegValueWorkItem(root, _key_path, _name, _int_value, true); |
| 146 } | 208 } |
| 147 } | 209 } |
| 148 | 210 |
| 149 // Checks if the current registry entry exists in HKLM registry and the value | 211 // Checks if the current registry entry exists in HKLM registry and the value |
| 150 // is same. | 212 // is same. |
| 151 bool ExistsInHKLM() { | 213 bool ExistsInHKLM() const { |
| 152 RegKey key(HKEY_LOCAL_MACHINE, _key_path.c_str()); | 214 RegKey key(HKEY_LOCAL_MACHINE, _key_path.c_str()); |
| 153 bool found = false; | 215 bool found = false; |
| 154 if (_is_string) { | 216 if (_is_string) { |
| 155 std::wstring read_value; | 217 std::wstring read_value; |
| 156 found = (key.ReadValue(_name.c_str(), &read_value)) && | 218 found = (key.ReadValue(_name.c_str(), &read_value)) && |
| 157 (read_value.size() == _value.size()) && | 219 (read_value.size() == _value.size()) && |
| 158 (std::equal(_value.begin(), _value.end(), read_value.begin(), | 220 (std::equal(_value.begin(), _value.end(), read_value.begin(), |
| 159 CaseInsensitiveCompare<wchar_t>())); | 221 CaseInsensitiveCompare<wchar_t>())); |
| 160 } else { | 222 } else { |
| 161 DWORD read_value; | 223 DWORD read_value; |
| 162 found = key.ReadValueDW(_name.c_str(), &read_value) && | 224 found = key.ReadValueDW(_name.c_str(), &read_value) && |
| 163 read_value == _int_value; | 225 read_value == _int_value; |
| 164 } | 226 } |
| 165 key.Close(); | 227 key.Close(); |
| 166 return found; | 228 return found; |
| 167 } | 229 } |
| 168 | 230 |
| 169 // Checks if the current registry entry exists in HKLM registry | 231 // Checks if the current registry entry exists in HKLM registry |
| 170 // (only the name). | 232 // (only the name). |
| 171 bool NameExistsInHKLM() { | 233 bool NameExistsInHKLM() const { |
| 172 RegKey key(HKEY_LOCAL_MACHINE, _key_path.c_str()); | 234 RegKey key(HKEY_LOCAL_MACHINE, _key_path.c_str()); |
| 173 bool found = false; | 235 bool found = false; |
| 174 if (_is_string) { | 236 if (_is_string) { |
| 175 std::wstring read_value; | 237 std::wstring read_value; |
| 176 found = key.ReadValue(_name.c_str(), &read_value); | 238 found = key.ReadValue(_name.c_str(), &read_value); |
| 177 } else { | 239 } else { |
| 178 DWORD read_value; | 240 DWORD read_value; |
| 179 found = key.ReadValueDW(_name.c_str(), &read_value); | 241 found = key.ReadValueDW(_name.c_str(), &read_value); |
| 180 } | 242 } |
| 181 key.Close(); | 243 key.Close(); |
| 182 return found; | 244 return found; |
| 183 } | 245 } |
| 184 | 246 |
| 185 private: | 247 private: |
| 248 DISALLOW_COPY_AND_ASSIGN(RegistryEntry); |
| 249 |
| 186 // Create a object that represent default value of a key | 250 // Create a object that represent default value of a key |
| 187 RegistryEntry(const std::wstring& key_path, const std::wstring& value) | 251 RegistryEntry(const std::wstring& key_path, const std::wstring& value) |
| 188 : _key_path(key_path), _name(), | 252 : _key_path(key_path), _name(), |
| 189 _is_string(true), _value(value), _int_value(0) { | 253 _is_string(true), _value(value), _int_value(0) { |
| 190 } | 254 } |
| 191 | 255 |
| 192 // Create a object that represent a key of type REG_SZ | 256 // Create a object that represent a key of type REG_SZ |
| 193 RegistryEntry(const std::wstring& key_path, const std::wstring& name, | 257 RegistryEntry(const std::wstring& key_path, const std::wstring& name, |
| 194 const std::wstring& value) | 258 const std::wstring& value) |
| 195 : _key_path(key_path), _name(name), | 259 : _key_path(key_path), _name(name), |
| 196 _is_string(true), _value(value), _int_value(0) { | 260 _is_string(true), _value(value), _int_value(0) { |
| 197 } | 261 } |
| 198 | 262 |
| 199 // Create a object that represent a key of integer type | 263 // Create a object that represent a key of integer type |
| 200 RegistryEntry(const std::wstring& key_path, const std::wstring& name, | 264 RegistryEntry(const std::wstring& key_path, const std::wstring& name, |
| 201 DWORD value) | 265 DWORD value) |
| 202 : _key_path(key_path), _name(name), | 266 : _key_path(key_path), _name(name), |
| 203 _is_string(false), _value(), _int_value(value) { | 267 _is_string(false), _value(), _int_value(value) { |
| 204 } | 268 } |
| 205 | 269 |
| 206 std::wstring _key_path; // key path for the registry entry | 270 std::wstring _key_path; // key path for the registry entry |
| 207 std::wstring _name; // name of the registry entry | 271 std::wstring _name; // name of the registry entry |
| 208 bool _is_string; // true if current registry entry is of type REG_SZ | 272 bool _is_string; // true if current registry entry is of type REG_SZ |
| 209 std::wstring _value; // string value (useful if _is_string = true) | 273 std::wstring _value; // string value (useful if _is_string = true) |
| 210 DWORD _int_value; // integer value (useful if _is_string = false) | 274 DWORD _int_value; // integer value (useful if _is_string = false) |
| 211 }; // class RegistryEntry | 275 }; // class RegistryEntry |
| 212 | 276 |
| 213 | 277 |
| 214 // This method checks if Chrome is already registered on the local machine. | 278 // This method converts all the RegistryEntries from the given list to |
| 215 // It gets all the required registry entries for Chrome and then checks if | 279 // Set/CreateRegWorkItems and runs them using WorkItemList. |
| 216 // they exist in HKLM. Returns true if all the entries exist, otherwise false. | 280 bool AddRegistryEntries(HKEY root, const std::list<RegistryEntry*>& entries) { |
| 217 bool IsChromeRegistered(const std::wstring& chrome_exe) { | |
| 218 bool registered = true; | |
| 219 std::list<RegistryEntry*> entries = RegistryEntry::GetAllEntries(chrome_exe); | |
| 220 for (std::list<RegistryEntry*>::iterator itr = entries.begin(); | |
| 221 itr != entries.end(); ++itr) { | |
| 222 if (registered && !(*itr)->ExistsInHKLM()) | |
| 223 registered = false; | |
| 224 delete (*itr); | |
| 225 } | |
| 226 LOG(INFO) << "Check for Chrome registration returned " << registered; | |
| 227 return registered; | |
| 228 } | |
| 229 | |
| 230 bool BindChromeAssociations(HKEY root_key, const std::wstring& chrome_exe) { | |
| 231 // Create a list of registry entries to create so that we can rollback | |
| 232 // in case of problem. | |
| 233 scoped_ptr<WorkItemList> items(WorkItem::CreateWorkItemList()); | 281 scoped_ptr<WorkItemList> items(WorkItem::CreateWorkItemList()); |
| 234 | 282 |
| 235 // file extension associations | 283 for (std::list<RegistryEntry*>::const_iterator itr = entries.begin(); |
| 236 std::wstring classes_path(ShellUtil::kRegClasses); | 284 itr != entries.end(); ++itr) |
| 237 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { | 285 (*itr)->AddToWorkItemList(root, items.get()); |
| 238 std::wstring key_path = classes_path + L"\\" + | |
| 239 ShellUtil::kFileAssociations[i]; | |
| 240 items->AddCreateRegKeyWorkItem(root_key, key_path); | |
| 241 items->AddSetRegValueWorkItem(root_key, key_path, L"", | |
| 242 ShellUtil::kChromeHTMLProgId, true); | |
| 243 } | |
| 244 | |
| 245 // .crx file type extension | |
| 246 std::wstring file_extension_key = classes_path + L"\\." + | |
| 247 chrome::kExtensionFileExtension; | |
| 248 items->AddCreateRegKeyWorkItem(root_key, file_extension_key); | |
| 249 items->AddSetRegValueWorkItem(root_key, file_extension_key, L"", | |
| 250 ShellUtil::kChromeExtProgId, true); | |
| 251 | |
| 252 | |
| 253 // protocols associations | |
| 254 std::wstring chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); | |
| 255 std::wstring chrome_icon(chrome_exe); | |
| 256 ShellUtil::GetChromeIcon(chrome_icon); | |
| 257 for (int i = 0; ShellUtil::kProtocolAssociations[i] != NULL; i++) { | |
| 258 std::wstring key_path = classes_path + L"\\" + | |
| 259 ShellUtil::kProtocolAssociations[i]; | |
| 260 // <root hkey>\Software\Classes\<protocol>\DefaultIcon | |
| 261 std::wstring icon_path = key_path + ShellUtil::kRegDefaultIcon; | |
| 262 items->AddCreateRegKeyWorkItem(root_key, icon_path); | |
| 263 items->AddSetRegValueWorkItem(root_key, icon_path, L"", | |
| 264 chrome_icon, true); | |
| 265 // <root hkey>\Software\Classes\<protocol>\shell\open\command | |
| 266 std::wstring shell_path = key_path + ShellUtil::kRegShellOpen; | |
| 267 items->AddCreateRegKeyWorkItem(root_key, shell_path); | |
| 268 items->AddSetRegValueWorkItem(root_key, shell_path, L"", | |
| 269 chrome_open, true); | |
| 270 // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec | |
| 271 std::wstring dde_path = key_path + L"\\shell\\open\\ddeexec"; | |
| 272 items->AddCreateRegKeyWorkItem(root_key, dde_path); | |
| 273 items->AddSetRegValueWorkItem(root_key, dde_path, L"", L"", true); | |
| 274 // <root hkey>\Software\Classes\<protocol>\shell\@ | |
| 275 std::wstring protocol_shell_path = key_path + ShellUtil::kRegShellPath; | |
| 276 items->AddSetRegValueWorkItem(root_key, protocol_shell_path, L"", | |
| 277 L"open", true); | |
| 278 } | |
| 279 | |
| 280 // start->Internet shortcut. | |
| 281 std::wstring start_internet(ShellUtil::kRegStartMenuInternet); | |
| 282 items->AddCreateRegKeyWorkItem(root_key, start_internet); | |
| 283 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
| 284 items->AddSetRegValueWorkItem(root_key, start_internet, L"", | |
| 285 dist->GetApplicationName(), true); | |
| 286 | 286 |
| 287 // Apply all the registry changes and if there is a problem, rollback | 287 // Apply all the registry changes and if there is a problem, rollback |
| 288 if (!items->Do()) { | 288 if (!items->Do()) { |
| 289 LOG(ERROR) << "Error while registering Chrome as default browser"; | |
| 290 items->Rollback(); | 289 items->Rollback(); |
| 291 return false; | 290 return false; |
| 292 } | 291 } |
| 293 return true; | 292 return true; |
| 294 } | 293 } |
| 295 | 294 |
| 296 // Populate work_item_list with WorkItem entries that will add chrome.exe to | 295 // This method checks if Chrome is already registered on the local machine. |
| 297 // the set of App Paths registry keys so that ShellExecute can find it. Note | 296 // It gets all the required registry entries for Chrome and then checks if |
| 298 // that this is done in HKLM, regardless of whether this is a single-user | 297 // they exist in HKLM. Returns true if all the entries exist, otherwise false. |
| 299 // install or not. For non-admin users, this will fail. | 298 bool IsChromeRegistered(const std::wstring& chrome_exe, |
| 300 // chrome_exe: full path to chrome.exe | 299 const std::wstring& suffix) { |
| 301 // work_item_list: pointer to the WorkItemList that will be populated | 300 bool registered = true; |
| 302 void AddChromeAppPathWorkItems(const std::wstring& chrome_exe, | 301 std::list<RegistryEntry*> entries; |
| 303 WorkItemList* item_list) { | 302 STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries); |
| 304 FilePath chrome_path(chrome_exe); | 303 RegistryEntry::GetProgIdEntries(chrome_exe, suffix, &entries); |
| 305 std::wstring app_path_key(ShellUtil::kAppPathsRegistryKey); | 304 RegistryEntry::GetSystemEntries(chrome_exe, suffix, &entries); |
| 306 file_util::AppendToPath(&app_path_key, chrome_path.BaseName().value()); | 305 for (std::list<RegistryEntry*>::const_iterator itr = entries.begin(); |
| 307 item_list->AddCreateRegKeyWorkItem(HKEY_LOCAL_MACHINE, app_path_key); | 306 itr != entries.end() && registered; ++itr) { |
| 308 item_list->AddSetRegValueWorkItem(HKEY_LOCAL_MACHINE, app_path_key, L"", | 307 // We do not need registered = registered && ... since the loop condition |
| 309 chrome_exe, true); | 308 // is set to exit early. |
| 310 item_list->AddSetRegValueWorkItem(HKEY_LOCAL_MACHINE, app_path_key, | 309 registered = (*itr)->ExistsInHKLM(); |
| 311 ShellUtil::kAppPathsRegistryPathName, | 310 } |
| 312 chrome_path.DirName().value(), true); | 311 return registered; |
| 313 } | 312 } |
| 314 | 313 |
| 315 // This method creates the registry entries required for Add/Remove Programs-> | 314 // This method registers Chrome on Vista by launching eleavated setup.exe. |
| 316 // Set Program Access and Defaults, Start->Default Programs on Windows Vista | 315 // That will show user standard Vista elevation prompt. If user accepts it |
| 317 // and Chrome ProgIds for file extension and protocol handler. root_key is | 316 // the new process will make the necessary changes and return SUCCESS that |
| 318 // the root registry (HKLM or HKCU). | 317 // we capture and return. |
| 319 bool SetAccessDefaultRegEntries(HKEY root_key, | 318 bool ElevateAndRegisterChrome(const std::wstring& chrome_exe, |
| 320 const std::wstring& chrome_exe) { | 319 const std::wstring& suffix) { |
| 321 LOG(INFO) << "Registering Chrome browser " << chrome_exe; | 320 std::wstring exe_path(file_util::GetDirectoryFromPath(chrome_exe)); |
| 322 // Create a list of registry entries work items so that we can rollback | 321 file_util::AppendToPath(&exe_path, installer_util::kSetupExe); |
| 323 // in case of problem. | 322 if (!file_util::PathExists(exe_path)) { |
| 324 scoped_ptr<WorkItemList> items(WorkItem::CreateWorkItemList()); | 323 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| 324 HKEY reg_root = InstallUtil::IsPerUserInstall(chrome_exe.c_str()) ? |
| 325 HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; |
| 326 RegKey key(reg_root, dist->GetUninstallRegPath().c_str()); |
| 327 key.ReadValue(installer_util::kUninstallStringField, &exe_path); |
| 328 CommandLine command_line(L""); |
| 329 command_line.ParseFromString(exe_path); |
| 330 exe_path = command_line.program(); |
| 331 } |
| 332 if (file_util::PathExists(exe_path)) { |
| 333 std::wstring params(L"--"); |
| 334 params.append(installer_util::switches::kRegisterChromeBrowser); |
| 335 params.append(L"=\"" + chrome_exe + L"\""); |
| 336 if (!suffix.empty()) { |
| 337 params.append(L"--"); |
| 338 params.append(installer_util::switches::kRegisterChromeBrowserSuffix); |
| 339 params.append(L"=\"" + suffix + L"\""); |
| 340 } |
| 341 DWORD ret_val = 0; |
| 342 InstallUtil::ExecuteExeAsAdmin(exe_path, params, &ret_val); |
| 343 if (ret_val == 0) |
| 344 return true; |
| 345 } |
| 346 return false; |
| 347 } |
| 325 | 348 |
| 326 std::list<RegistryEntry*> entries = RegistryEntry::GetAllEntries(chrome_exe); | 349 // This method checks if user specific default browser registry entry exists. |
| 327 for (std::list<RegistryEntry*>::iterator itr = entries.begin(); | 350 // (i.e. Software\Clients\StartMenuInternet\Chromium.<user>) |
| 328 itr != entries.end(); ++itr) { | 351 bool UserSpecificDefaultBrowserEntryExists() { |
| 329 (*itr)->AddToWorkItemList(root_key, items.get()); | 352 std::wstring suffix; |
| 330 delete (*itr); | 353 if (!ShellUtil::GetUserSpecificDefaultBrowserSuffix(&suffix)) |
| 354 return false; |
| 355 |
| 356 std::wstring start_menu_entry(ShellUtil::kRegStartMenuInternet); |
| 357 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| 358 start_menu_entry.append(L"\\" + dist->GetApplicationName() + suffix); |
| 359 RegKey key(HKEY_LOCAL_MACHINE, start_menu_entry.c_str()); |
| 360 return key.Valid(); |
| 361 } |
| 362 |
| 363 // This method tries to figure out if another user has already registered her |
| 364 // own copy of Chrome so that we can avoid overwriting it and append current |
| 365 // user's login name to default browser registry entries. This function is |
| 366 // not meant to detect all cases. It just tries to handle the most common case. |
| 367 // All the conditions below have to be true for it to return true: |
| 368 // - Software\Clients\StartMenuInternet\Chromium\"" key should have a valid |
| 369 // value. |
| 370 // - The value should not be same as given value in |chrome_exe| |
| 371 // - Finally to handle the default install path (C:\Document and Settings\ |
| 372 // <user>\Local Settings\Application Data\Chromium\Application) the value |
| 373 // of the above key should differ from |chrome_exe| only in user name. |
| 374 bool AnotherUserHasDefaultBrowser(const std::wstring& chrome_exe) { |
| 375 std::wstring reg_key(ShellUtil::kRegStartMenuInternet); |
| 376 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| 377 reg_key.append(L"\\" + dist->GetApplicationName() + ShellUtil::kRegShellOpen); |
| 378 RegKey key(HKEY_LOCAL_MACHINE, reg_key.c_str()); |
| 379 std::wstring registry_chrome_exe; |
| 380 if (!key.ReadValue(L"", ®istry_chrome_exe) || |
| 381 registry_chrome_exe.length() < 2) |
| 382 return false; |
| 383 |
| 384 registry_chrome_exe = registry_chrome_exe.substr(1, |
| 385 registry_chrome_exe.length() - 2); |
| 386 if ((registry_chrome_exe.size() == chrome_exe.size()) && |
| 387 (std::equal(chrome_exe.begin(), chrome_exe.end(), |
| 388 registry_chrome_exe.begin(), |
| 389 CaseInsensitiveCompare<wchar_t>()))) |
| 390 return false; |
| 391 |
| 392 std::vector<std::wstring> v1, v2; |
| 393 SplitString(registry_chrome_exe, L'\\', &v1); |
| 394 SplitString(chrome_exe, L'\\', &v2); |
| 395 if (v1.size() == 0 || v2.size() == 0 || v1.size() != v2.size()) |
| 396 return false; |
| 397 |
| 398 // Now check that only one of the values within two '\' chars differ. |
| 399 std::vector<std::wstring>::iterator itr1 = v1.begin(); |
| 400 std::vector<std::wstring>::iterator itr2 = v2.begin(); |
| 401 bool one_mismatch = false; |
| 402 for ( ; itr1 < v1.end() && itr2 < v2.end(); ++itr1, ++itr2) { |
| 403 std::wstring s1 = *itr1; |
| 404 std::wstring s2 = *itr2; |
| 405 if ((s1.size() != s2.size()) || |
| 406 (!std::equal(s1.begin(), s1.end(), |
| 407 s2.begin(), CaseInsensitiveCompare<wchar_t>()))) { |
| 408 if (one_mismatch) |
| 409 return false; |
| 410 else |
| 411 one_mismatch = true; |
| 412 } |
| 331 } | 413 } |
| 332 | |
| 333 // Append the App Paths registry entries. Do this only if we are an admin, | |
| 334 // since they are always written to HKLM. | |
| 335 if (IsUserAnAdmin()) | |
| 336 AddChromeAppPathWorkItems(chrome_exe, items.get()); | |
| 337 | |
| 338 // Apply all the registry changes and if there is a problem, rollback. | |
| 339 if (!items->Do()) { | |
| 340 LOG(ERROR) << "Failed to add Chrome to Set Program Access and Defaults"; | |
| 341 items->Rollback(); | |
| 342 return false; | |
| 343 } | |
| 344 | |
| 345 return true; | 414 return true; |
| 346 } | 415 } |
| 347 | 416 |
| 348 | |
| 349 // This method registers Chrome on Vista. It checks if we are currently | |
| 350 // running as admin and if not, it launches setup.exe as administrator which | |
| 351 // will show user standard Vista elevation prompt. If user accepts it | |
| 352 // the new process will make the necessary changes and return SUCCESS that | |
| 353 // we capture and return. | |
| 354 ShellUtil::RegisterStatus RegisterOnVista(const std::wstring& chrome_exe, | |
| 355 bool skip_if_not_admin) { | |
| 356 if (IsUserAnAdmin() && | |
| 357 SetAccessDefaultRegEntries(HKEY_LOCAL_MACHINE, chrome_exe)) | |
| 358 return ShellUtil::SUCCESS; | |
| 359 | |
| 360 if (!skip_if_not_admin) { | |
| 361 std::wstring exe_path(file_util::GetDirectoryFromPath(chrome_exe)); | |
| 362 file_util::AppendToPath(&exe_path, installer_util::kSetupExe); | |
| 363 if (!file_util::PathExists(exe_path)) { | |
| 364 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
| 365 HKEY reg_root = InstallUtil::IsPerUserInstall(chrome_exe.c_str()) ? | |
| 366 HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; | |
| 367 RegKey key(reg_root, dist->GetUninstallRegPath().c_str()); | |
| 368 key.ReadValue(installer_util::kUninstallStringField, &exe_path); | |
| 369 CommandLine command_line(L""); | |
| 370 command_line.ParseFromString(exe_path); | |
| 371 exe_path = command_line.program(); | |
| 372 } | |
| 373 if (file_util::PathExists(exe_path)) { | |
| 374 std::wstring params(L"--"); | |
| 375 params.append(installer_util::switches::kRegisterChromeBrowser); | |
| 376 params.append(L"=\"" + chrome_exe + L"\""); | |
| 377 DWORD ret_val = ShellUtil::SUCCESS; | |
| 378 InstallUtil::ExecuteExeAsAdmin(exe_path, params, &ret_val); | |
| 379 if (ret_val == ShellUtil::SUCCESS) | |
| 380 return ShellUtil::SUCCESS; | |
| 381 } | |
| 382 } | |
| 383 return ShellUtil::FAILURE; | |
| 384 } | |
| 385 | |
| 386 } // namespace | 417 } // namespace |
| 387 | 418 |
| 388 | 419 |
| 389 const wchar_t* ShellUtil::kRegDefaultIcon = L"\\DefaultIcon"; | 420 const wchar_t* ShellUtil::kRegDefaultIcon = L"\\DefaultIcon"; |
| 390 const wchar_t* ShellUtil::kRegShellPath = L"\\shell"; | 421 const wchar_t* ShellUtil::kRegShellPath = L"\\shell"; |
| 391 const wchar_t* ShellUtil::kRegShellOpen = L"\\shell\\open\\command"; | 422 const wchar_t* ShellUtil::kRegShellOpen = L"\\shell\\open\\command"; |
| 392 const wchar_t* ShellUtil::kRegStartMenuInternet = | 423 const wchar_t* ShellUtil::kRegStartMenuInternet = |
| 393 L"Software\\Clients\\StartMenuInternet"; | 424 L"Software\\Clients\\StartMenuInternet"; |
| 394 const wchar_t* ShellUtil::kRegClasses = L"Software\\Classes"; | 425 const wchar_t* ShellUtil::kRegClasses = L"Software\\Classes"; |
| 395 const wchar_t* ShellUtil::kRegRegisteredApplications = | 426 const wchar_t* ShellUtil::kRegRegisteredApplications = |
| 396 L"Software\\RegisteredApplications"; | 427 L"Software\\RegisteredApplications"; |
| 397 const wchar_t* ShellUtil::kRegVistaUrlPrefs = | 428 const wchar_t* ShellUtil::kRegVistaUrlPrefs = |
| 398 L"Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\" | 429 L"Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\" |
| 399 L"http\\UserChoice"; | 430 L"http\\UserChoice"; |
| 400 const wchar_t* ShellUtil::kAppPathsRegistryKey = | 431 const wchar_t* ShellUtil::kAppPathsRegistryKey = |
| 401 L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths"; | 432 L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths"; |
| 402 const wchar_t* ShellUtil::kAppPathsRegistryPathName = L"Path"; | 433 const wchar_t* ShellUtil::kAppPathsRegistryPathName = L"Path"; |
| 403 | 434 |
| 404 #if defined(GOOGLE_CHROME_BUILD) | 435 #if defined(GOOGLE_CHROME_BUILD) |
| 405 const wchar_t* ShellUtil::kChromeExtProgId = L"ChromeExt"; | 436 const wchar_t* ShellUtil::kChromeExtProgId = L"ChromeExt"; |
| 406 const wchar_t* ShellUtil::kChromeHTMLProgId = L"ChromeHTML"; | 437 const wchar_t* ShellUtil::kChromeHTMLProgId = L"ChromeHTML"; |
| 407 const wchar_t* ShellUtil::kChromeHTMLProgIdDesc = L"Chrome HTML"; | 438 const wchar_t* ShellUtil::kChromeHTMLProgIdDesc = L"Chrome HTML Document"; |
| 408 #else | 439 #else |
| 409 const wchar_t* ShellUtil::kChromeExtProgId = L"ChromiumExt"; | 440 const wchar_t* ShellUtil::kChromeExtProgId = L"ChromiumExt"; |
| 410 const wchar_t* ShellUtil::kChromeHTMLProgId = L"ChromiumHTML"; | 441 const wchar_t* ShellUtil::kChromeHTMLProgId = L"ChromiumHTML"; |
| 411 const wchar_t* ShellUtil::kChromeHTMLProgIdDesc = L"Chromium HTML"; | 442 const wchar_t* ShellUtil::kChromeHTMLProgIdDesc = L"Chromium HTML Document"; |
| 412 #endif | 443 #endif |
| 413 | 444 |
| 414 const wchar_t* ShellUtil::kFileAssociations[] = {L".htm", L".html", L".shtml", | 445 const wchar_t* ShellUtil::kFileAssociations[] = {L".htm", L".html", L".shtml", |
| 415 L".xht", L".xhtml", NULL}; | 446 L".xht", L".xhtml", NULL}; |
| 416 const wchar_t* ShellUtil::kProtocolAssociations[] = {L"ftp", L"http", L"https", | 447 const wchar_t* ShellUtil::kProtocolAssociations[] = {L"ftp", L"http", L"https", |
| 417 NULL}; | 448 NULL}; |
| 418 const wchar_t* ShellUtil::kRegUrlProtocol = L"URL Protocol"; | 449 const wchar_t* ShellUtil::kRegUrlProtocol = L"URL Protocol"; |
| 419 | 450 |
| 420 const wchar_t* ShellUtil::kChromeExtProgIdDesc = L"Chrome Extension Installer"; | 451 const wchar_t* ShellUtil::kChromeExtProgIdDesc = L"Chrome Extension Installer"; |
| 421 | 452 |
| 422 ShellUtil::RegisterStatus ShellUtil::AddChromeToSetAccessDefaults( | |
| 423 const std::wstring& chrome_exe, bool skip_if_not_admin) { | |
| 424 if (IsChromeRegistered(chrome_exe)) | |
| 425 return ShellUtil::SUCCESS; | |
| 426 | |
| 427 if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) | |
| 428 return RegisterOnVista(chrome_exe, skip_if_not_admin); | |
| 429 | |
| 430 // Try adding these entries to HKLM first and if that fails try adding | |
| 431 // to HKCU. | |
| 432 if (SetAccessDefaultRegEntries(HKEY_LOCAL_MACHINE, chrome_exe)) | |
| 433 return ShellUtil::SUCCESS; | |
| 434 | |
| 435 if (!skip_if_not_admin && | |
| 436 SetAccessDefaultRegEntries(HKEY_CURRENT_USER, chrome_exe)) | |
| 437 return ShellUtil::REGISTERED_PER_USER; | |
| 438 | |
| 439 return ShellUtil::FAILURE; | |
| 440 } | |
| 441 | |
| 442 bool ShellUtil::AdminNeededForRegistryCleanup() { | 453 bool ShellUtil::AdminNeededForRegistryCleanup() { |
| 443 bool cleanup_needed = false; | 454 bool cleanup_needed = false; |
| 444 std::list<RegistryEntry*> entries = RegistryEntry::GetAllEntries( | 455 std::list<RegistryEntry*> entries; |
| 445 installer_util::kChromeExe); | 456 STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries); |
| 446 for (std::list<RegistryEntry*>::iterator itr = entries.begin(); | 457 RegistryEntry::GetProgIdEntries(L"chrome.exe", L"", &entries); |
| 447 itr != entries.end(); ++itr) { | 458 RegistryEntry::GetSystemEntries(L"chrome.exe", L"", &entries); |
| 448 if (!cleanup_needed && (*itr)->NameExistsInHKLM()) | 459 |
| 449 cleanup_needed = true; | 460 std::wstring suffix; |
| 450 delete (*itr); | 461 GetUserSpecificDefaultBrowserSuffix(&suffix); |
| 462 RegistryEntry::GetProgIdEntries(L"chrome.exe", suffix, &entries); |
| 463 RegistryEntry::GetSystemEntries(L"chrome.exe", suffix, &entries); |
| 464 for (std::list<RegistryEntry*>::const_iterator itr = entries.begin(); |
| 465 itr != entries.end() && !cleanup_needed; ++itr) { |
| 466 cleanup_needed = (*itr)->NameExistsInHKLM(); |
| 451 } | 467 } |
| 452 return cleanup_needed; | 468 return cleanup_needed; |
| 453 } | 469 } |
| 454 | 470 |
| 455 bool ShellUtil::GetChromeIcon(std::wstring& chrome_icon) { | |
| 456 if (chrome_icon.empty()) | |
| 457 return false; | |
| 458 | |
| 459 chrome_icon.append(L",0"); | |
| 460 return true; | |
| 461 } | |
| 462 | |
| 463 std::wstring ShellUtil::GetChromeShellOpenCmd(const std::wstring& chrome_exe) { | |
| 464 return L"\"" + chrome_exe + L"\" -- \"%1\""; | |
| 465 } | |
| 466 | |
| 467 std::wstring ShellUtil::GetChromeInstallExtensionCmd( | |
| 468 const std::wstring& chrome_exe) { | |
| 469 return L"\"" + chrome_exe + L"\" --install-extension=\"%1\""; | |
| 470 } | |
| 471 | |
| 472 bool ShellUtil::GetChromeShortcutName(std::wstring* shortcut, bool alternate) { | |
| 473 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
| 474 shortcut->assign(alternate ? dist->GetAlternateApplicationName() : | |
| 475 dist->GetApplicationName()); | |
| 476 shortcut->append(L".lnk"); | |
| 477 return true; | |
| 478 } | |
| 479 | |
| 480 bool ShellUtil::GetDesktopPath(bool system_level, std::wstring* path) { | |
| 481 wchar_t desktop[MAX_PATH]; | |
| 482 int dir = system_level ? CSIDL_COMMON_DESKTOPDIRECTORY : | |
| 483 CSIDL_DESKTOPDIRECTORY; | |
| 484 if (FAILED(SHGetFolderPath(NULL, dir, NULL, SHGFP_TYPE_CURRENT, desktop))) | |
| 485 return false; | |
| 486 *path = desktop; | |
| 487 return true; | |
| 488 } | |
| 489 | |
| 490 bool ShellUtil::GetQuickLaunchPath(bool system_level, std::wstring* path) { | |
| 491 const static wchar_t* kQuickLaunchPath = | |
| 492 L"Microsoft\\Internet Explorer\\Quick Launch"; | |
| 493 wchar_t qlaunch[MAX_PATH]; | |
| 494 if (system_level) { | |
| 495 // We are accessing GetDefaultUserProfileDirectory this way so that we do | |
| 496 // not have to declare dependency to Userenv.lib for chrome.exe | |
| 497 typedef BOOL (WINAPI *PROFILE_FUNC)(LPWSTR, LPDWORD); | |
| 498 HMODULE module = LoadLibrary(L"Userenv.dll"); | |
| 499 PROFILE_FUNC p = reinterpret_cast<PROFILE_FUNC>(GetProcAddress(module, | |
| 500 "GetDefaultUserProfileDirectoryW")); | |
| 501 DWORD size = _countof(qlaunch); | |
| 502 if ((p == NULL) || ((p)(qlaunch, &size) != TRUE)) | |
| 503 return false; | |
| 504 *path = qlaunch; | |
| 505 if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) { | |
| 506 file_util::AppendToPath(path, L"AppData\\Roaming"); | |
| 507 } else { | |
| 508 file_util::AppendToPath(path, L"Application Data"); | |
| 509 } | |
| 510 } else { | |
| 511 if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, | |
| 512 SHGFP_TYPE_CURRENT, qlaunch))) | |
| 513 return false; | |
| 514 *path = qlaunch; | |
| 515 } | |
| 516 file_util::AppendToPath(path, kQuickLaunchPath); | |
| 517 return true; | |
| 518 } | |
| 519 | |
| 520 bool ShellUtil::CreateChromeDesktopShortcut(const std::wstring& chrome_exe, | 471 bool ShellUtil::CreateChromeDesktopShortcut(const std::wstring& chrome_exe, |
| 521 const std::wstring& description, | 472 const std::wstring& description, |
| 522 int shell_change, bool alternate, | 473 int shell_change, bool alternate, |
| 523 bool create_new) { | 474 bool create_new) { |
| 524 std::wstring shortcut_name; | 475 std::wstring shortcut_name; |
| 525 if (!ShellUtil::GetChromeShortcutName(&shortcut_name, alternate)) | 476 if (!ShellUtil::GetChromeShortcutName(&shortcut_name, alternate)) |
| 526 return false; | 477 return false; |
| 527 | 478 |
| 528 bool ret = true; | 479 bool ret = true; |
| 529 if (shell_change & ShellUtil::CURRENT_USER) { | 480 if (shell_change & ShellUtil::CURRENT_USER) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 ret = ShellUtil::UpdateChromeShortcut(chrome_exe, default_ql_path, | 531 ret = ShellUtil::UpdateChromeShortcut(chrome_exe, default_ql_path, |
| 581 L"", create_new) && ret; | 532 L"", create_new) && ret; |
| 582 } else { | 533 } else { |
| 583 ret = false; | 534 ret = false; |
| 584 } | 535 } |
| 585 } | 536 } |
| 586 | 537 |
| 587 return ret; | 538 return ret; |
| 588 } | 539 } |
| 589 | 540 |
| 541 std::wstring ShellUtil::GetChromeIcon(const std::wstring& chrome_exe) { |
| 542 std::wstring chrome_icon(chrome_exe); |
| 543 chrome_icon.append(L",0"); |
| 544 return chrome_icon; |
| 545 } |
| 546 |
| 547 std::wstring ShellUtil::GetChromeInstallExtensionCmd( |
| 548 const std::wstring& chrome_exe) { |
| 549 return L"\"" + chrome_exe + L"\" --install-extension=\"%1\""; |
| 550 } |
| 551 |
| 552 std::wstring ShellUtil::GetChromeShellOpenCmd(const std::wstring& chrome_exe) { |
| 553 return L"\"" + chrome_exe + L"\" -- \"%1\""; |
| 554 } |
| 555 |
| 556 bool ShellUtil::GetChromeShortcutName(std::wstring* shortcut, bool alternate) { |
| 557 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| 558 shortcut->assign(alternate ? dist->GetAlternateApplicationName() : |
| 559 dist->GetApplicationName()); |
| 560 shortcut->append(L".lnk"); |
| 561 return true; |
| 562 } |
| 563 |
| 564 bool ShellUtil::GetDesktopPath(bool system_level, std::wstring* path) { |
| 565 wchar_t desktop[MAX_PATH]; |
| 566 int dir = system_level ? CSIDL_COMMON_DESKTOPDIRECTORY : |
| 567 CSIDL_DESKTOPDIRECTORY; |
| 568 if (FAILED(SHGetFolderPath(NULL, dir, NULL, SHGFP_TYPE_CURRENT, desktop))) |
| 569 return false; |
| 570 *path = desktop; |
| 571 return true; |
| 572 } |
| 573 |
| 574 bool ShellUtil::GetQuickLaunchPath(bool system_level, std::wstring* path) { |
| 575 const static wchar_t* kQuickLaunchPath = |
| 576 L"Microsoft\\Internet Explorer\\Quick Launch"; |
| 577 wchar_t qlaunch[MAX_PATH]; |
| 578 if (system_level) { |
| 579 // We are accessing GetDefaultUserProfileDirectory this way so that we do |
| 580 // not have to declare dependency to Userenv.lib for chrome.exe |
| 581 typedef BOOL (WINAPI *PROFILE_FUNC)(LPWSTR, LPDWORD); |
| 582 HMODULE module = LoadLibrary(L"Userenv.dll"); |
| 583 PROFILE_FUNC p = reinterpret_cast<PROFILE_FUNC>(GetProcAddress(module, |
| 584 "GetDefaultUserProfileDirectoryW")); |
| 585 DWORD size = _countof(qlaunch); |
| 586 if ((p == NULL) || ((p)(qlaunch, &size) != TRUE)) |
| 587 return false; |
| 588 *path = qlaunch; |
| 589 if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) { |
| 590 file_util::AppendToPath(path, L"AppData\\Roaming"); |
| 591 } else { |
| 592 file_util::AppendToPath(path, L"Application Data"); |
| 593 } |
| 594 } else { |
| 595 if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, |
| 596 SHGFP_TYPE_CURRENT, qlaunch))) |
| 597 return false; |
| 598 *path = qlaunch; |
| 599 } |
| 600 file_util::AppendToPath(path, kQuickLaunchPath); |
| 601 return true; |
| 602 } |
| 603 |
| 604 bool ShellUtil::GetUserSpecificDefaultBrowserSuffix(std::wstring* entry) { |
| 605 wchar_t user_name[256]; |
| 606 DWORD size = _countof(user_name); |
| 607 if (::GetUserName(user_name, &size) == 0) |
| 608 return false; |
| 609 entry->assign(L"."); |
| 610 entry->append(user_name); |
| 611 return true; |
| 612 } |
| 613 |
| 590 bool ShellUtil::MakeChromeDefault(int shell_change, | 614 bool ShellUtil::MakeChromeDefault(int shell_change, |
| 591 const std::wstring& chrome_exe) { | 615 const std::wstring& chrome_exe, |
| 616 bool elevate_if_not_admin) { |
| 617 ShellUtil::RegisterChromeBrowser(chrome_exe, L"", elevate_if_not_admin); |
| 618 |
| 592 bool ret = true; | 619 bool ret = true; |
| 593 // First use the new "recommended" way on Vista to make Chrome default | 620 // First use the new "recommended" way on Vista to make Chrome default |
| 594 // browser. | 621 // browser. |
| 595 if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) { | 622 if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) { |
| 596 LOG(INFO) << "Registering Chrome as default browser on Vista."; | 623 LOG(INFO) << "Registering Chrome as default browser on Vista."; |
| 597 IApplicationAssociationRegistration* pAAR; | 624 IApplicationAssociationRegistration* pAAR; |
| 598 HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration, | 625 HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration, |
| 599 NULL, CLSCTX_INPROC, __uuidof(IApplicationAssociationRegistration), | 626 NULL, CLSCTX_INPROC, __uuidof(IApplicationAssociationRegistration), |
| 600 (void**)&pAAR); | 627 (void**)&pAAR); |
| 601 if (SUCCEEDED(hr)) { | 628 if (SUCCEEDED(hr)) { |
| 602 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | 629 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| 603 hr = pAAR->SetAppAsDefaultAll(dist->GetApplicationName().c_str()); | 630 hr = pAAR->SetAppAsDefaultAll(dist->GetApplicationName().c_str()); |
| 604 pAAR->Release(); | 631 pAAR->Release(); |
| 605 } | 632 } |
| 606 if (!SUCCEEDED(hr)) { | 633 if (!SUCCEEDED(hr)) { |
| 607 ret = false; | 634 ret = false; |
| 608 LOG(ERROR) << "Could not make Chrome default browser."; | 635 LOG(ERROR) << "Could not make Chrome default browser."; |
| 609 } | 636 } |
| 610 } | 637 } |
| 611 | 638 |
| 612 // Now use the old way to associate Chrome with supported protocols and file | 639 // Now use the old way to associate Chrome with supported protocols and file |
| 613 // associations. This should not be required on Vista but since some | 640 // associations. This should not be required on Vista but since some |
| 614 // applications still read Software\Classes\http key directly, we have to do | 641 // applications still read Software\Classes\http key directly, we have to do |
| 615 // this on Vista also. | 642 // this on Vista also. |
| 643 |
| 644 std::list<RegistryEntry*> entries; |
| 645 STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries); |
| 646 std::wstring suffix; |
| 647 if (UserSpecificDefaultBrowserEntryExists()) |
| 648 GetUserSpecificDefaultBrowserSuffix(&suffix); |
| 649 RegistryEntry::GetUserEntries(chrome_exe, suffix, &entries); |
| 616 // Change the default browser for current user. | 650 // Change the default browser for current user. |
| 617 if ((shell_change & ShellUtil::CURRENT_USER) && | 651 if ((shell_change & ShellUtil::CURRENT_USER) && |
| 618 !BindChromeAssociations(HKEY_CURRENT_USER, chrome_exe)) | 652 !AddRegistryEntries(HKEY_CURRENT_USER, entries)) |
| 619 ret = false; | 653 ret = false; |
| 620 | 654 |
| 621 // Chrome as default browser at system level. | 655 // Chrome as default browser at system level. |
| 622 if ((shell_change & ShellUtil::SYSTEM_LEVEL) && | 656 if ((shell_change & ShellUtil::SYSTEM_LEVEL) && |
| 623 !BindChromeAssociations(HKEY_LOCAL_MACHINE, chrome_exe)) | 657 !AddRegistryEntries(HKEY_LOCAL_MACHINE, entries)) |
| 624 ret = false; | 658 ret = false; |
| 625 | 659 |
| 626 // Send Windows notification event so that it can update icons for | 660 // Send Windows notification event so that it can update icons for |
| 627 // file associations. | 661 // file associations. |
| 628 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); | 662 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); |
| 629 return ret; | 663 return ret; |
| 630 } | 664 } |
| 631 | 665 |
| 666 bool ShellUtil::RegisterChromeBrowser(const std::wstring& chrome_exe, |
| 667 const std::wstring& unique_suffix, |
| 668 bool elevate_if_not_admin) { |
| 669 // First figure out we need to append a suffix to the registry entries to |
| 670 // make them unique. |
| 671 std::wstring suffix; |
| 672 if (!unique_suffix.empty()) { |
| 673 suffix = unique_suffix; |
| 674 } else if (InstallUtil::IsPerUserInstall(chrome_exe.c_str()) && |
| 675 (UserSpecificDefaultBrowserEntryExists() || |
| 676 AnotherUserHasDefaultBrowser(chrome_exe))) { |
| 677 GetUserSpecificDefaultBrowserSuffix(&suffix); |
| 678 } |
| 679 |
| 680 // Check if Chromium is already registered with this suffix. |
| 681 if (IsChromeRegistered(chrome_exe, suffix)) |
| 682 return true; |
| 683 |
| 684 // If user is an admin try to register and return the status. |
| 685 if (IsUserAnAdmin()) { |
| 686 std::list<RegistryEntry*> entries; |
| 687 STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries); |
| 688 RegistryEntry::GetProgIdEntries(chrome_exe, suffix, &entries); |
| 689 RegistryEntry::GetSystemEntries(chrome_exe, suffix, &entries); |
| 690 return AddRegistryEntries(HKEY_LOCAL_MACHINE, entries); |
| 691 } |
| 692 |
| 693 // If user is not an admin and OS is Vista, try to elevate and register. |
| 694 if (elevate_if_not_admin && |
| 695 win_util::GetWinVersion() >= win_util::WINVERSION_VISTA && |
| 696 ElevateAndRegisterChrome(chrome_exe, suffix)) |
| 697 return true; |
| 698 |
| 699 // If we got to this point then all we can do is create ProgIds under HKCU |
| 700 // on XP as well as Vista. |
| 701 std::list<RegistryEntry*> entries; |
| 702 STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries); |
| 703 RegistryEntry::GetProgIdEntries(chrome_exe, L"", &entries); |
| 704 return AddRegistryEntries(HKEY_CURRENT_USER, entries); |
| 705 } |
| 706 |
| 632 bool ShellUtil::RemoveChromeDesktopShortcut(int shell_change, bool alternate) { | 707 bool ShellUtil::RemoveChromeDesktopShortcut(int shell_change, bool alternate) { |
| 633 std::wstring shortcut_name; | 708 std::wstring shortcut_name; |
| 634 if (!ShellUtil::GetChromeShortcutName(&shortcut_name, alternate)) | 709 if (!ShellUtil::GetChromeShortcutName(&shortcut_name, alternate)) |
| 635 return false; | 710 return false; |
| 636 | 711 |
| 637 bool ret = true; | 712 bool ret = true; |
| 638 if (shell_change & ShellUtil::CURRENT_USER) { | 713 if (shell_change & ShellUtil::CURRENT_USER) { |
| 639 std::wstring shortcut_path; | 714 std::wstring shortcut_path; |
| 640 if (ShellUtil::GetDesktopPath(false, &shortcut_path)) { | 715 if (ShellUtil::GetDesktopPath(false, &shortcut_path)) { |
| 641 file_util::AppendToPath(&shortcut_path, shortcut_name); | 716 file_util::AppendToPath(&shortcut_path, shortcut_name); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 704 } else { | 779 } else { |
| 705 return file_util::UpdateShortcutLink(chrome_exe.c_str(), // target | 780 return file_util::UpdateShortcutLink(chrome_exe.c_str(), // target |
| 706 shortcut.c_str(), // shortcut | 781 shortcut.c_str(), // shortcut |
| 707 chrome_path.c_str(), // working dir | 782 chrome_path.c_str(), // working dir |
| 708 NULL, // arguments | 783 NULL, // arguments |
| 709 description.c_str(), // description | 784 description.c_str(), // description |
| 710 chrome_exe.c_str(), // icon file | 785 chrome_exe.c_str(), // icon file |
| 711 0); // icon index | 786 0); // icon index |
| 712 } | 787 } |
| 713 } | 788 } |
| OLD | NEW |