| OLD | NEW |
| 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 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 }; | 214 }; |
| 215 | 215 |
| 216 // Returns the Windows browser client registration key for Chrome. For | 216 // Returns the Windows browser client registration key for Chrome. For |
| 217 // example: "Software\Clients\StartMenuInternet\Chromium[.user]". Strictly | 217 // example: "Software\Clients\StartMenuInternet\Chromium[.user]". Strictly |
| 218 // speaking, we should use the name of the executable (e.g., "chrome.exe"), | 218 // speaking, we should use the name of the executable (e.g., "chrome.exe"), |
| 219 // but that ship has sailed. The cost of switching now is re-prompting users | 219 // but that ship has sailed. The cost of switching now is re-prompting users |
| 220 // to make Chrome their default browser, which isn't polite. |suffix| is the | 220 // to make Chrome their default browser, which isn't polite. |suffix| is the |
| 221 // user-specific registration suffix; see GetUserSpecificDefaultBrowserSuffix | 221 // user-specific registration suffix; see GetUserSpecificDefaultBrowserSuffix |
| 222 // in shell_util.h for details. | 222 // in shell_util.h for details. |
| 223 static base::string16 GetBrowserClientKey(BrowserDistribution* dist, | 223 static base::string16 GetBrowserClientKey(BrowserDistribution* dist, |
| 224 const base::string16& suffix) { | 224 const base::string16& suffix); |
| 225 DCHECK(suffix.empty() || suffix[0] == L'.'); | |
| 226 return base::string16(ShellUtil::kRegStartMenuInternet) | |
| 227 .append(1, L'\\') | |
| 228 .append(dist->GetBaseAppName()) | |
| 229 .append(suffix); | |
| 230 } | |
| 231 | 225 |
| 232 // Returns the Windows Default Programs capabilities key for Chrome. For | 226 // Returns the Windows Default Programs capabilities key for Chrome. For |
| 233 // example: | 227 // example: |
| 234 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities". | 228 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities". |
| 235 static base::string16 GetCapabilitiesKey(BrowserDistribution* dist, | 229 static base::string16 GetCapabilitiesKey(BrowserDistribution* dist, |
| 236 const base::string16& suffix) { | 230 const base::string16& suffix); |
| 237 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities"); | |
| 238 } | |
| 239 | 231 |
| 240 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. This is | 232 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. This is |
| 241 // only needed for registring a web browser, not for general associations. | 233 // only needed for registring a web browser, not for general associations. |
| 242 static ScopedVector<RegistryEntry> GetChromeDelegateExecuteEntries( | 234 static ScopedVector<RegistryEntry> GetChromeDelegateExecuteEntries( |
| 243 const base::FilePath& chrome_exe, | 235 const base::FilePath& chrome_exe, |
| 244 const ApplicationInfo& app_info) { | 236 const ApplicationInfo& app_info); |
| 245 ScopedVector<RegistryEntry> entries; | |
| 246 | |
| 247 base::string16 app_id_shell_key(ShellUtil::kRegClasses); | |
| 248 app_id_shell_key.push_back(base::FilePath::kSeparators[0]); | |
| 249 app_id_shell_key.append(app_info.app_id); | |
| 250 app_id_shell_key.append(ShellUtil::kRegExePath); | |
| 251 app_id_shell_key.append(ShellUtil::kRegShellPath); | |
| 252 | |
| 253 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open | |
| 254 entries.push_back( | |
| 255 new RegistryEntry(app_id_shell_key, ShellUtil::kRegVerbOpen)); | |
| 256 | |
| 257 // The command to execute when opening this application via the Metro UI. | |
| 258 const base::string16 delegate_command( | |
| 259 ShellUtil::GetChromeDelegateCommand(chrome_exe)); | |
| 260 | |
| 261 // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is | |
| 262 // registered to handle some verbs. This registration has the side-effect | |
| 263 // that these verbs now show up in the shortcut's context menu. We | |
| 264 // mitigate this side-effect by making the context menu entries | |
| 265 // user readable/localized strings. See relevant MSDN article: | |
| 266 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx | |
| 267 static const struct { | |
| 268 const wchar_t* verb; | |
| 269 int name_id; | |
| 270 } verbs[] = { | |
| 271 {ShellUtil::kRegVerbOpen, -1}, | |
| 272 {ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE}, | |
| 273 }; | |
| 274 for (const auto& verb_and_id : verbs) { | |
| 275 base::string16 sub_path(app_id_shell_key); | |
| 276 sub_path.push_back(base::FilePath::kSeparators[0]); | |
| 277 sub_path.append(verb_and_id.verb); | |
| 278 | |
| 279 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb> | |
| 280 if (verb_and_id.name_id != -1) { | |
| 281 // TODO(grt): http://crbug.com/75152 Write a reference to a localized | |
| 282 // resource. | |
| 283 const base::string16 verb_name( | |
| 284 installer::GetLocalizedString(verb_and_id.name_id)); | |
| 285 entries.push_back(new RegistryEntry(sub_path, verb_name.c_str())); | |
| 286 } | |
| 287 entries.push_back( | |
| 288 new RegistryEntry(sub_path, L"CommandId", L"Browser.Launch")); | |
| 289 | |
| 290 sub_path.push_back(base::FilePath::kSeparators[0]); | |
| 291 sub_path.append(ShellUtil::kRegCommand); | |
| 292 | |
| 293 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command | |
| 294 entries.push_back(new RegistryEntry(sub_path, delegate_command)); | |
| 295 entries.push_back(new RegistryEntry( | |
| 296 sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid)); | |
| 297 } | |
| 298 | |
| 299 return entries.Pass(); | |
| 300 } | |
| 301 | 237 |
| 302 // This method returns a list of all the registry entries that | 238 // This method returns a list of all the registry entries that |
| 303 // are needed to register this installation's ProgId and AppId. | 239 // are needed to register this installation's ProgId and AppId. |
| 304 // These entries need to be registered in HKLM prior to Win8. | 240 // These entries need to be registered in HKLM prior to Win8. |
| 305 static void GetChromeProgIdEntries(BrowserDistribution* dist, | 241 static void GetChromeProgIdEntries(BrowserDistribution* dist, |
| 306 const base::FilePath& chrome_exe, | 242 const base::FilePath& chrome_exe, |
| 307 const base::string16& suffix, | 243 const base::string16& suffix, |
| 308 ScopedVector<RegistryEntry>* entries) { | 244 ScopedVector<RegistryEntry>* entries); |
| 309 int chrome_icon_index = | |
| 310 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME); | |
| 311 | |
| 312 ApplicationInfo app_info; | |
| 313 app_info.prog_id = GetBrowserProgId(suffix); | |
| 314 app_info.file_type_name = dist->GetBrowserProgIdDesc(); | |
| 315 // File types associated with Chrome are just given the Chrome icon. | |
| 316 app_info.file_type_icon_path = chrome_exe; | |
| 317 app_info.file_type_icon_index = chrome_icon_index; | |
| 318 app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe); | |
| 319 // For user-level installs: entries for the app id will be in HKCU; thus we | |
| 320 // do not need a suffix on those entries. | |
| 321 app_info.app_id = ShellUtil::GetBrowserModelId( | |
| 322 dist, InstallUtil::IsPerUserInstall(chrome_exe)); | |
| 323 | |
| 324 // TODO(grt): http://crbug.com/75152 Write a reference to a localized | |
| 325 // resource for name, description, and company. | |
| 326 app_info.application_name = dist->GetDisplayName(); | |
| 327 app_info.application_icon_path = chrome_exe; | |
| 328 app_info.application_icon_index = chrome_icon_index; | |
| 329 app_info.application_description = dist->GetAppDescription(); | |
| 330 app_info.publisher_name = dist->GetPublisherName(); | |
| 331 | |
| 332 app_info.delegate_clsid = dist->GetCommandExecuteImplClsid(); | |
| 333 | |
| 334 GetProgIdEntries(app_info, entries); | |
| 335 | |
| 336 if (!app_info.delegate_clsid.empty()) { | |
| 337 ScopedVector<RegistryEntry> delegate_execute_entries = | |
| 338 GetChromeDelegateExecuteEntries(chrome_exe, app_info); | |
| 339 if (!base::win::IsChromeMetroSupported()) { | |
| 340 // Remove the keys (not only their values) so that Windows will continue | |
| 341 // to launch Chrome without a pesky association error. | |
| 342 for (RegistryEntry* entry : delegate_execute_entries) | |
| 343 entry->set_removal_flag(RemovalFlag::KEY); | |
| 344 } | |
| 345 // Move |delegate_execute_entries| to |entries|. | |
| 346 entries->insert(entries->end(), delegate_execute_entries.begin(), | |
| 347 delegate_execute_entries.end()); | |
| 348 delegate_execute_entries.weak_clear(); | |
| 349 } | |
| 350 } | |
| 351 | 245 |
| 352 // Gets the registry entries to register an application in the Windows | 246 // Gets the registry entries to register an application in the Windows |
| 353 // registry. |app_info| provides all of the information needed. | 247 // registry. |app_info| provides all of the information needed. |
| 354 static void GetProgIdEntries(const ApplicationInfo& app_info, | 248 static void GetProgIdEntries(const ApplicationInfo& app_info, |
| 355 ScopedVector<RegistryEntry>* entries) { | 249 ScopedVector<RegistryEntry>* entries); |
| 356 // Basic sanity checks. | |
| 357 DCHECK(!app_info.prog_id.empty()); | |
| 358 DCHECK_NE(L'.', app_info.prog_id[0]); | |
| 359 | |
| 360 // File association ProgId | |
| 361 base::string16 prog_id_path(ShellUtil::kRegClasses); | |
| 362 prog_id_path.push_back(base::FilePath::kSeparators[0]); | |
| 363 prog_id_path.append(app_info.prog_id); | |
| 364 entries->push_back( | |
| 365 new RegistryEntry(prog_id_path, app_info.file_type_name)); | |
| 366 entries->push_back(new RegistryEntry( | |
| 367 prog_id_path + ShellUtil::kRegDefaultIcon, | |
| 368 ShellUtil::FormatIconLocation(app_info.file_type_icon_path, | |
| 369 app_info.file_type_icon_index))); | |
| 370 entries->push_back(new RegistryEntry( | |
| 371 prog_id_path + ShellUtil::kRegShellOpen, app_info.command_line)); | |
| 372 if (!app_info.delegate_clsid.empty()) { | |
| 373 entries->push_back( | |
| 374 new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen, | |
| 375 ShellUtil::kRegDelegateExecute, | |
| 376 app_info.delegate_clsid)); | |
| 377 // If Metro is not supported, remove the DelegateExecute entry instead of | |
| 378 // adding it. | |
| 379 if (!base::win::IsChromeMetroSupported()) | |
| 380 entries->back()->set_removal_flag(RemovalFlag::VALUE); | |
| 381 } | |
| 382 | |
| 383 // The following entries are required as of Windows 8, but do not | |
| 384 // depend on the DelegateExecute verb handler being set. | |
| 385 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { | |
| 386 if (!app_info.app_id.empty()) { | |
| 387 entries->push_back(new RegistryEntry( | |
| 388 prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id)); | |
| 389 } | |
| 390 | |
| 391 // Add \Software\Classes\<prog_id>\Application entries | |
| 392 base::string16 application_path(prog_id_path + | |
| 393 ShellUtil::kRegApplication); | |
| 394 if (!app_info.app_id.empty()) { | |
| 395 entries->push_back(new RegistryEntry( | |
| 396 application_path, ShellUtil::kRegAppUserModelId, app_info.app_id)); | |
| 397 } | |
| 398 if (!app_info.application_icon_path.empty()) { | |
| 399 entries->push_back(new RegistryEntry( | |
| 400 application_path, | |
| 401 ShellUtil::kRegApplicationIcon, | |
| 402 ShellUtil::FormatIconLocation(app_info.application_icon_path, | |
| 403 app_info.application_icon_index))); | |
| 404 } | |
| 405 if (!app_info.application_name.empty()) { | |
| 406 entries->push_back(new RegistryEntry(application_path, | |
| 407 ShellUtil::kRegApplicationName, | |
| 408 app_info.application_name)); | |
| 409 } | |
| 410 if (!app_info.application_description.empty()) { | |
| 411 entries->push_back( | |
| 412 new RegistryEntry(application_path, | |
| 413 ShellUtil::kRegApplicationDescription, | |
| 414 app_info.application_description)); | |
| 415 } | |
| 416 if (!app_info.publisher_name.empty()) { | |
| 417 entries->push_back(new RegistryEntry(application_path, | |
| 418 ShellUtil::kRegApplicationCompany, | |
| 419 app_info.publisher_name)); | |
| 420 } | |
| 421 } | |
| 422 } | |
| 423 | 250 |
| 424 // This method returns a list of the registry entries needed to declare a | 251 // This method returns a list of the registry entries needed to declare a |
| 425 // capability of handling a protocol on Windows. | 252 // capability of handling a protocol on Windows. |
| 426 static void GetProtocolCapabilityEntries( | 253 static void GetProtocolCapabilityEntries( |
| 427 BrowserDistribution* dist, | 254 BrowserDistribution* dist, |
| 428 const base::string16& suffix, | 255 const base::string16& suffix, |
| 429 const base::string16& protocol, | 256 const base::string16& protocol, |
| 430 ScopedVector<RegistryEntry>* entries) { | 257 ScopedVector<RegistryEntry>* entries); |
| 431 entries->push_back(new RegistryEntry( | |
| 432 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"), | |
| 433 protocol, GetBrowserProgId(suffix))); | |
| 434 } | |
| 435 | 258 |
| 436 // This method returns a list of the registry entries required to register | 259 // This method returns a list of the registry entries required to register |
| 437 // this installation in "RegisteredApplications" on Windows (to appear in | 260 // this installation in "RegisteredApplications" on Windows (to appear in |
| 438 // Default Programs, StartMenuInternet, etc.). | 261 // Default Programs, StartMenuInternet, etc.). |
| 439 // These entries need to be registered in HKLM prior to Win8. | 262 // These entries need to be registered in HKLM prior to Win8. |
| 440 // If |suffix| is not empty, these entries are guaranteed to be unique on this | 263 // If |suffix| is not empty, these entries are guaranteed to be unique on this |
| 441 // machine. | 264 // machine. |
| 442 static void GetShellIntegrationEntries(BrowserDistribution* dist, | 265 static void GetShellIntegrationEntries(BrowserDistribution* dist, |
| 443 const base::FilePath& chrome_exe, | 266 const base::FilePath& chrome_exe, |
| 444 const base::string16& suffix, | 267 const base::string16& suffix, |
| 445 ScopedVector<RegistryEntry>* entries) { | 268 ScopedVector<RegistryEntry>* entries); |
| 446 const base::string16 icon_path( | |
| 447 ShellUtil::FormatIconLocation( | |
| 448 chrome_exe, | |
| 449 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME))); | |
| 450 const base::string16 quoted_exe_path(L"\"" + chrome_exe.value() + L"\""); | |
| 451 | |
| 452 // Register for the Start Menu "Internet" link (pre-Win7). | |
| 453 const base::string16 start_menu_entry(GetBrowserClientKey(dist, suffix)); | |
| 454 // Register Chrome's display name. | |
| 455 // TODO(grt): http://crbug.com/75152 Also set LocalizedString; see | |
| 456 // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144109(v=VS.85)
.aspx#registering_the_display_name | |
| 457 entries->push_back(new RegistryEntry( | |
| 458 start_menu_entry, dist->GetDisplayName())); | |
| 459 // Register the "open" verb for launching Chrome via the "Internet" link. | |
| 460 entries->push_back(new RegistryEntry( | |
| 461 start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path)); | |
| 462 // Register Chrome's icon for the Start Menu "Internet" link. | |
| 463 entries->push_back(new RegistryEntry( | |
| 464 start_menu_entry + ShellUtil::kRegDefaultIcon, icon_path)); | |
| 465 | |
| 466 // Register installation information. | |
| 467 base::string16 install_info(start_menu_entry + L"\\InstallInfo"); | |
| 468 // Note: not using CommandLine since it has ambiguous rules for quoting | |
| 469 // strings. | |
| 470 entries->push_back(new RegistryEntry(install_info, kReinstallCommand, | |
| 471 quoted_exe_path + L" --" + | |
| 472 base::ASCIIToUTF16(switches::kMakeDefaultBrowser))); | |
| 473 entries->push_back(new RegistryEntry(install_info, L"HideIconsCommand", | |
| 474 quoted_exe_path + L" --" + | |
| 475 base::ASCIIToUTF16(switches::kHideIcons))); | |
| 476 entries->push_back(new RegistryEntry(install_info, L"ShowIconsCommand", | |
| 477 quoted_exe_path + L" --" + | |
| 478 base::ASCIIToUTF16(switches::kShowIcons))); | |
| 479 entries->push_back(new RegistryEntry(install_info, L"IconsVisible", 1)); | |
| 480 | |
| 481 // Register with Default Programs. | |
| 482 const base::string16 reg_app_name(dist->GetBaseAppName().append(suffix)); | |
| 483 // Tell Windows where to find Chrome's Default Programs info. | |
| 484 const base::string16 capabilities(GetCapabilitiesKey(dist, suffix)); | |
| 485 entries->push_back(new RegistryEntry(ShellUtil::kRegRegisteredApplications, | |
| 486 reg_app_name, capabilities)); | |
| 487 // Write out Chrome's Default Programs info. | |
| 488 // TODO(grt): http://crbug.com/75152 Write a reference to a localized | |
| 489 // resource rather than this. | |
| 490 entries->push_back(new RegistryEntry( | |
| 491 capabilities, ShellUtil::kRegApplicationDescription, | |
| 492 dist->GetLongAppDescription())); | |
| 493 entries->push_back(new RegistryEntry( | |
| 494 capabilities, ShellUtil::kRegApplicationIcon, icon_path)); | |
| 495 entries->push_back(new RegistryEntry( | |
| 496 capabilities, ShellUtil::kRegApplicationName, | |
| 497 dist->GetDisplayName())); | |
| 498 | |
| 499 entries->push_back(new RegistryEntry(capabilities + L"\\Startmenu", | |
| 500 L"StartMenuInternet", reg_app_name)); | |
| 501 | |
| 502 const base::string16 html_prog_id(GetBrowserProgId(suffix)); | |
| 503 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) { | |
| 504 entries->push_back(new RegistryEntry( | |
| 505 capabilities + L"\\FileAssociations", | |
| 506 ShellUtil::kPotentialFileAssociations[i], html_prog_id)); | |
| 507 } | |
| 508 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; | |
| 509 i++) { | |
| 510 entries->push_back(new RegistryEntry( | |
| 511 capabilities + L"\\URLAssociations", | |
| 512 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id)); | |
| 513 } | |
| 514 } | |
| 515 | 269 |
| 516 // This method returns a list of the registry entries required for this | 270 // This method returns a list of the registry entries required for this |
| 517 // installation to be registered in the Windows shell. | 271 // installation to be registered in the Windows shell. |
| 518 // In particular: | 272 // In particular: |
| 519 // - App Paths | 273 // - App Paths |
| 520 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121 | 274 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121 |
| 521 // - File Associations | 275 // - File Associations |
| 522 // http://msdn.microsoft.com/en-us/library/bb166549 | 276 // http://msdn.microsoft.com/en-us/library/bb166549 |
| 523 // These entries need to be registered in HKLM prior to Win8. | 277 // These entries need to be registered in HKLM prior to Win8. |
| 524 static void GetChromeAppRegistrationEntries( | 278 static void GetChromeAppRegistrationEntries( |
| 525 const base::FilePath& chrome_exe, | 279 const base::FilePath& chrome_exe, |
| 526 const base::string16& suffix, | 280 const base::string16& suffix, |
| 527 ScopedVector<RegistryEntry>* entries) { | 281 ScopedVector<RegistryEntry>* entries); |
| 528 base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey); | |
| 529 app_path_key.push_back(base::FilePath::kSeparators[0]); | |
| 530 app_path_key.append(chrome_exe.BaseName().value()); | |
| 531 entries->push_back(new RegistryEntry(app_path_key, chrome_exe.value())); | |
| 532 entries->push_back(new RegistryEntry(app_path_key, | |
| 533 ShellUtil::kAppPathsRegistryPathName, | |
| 534 chrome_exe.DirName().value())); | |
| 535 | |
| 536 const base::string16 html_prog_id(GetBrowserProgId(suffix)); | |
| 537 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) { | |
| 538 GetAppExtRegistrationEntries( | |
| 539 html_prog_id, ShellUtil::kPotentialFileAssociations[i], entries); | |
| 540 } | |
| 541 } | |
| 542 | 282 |
| 543 // Gets the registry entries to register an application as a handler for a | 283 // Gets the registry entries to register an application as a handler for a |
| 544 // particular file extension. |prog_id| is the ProgId used by Windows for the | 284 // particular file extension. |prog_id| is the ProgId used by Windows for the |
| 545 // application. |ext| is the file extension, which must begin with a '.'. | 285 // application. |ext| is the file extension, which must begin with a '.'. |
| 546 static void GetAppExtRegistrationEntries( | 286 static void GetAppExtRegistrationEntries( |
| 547 const base::string16& prog_id, | 287 const base::string16& prog_id, |
| 548 const base::string16& ext, | 288 const base::string16& ext, |
| 549 ScopedVector<RegistryEntry>* entries) { | 289 ScopedVector<RegistryEntry>* entries); |
| 550 // In HKEY_CURRENT_USER\Software\Classes\EXT\OpenWithProgids, create an | |
| 551 // empty value with this class's ProgId. | |
| 552 base::string16 key_name(ShellUtil::kRegClasses); | |
| 553 key_name.push_back(base::FilePath::kSeparators[0]); | |
| 554 key_name.append(ext); | |
| 555 key_name.push_back(base::FilePath::kSeparators[0]); | |
| 556 key_name.append(ShellUtil::kRegOpenWithProgids); | |
| 557 entries->push_back(new RegistryEntry(key_name, prog_id, base::string16())); | |
| 558 } | |
| 559 | 290 |
| 560 // Gets the registry entries to register an application as the default handler | 291 // Gets the registry entries to register an application as the default handler |
| 561 // for a particular file extension. |prog_id| is the ProgId used by Windows | 292 // for a particular file extension. |prog_id| is the ProgId used by Windows |
| 562 // for the application. |ext| is the file extension, which must begin with a | 293 // for the application. |ext| is the file extension, which must begin with a |
| 563 // '.'. If |overwrite_existing|, always sets the default handler; otherwise | 294 // '.'. If |overwrite_existing|, always sets the default handler; otherwise |
| 564 // only sets if there is no existing default. | 295 // only sets if there is no existing default. |
| 565 // | 296 // |
| 566 // This has no effect on Windows 8. Windows 8 ignores the default and lets the | 297 // This has no effect on Windows 8. Windows 8 ignores the default and lets the |
| 567 // user choose. If there is only one handler for a file, it will automatically | 298 // user choose. If there is only one handler for a file, it will automatically |
| 568 // become the default. Otherwise, the first time the user opens a file, they | 299 // become the default. Otherwise, the first time the user opens a file, they |
| 569 // are presented with the dialog to set the default handler. (This is roughly | 300 // are presented with the dialog to set the default handler. (This is roughly |
| 570 // equivalent to being called with |overwrite_existing| false.) | 301 // equivalent to being called with |overwrite_existing| false.) |
| 571 static void GetAppDefaultRegistrationEntries( | 302 static void GetAppDefaultRegistrationEntries( |
| 572 const base::string16& prog_id, | 303 const base::string16& prog_id, |
| 573 const base::string16& ext, | 304 const base::string16& ext, |
| 574 bool overwrite_existing, | 305 bool overwrite_existing, |
| 575 ScopedVector<RegistryEntry>* entries) { | 306 ScopedVector<RegistryEntry>* entries); |
| 576 // Set the default value of HKEY_CURRENT_USER\Software\Classes\EXT to this | |
| 577 // class's name. | |
| 578 base::string16 key_name(ShellUtil::kRegClasses); | |
| 579 key_name.push_back(base::FilePath::kSeparators[0]); | |
| 580 key_name.append(ext); | |
| 581 scoped_ptr<RegistryEntry> default_association( | |
| 582 new RegistryEntry(key_name, prog_id)); | |
| 583 if (overwrite_existing || | |
| 584 !default_association->KeyExistsInRegistry( | |
| 585 RegistryEntry::LOOK_IN_HKCU)) { | |
| 586 entries->push_back(default_association.release()); | |
| 587 } | |
| 588 } | |
| 589 | 307 |
| 590 // This method returns a list of all the user level registry entries that | 308 // This method returns a list of all the user level registry entries that |
| 591 // are needed to make Chromium the default handler for a protocol on XP. | 309 // are needed to make Chromium the default handler for a protocol on XP. |
| 592 static void GetXPStyleUserProtocolEntries( | 310 static void GetXPStyleUserProtocolEntries( |
| 593 const base::string16& protocol, | 311 const base::string16& protocol, |
| 594 const base::string16& chrome_icon, | 312 const base::string16& chrome_icon, |
| 595 const base::string16& chrome_open, | 313 const base::string16& chrome_open, |
| 596 ScopedVector<RegistryEntry>* entries) { | 314 ScopedVector<RegistryEntry>* entries); |
| 597 // Protocols associations. | |
| 598 base::string16 url_key(ShellUtil::kRegClasses); | |
| 599 url_key.push_back(base::FilePath::kSeparators[0]); | |
| 600 url_key.append(protocol); | |
| 601 | |
| 602 // This registry value tells Windows that this 'class' is a URL scheme | |
| 603 // so IE, explorer and other apps will route it to our handler. | |
| 604 // <root hkey>\Software\Classes\<protocol>\URL Protocol | |
| 605 entries->push_back(new RegistryEntry(url_key, | |
| 606 ShellUtil::kRegUrlProtocol, base::string16())); | |
| 607 | |
| 608 // <root hkey>\Software\Classes\<protocol>\DefaultIcon | |
| 609 base::string16 icon_key = url_key + ShellUtil::kRegDefaultIcon; | |
| 610 entries->push_back(new RegistryEntry(icon_key, chrome_icon)); | |
| 611 | |
| 612 // <root hkey>\Software\Classes\<protocol>\shell\open\command | |
| 613 base::string16 shell_key = url_key + ShellUtil::kRegShellOpen; | |
| 614 entries->push_back(new RegistryEntry(shell_key, chrome_open)); | |
| 615 | |
| 616 // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec | |
| 617 base::string16 dde_key = url_key + L"\\shell\\open\\ddeexec"; | |
| 618 entries->push_back(new RegistryEntry(dde_key, base::string16())); | |
| 619 | |
| 620 // <root hkey>\Software\Classes\<protocol>\shell\@ | |
| 621 base::string16 protocol_shell_key = url_key + ShellUtil::kRegShellPath; | |
| 622 entries->push_back(new RegistryEntry(protocol_shell_key, L"open")); | |
| 623 } | |
| 624 | 315 |
| 625 // This method returns a list of all the user level registry entries that | 316 // This method returns a list of all the user level registry entries that |
| 626 // are needed to make Chromium default browser on XP. | 317 // are needed to make Chromium default browser on XP. |
| 627 // Some of these entries are irrelevant in recent versions of Windows, but | 318 // Some of these entries are irrelevant in recent versions of Windows, but |
| 628 // we register them anyways as some legacy apps are hardcoded to lookup those | 319 // we register them anyways as some legacy apps are hardcoded to lookup those |
| 629 // values. | 320 // values. |
| 630 static void GetXPStyleDefaultBrowserUserEntries( | 321 static void GetXPStyleDefaultBrowserUserEntries( |
| 631 BrowserDistribution* dist, | 322 BrowserDistribution* dist, |
| 632 const base::FilePath& chrome_exe, | 323 const base::FilePath& chrome_exe, |
| 633 const base::string16& suffix, | 324 const base::string16& suffix, |
| 634 ScopedVector<RegistryEntry>* entries) { | 325 ScopedVector<RegistryEntry>* entries); |
| 635 // File extension associations. | |
| 636 base::string16 html_prog_id(GetBrowserProgId(suffix)); | |
| 637 for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) { | |
| 638 GetAppDefaultRegistrationEntries( | |
| 639 html_prog_id, ShellUtil::kDefaultFileAssociations[i], true, entries); | |
| 640 } | |
| 641 | |
| 642 // Protocols associations. | |
| 643 base::string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); | |
| 644 base::string16 chrome_icon = | |
| 645 ShellUtil::FormatIconLocation( | |
| 646 chrome_exe, | |
| 647 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); | |
| 648 for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) { | |
| 649 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i], | |
| 650 chrome_icon, chrome_open, entries); | |
| 651 } | |
| 652 | |
| 653 // start->Internet shortcut. | |
| 654 base::string16 start_menu(ShellUtil::kRegStartMenuInternet); | |
| 655 base::string16 app_name = dist->GetBaseAppName() + suffix; | |
| 656 entries->push_back(new RegistryEntry(start_menu, app_name)); | |
| 657 } | |
| 658 | 326 |
| 659 // Flags this RegistryKey with |removal_flag|, indicating that it should be | 327 // Flags this RegistryKey with |removal_flag|, indicating that it should be |
| 660 // removed rather than created. Note that this will not result in cleaning up | 328 // removed rather than created. Note that this will not result in cleaning up |
| 661 // the entire registry hierarchy below RegistryEntry even if it is left empty | 329 // the entire registry hierarchy below RegistryEntry even if it is left empty |
| 662 // by this operation (this should thus not be used for uninstall, but only to | 330 // by this operation (this should thus not be used for uninstall, but only to |
| 663 // unregister keys that should explicitly no longer be active in the current | 331 // unregister keys that should explicitly no longer be active in the current |
| 664 // configuration). | 332 // configuration). |
| 665 void set_removal_flag(RemovalFlag removal_flag) { | 333 void set_removal_flag(RemovalFlag removal_flag) { |
| 666 removal_flag_ = removal_flag; | 334 removal_flag_ = removal_flag; |
| 667 } | 335 } |
| 668 | 336 |
| 669 // Generates work_item tasks required to create (or potentially delete based | 337 // Generates work_item tasks required to create (or potentially delete based |
| 670 // on |removal_flag_|) the current RegistryEntry and add them to the given | 338 // on |removal_flag_|) the current RegistryEntry and add them to the given |
| 671 // work item list. | 339 // work item list. |
| 672 void AddToWorkItemList(HKEY root, WorkItemList *items) const { | 340 void AddToWorkItemList(HKEY root, WorkItemList* items) const; |
| 673 if (removal_flag_ == RemovalFlag::VALUE) { | |
| 674 items->AddDeleteRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, | |
| 675 name_); | |
| 676 } else if (removal_flag_ == RemovalFlag::KEY) { | |
| 677 items->AddDeleteRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); | |
| 678 } else { | |
| 679 DCHECK(removal_flag_ == RemovalFlag::NONE); | |
| 680 items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); | |
| 681 if (is_string_) { | |
| 682 items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, | |
| 683 name_, value_, true); | |
| 684 } else { | |
| 685 items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, | |
| 686 name_, int_value_, true); | |
| 687 } | |
| 688 } | |
| 689 } | |
| 690 | 341 |
| 691 // Returns true if this key is flagged for removal. | 342 // Returns true if this key is flagged for removal. |
| 692 bool IsFlaggedForRemoval() const { | 343 bool IsFlaggedForRemoval() const { |
| 693 return removal_flag_ != RemovalFlag::NONE; | 344 return removal_flag_ != RemovalFlag::NONE; |
| 694 } | 345 } |
| 695 | 346 |
| 696 // Checks if the current registry entry exists in HKCU\|key_path_|\|name_| | 347 // Checks if the current registry entry exists in HKCU\|key_path_|\|name_| |
| 697 // and value is |value_|. If the key does NOT exist in HKCU, checks for | 348 // and value is |value_|. If the key does NOT exist in HKCU, checks for |
| 698 // the correct name and value in HKLM. | 349 // the correct name and value in HKLM. |
| 699 // |look_for_in| specifies roots (HKCU and/or HKLM) in which to look for the | 350 // |look_for_in| specifies roots (HKCU and/or HKLM) in which to look for the |
| 700 // key, unspecified roots are not looked into (i.e. the the key is assumed not | 351 // key, unspecified roots are not looked into (i.e. the the key is assumed not |
| 701 // to exist in them). | 352 // to exist in them). |
| 702 // |look_for_in| must at least specify one root to look into. | 353 // |look_for_in| must at least specify one root to look into. |
| 703 // If |look_for_in| is LOOK_IN_HKCU_THEN_HKLM, this method mimics Windows' | 354 // If |look_for_in| is LOOK_IN_HKCU_THEN_HKLM, this method mimics Windows' |
| 704 // behavior when searching in HKCR (HKCU takes precedence over HKLM). For | 355 // behavior when searching in HKCR (HKCU takes precedence over HKLM). For |
| 705 // registrations outside of HKCR on versions of Windows prior to Win8, | 356 // registrations outside of HKCR on versions of Windows prior to Win8, |
| 706 // Chrome's values go in HKLM. This function will make unnecessary (but | 357 // Chrome's values go in HKLM. This function will make unnecessary (but |
| 707 // harmless) queries into HKCU in that case. | 358 // harmless) queries into HKCU in that case. |
| 708 bool ExistsInRegistry(uint32 look_for_in) const { | 359 bool ExistsInRegistry(uint32 look_for_in) const; |
| 709 DCHECK(look_for_in); | |
| 710 | |
| 711 RegistryStatus status = DOES_NOT_EXIST; | |
| 712 if (look_for_in & LOOK_IN_HKCU) | |
| 713 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); | |
| 714 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) | |
| 715 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); | |
| 716 return status == SAME_VALUE; | |
| 717 } | |
| 718 | 360 |
| 719 // Checks if the current registry entry exists in \|key_path_|\|name_|, | 361 // Checks if the current registry entry exists in \|key_path_|\|name_|, |
| 720 // regardless of value. Same lookup rules as ExistsInRegistry. | 362 // regardless of value. Same lookup rules as ExistsInRegistry. |
| 721 // Unlike ExistsInRegistry, this returns true if some other value is present | 363 // Unlike ExistsInRegistry, this returns true if some other value is present |
| 722 // with the same key. | 364 // with the same key. |
| 723 bool KeyExistsInRegistry(uint32 look_for_in) const { | 365 bool KeyExistsInRegistry(uint32 look_for_in) const; |
| 724 DCHECK(look_for_in); | |
| 725 | |
| 726 RegistryStatus status = DOES_NOT_EXIST; | |
| 727 if (look_for_in & LOOK_IN_HKCU) | |
| 728 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); | |
| 729 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) | |
| 730 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); | |
| 731 return status != DOES_NOT_EXIST; | |
| 732 } | |
| 733 | 366 |
| 734 private: | 367 private: |
| 735 // States this RegistryKey can be in compared to the registry. | 368 // States this RegistryKey can be in compared to the registry. |
| 736 enum RegistryStatus { | 369 enum RegistryStatus { |
| 737 // |name_| does not exist in the registry | 370 // |name_| does not exist in the registry |
| 738 DOES_NOT_EXIST, | 371 DOES_NOT_EXIST, |
| 739 // |name_| exists, but its value != |value_| | 372 // |name_| exists, but its value != |value_| |
| 740 DIFFERENT_VALUE, | 373 DIFFERENT_VALUE, |
| 741 // |name_| exists and its value is |value_| | 374 // |name_| exists and its value is |value_| |
| 742 SAME_VALUE, | 375 SAME_VALUE, |
| 743 }; | 376 }; |
| 744 | 377 |
| 745 // Create a object that represent default value of a key | 378 // Create a object that represent default value of a key |
| 746 RegistryEntry(const base::string16& key_path, const base::string16& value) | 379 RegistryEntry(const base::string16& key_path, const base::string16& value); |
| 747 : key_path_(key_path), | |
| 748 name_(), | |
| 749 is_string_(true), | |
| 750 value_(value), | |
| 751 int_value_(0), | |
| 752 removal_flag_(RemovalFlag::NONE) {} | |
| 753 | 380 |
| 754 // Create a object that represent a key of type REG_SZ | 381 // Create a object that represent a key of type REG_SZ |
| 755 RegistryEntry(const base::string16& key_path, | 382 RegistryEntry(const base::string16& key_path, |
| 756 const base::string16& name, | 383 const base::string16& name, |
| 757 const base::string16& value) | 384 const base::string16& value); |
| 758 : key_path_(key_path), | |
| 759 name_(name), | |
| 760 is_string_(true), | |
| 761 value_(value), | |
| 762 int_value_(0), | |
| 763 removal_flag_(RemovalFlag::NONE) {} | |
| 764 | 385 |
| 765 // Create a object that represent a key of integer type | 386 // Create a object that represent a key of integer type |
| 766 RegistryEntry(const base::string16& key_path, | 387 RegistryEntry(const base::string16& key_path, |
| 767 const base::string16& name, | 388 const base::string16& name, |
| 768 DWORD value) | 389 DWORD value); |
| 769 : key_path_(key_path), | |
| 770 name_(name), | |
| 771 is_string_(false), | |
| 772 value_(), | |
| 773 int_value_(value), | |
| 774 removal_flag_(RemovalFlag::NONE) {} | |
| 775 | 390 |
| 776 base::string16 key_path_; // key path for the registry entry | 391 base::string16 key_path_; // key path for the registry entry |
| 777 base::string16 name_; // name of the registry entry | 392 base::string16 name_; // name of the registry entry |
| 778 bool is_string_; // true if current registry entry is of type REG_SZ | 393 bool is_string_; // true if current registry entry is of type REG_SZ |
| 779 base::string16 value_; // string value (useful if is_string_ = true) | 394 base::string16 value_; // string value (useful if is_string_ = true) |
| 780 DWORD int_value_; // integer value (useful if is_string_ = false) | 395 DWORD int_value_; // integer value (useful if is_string_ = false) |
| 781 | 396 |
| 782 // Identifies whether this RegistryEntry is flagged for removal (i.e. no | 397 // Identifies whether this RegistryEntry is flagged for removal (i.e. no |
| 783 // longer relevant on the configuration it was created under). | 398 // longer relevant on the configuration it was created under). |
| 784 RemovalFlag removal_flag_; | 399 RemovalFlag removal_flag_; |
| 785 | 400 |
| 786 // Helper function for ExistsInRegistry(). | 401 // Helper function for ExistsInRegistry(). |
| 787 // Returns the RegistryStatus of the current registry entry in | 402 // Returns the RegistryStatus of the current registry entry in |
| 788 // |root|\|key_path_|\|name_|. | 403 // |root|\|key_path_|\|name_|. |
| 789 RegistryStatus StatusInRegistryUnderRoot(HKEY root) const { | 404 RegistryStatus StatusInRegistryUnderRoot(HKEY root) const; |
| 790 RegKey key(root, key_path_.c_str(), KEY_QUERY_VALUE); | |
| 791 bool found = false; | |
| 792 bool correct_value = false; | |
| 793 if (is_string_) { | |
| 794 base::string16 read_value; | |
| 795 found = key.ReadValue(name_.c_str(), &read_value) == ERROR_SUCCESS; | |
| 796 if (found) { | |
| 797 correct_value = read_value.size() == value_.size() && | |
| 798 ::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, | |
| 799 read_value.data(), | |
| 800 base::saturated_cast<int>(read_value.size()), | |
| 801 value_.data(), | |
| 802 base::saturated_cast<int>(value_.size())) | |
| 803 == CSTR_EQUAL; | |
| 804 } | |
| 805 } else { | |
| 806 DWORD read_value; | |
| 807 found = key.ReadValueDW(name_.c_str(), &read_value) == ERROR_SUCCESS; | |
| 808 if (found) | |
| 809 correct_value = read_value == int_value_; | |
| 810 } | |
| 811 return found ? | |
| 812 (correct_value ? SAME_VALUE : DIFFERENT_VALUE) : DOES_NOT_EXIST; | |
| 813 } | |
| 814 | 405 |
| 815 DISALLOW_COPY_AND_ASSIGN(RegistryEntry); | 406 DISALLOW_COPY_AND_ASSIGN(RegistryEntry); |
| 816 }; // class RegistryEntry | 407 }; // class RegistryEntry |
| 817 | 408 |
| 409 // static |
| 410 base::string16 RegistryEntry::GetBrowserClientKey( |
| 411 BrowserDistribution* dist, |
| 412 const base::string16& suffix) { |
| 413 DCHECK(suffix.empty() || suffix[0] == L'.'); |
| 414 return base::string16(ShellUtil::kRegStartMenuInternet) |
| 415 .append(1, L'\\') |
| 416 .append(dist->GetBaseAppName()) |
| 417 .append(suffix); |
| 418 } |
| 419 |
| 420 // static |
| 421 base::string16 RegistryEntry::GetCapabilitiesKey(BrowserDistribution* dist, |
| 422 const base::string16& suffix) { |
| 423 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities"); |
| 424 } |
| 425 |
| 426 // static |
| 427 ScopedVector<RegistryEntry> RegistryEntry::GetChromeDelegateExecuteEntries( |
| 428 const base::FilePath& chrome_exe, |
| 429 const RegistryEntry::ApplicationInfo& app_info) { |
| 430 ScopedVector<RegistryEntry> entries; |
| 431 |
| 432 base::string16 app_id_shell_key(ShellUtil::kRegClasses); |
| 433 app_id_shell_key.push_back(base::FilePath::kSeparators[0]); |
| 434 app_id_shell_key.append(app_info.app_id); |
| 435 app_id_shell_key.append(ShellUtil::kRegExePath); |
| 436 app_id_shell_key.append(ShellUtil::kRegShellPath); |
| 437 |
| 438 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open |
| 439 entries.push_back( |
| 440 new RegistryEntry(app_id_shell_key, ShellUtil::kRegVerbOpen)); |
| 441 |
| 442 // The command to execute when opening this application via the Metro UI. |
| 443 const base::string16 delegate_command( |
| 444 ShellUtil::GetChromeDelegateCommand(chrome_exe)); |
| 445 |
| 446 // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is |
| 447 // registered to handle some verbs. This registration has the side-effect |
| 448 // that these verbs now show up in the shortcut's context menu. We |
| 449 // mitigate this side-effect by making the context menu entries |
| 450 // user readable/localized strings. See relevant MSDN article: |
| 451 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx |
| 452 static const struct { |
| 453 const wchar_t* verb; |
| 454 int name_id; |
| 455 } verbs[] = { |
| 456 {ShellUtil::kRegVerbOpen, -1}, |
| 457 {ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE}, |
| 458 }; |
| 459 for (const auto& verb_and_id : verbs) { |
| 460 base::string16 sub_path(app_id_shell_key); |
| 461 sub_path.push_back(base::FilePath::kSeparators[0]); |
| 462 sub_path.append(verb_and_id.verb); |
| 463 |
| 464 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb> |
| 465 if (verb_and_id.name_id != -1) { |
| 466 // TODO(grt): http://crbug.com/75152 Write a reference to a localized |
| 467 // resource. |
| 468 const base::string16 verb_name( |
| 469 installer::GetLocalizedString(verb_and_id.name_id)); |
| 470 entries.push_back(new RegistryEntry(sub_path, verb_name.c_str())); |
| 471 } |
| 472 entries.push_back( |
| 473 new RegistryEntry(sub_path, L"CommandId", L"Browser.Launch")); |
| 474 |
| 475 sub_path.push_back(base::FilePath::kSeparators[0]); |
| 476 sub_path.append(ShellUtil::kRegCommand); |
| 477 |
| 478 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command |
| 479 entries.push_back(new RegistryEntry(sub_path, delegate_command)); |
| 480 entries.push_back(new RegistryEntry( |
| 481 sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid)); |
| 482 } |
| 483 |
| 484 return entries.Pass(); |
| 485 } |
| 486 |
| 487 // static |
| 488 void RegistryEntry::GetChromeProgIdEntries( |
| 489 BrowserDistribution* dist, |
| 490 const base::FilePath& chrome_exe, |
| 491 const base::string16& suffix, |
| 492 ScopedVector<RegistryEntry>* entries) { |
| 493 int chrome_icon_index = |
| 494 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME); |
| 495 |
| 496 ApplicationInfo app_info; |
| 497 app_info.prog_id = GetBrowserProgId(suffix); |
| 498 app_info.file_type_name = dist->GetBrowserProgIdDesc(); |
| 499 // File types associated with Chrome are just given the Chrome icon. |
| 500 app_info.file_type_icon_path = chrome_exe; |
| 501 app_info.file_type_icon_index = chrome_icon_index; |
| 502 app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe); |
| 503 // For user-level installs: entries for the app id will be in HKCU; thus we |
| 504 // do not need a suffix on those entries. |
| 505 app_info.app_id = ShellUtil::GetBrowserModelId( |
| 506 dist, InstallUtil::IsPerUserInstall(chrome_exe)); |
| 507 |
| 508 // TODO(grt): http://crbug.com/75152 Write a reference to a localized |
| 509 // resource for name, description, and company. |
| 510 app_info.application_name = dist->GetDisplayName(); |
| 511 app_info.application_icon_path = chrome_exe; |
| 512 app_info.application_icon_index = chrome_icon_index; |
| 513 app_info.application_description = dist->GetAppDescription(); |
| 514 app_info.publisher_name = dist->GetPublisherName(); |
| 515 |
| 516 app_info.delegate_clsid = dist->GetCommandExecuteImplClsid(); |
| 517 |
| 518 GetProgIdEntries(app_info, entries); |
| 519 |
| 520 if (!app_info.delegate_clsid.empty()) { |
| 521 ScopedVector<RegistryEntry> delegate_execute_entries = |
| 522 GetChromeDelegateExecuteEntries(chrome_exe, app_info); |
| 523 if (!base::win::IsChromeMetroSupported()) { |
| 524 // Remove the keys (not only their values) so that Windows will continue |
| 525 // to launch Chrome without a pesky association error. |
| 526 for (RegistryEntry* entry : delegate_execute_entries) |
| 527 entry->set_removal_flag(RemovalFlag::KEY); |
| 528 } |
| 529 // Move |delegate_execute_entries| to |entries|. |
| 530 entries->insert(entries->end(), delegate_execute_entries.begin(), |
| 531 delegate_execute_entries.end()); |
| 532 delegate_execute_entries.weak_clear(); |
| 533 } |
| 534 } |
| 535 |
| 536 // static |
| 537 void RegistryEntry::GetProgIdEntries( |
| 538 const RegistryEntry::ApplicationInfo& app_info, |
| 539 ScopedVector<RegistryEntry>* entries) { |
| 540 // Basic sanity checks. |
| 541 DCHECK(!app_info.prog_id.empty()); |
| 542 DCHECK_NE(L'.', app_info.prog_id[0]); |
| 543 |
| 544 // File association ProgId |
| 545 base::string16 prog_id_path(ShellUtil::kRegClasses); |
| 546 prog_id_path.push_back(base::FilePath::kSeparators[0]); |
| 547 prog_id_path.append(app_info.prog_id); |
| 548 entries->push_back(new RegistryEntry(prog_id_path, app_info.file_type_name)); |
| 549 entries->push_back(new RegistryEntry( |
| 550 prog_id_path + ShellUtil::kRegDefaultIcon, |
| 551 ShellUtil::FormatIconLocation(app_info.file_type_icon_path, |
| 552 app_info.file_type_icon_index))); |
| 553 entries->push_back(new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen, |
| 554 app_info.command_line)); |
| 555 if (!app_info.delegate_clsid.empty()) { |
| 556 entries->push_back(new RegistryEntry( |
| 557 prog_id_path + ShellUtil::kRegShellOpen, ShellUtil::kRegDelegateExecute, |
| 558 app_info.delegate_clsid)); |
| 559 // If Metro is not supported, remove the DelegateExecute entry instead of |
| 560 // adding it. |
| 561 if (!base::win::IsChromeMetroSupported()) |
| 562 entries->back()->set_removal_flag(RemovalFlag::VALUE); |
| 563 } |
| 564 |
| 565 // The following entries are required as of Windows 8, but do not |
| 566 // depend on the DelegateExecute verb handler being set. |
| 567 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { |
| 568 if (!app_info.app_id.empty()) { |
| 569 entries->push_back(new RegistryEntry( |
| 570 prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id)); |
| 571 } |
| 572 |
| 573 // Add \Software\Classes\<prog_id>\Application entries |
| 574 base::string16 application_path(prog_id_path + ShellUtil::kRegApplication); |
| 575 if (!app_info.app_id.empty()) { |
| 576 entries->push_back(new RegistryEntry( |
| 577 application_path, ShellUtil::kRegAppUserModelId, app_info.app_id)); |
| 578 } |
| 579 if (!app_info.application_icon_path.empty()) { |
| 580 entries->push_back(new RegistryEntry( |
| 581 application_path, ShellUtil::kRegApplicationIcon, |
| 582 ShellUtil::FormatIconLocation(app_info.application_icon_path, |
| 583 app_info.application_icon_index))); |
| 584 } |
| 585 if (!app_info.application_name.empty()) { |
| 586 entries->push_back(new RegistryEntry(application_path, |
| 587 ShellUtil::kRegApplicationName, |
| 588 app_info.application_name)); |
| 589 } |
| 590 if (!app_info.application_description.empty()) { |
| 591 entries->push_back(new RegistryEntry( |
| 592 application_path, ShellUtil::kRegApplicationDescription, |
| 593 app_info.application_description)); |
| 594 } |
| 595 if (!app_info.publisher_name.empty()) { |
| 596 entries->push_back(new RegistryEntry(application_path, |
| 597 ShellUtil::kRegApplicationCompany, |
| 598 app_info.publisher_name)); |
| 599 } |
| 600 } |
| 601 } |
| 602 |
| 603 // static |
| 604 void RegistryEntry::GetProtocolCapabilityEntries( |
| 605 BrowserDistribution* dist, |
| 606 const base::string16& suffix, |
| 607 const base::string16& protocol, |
| 608 ScopedVector<RegistryEntry>* entries) { |
| 609 entries->push_back(new RegistryEntry( |
| 610 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"), protocol, |
| 611 GetBrowserProgId(suffix))); |
| 612 } |
| 613 |
| 614 // static |
| 615 void RegistryEntry::GetShellIntegrationEntries( |
| 616 BrowserDistribution* dist, |
| 617 const base::FilePath& chrome_exe, |
| 618 const base::string16& suffix, |
| 619 ScopedVector<RegistryEntry>* entries) { |
| 620 const base::string16 icon_path(ShellUtil::FormatIconLocation( |
| 621 chrome_exe, dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME))); |
| 622 const base::string16 quoted_exe_path(L"\"" + chrome_exe.value() + L"\""); |
| 623 |
| 624 // Register for the Start Menu "Internet" link (pre-Win7). |
| 625 const base::string16 start_menu_entry(GetBrowserClientKey(dist, suffix)); |
| 626 // Register Chrome's display name. |
| 627 // TODO(grt): http://crbug.com/75152 Also set LocalizedString; see |
| 628 // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144109(v=VS.85).a
spx#registering_the_display_name |
| 629 entries->push_back( |
| 630 new RegistryEntry(start_menu_entry, dist->GetDisplayName())); |
| 631 // Register the "open" verb for launching Chrome via the "Internet" link. |
| 632 entries->push_back(new RegistryEntry( |
| 633 start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path)); |
| 634 // Register Chrome's icon for the Start Menu "Internet" link. |
| 635 entries->push_back(new RegistryEntry( |
| 636 start_menu_entry + ShellUtil::kRegDefaultIcon, icon_path)); |
| 637 |
| 638 // Register installation information. |
| 639 base::string16 install_info(start_menu_entry + L"\\InstallInfo"); |
| 640 // Note: not using CommandLine since it has ambiguous rules for quoting |
| 641 // strings. |
| 642 entries->push_back( |
| 643 new RegistryEntry(install_info, kReinstallCommand, |
| 644 quoted_exe_path + L" --" + |
| 645 base::ASCIIToUTF16(switches::kMakeDefaultBrowser))); |
| 646 entries->push_back(new RegistryEntry( |
| 647 install_info, L"HideIconsCommand", |
| 648 quoted_exe_path + L" --" + base::ASCIIToUTF16(switches::kHideIcons))); |
| 649 entries->push_back(new RegistryEntry( |
| 650 install_info, L"ShowIconsCommand", |
| 651 quoted_exe_path + L" --" + base::ASCIIToUTF16(switches::kShowIcons))); |
| 652 entries->push_back(new RegistryEntry(install_info, L"IconsVisible", 1)); |
| 653 |
| 654 // Register with Default Programs. |
| 655 const base::string16 reg_app_name(dist->GetBaseAppName().append(suffix)); |
| 656 // Tell Windows where to find Chrome's Default Programs info. |
| 657 const base::string16 capabilities(GetCapabilitiesKey(dist, suffix)); |
| 658 entries->push_back(new RegistryEntry(ShellUtil::kRegRegisteredApplications, |
| 659 reg_app_name, capabilities)); |
| 660 // Write out Chrome's Default Programs info. |
| 661 // TODO(grt): http://crbug.com/75152 Write a reference to a localized |
| 662 // resource rather than this. |
| 663 entries->push_back(new RegistryEntry(capabilities, |
| 664 ShellUtil::kRegApplicationDescription, |
| 665 dist->GetLongAppDescription())); |
| 666 entries->push_back(new RegistryEntry( |
| 667 capabilities, ShellUtil::kRegApplicationIcon, icon_path)); |
| 668 entries->push_back(new RegistryEntry( |
| 669 capabilities, ShellUtil::kRegApplicationName, dist->GetDisplayName())); |
| 670 |
| 671 entries->push_back(new RegistryEntry(capabilities + L"\\Startmenu", |
| 672 L"StartMenuInternet", reg_app_name)); |
| 673 |
| 674 const base::string16 html_prog_id(GetBrowserProgId(suffix)); |
| 675 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) { |
| 676 entries->push_back(new RegistryEntry( |
| 677 capabilities + L"\\FileAssociations", |
| 678 ShellUtil::kPotentialFileAssociations[i], html_prog_id)); |
| 679 } |
| 680 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; i++) { |
| 681 entries->push_back(new RegistryEntry( |
| 682 capabilities + L"\\URLAssociations", |
| 683 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id)); |
| 684 } |
| 685 } |
| 686 |
| 687 // static |
| 688 void RegistryEntry::GetChromeAppRegistrationEntries( |
| 689 const base::FilePath& chrome_exe, |
| 690 const base::string16& suffix, |
| 691 ScopedVector<RegistryEntry>* entries) { |
| 692 base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey); |
| 693 app_path_key.push_back(base::FilePath::kSeparators[0]); |
| 694 app_path_key.append(chrome_exe.BaseName().value()); |
| 695 entries->push_back(new RegistryEntry(app_path_key, chrome_exe.value())); |
| 696 entries->push_back(new RegistryEntry(app_path_key, |
| 697 ShellUtil::kAppPathsRegistryPathName, |
| 698 chrome_exe.DirName().value())); |
| 699 |
| 700 const base::string16 html_prog_id(GetBrowserProgId(suffix)); |
| 701 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) { |
| 702 GetAppExtRegistrationEntries( |
| 703 html_prog_id, ShellUtil::kPotentialFileAssociations[i], entries); |
| 704 } |
| 705 } |
| 706 |
| 707 // static |
| 708 void RegistryEntry::GetAppExtRegistrationEntries( |
| 709 const base::string16& prog_id, |
| 710 const base::string16& ext, |
| 711 ScopedVector<RegistryEntry>* entries) { |
| 712 // In HKEY_CURRENT_USER\Software\Classes\EXT\OpenWithProgids, create an |
| 713 // empty value with this class's ProgId. |
| 714 base::string16 key_name(ShellUtil::kRegClasses); |
| 715 key_name.push_back(base::FilePath::kSeparators[0]); |
| 716 key_name.append(ext); |
| 717 key_name.push_back(base::FilePath::kSeparators[0]); |
| 718 key_name.append(ShellUtil::kRegOpenWithProgids); |
| 719 entries->push_back(new RegistryEntry(key_name, prog_id, base::string16())); |
| 720 } |
| 721 |
| 722 // static |
| 723 void RegistryEntry::GetAppDefaultRegistrationEntries( |
| 724 const base::string16& prog_id, |
| 725 const base::string16& ext, |
| 726 bool overwrite_existing, |
| 727 ScopedVector<RegistryEntry>* entries) { |
| 728 // Set the default value of HKEY_CURRENT_USER\Software\Classes\EXT to this |
| 729 // class's name. |
| 730 base::string16 key_name(ShellUtil::kRegClasses); |
| 731 key_name.push_back(base::FilePath::kSeparators[0]); |
| 732 key_name.append(ext); |
| 733 scoped_ptr<RegistryEntry> default_association( |
| 734 new RegistryEntry(key_name, prog_id)); |
| 735 if (overwrite_existing || |
| 736 !default_association->KeyExistsInRegistry(RegistryEntry::LOOK_IN_HKCU)) { |
| 737 entries->push_back(default_association.release()); |
| 738 } |
| 739 } |
| 740 |
| 741 // static |
| 742 void RegistryEntry::GetXPStyleUserProtocolEntries( |
| 743 const base::string16& protocol, |
| 744 const base::string16& chrome_icon, |
| 745 const base::string16& chrome_open, |
| 746 ScopedVector<RegistryEntry>* entries) { |
| 747 // Protocols associations. |
| 748 base::string16 url_key(ShellUtil::kRegClasses); |
| 749 url_key.push_back(base::FilePath::kSeparators[0]); |
| 750 url_key.append(protocol); |
| 751 |
| 752 // This registry value tells Windows that this 'class' is a URL scheme |
| 753 // so IE, explorer and other apps will route it to our handler. |
| 754 // <root hkey>\Software\Classes\<protocol>\URL Protocol |
| 755 entries->push_back( |
| 756 new RegistryEntry(url_key, ShellUtil::kRegUrlProtocol, base::string16())); |
| 757 |
| 758 // <root hkey>\Software\Classes\<protocol>\DefaultIcon |
| 759 base::string16 icon_key = url_key + ShellUtil::kRegDefaultIcon; |
| 760 entries->push_back(new RegistryEntry(icon_key, chrome_icon)); |
| 761 |
| 762 // <root hkey>\Software\Classes\<protocol>\shell\open\command |
| 763 base::string16 shell_key = url_key + ShellUtil::kRegShellOpen; |
| 764 entries->push_back(new RegistryEntry(shell_key, chrome_open)); |
| 765 |
| 766 // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec |
| 767 base::string16 dde_key = url_key + L"\\shell\\open\\ddeexec"; |
| 768 entries->push_back(new RegistryEntry(dde_key, base::string16())); |
| 769 |
| 770 // <root hkey>\Software\Classes\<protocol>\shell\@ |
| 771 base::string16 protocol_shell_key = url_key + ShellUtil::kRegShellPath; |
| 772 entries->push_back(new RegistryEntry(protocol_shell_key, L"open")); |
| 773 } |
| 774 |
| 775 // static |
| 776 void RegistryEntry::GetXPStyleDefaultBrowserUserEntries( |
| 777 BrowserDistribution* dist, |
| 778 const base::FilePath& chrome_exe, |
| 779 const base::string16& suffix, |
| 780 ScopedVector<RegistryEntry>* entries) { |
| 781 // File extension associations. |
| 782 base::string16 html_prog_id(GetBrowserProgId(suffix)); |
| 783 for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) { |
| 784 GetAppDefaultRegistrationEntries( |
| 785 html_prog_id, ShellUtil::kDefaultFileAssociations[i], true, entries); |
| 786 } |
| 787 |
| 788 // Protocols associations. |
| 789 base::string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); |
| 790 base::string16 chrome_icon = ShellUtil::FormatIconLocation( |
| 791 chrome_exe, dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); |
| 792 for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) { |
| 793 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i], |
| 794 chrome_icon, chrome_open, entries); |
| 795 } |
| 796 |
| 797 // start->Internet shortcut. |
| 798 base::string16 start_menu(ShellUtil::kRegStartMenuInternet); |
| 799 base::string16 app_name = dist->GetBaseAppName() + suffix; |
| 800 entries->push_back(new RegistryEntry(start_menu, app_name)); |
| 801 } |
| 802 |
| 803 void RegistryEntry::AddToWorkItemList(HKEY root, WorkItemList* items) const { |
| 804 if (removal_flag_ == RemovalFlag::VALUE) { |
| 805 items->AddDeleteRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, |
| 806 name_); |
| 807 } else if (removal_flag_ == RemovalFlag::KEY) { |
| 808 items->AddDeleteRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); |
| 809 } else { |
| 810 DCHECK(removal_flag_ == RemovalFlag::NONE); |
| 811 items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); |
| 812 if (is_string_) { |
| 813 items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, |
| 814 name_, value_, true); |
| 815 } else { |
| 816 items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, |
| 817 name_, int_value_, true); |
| 818 } |
| 819 } |
| 820 } |
| 821 |
| 822 bool RegistryEntry::ExistsInRegistry(uint32 look_for_in) const { |
| 823 DCHECK(look_for_in); |
| 824 |
| 825 RegistryStatus status = DOES_NOT_EXIST; |
| 826 if (look_for_in & LOOK_IN_HKCU) |
| 827 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); |
| 828 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) |
| 829 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); |
| 830 return status == SAME_VALUE; |
| 831 } |
| 832 |
| 833 bool RegistryEntry::KeyExistsInRegistry(uint32 look_for_in) const { |
| 834 DCHECK(look_for_in); |
| 835 |
| 836 RegistryStatus status = DOES_NOT_EXIST; |
| 837 if (look_for_in & LOOK_IN_HKCU) |
| 838 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); |
| 839 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) |
| 840 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); |
| 841 return status != DOES_NOT_EXIST; |
| 842 } |
| 843 |
| 844 RegistryEntry::RegistryEntry(const base::string16& key_path, |
| 845 const base::string16& value) |
| 846 : key_path_(key_path), |
| 847 name_(), |
| 848 is_string_(true), |
| 849 value_(value), |
| 850 int_value_(0), |
| 851 removal_flag_(RemovalFlag::NONE) {} |
| 852 |
| 853 RegistryEntry::RegistryEntry(const base::string16& key_path, |
| 854 const base::string16& name, |
| 855 const base::string16& value) |
| 856 : key_path_(key_path), |
| 857 name_(name), |
| 858 is_string_(true), |
| 859 value_(value), |
| 860 int_value_(0), |
| 861 removal_flag_(RemovalFlag::NONE) {} |
| 862 |
| 863 RegistryEntry::RegistryEntry(const base::string16& key_path, |
| 864 const base::string16& name, |
| 865 DWORD value) |
| 866 : key_path_(key_path), |
| 867 name_(name), |
| 868 is_string_(false), |
| 869 value_(), |
| 870 int_value_(value), |
| 871 removal_flag_(RemovalFlag::NONE) {} |
| 872 |
| 873 RegistryEntry::RegistryStatus RegistryEntry::StatusInRegistryUnderRoot( |
| 874 HKEY root) const { |
| 875 RegKey key(root, key_path_.c_str(), KEY_QUERY_VALUE); |
| 876 bool found = false; |
| 877 bool correct_value = false; |
| 878 if (is_string_) { |
| 879 base::string16 read_value; |
| 880 found = key.ReadValue(name_.c_str(), &read_value) == ERROR_SUCCESS; |
| 881 if (found) { |
| 882 correct_value = |
| 883 read_value.size() == value_.size() && |
| 884 ::CompareString( |
| 885 LOCALE_USER_DEFAULT, NORM_IGNORECASE, read_value.data(), |
| 886 base::saturated_cast<int>(read_value.size()), value_.data(), |
| 887 base::saturated_cast<int>(value_.size())) == CSTR_EQUAL; |
| 888 } |
| 889 } else { |
| 890 DWORD read_value; |
| 891 found = key.ReadValueDW(name_.c_str(), &read_value) == ERROR_SUCCESS; |
| 892 if (found) |
| 893 correct_value = read_value == int_value_; |
| 894 } |
| 895 return found ? (correct_value ? SAME_VALUE : DIFFERENT_VALUE) |
| 896 : DOES_NOT_EXIST; |
| 897 } |
| 818 | 898 |
| 819 // This method converts all the RegistryEntries from the given list to | 899 // This method converts all the RegistryEntries from the given list to |
| 820 // Set/CreateRegWorkItems and runs them using WorkItemList. | 900 // Set/CreateRegWorkItems and runs them using WorkItemList. |
| 821 bool AddRegistryEntries(HKEY root, const ScopedVector<RegistryEntry>& entries) { | 901 bool AddRegistryEntries(HKEY root, const ScopedVector<RegistryEntry>& entries) { |
| 822 scoped_ptr<WorkItemList> items(WorkItem::CreateWorkItemList()); | 902 scoped_ptr<WorkItemList> items(WorkItem::CreateWorkItemList()); |
| 823 | 903 |
| 824 for (ScopedVector<RegistryEntry>::const_iterator itr = entries.begin(); | 904 for (ScopedVector<RegistryEntry>::const_iterator itr = entries.begin(); |
| 825 itr != entries.end(); ++itr) | 905 itr != entries.end(); ++itr) |
| 826 (*itr)->AddToWorkItemList(root, items.get()); | 906 (*itr)->AddToWorkItemList(root, items.get()); |
| 827 | 907 |
| (...skipping 1692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2520 base::string16 key_path(ShellUtil::kRegClasses); | 2600 base::string16 key_path(ShellUtil::kRegClasses); |
| 2521 key_path.push_back(base::FilePath::kSeparators[0]); | 2601 key_path.push_back(base::FilePath::kSeparators[0]); |
| 2522 key_path.append(prog_id); | 2602 key_path.append(prog_id); |
| 2523 return InstallUtil::DeleteRegistryKey( | 2603 return InstallUtil::DeleteRegistryKey( |
| 2524 HKEY_CURRENT_USER, key_path, WorkItem::kWow64Default); | 2604 HKEY_CURRENT_USER, key_path, WorkItem::kWow64Default); |
| 2525 | 2605 |
| 2526 // TODO(mgiuca): Remove the extension association entries. This requires that | 2606 // TODO(mgiuca): Remove the extension association entries. This requires that |
| 2527 // the extensions associated with a particular prog_id are stored in that | 2607 // the extensions associated with a particular prog_id are stored in that |
| 2528 // prog_id's key. | 2608 // prog_id's key. |
| 2529 } | 2609 } |
| OLD | NEW |