Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(589)

Side by Side Diff: chrome/installer/util/shell_registry_util.cc

Issue 1578833003: Moved shell_util functions into new shell_registry_util module. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/installer/util/shell_registry_util.h ('k') | chrome/installer/util/shell_util.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/installer/util/shell_registry_util.h"
6
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/win/windows_version.h"
10 #include "chrome/common/chrome_switches.h"
11 #include "chrome/installer/util/browser_distribution.h"
12 #include "chrome/installer/util/install_util.h"
13 #include "chrome/installer/util/installer_util_strings.h"
14 #include "chrome/installer/util/l10n_string_util.h"
15 #include "chrome/installer/util/registry_entry.h"
16 #include "chrome/installer/util/shell_util.h"
17
18 namespace installer_util {
19
20 namespace {
21
22 // Returns the current (or installed) browser's ProgId (e.g.
23 // "ChromeHTML|suffix|").
24 // |suffix| can be the empty string.
25 base::string16 GetBrowserProgId(const base::string16& suffix) {
26 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
27 base::string16 chrome_html(dist->GetBrowserProgIdPrefix());
28 chrome_html.append(suffix);
29
30 // ProgIds cannot be longer than 39 characters.
31 // Ref: http://msdn.microsoft.com/en-us/library/aa911706.aspx.
32 // Make all new registrations comply with this requirement (existing
33 // registrations must be preserved).
34 base::string16 new_style_suffix;
35 if (ShellUtil::GetUserSpecificRegistrySuffix(&new_style_suffix) &&
36 suffix == new_style_suffix && chrome_html.length() > 39) {
37 NOTREACHED();
38 chrome_html.erase(39);
39 }
40 return chrome_html;
41 }
42
43 // Returns the Windows Default Programs capabilities key for Chrome. For
44 // example:
45 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities".
46 base::string16 GetCapabilitiesKey(BrowserDistribution* dist,
47 const base::string16& suffix) {
48 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities");
49 }
50
51 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. This is only
52 // needed for registring a web browser, not for general associations.
53 ScopedVector<RegistryEntry> GetChromeDelegateExecuteEntries(
54 const base::FilePath& chrome_exe,
55 const ApplicationInfo& app_info) {
56 ScopedVector<RegistryEntry> entries;
57
58 base::string16 app_id_shell_key(ShellUtil::kRegClasses);
59 app_id_shell_key.push_back(base::FilePath::kSeparators[0]);
60 app_id_shell_key.append(app_info.app_id);
61 app_id_shell_key.append(ShellUtil::kRegExePath);
62 app_id_shell_key.append(ShellUtil::kRegShellPath);
63
64 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open
65 entries.push_back(
66 new RegistryEntry(app_id_shell_key, ShellUtil::kRegVerbOpen));
67
68 // The command to execute when opening this application via the Metro UI.
69 const base::string16 delegate_command(
70 ShellUtil::GetChromeDelegateCommand(chrome_exe));
71
72 // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is
73 // registered to handle some verbs. This registration has the side-effect
74 // that these verbs now show up in the shortcut's context menu. We
75 // mitigate this side-effect by making the context menu entries
76 // user readable/localized strings. See relevant MSDN article:
77 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx
78 static const struct {
79 const wchar_t* verb;
80 int name_id;
81 } verbs[] = {
82 {ShellUtil::kRegVerbOpen, -1},
83 {ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE},
84 };
85 for (const auto& verb_and_id : verbs) {
86 base::string16 sub_path(app_id_shell_key);
87 sub_path.push_back(base::FilePath::kSeparators[0]);
88 sub_path.append(verb_and_id.verb);
89
90 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>
91 if (verb_and_id.name_id != -1) {
92 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
93 // resource.
94 const base::string16 verb_name(
95 installer::GetLocalizedString(verb_and_id.name_id));
96 entries.push_back(new RegistryEntry(sub_path, verb_name.c_str()));
97 }
98 entries.push_back(
99 new RegistryEntry(sub_path, L"CommandId", L"Browser.Launch"));
100
101 sub_path.push_back(base::FilePath::kSeparators[0]);
102 sub_path.append(ShellUtil::kRegCommand);
103
104 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command
105 entries.push_back(new RegistryEntry(sub_path, delegate_command));
106 entries.push_back(new RegistryEntry(
107 sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid));
108 }
109
110 return entries;
111 }
112
113 } // namespace
114
115 const wchar_t kReinstallCommand[] = L"ReinstallCommand";
116
117 base::string16 GetBrowserClientKey(BrowserDistribution* dist,
118 const base::string16& suffix) {
119 DCHECK(suffix.empty() || suffix[0] == L'.');
120 return base::string16(ShellUtil::kRegStartMenuInternet)
121 .append(1, L'\\')
122 .append(dist->GetBaseAppName())
123 .append(suffix);
124 }
125
126 void GetProgIdEntries(const ApplicationInfo& app_info,
127 ScopedVector<RegistryEntry>* entries) {
128 // Basic sanity checks.
129 DCHECK(!app_info.prog_id.empty());
130 DCHECK_NE(L'.', app_info.prog_id[0]);
131
132 // File association ProgId
133 base::string16 prog_id_path(ShellUtil::kRegClasses);
134 prog_id_path.push_back(base::FilePath::kSeparators[0]);
135 prog_id_path.append(app_info.prog_id);
136 entries->push_back(new RegistryEntry(prog_id_path, app_info.file_type_name));
137 entries->push_back(new RegistryEntry(
138 prog_id_path + ShellUtil::kRegDefaultIcon,
139 ShellUtil::FormatIconLocation(app_info.file_type_icon_path,
140 app_info.file_type_icon_index)));
141 entries->push_back(new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen,
142 app_info.command_line));
143 if (!app_info.delegate_clsid.empty()) {
144 entries->push_back(new RegistryEntry(
145 prog_id_path + ShellUtil::kRegShellOpen, ShellUtil::kRegDelegateExecute,
146 app_info.delegate_clsid));
147 // TODO(scottmg): Simplify after Metro removal. https://crbug.com/558054.
148 entries->back()->set_removal_flag(RegistryEntry::RemovalFlag::VALUE);
149 }
150
151 // The following entries are required as of Windows 8, but do not
152 // depend on the DelegateExecute verb handler being set.
153 if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
154 if (!app_info.app_id.empty()) {
155 entries->push_back(new RegistryEntry(
156 prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
157 }
158
159 // Add \Software\Classes\<prog_id>\Application entries
160 base::string16 application_path(prog_id_path + ShellUtil::kRegApplication);
161 if (!app_info.app_id.empty()) {
162 entries->push_back(new RegistryEntry(
163 application_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
164 }
165 if (!app_info.application_icon_path.empty()) {
166 entries->push_back(new RegistryEntry(
167 application_path, ShellUtil::kRegApplicationIcon,
168 ShellUtil::FormatIconLocation(app_info.application_icon_path,
169 app_info.application_icon_index)));
170 }
171 if (!app_info.application_name.empty()) {
172 entries->push_back(new RegistryEntry(application_path,
173 ShellUtil::kRegApplicationName,
174 app_info.application_name));
175 }
176 if (!app_info.application_description.empty()) {
177 entries->push_back(new RegistryEntry(
178 application_path, ShellUtil::kRegApplicationDescription,
179 app_info.application_description));
180 }
181 if (!app_info.publisher_name.empty()) {
182 entries->push_back(new RegistryEntry(application_path,
183 ShellUtil::kRegApplicationCompany,
184 app_info.publisher_name));
185 }
186 }
187 }
188
189 void GetChromeProgIdEntries(BrowserDistribution* dist,
190 const base::FilePath& chrome_exe,
191 const base::string16& suffix,
192 ScopedVector<RegistryEntry>* entries) {
193 int chrome_icon_index =
194 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME);
195
196 ApplicationInfo app_info;
197 app_info.prog_id = GetBrowserProgId(suffix);
198 app_info.file_type_name = dist->GetBrowserProgIdDesc();
199 // File types associated with Chrome are just given the Chrome icon.
200 app_info.file_type_icon_path = chrome_exe;
201 app_info.file_type_icon_index = chrome_icon_index;
202 app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
203 // For user-level installs: entries for the app id will be in HKCU; thus we
204 // do not need a suffix on those entries.
205 app_info.app_id = ShellUtil::GetBrowserModelId(
206 dist, InstallUtil::IsPerUserInstall(chrome_exe));
207
208 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
209 // resource for name, description, and company.
210 app_info.application_name = dist->GetDisplayName();
211 app_info.application_icon_path = chrome_exe;
212 app_info.application_icon_index = chrome_icon_index;
213 app_info.application_description = dist->GetAppDescription();
214 app_info.publisher_name = dist->GetPublisherName();
215
216 app_info.delegate_clsid = dist->GetCommandExecuteImplClsid();
217
218 GetProgIdEntries(app_info, entries);
219
220 if (!app_info.delegate_clsid.empty()) {
221 ScopedVector<RegistryEntry> delegate_execute_entries =
222 GetChromeDelegateExecuteEntries(chrome_exe, app_info);
223 // Remove the keys (not only their values) so that Windows will continue
224 // to launch Chrome without a pesky association error.
225 // TODO(scottmg): Simplify after Metro removal. https://crbug.com/558054.
226 for (RegistryEntry* entry : delegate_execute_entries)
227 entry->set_removal_flag(RegistryEntry::RemovalFlag::KEY);
228 // Move |delegate_execute_entries| to |entries|.
229 entries->insert(entries->end(), delegate_execute_entries.begin(),
230 delegate_execute_entries.end());
231 delegate_execute_entries.weak_clear();
232 }
233 }
234
235 void GetProtocolCapabilityEntries(BrowserDistribution* dist,
236 const base::string16& suffix,
237 const base::string16& protocol,
238 ScopedVector<RegistryEntry>* entries) {
239 entries->push_back(new RegistryEntry(
240 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"), protocol,
241 GetBrowserProgId(suffix)));
242 }
243
244 void GetShellIntegrationEntries(BrowserDistribution* dist,
245 const base::FilePath& chrome_exe,
246 const base::string16& suffix,
247 ScopedVector<RegistryEntry>* entries) {
248 const base::string16 icon_path(ShellUtil::FormatIconLocation(
249 chrome_exe, dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)));
250 const base::string16 quoted_exe_path(L"\"" + chrome_exe.value() + L"\"");
251
252 // Register for the Start Menu "Internet" link (pre-Win7).
253 const base::string16 start_menu_entry(GetBrowserClientKey(dist, suffix));
254 // Register Chrome's display name.
255 // TODO(grt): http://crbug.com/75152 Also set LocalizedString; see
256 // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144109(v=VS.85).a spx#registering_the_display_name
257 entries->push_back(
258 new RegistryEntry(start_menu_entry, dist->GetDisplayName()));
259 // Register the "open" verb for launching Chrome via the "Internet" link.
260 entries->push_back(new RegistryEntry(
261 start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path));
262 // Register Chrome's icon for the Start Menu "Internet" link.
263 entries->push_back(new RegistryEntry(
264 start_menu_entry + ShellUtil::kRegDefaultIcon, icon_path));
265
266 // Register installation information.
267 base::string16 install_info(start_menu_entry + L"\\InstallInfo");
268 // Note: not using CommandLine since it has ambiguous rules for quoting
269 // strings.
270 entries->push_back(
271 new RegistryEntry(install_info, kReinstallCommand,
272 quoted_exe_path + L" --" +
273 base::ASCIIToUTF16(switches::kMakeDefaultBrowser)));
274 entries->push_back(new RegistryEntry(
275 install_info, L"HideIconsCommand",
276 quoted_exe_path + L" --" + base::ASCIIToUTF16(switches::kHideIcons)));
277 entries->push_back(new RegistryEntry(
278 install_info, L"ShowIconsCommand",
279 quoted_exe_path + L" --" + base::ASCIIToUTF16(switches::kShowIcons)));
280 entries->push_back(new RegistryEntry(install_info, L"IconsVisible", 1));
281
282 // Register with Default Programs.
283 const base::string16 reg_app_name(dist->GetBaseAppName().append(suffix));
284 // Tell Windows where to find Chrome's Default Programs info.
285 const base::string16 capabilities(GetCapabilitiesKey(dist, suffix));
286 entries->push_back(new RegistryEntry(ShellUtil::kRegRegisteredApplications,
287 reg_app_name, capabilities));
288 // Write out Chrome's Default Programs info.
289 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
290 // resource rather than this.
291 entries->push_back(new RegistryEntry(capabilities,
292 ShellUtil::kRegApplicationDescription,
293 dist->GetLongAppDescription()));
294 entries->push_back(new RegistryEntry(
295 capabilities, ShellUtil::kRegApplicationIcon, icon_path));
296 entries->push_back(new RegistryEntry(
297 capabilities, ShellUtil::kRegApplicationName, dist->GetDisplayName()));
298
299 entries->push_back(new RegistryEntry(capabilities + L"\\Startmenu",
300 L"StartMenuInternet", reg_app_name));
301
302 const base::string16 html_prog_id(GetBrowserProgId(suffix));
303 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
304 entries->push_back(new RegistryEntry(
305 capabilities + L"\\FileAssociations",
306 ShellUtil::kPotentialFileAssociations[i], html_prog_id));
307 }
308 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; i++) {
309 entries->push_back(new RegistryEntry(
310 capabilities + L"\\URLAssociations",
311 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id));
312 }
313 }
314
315 void GetAppExtRegistrationEntries(const base::string16& prog_id,
316 const base::string16& ext,
317 ScopedVector<RegistryEntry>* entries) {
318 // In HKEY_CURRENT_USER\Software\Classes\EXT\OpenWithProgids, create an
319 // empty value with this class's ProgId.
320 base::string16 key_name(ShellUtil::kRegClasses);
321 key_name.push_back(base::FilePath::kSeparators[0]);
322 key_name.append(ext);
323 key_name.push_back(base::FilePath::kSeparators[0]);
324 key_name.append(ShellUtil::kRegOpenWithProgids);
325 entries->push_back(new RegistryEntry(key_name, prog_id, base::string16()));
326 }
327
328 void GetChromeAppRegistrationEntries(const base::FilePath& chrome_exe,
329 const base::string16& suffix,
330 ScopedVector<RegistryEntry>* entries) {
331 base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey);
332 app_path_key.push_back(base::FilePath::kSeparators[0]);
333 app_path_key.append(chrome_exe.BaseName().value());
334 entries->push_back(new RegistryEntry(app_path_key, chrome_exe.value()));
335 entries->push_back(new RegistryEntry(app_path_key,
336 ShellUtil::kAppPathsRegistryPathName,
337 chrome_exe.DirName().value()));
338
339 const base::string16 html_prog_id(GetBrowserProgId(suffix));
340 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
341 GetAppExtRegistrationEntries(
342 html_prog_id, ShellUtil::kPotentialFileAssociations[i], entries);
343 }
344 }
345
346 void GetAppDefaultRegistrationEntries(const base::string16& prog_id,
347 const base::string16& ext,
348 bool overwrite_existing,
349 ScopedVector<RegistryEntry>* entries) {
350 // Set the default value of HKEY_CURRENT_USER\Software\Classes\EXT to this
351 // class's name.
352 base::string16 key_name(ShellUtil::kRegClasses);
353 key_name.push_back(base::FilePath::kSeparators[0]);
354 key_name.append(ext);
355 scoped_ptr<RegistryEntry> default_association(
356 new RegistryEntry(key_name, prog_id));
357 if (overwrite_existing ||
358 !default_association->KeyExistsInRegistry(RegistryEntry::LOOK_IN_HKCU)) {
359 entries->push_back(default_association.release());
360 }
361 }
362
363 void GetXPStyleUserProtocolEntries(const base::string16& protocol,
364 const base::string16& chrome_icon,
365 const base::string16& chrome_open,
366 ScopedVector<RegistryEntry>* entries) {
367 // Protocols associations.
368 base::string16 url_key(ShellUtil::kRegClasses);
369 url_key.push_back(base::FilePath::kSeparators[0]);
370 url_key.append(protocol);
371
372 // This registry value tells Windows that this 'class' is a URL scheme
373 // so IE, explorer and other apps will route it to our handler.
374 // <root hkey>\Software\Classes\<protocol>\URL Protocol
375 entries->push_back(
376 new RegistryEntry(url_key, ShellUtil::kRegUrlProtocol, base::string16()));
377
378 // <root hkey>\Software\Classes\<protocol>\DefaultIcon
379 base::string16 icon_key = url_key + ShellUtil::kRegDefaultIcon;
380 entries->push_back(new RegistryEntry(icon_key, chrome_icon));
381
382 // <root hkey>\Software\Classes\<protocol>\shell\open\command
383 base::string16 shell_key = url_key + ShellUtil::kRegShellOpen;
384 entries->push_back(new RegistryEntry(shell_key, chrome_open));
385
386 // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec
387 base::string16 dde_key = url_key + L"\\shell\\open\\ddeexec";
388 entries->push_back(new RegistryEntry(dde_key, base::string16()));
389
390 // <root hkey>\Software\Classes\<protocol>\shell\@
391 base::string16 protocol_shell_key = url_key + ShellUtil::kRegShellPath;
392 entries->push_back(new RegistryEntry(protocol_shell_key, L"open"));
393 }
394
395 void GetXPStyleDefaultBrowserUserEntries(BrowserDistribution* dist,
396 const base::FilePath& chrome_exe,
397 const base::string16& suffix,
398 ScopedVector<RegistryEntry>* entries) {
399 // File extension associations.
400 base::string16 html_prog_id(GetBrowserProgId(suffix));
401 for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) {
402 GetAppDefaultRegistrationEntries(
403 html_prog_id, ShellUtil::kDefaultFileAssociations[i], true, entries);
404 }
405
406 // Protocols associations.
407 base::string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
408 base::string16 chrome_icon = ShellUtil::FormatIconLocation(
409 chrome_exe, dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME));
410 for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) {
411 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i],
412 chrome_icon, chrome_open, entries);
413 }
414
415 // start->Internet shortcut.
416 base::string16 start_menu(ShellUtil::kRegStartMenuInternet);
417 base::string16 app_name = dist->GetBaseAppName() + suffix;
418 entries->push_back(new RegistryEntry(start_menu, app_name));
419 }
420
421 } // namespace installer_util
OLDNEW
« no previous file with comments | « chrome/installer/util/shell_registry_util.h ('k') | chrome/installer/util/shell_util.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698