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 |