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