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

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

Issue 487693002: ShellUtil: Add generic methods to add/delete Windows file associations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Created 6 years, 3 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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" 10 #include "chrome/installer/util/shell_util.h"
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 // class. 184 // class.
185 class RegistryEntry { 185 class RegistryEntry {
186 public: 186 public:
187 // A bit-field enum of places to look for this key in the Windows registry. 187 // A bit-field enum of places to look for this key in the Windows registry.
188 enum LookForIn { 188 enum LookForIn {
189 LOOK_IN_HKCU = 1 << 0, 189 LOOK_IN_HKCU = 1 << 0,
190 LOOK_IN_HKLM = 1 << 1, 190 LOOK_IN_HKLM = 1 << 1,
191 LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM, 191 LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM,
192 }; 192 };
193 193
194 // Details about a Windows application, to be entered into the registry for
195 // the purpose of file associations.
196 struct ApplicationInfo {
197 ApplicationInfo()
198 : set_delegate_execute(false),
199 file_type_icon_index(0),
200 application_icon_index(0) {}
201
202 // The unique internal name Windows will use for file associations with this
203 // application.
204 base::string16 prog_id;
205 // The friendly name, and the path of the icon that will be used for files
206 // of these types when associated with this application by default. (They
207 // are NOT the name/icon that will represent the application under the Open
208 // With menu.)
209 base::string16 file_type_name;
210 // TODO(mgiuca): |file_type_icon_path| should be a base::FilePath.
gab 2014/09/12 13:32:37 Agreed as that makes types more explicit, what pre
Matt Giuca 2014/09/15 03:49:46 Yes, I want to avoid touching heaps of other code
211 base::string16 file_type_icon_path;
212 int file_type_icon_index;
213 // The command to execute when opening a file via this association. It
214 // should contain "%1" to pass the filename as an argument.
215 // TODO(mgiuca): |command_line| should be a base::CommandLine.
216 base::string16 command_line;
217 // The unique internal name used by Windows 8 for this application. Distinct
218 // from |prog_id|. May be empty.
219 base::string16 app_id;
220
221 // User-visible details about this application. Any of these may be empty.
222 base::string16 application_name;
223 // TODO(mgiuca): |application_icon_path| should be a base::FilePath.
224 base::string16 application_icon_path;
225 int application_icon_index;
226 base::string16 application_description;
227 base::string16 publisher_name;
gab 2014/09/12 13:32:37 This is the core info, I'd say put this block firs
Matt Giuca 2014/09/15 03:49:46 What do you mean by "core info"? All of this is op
228
229 // Whether the application will have a DelegateExecute key. This should only
230 // be used by Windows 8 Metro web browsers (i.e. Chrome itself). All other
231 // fields in this section are ignored if this is false.
232 bool set_delegate_execute;
233 // A GUID for this application.
234 base::string16 delegate_guid;
235 // The command to execute when opening this application via the Metro UI.
236 base::string16 delegate_command;
237 };
238
194 // Returns the Windows browser client registration key for Chrome. For 239 // Returns the Windows browser client registration key for Chrome. For
195 // example: "Software\Clients\StartMenuInternet\Chromium[.user]". Strictly 240 // example: "Software\Clients\StartMenuInternet\Chromium[.user]". Strictly
196 // speaking, we should use the name of the executable (e.g., "chrome.exe"), 241 // speaking, we should use the name of the executable (e.g., "chrome.exe"),
197 // but that ship has sailed. The cost of switching now is re-prompting users 242 // but that ship has sailed. The cost of switching now is re-prompting users
198 // to make Chrome their default browser, which isn't polite. |suffix| is the 243 // to make Chrome their default browser, which isn't polite. |suffix| is the
199 // user-specific registration suffix; see GetUserSpecificDefaultBrowserSuffix 244 // user-specific registration suffix; see GetUserSpecificDefaultBrowserSuffix
200 // in shell_util.h for details. 245 // in shell_util.h for details.
201 static base::string16 GetBrowserClientKey(BrowserDistribution* dist, 246 static base::string16 GetBrowserClientKey(BrowserDistribution* dist,
202 const base::string16& suffix) { 247 const base::string16& suffix) {
203 DCHECK(suffix.empty() || suffix[0] == L'.'); 248 DCHECK(suffix.empty() || suffix[0] == L'.');
204 return base::string16(ShellUtil::kRegStartMenuInternet) 249 return base::string16(ShellUtil::kRegStartMenuInternet)
205 .append(1, L'\\') 250 .append(1, L'\\')
206 .append(dist->GetBaseAppName()) 251 .append(dist->GetBaseAppName())
207 .append(suffix); 252 .append(suffix);
208 } 253 }
209 254
210 // Returns the Windows Default Programs capabilities key for Chrome. For 255 // Returns the Windows Default Programs capabilities key for Chrome. For
211 // example: 256 // example:
212 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities". 257 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities".
213 static base::string16 GetCapabilitiesKey(BrowserDistribution* dist, 258 static base::string16 GetCapabilitiesKey(BrowserDistribution* dist,
214 const base::string16& suffix) { 259 const base::string16& suffix) {
215 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities"); 260 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities");
216 } 261 }
217 262
218 // This method returns a list of all the registry entries that 263 // This method returns a list of all the registry entries that
219 // are needed to register this installation's ProgId and AppId. 264 // are needed to register this installation's ProgId and AppId.
220 // These entries need to be registered in HKLM prior to Win8. 265 // These entries need to be registered in HKLM prior to Win8.
221 static void GetProgIdEntries(BrowserDistribution* dist, 266 static void GetChromeProgIdEntries(BrowserDistribution* dist,
222 const base::string16& chrome_exe, 267 const base::string16& chrome_exe,
223 const base::string16& suffix, 268 const base::string16& suffix,
224 ScopedVector<RegistryEntry>* entries) { 269 ScopedVector<RegistryEntry>* entries) {
225 base::string16 icon_path( 270 ApplicationInfo app_info;
226 ShellUtil::FormatIconLocation( 271 app_info.prog_id = GetBrowserProgId(suffix);
227 chrome_exe, 272 app_info.file_type_name = dist->GetBrowserProgIdDesc();
228 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME))); 273 app_info.file_type_icon_path = chrome_exe;
229 base::string16 open_cmd(ShellUtil::GetChromeShellOpenCmd(chrome_exe)); 274 app_info.file_type_icon_index =
230 base::string16 delegate_command( 275 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME);
231 ShellUtil::GetChromeDelegateCommand(chrome_exe)); 276 app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
232 // For user-level installs: entries for the app id and DelegateExecute verb 277 // For user-level installs: entries for the app id will be in HKCU; thus we
233 // handler will be in HKCU; thus we do not need a suffix on those entries. 278 // do not need a suffix on those entries.
234 base::string16 app_id( 279 app_info.app_id = ShellUtil::GetBrowserModelId(
235 ShellUtil::GetBrowserModelId( 280 dist, InstallUtil::IsPerUserInstall(chrome_exe.c_str()));
236 dist, InstallUtil::IsPerUserInstall(chrome_exe.c_str())));
237 base::string16 delegate_guid;
238 bool set_delegate_execute =
239 IsChromeMetroSupported() &&
240 dist->GetCommandExecuteImplClsid(&delegate_guid);
241 281
242 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. 282 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8.
243 if (set_delegate_execute) { 283 app_info.delegate_command = ShellUtil::GetChromeDelegateCommand(chrome_exe);
284 app_info.set_delegate_execute =
285 IsChromeMetroSupported() &&
286 dist->GetCommandExecuteImplClsid(&app_info.delegate_guid);
287
288 // The Chrome app icon path is the same as its file type path.
289 app_info.application_name = dist->GetDisplayName();
290 app_info.application_icon_path = app_info.file_type_icon_path;
291 app_info.application_icon_index = app_info.file_type_icon_index;
292 app_info.application_description = dist->GetAppDescription();
293 app_info.publisher_name = dist->GetPublisherName();
gab 2014/09/12 13:32:36 As mentioned above, put this information first (an
Matt Giuca 2014/09/15 03:49:46 See comment above. OK I've done the latter sugges
294
295 GetProgIdEntries(app_info, entries);
296 }
297
298 // Gets the registry entries to register an application in the Windows
299 // registry. |app_info| provides all of the information needed.
300 static void GetProgIdEntries(const ApplicationInfo& app_info,
301 ScopedVector<RegistryEntry>* entries) {
302 if (app_info.set_delegate_execute) {
244 base::string16 model_id_shell(ShellUtil::kRegClasses); 303 base::string16 model_id_shell(ShellUtil::kRegClasses);
245 model_id_shell.push_back(base::FilePath::kSeparators[0]); 304 model_id_shell.push_back(base::FilePath::kSeparators[0]);
246 model_id_shell.append(app_id); 305 model_id_shell.append(app_info.app_id);
247 model_id_shell.append(ShellUtil::kRegExePath); 306 model_id_shell.append(ShellUtil::kRegExePath);
248 model_id_shell.append(ShellUtil::kRegShellPath); 307 model_id_shell.append(ShellUtil::kRegShellPath);
249 308
250 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open 309 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open
251 entries->push_back(new RegistryEntry(model_id_shell, 310 entries->push_back(new RegistryEntry(model_id_shell,
252 ShellUtil::kRegVerbOpen)); 311 ShellUtil::kRegVerbOpen));
253 312
254 // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is 313 // Each shortcut has an appid; which, as of Windows 8, is registered to
255 // registered to handle some verbs. This registration has the side-effect 314 // handle some verbs. This registration has the side-effect that these
256 // that these verbs now show up in the shortcut's context menu. We 315 // verbs now show up in the shortcut's context menu. We mitigate this
257 // mitigate this side-effect by making the context menu entries 316 // side-effect by making the context menu entries user readable/localized
258 // user readable/localized strings. See relevant MSDN article: 317 // strings. See relevant MSDN article:
259 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx 318 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx
260 const struct { 319 const struct {
261 const wchar_t* verb; 320 const wchar_t* verb;
262 int name_id; 321 int name_id;
263 } verbs[] = { 322 } verbs[] = {
264 { ShellUtil::kRegVerbOpen, -1 }, 323 { ShellUtil::kRegVerbOpen, -1 },
265 { ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE }, 324 { ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE },
266 }; 325 };
267 for (size_t i = 0; i < arraysize(verbs); ++i) { 326 for (size_t i = 0; i < arraysize(verbs); ++i) {
268 base::string16 sub_path(model_id_shell); 327 base::string16 sub_path(model_id_shell);
269 sub_path.push_back(base::FilePath::kSeparators[0]); 328 sub_path.push_back(base::FilePath::kSeparators[0]);
270 sub_path.append(verbs[i].verb); 329 sub_path.append(verbs[i].verb);
271 330
272 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb> 331 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>
273 if (verbs[i].name_id != -1) { 332 if (verbs[i].name_id != -1) {
274 // TODO(grt): http://crbug.com/75152 Write a reference to a localized 333 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
275 // resource. 334 // resource.
276 base::string16 verb_name( 335 base::string16 verb_name(
277 installer::GetLocalizedString(verbs[i].name_id)); 336 installer::GetLocalizedString(verbs[i].name_id));
278 entries->push_back(new RegistryEntry(sub_path, verb_name.c_str())); 337 entries->push_back(new RegistryEntry(sub_path, verb_name.c_str()));
279 } 338 }
280 entries->push_back(new RegistryEntry( 339 entries->push_back(new RegistryEntry(
281 sub_path, L"CommandId", L"Browser.Launch")); 340 sub_path, L"CommandId", L"Browser.Launch"));
282 341
283 sub_path.push_back(base::FilePath::kSeparators[0]); 342 sub_path.push_back(base::FilePath::kSeparators[0]);
284 sub_path.append(ShellUtil::kRegCommand); 343 sub_path.append(ShellUtil::kRegCommand);
285 344
286 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command 345 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command
287 entries->push_back(new RegistryEntry(sub_path, delegate_command)); 346 entries->push_back(
347 new RegistryEntry(sub_path, app_info.delegate_command));
288 entries->push_back(new RegistryEntry( 348 entries->push_back(new RegistryEntry(
289 sub_path, ShellUtil::kRegDelegateExecute, delegate_guid)); 349 sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_guid));
290 } 350 }
291 } 351 }
292 352
293 // File association ProgId 353 // File association ProgId
294 base::string16 chrome_html_prog_id(ShellUtil::kRegClasses); 354 base::string16 prog_id_path(ShellUtil::kRegClasses);
295 chrome_html_prog_id.push_back(base::FilePath::kSeparators[0]); 355 prog_id_path.push_back(base::FilePath::kSeparators[0]);
296 chrome_html_prog_id.append(GetBrowserProgId(suffix)); 356 prog_id_path.append(app_info.prog_id);
357 entries->push_back(
358 new RegistryEntry(prog_id_path, app_info.file_type_name));
297 entries->push_back(new RegistryEntry( 359 entries->push_back(new RegistryEntry(
298 chrome_html_prog_id, dist->GetBrowserProgIdDesc())); 360 prog_id_path + ShellUtil::kRegDefaultIcon,
361 ShellUtil::FormatIconLocation(app_info.file_type_icon_path,
362 app_info.file_type_icon_index)));
299 entries->push_back(new RegistryEntry( 363 entries->push_back(new RegistryEntry(
300 chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); 364 prog_id_path + ShellUtil::kRegShellOpen, app_info.command_line));
301 entries->push_back(new RegistryEntry( 365 if (app_info.set_delegate_execute) {
302 chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd)); 366 entries->push_back(
303 if (set_delegate_execute) { 367 new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen,
304 entries->push_back(new RegistryEntry( 368 ShellUtil::kRegDelegateExecute,
305 chrome_html_prog_id + ShellUtil::kRegShellOpen, 369 app_info.delegate_guid));
306 ShellUtil::kRegDelegateExecute, delegate_guid));
307 } 370 }
308 371
309 // The following entries are required as of Windows 8, but do not 372 // The following entries are required as of Windows 8, but do not
310 // depend on the DelegateExecute verb handler being set. 373 // depend on the DelegateExecute verb handler being set.
311 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { 374 if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
312 entries->push_back(new RegistryEntry( 375 if (!app_info.app_id.empty()) {
313 chrome_html_prog_id, ShellUtil::kRegAppUserModelId, app_id)); 376 entries->push_back(new RegistryEntry(
377 prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
378 }
314 379
315 // Add \Software\Classes\ChromeHTML\Application entries 380 // Add \Software\Classes\<prog_id>\Application entries
316 base::string16 chrome_application(chrome_html_prog_id + 381 base::string16 application_path(prog_id_path +
317 ShellUtil::kRegApplication); 382 ShellUtil::kRegApplication);
318 entries->push_back(new RegistryEntry( 383 if (!app_info.app_id.empty()) {
319 chrome_application, ShellUtil::kRegAppUserModelId, app_id)); 384 entries->push_back(new RegistryEntry(
320 entries->push_back(new RegistryEntry( 385 application_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
321 chrome_application, ShellUtil::kRegApplicationIcon, icon_path)); 386 }
387 if (!app_info.application_icon_path.empty()) {
388 entries->push_back(new RegistryEntry(
389 application_path,
390 ShellUtil::kRegApplicationIcon,
391 ShellUtil::FormatIconLocation(app_info.application_icon_path,
392 app_info.application_icon_index)));
393 }
322 // TODO(grt): http://crbug.com/75152 Write a reference to a localized 394 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
gab 2014/09/12 13:32:36 This TODO now belongs in the Chrome specific metho
Matt Giuca 2014/09/15 03:49:46 Done.
323 // resource for name, description, and company. 395 // resource for name, description, and company.
324 entries->push_back(new RegistryEntry( 396 if (!app_info.application_name.empty()) {
325 chrome_application, ShellUtil::kRegApplicationName, 397 entries->push_back(new RegistryEntry(application_path,
326 dist->GetDisplayName())); 398 ShellUtil::kRegApplicationName,
327 entries->push_back(new RegistryEntry( 399 app_info.application_name));
328 chrome_application, ShellUtil::kRegApplicationDescription, 400 }
329 dist->GetAppDescription())); 401 if (!app_info.application_description.empty()) {
330 entries->push_back(new RegistryEntry( 402 entries->push_back(
331 chrome_application, ShellUtil::kRegApplicationCompany, 403 new RegistryEntry(application_path,
332 dist->GetPublisherName())); 404 ShellUtil::kRegApplicationDescription,
405 app_info.application_description));
406 }
407 if (!app_info.publisher_name.empty()) {
408 entries->push_back(new RegistryEntry(application_path,
409 ShellUtil::kRegApplicationCompany,
410 app_info.publisher_name));
411 }
gab 2014/09/12 13:32:36 Does it really hurt to set those if they're empty?
Matt Giuca 2014/09/15 03:49:46 I don't know, but I could imagine Windows treating
333 } 412 }
334 } 413 }
335 414
336 // This method returns a list of the registry entries needed to declare a 415 // This method returns a list of the registry entries needed to declare a
337 // capability of handling a protocol on Windows. 416 // capability of handling a protocol on Windows.
338 static void GetProtocolCapabilityEntries( 417 static void GetProtocolCapabilityEntries(
339 BrowserDistribution* dist, 418 BrowserDistribution* dist,
340 const base::string16& suffix, 419 const base::string16& suffix,
341 const base::string16& protocol, 420 const base::string16& protocol,
342 ScopedVector<RegistryEntry>* entries) { 421 ScopedVector<RegistryEntry>* entries) {
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 } 505 }
427 506
428 // This method returns a list of the registry entries required for this 507 // This method returns a list of the registry entries required for this
429 // installation to be registered in the Windows shell. 508 // installation to be registered in the Windows shell.
430 // In particular: 509 // In particular:
431 // - App Paths 510 // - App Paths
432 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121 511 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
433 // - File Associations 512 // - File Associations
434 // http://msdn.microsoft.com/en-us/library/bb166549 513 // http://msdn.microsoft.com/en-us/library/bb166549
435 // These entries need to be registered in HKLM prior to Win8. 514 // These entries need to be registered in HKLM prior to Win8.
436 static void GetAppRegistrationEntries(const base::string16& chrome_exe, 515 static void GetChromeAppRegistrationEntries(
437 const base::string16& suffix, 516 const base::string16& chrome_exe,
438 ScopedVector<RegistryEntry>* entries) { 517 const base::string16& suffix,
518 ScopedVector<RegistryEntry>* entries) {
439 const base::FilePath chrome_path(chrome_exe); 519 const base::FilePath chrome_path(chrome_exe);
440 base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey); 520 base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey);
441 app_path_key.push_back(base::FilePath::kSeparators[0]); 521 app_path_key.push_back(base::FilePath::kSeparators[0]);
442 app_path_key.append(chrome_path.BaseName().value()); 522 app_path_key.append(chrome_path.BaseName().value());
443 entries->push_back(new RegistryEntry(app_path_key, chrome_exe)); 523 entries->push_back(new RegistryEntry(app_path_key, chrome_exe));
444 entries->push_back(new RegistryEntry(app_path_key, 524 entries->push_back(new RegistryEntry(app_path_key,
445 ShellUtil::kAppPathsRegistryPathName, chrome_path.DirName().value())); 525 ShellUtil::kAppPathsRegistryPathName, chrome_path.DirName().value()));
446 526
447 const base::string16 html_prog_id(GetBrowserProgId(suffix)); 527 const base::string16 html_prog_id(GetBrowserProgId(suffix));
448 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) { 528 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
449 base::string16 key(ShellUtil::kRegClasses); 529 GetAppExtRegistrationEntries(
450 key.push_back(base::FilePath::kSeparators[0]); 530 html_prog_id, ShellUtil::kPotentialFileAssociations[i], entries);
451 key.append(ShellUtil::kPotentialFileAssociations[i]);
452 key.push_back(base::FilePath::kSeparators[0]);
453 key.append(ShellUtil::kRegOpenWithProgids);
454 entries->push_back(
455 new RegistryEntry(key, html_prog_id, base::string16()));
456 } 531 }
457 } 532 }
458 533
534 // Gets the registry entries to register an application as a handler for a
535 // particular file extension. |prog_id| is the unique internal name Windows
536 // uses for the application. |ext| is the file extension, which must begin
537 // with a '.'.
538 static void GetAppExtRegistrationEntries(
539 const base::string16& prog_id,
540 const base::string16& ext,
541 ScopedVector<RegistryEntry>* entries) {
542 // In HKEY_CLASSES_ROOT\EXT\OpenWithProgids, create an empty value with this
543 // class's name.
gab 2014/09/12 13:32:37 s/name/prog_id
Matt Giuca 2014/09/15 03:49:46 Done.
544 base::string16 key_name(ShellUtil::kRegClasses);
545 key_name.push_back(base::FilePath::kSeparators[0]);
546 key_name.append(ext);
547 key_name.push_back(base::FilePath::kSeparators[0]);
548 key_name.append(ShellUtil::kRegOpenWithProgids);
549 entries->push_back(new RegistryEntry(key_name, prog_id, base::string16()));
550 }
551
552 // Gets the registry entries to register an application as the default handler
553 // for a particular file extension. |prog_id| is the unique internal name
554 // Windows uses for the application. |ext| is the file extension, which must
555 // begin with a '.'. If |overwrite_existing|, always sets the default handler;
556 // otherwise only sets if there is no existing default.
557 static void GetAppDefaultRegistrationEntries(
gab 2014/09/12 13:32:36 Note in the method name that these are XP style de
Matt Giuca 2014/09/15 03:49:45 They certainly work in Windows 7 (haven't tested i
gab 2014/09/18 01:16:15 You're right that IApplicationAssociationRegistrat
Matt Giuca 2014/09/30 10:21:12 Where on that page ([1]) does it say it doesn't wo
gab 2014/10/01 14:31:11 Browsers are special indeed in that being default
Matt Giuca 2014/10/02 09:36:33 I have completed my investigation on Windows 8, an
558 const base::string16& prog_id,
559 const base::string16& ext,
560 bool overwrite_existing,
561 ScopedVector<RegistryEntry>* entries) {
562 // Set the default value of HKEY_CLASSES_ROOT\EXT to this class's name.
563 base::string16 key_name(ShellUtil::kRegClasses);
564 key_name.push_back(base::FilePath::kSeparators[0]);
565 key_name.append(ext);
566 scoped_ptr<RegistryEntry> default_association(
567 new RegistryEntry(key_name, prog_id));
568 if (overwrite_existing ||
569 !default_association->KeyExistsInRegistry(RegistryEntry::LOOK_IN_HKCU))
570 entries->push_back(default_association.release());
gab 2014/09/12 13:32:36 nit: {} since conditional is multiline
Matt Giuca 2014/09/15 03:49:45 Done.
571 }
572
459 // This method returns a list of all the user level registry entries that 573 // This method returns a list of all the user level registry entries that
460 // are needed to make Chromium the default handler for a protocol on XP. 574 // are needed to make Chromium the default handler for a protocol on XP.
461 static void GetXPStyleUserProtocolEntries( 575 static void GetXPStyleUserProtocolEntries(
462 const base::string16& protocol, 576 const base::string16& protocol,
463 const base::string16& chrome_icon, 577 const base::string16& chrome_icon,
464 const base::string16& chrome_open, 578 const base::string16& chrome_open,
465 ScopedVector<RegistryEntry>* entries) { 579 ScopedVector<RegistryEntry>* entries) {
466 // Protocols associations. 580 // Protocols associations.
467 base::string16 url_key(ShellUtil::kRegClasses); 581 base::string16 url_key(ShellUtil::kRegClasses);
468 url_key.push_back(base::FilePath::kSeparators[0]); 582 url_key.push_back(base::FilePath::kSeparators[0]);
(...skipping 28 matching lines...) Expand all
497 // we register them anyways as some legacy apps are hardcoded to lookup those 611 // we register them anyways as some legacy apps are hardcoded to lookup those
498 // values. 612 // values.
499 static void GetXPStyleDefaultBrowserUserEntries( 613 static void GetXPStyleDefaultBrowserUserEntries(
500 BrowserDistribution* dist, 614 BrowserDistribution* dist,
501 const base::string16& chrome_exe, 615 const base::string16& chrome_exe,
502 const base::string16& suffix, 616 const base::string16& suffix,
503 ScopedVector<RegistryEntry>* entries) { 617 ScopedVector<RegistryEntry>* entries) {
504 // File extension associations. 618 // File extension associations.
505 base::string16 html_prog_id(GetBrowserProgId(suffix)); 619 base::string16 html_prog_id(GetBrowserProgId(suffix));
506 for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) { 620 for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) {
507 base::string16 ext_key(ShellUtil::kRegClasses); 621 GetAppDefaultRegistrationEntries(
508 ext_key.push_back(base::FilePath::kSeparators[0]); 622 html_prog_id, ShellUtil::kDefaultFileAssociations[i], true, entries);
509 ext_key.append(ShellUtil::kDefaultFileAssociations[i]);
510 entries->push_back(new RegistryEntry(ext_key, html_prog_id));
511 } 623 }
512 624
513 // Protocols associations. 625 // Protocols associations.
514 base::string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); 626 base::string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
515 base::string16 chrome_icon = 627 base::string16 chrome_icon =
516 ShellUtil::FormatIconLocation( 628 ShellUtil::FormatIconLocation(
517 chrome_exe, 629 chrome_exe,
518 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); 630 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME));
519 for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) { 631 for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) {
520 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i], 632 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i],
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
556 DCHECK(look_for_in); 668 DCHECK(look_for_in);
557 669
558 RegistryStatus status = DOES_NOT_EXIST; 670 RegistryStatus status = DOES_NOT_EXIST;
559 if (look_for_in & LOOK_IN_HKCU) 671 if (look_for_in & LOOK_IN_HKCU)
560 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); 672 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER);
561 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) 673 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM))
562 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); 674 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE);
563 return status == SAME_VALUE; 675 return status == SAME_VALUE;
564 } 676 }
565 677
678 // Checks if the current registry entry exists in \|key_path_|\|name_|,
679 // regardless of value. Same lookup rules as ExistsInRegistry.
680 // Unlike ExistsInRegistry, this returns true if some other value is present
681 // with the same key.
682 bool KeyExistsInRegistry(uint32 look_for_in) const {
gab 2014/09/12 13:32:37 Seems your only caller of this cares only about HK
Matt Giuca 2014/09/15 03:49:46 I think for the latter reason that it's best to ke
683 DCHECK(look_for_in);
684
685 RegistryStatus status = DOES_NOT_EXIST;
686 if (look_for_in & LOOK_IN_HKCU)
687 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER);
688 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM))
689 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE);
690 return status != DOES_NOT_EXIST;
691 }
692
566 private: 693 private:
567 // States this RegistryKey can be in compared to the registry. 694 // States this RegistryKey can be in compared to the registry.
568 enum RegistryStatus { 695 enum RegistryStatus {
569 // |name_| does not exist in the registry 696 // |name_| does not exist in the registry
570 DOES_NOT_EXIST, 697 DOES_NOT_EXIST,
571 // |name_| exists, but its value != |value_| 698 // |name_| exists, but its value != |value_|
572 DIFFERENT_VALUE, 699 DIFFERENT_VALUE,
573 // |name_| exists and its value is |value_| 700 // |name_| exists and its value is |value_|
574 SAME_VALUE, 701 SAME_VALUE,
575 }; 702 };
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 // under a single registry root. Not doing so caused http://crbug.com/144910 for 796 // under a single registry root. Not doing so caused http://crbug.com/144910 for
670 // users who first-installed Chrome in that revision range (those users are 797 // users who first-installed Chrome in that revision range (those users are
671 // still impacted by http://crbug.com/144910). This method will keep returning 798 // still impacted by http://crbug.com/144910). This method will keep returning
672 // true for affected users (i.e. who have all the registrations, but over both 799 // true for affected users (i.e. who have all the registrations, but over both
673 // registry roots). 800 // registry roots).
674 bool IsChromeRegistered(BrowserDistribution* dist, 801 bool IsChromeRegistered(BrowserDistribution* dist,
675 const base::string16& chrome_exe, 802 const base::string16& chrome_exe,
676 const base::string16& suffix, 803 const base::string16& suffix,
677 uint32 look_for_in) { 804 uint32 look_for_in) {
678 ScopedVector<RegistryEntry> entries; 805 ScopedVector<RegistryEntry> entries;
679 RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, &entries); 806 RegistryEntry::GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries);
680 RegistryEntry::GetShellIntegrationEntries(dist, chrome_exe, suffix, &entries); 807 RegistryEntry::GetShellIntegrationEntries(dist, chrome_exe, suffix, &entries);
681 RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix, &entries); 808 RegistryEntry::GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries);
682 return AreEntriesRegistered(entries, look_for_in); 809 return AreEntriesRegistered(entries, look_for_in);
683 } 810 }
684 811
685 // This method checks if Chrome is already registered on the local machine 812 // This method checks if Chrome is already registered on the local machine
686 // for the requested protocol. It just checks the one value required for this. 813 // for the requested protocol. It just checks the one value required for this.
687 // See RegistryEntry::ExistsInRegistry for the behavior of |look_for_in|. 814 // See RegistryEntry::ExistsInRegistry for the behavior of |look_for_in|.
688 bool IsChromeRegisteredForProtocol(BrowserDistribution* dist, 815 bool IsChromeRegisteredForProtocol(BrowserDistribution* dist,
689 const base::string16& suffix, 816 const base::string16& suffix,
690 const base::string16& protocol, 817 const base::string16& protocol,
691 uint32 look_for_in) { 818 uint32 look_for_in) {
(...skipping 1364 matching lines...) Expand 10 before | Expand all | Expand 10 after
2056 // Check if chrome is already registered with this suffix. 2183 // Check if chrome is already registered with this suffix.
2057 if (IsChromeRegistered(dist, chrome_exe, suffix, look_for_in)) 2184 if (IsChromeRegistered(dist, chrome_exe, suffix, look_for_in))
2058 return true; 2185 return true;
2059 2186
2060 bool result = true; 2187 bool result = true;
2061 if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) { 2188 if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) {
2062 // Do the full registration if we can do it at user-level or if the user is 2189 // Do the full registration if we can do it at user-level or if the user is
2063 // an admin. 2190 // an admin.
2064 ScopedVector<RegistryEntry> progid_and_appreg_entries; 2191 ScopedVector<RegistryEntry> progid_and_appreg_entries;
2065 ScopedVector<RegistryEntry> shell_entries; 2192 ScopedVector<RegistryEntry> shell_entries;
2066 RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, 2193 RegistryEntry::GetChromeProgIdEntries(
2067 &progid_and_appreg_entries); 2194 dist, chrome_exe, suffix, &progid_and_appreg_entries);
2068 RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix, 2195 RegistryEntry::GetChromeAppRegistrationEntries(
2069 &progid_and_appreg_entries); 2196 chrome_exe, suffix, &progid_and_appreg_entries);
2070 RegistryEntry::GetShellIntegrationEntries( 2197 RegistryEntry::GetShellIntegrationEntries(
2071 dist, chrome_exe, suffix, &shell_entries); 2198 dist, chrome_exe, suffix, &shell_entries);
2072 result = (AddRegistryEntries(root, progid_and_appreg_entries) && 2199 result = (AddRegistryEntries(root, progid_and_appreg_entries) &&
2073 AddRegistryEntries(root, shell_entries)); 2200 AddRegistryEntries(root, shell_entries));
2074 } else if (elevate_if_not_admin && 2201 } else if (elevate_if_not_admin &&
2075 base::win::GetVersion() >= base::win::VERSION_VISTA && 2202 base::win::GetVersion() >= base::win::VERSION_VISTA &&
2076 ElevateAndRegisterChrome(dist, chrome_exe, suffix, base::string16())) { 2203 ElevateAndRegisterChrome(dist, chrome_exe, suffix, base::string16())) {
2077 // If the user is not an admin and OS is between Vista and Windows 7 2204 // If the user is not an admin and OS is between Vista and Windows 7
2078 // inclusively, try to elevate and register. This is only intended for 2205 // inclusively, try to elevate and register. This is only intended for
2079 // user-level installs as system-level installs should always be run with 2206 // user-level installs as system-level installs should always be run with
2080 // admin rights. 2207 // admin rights.
2081 result = true; 2208 result = true;
2082 } else { 2209 } else {
2083 // If we got to this point then all we can do is create ProgId and basic app 2210 // If we got to this point then all we can do is create ProgId and basic app
2084 // registrations under HKCU. 2211 // registrations under HKCU.
2085 ScopedVector<RegistryEntry> entries; 2212 ScopedVector<RegistryEntry> entries;
2086 RegistryEntry::GetProgIdEntries( 2213 RegistryEntry::GetChromeProgIdEntries(
2087 dist, chrome_exe, base::string16(), &entries); 2214 dist, chrome_exe, base::string16(), &entries);
2088 // Prefer to use |suffix|; unless Chrome's ProgIds are already registered 2215 // Prefer to use |suffix|; unless Chrome's ProgIds are already registered
2089 // with no suffix (as per the old registration style): in which case some 2216 // with no suffix (as per the old registration style): in which case some
2090 // other registry entries could refer to them and since we were not able to 2217 // other registry entries could refer to them and since we were not able to
2091 // set our HKLM entries above, we are better off not altering these here. 2218 // set our HKLM entries above, we are better off not altering these here.
2092 if (!AreEntriesRegistered(entries, RegistryEntry::LOOK_IN_HKCU)) { 2219 if (!AreEntriesRegistered(entries, RegistryEntry::LOOK_IN_HKCU)) {
2093 if (!suffix.empty()) { 2220 if (!suffix.empty()) {
2094 entries.clear(); 2221 entries.clear();
2095 RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, &entries); 2222 RegistryEntry::GetChromeProgIdEntries(
2096 RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix, &entries); 2223 dist, chrome_exe, suffix, &entries);
2224 RegistryEntry::GetChromeAppRegistrationEntries(
2225 chrome_exe, suffix, &entries);
2097 } 2226 }
2098 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); 2227 result = AddRegistryEntries(HKEY_CURRENT_USER, entries);
2099 } else { 2228 } else {
2100 // The ProgId is registered unsuffixed in HKCU, also register the app with 2229 // The ProgId is registered unsuffixed in HKCU, also register the app with
2101 // Windows in HKCU (this was not done in the old registration style and 2230 // Windows in HKCU (this was not done in the old registration style and
2102 // thus needs to be done after the above check for the unsuffixed 2231 // thus needs to be done after the above check for the unsuffixed
2103 // registration). 2232 // registration).
2104 entries.clear(); 2233 entries.clear();
2105 RegistryEntry::GetAppRegistrationEntries(chrome_exe, base::string16(), 2234 RegistryEntry::GetChromeAppRegistrationEntries(
2106 &entries); 2235 chrome_exe, base::string16(), &entries);
2107 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); 2236 result = AddRegistryEntries(HKEY_CURRENT_USER, entries);
2108 } 2237 }
2109 } 2238 }
2110 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); 2239 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
2111 return result; 2240 return result;
2112 } 2241 }
2113 2242
2114 bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist, 2243 bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist,
2115 const base::string16& chrome_exe, 2244 const base::string16& chrome_exe,
2116 const base::string16& unique_suffix, 2245 const base::string16& unique_suffix,
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
2285 // are any left...). 2414 // are any left...).
2286 if (free_bits >= 8 && next_byte_index < size) { 2415 if (free_bits >= 8 && next_byte_index < size) {
2287 free_bits -= 8; 2416 free_bits -= 8;
2288 bit_stream += bytes[next_byte_index++] << free_bits; 2417 bit_stream += bytes[next_byte_index++] << free_bits;
2289 } 2418 }
2290 } 2419 }
2291 2420
2292 DCHECK_EQ(ret.length(), encoded_length); 2421 DCHECK_EQ(ret.length(), encoded_length);
2293 return ret; 2422 return ret;
2294 } 2423 }
2424
2425 // static
2426 bool ShellUtil::AddFileAssociations(
2427 const base::string16& progid,
2428 const base::CommandLine& command_line,
2429 const base::string16& file_type_name,
2430 const base::FilePath& icon_path,
2431 const std::set<base::string16>& file_extensions) {
2432 ScopedVector<RegistryEntry> entries;
2433
2434 // Create a class for this app.
2435 RegistryEntry::ApplicationInfo app_info;
2436 app_info.prog_id = progid;
2437 app_info.file_type_name = file_type_name;
2438 app_info.file_type_icon_path = icon_path.value();
2439 app_info.file_type_icon_index = 0;
2440 app_info.command_line = command_line.GetCommandLineString();
2441 RegistryEntry::GetProgIdEntries(app_info, &entries);
2442
2443 // Associate each extension that the app can handle with the class. Set this
2444 // app as the default handler if and only if there is no existing default.
2445 for (std::set<base::string16>::const_iterator it = file_extensions.begin();
2446 it != file_extensions.end();
2447 ++it) {
2448 base::string16 ext(1, L'.');
gab 2014/09/12 13:32:36 Add this check above. DCHECK(!it->empty() && (*it
Matt Giuca 2014/09/15 03:49:46 Done.
2449 ext.append(*it);
2450 RegistryEntry::GetAppExtRegistrationEntries(progid, ext, &entries);
2451 RegistryEntry::GetAppDefaultRegistrationEntries(
2452 progid, ext, false, &entries);
2453 }
2454
2455 return AddRegistryEntries(HKEY_CURRENT_USER, entries);
2456 }
2457
2458 // static
2459 bool ShellUtil::DeleteFileAssociations(const base::string16& progid) {
2460 // Delete the key HKEY_CLASSES_ROOT\PROGID.
2461 base::string16 key_path(ShellUtil::kRegClasses);
2462 key_path.push_back(base::FilePath::kSeparators[0]);
2463 key_path.append(progid);
2464 return InstallUtil::DeleteRegistryKey(
2465 HKEY_CURRENT_USER, key_path, WorkItem::kWow64Default);
2466
2467 // Note: there is no need to remove the association from the extension to the
2468 // class, as Windows will ignore it. See:
2469 // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144148.aspx
gab 2014/09/12 13:32:37 Right but you should still delete the OpenWith reg
Matt Giuca 2014/09/15 03:49:46 While that document doesn't say *not* to remove th
gab 2014/09/18 01:16:15 The documentation *does* explicitly say that these
Matt Giuca 2014/09/30 10:21:12 But remember I will be calling this code far more
gab 2014/10/01 14:31:11 Ok fair enough, but I still think we should remove
Matt Giuca 2014/10/02 09:36:33 Acknowledged.
2470 }
OLDNEW
« chrome/installer/util/shell_util.h ('K') | « chrome/installer/util/shell_util.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698