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

Unified Diff: chrome/browser/shell_integration_win.cc

Issue 12321107: Move shell integration code from chrome/browser to apps (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 10 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/shell_integration_win.cc
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
deleted file mode 100644
index 5dd80834c0ab7b81ce673f99f255d24c920ac2c2..0000000000000000000000000000000000000000
--- a/chrome/browser/shell_integration_win.cc
+++ /dev/null
@@ -1,519 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/shell_integration.h"
-
-#include <windows.h>
-#include <shobjidl.h>
-#include <propkey.h>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "base/win/registry.h"
-#include "base/win/scoped_comptr.h"
-#include "base/win/scoped_propvariant.h"
-#include "base/win/shortcut.h"
-#include "base/win/windows_version.h"
-#include "chrome/browser/web_applications/web_app.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_paths_internal.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/installer/setup/setup_util.h"
-#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/create_reg_key_work_item.h"
-#include "chrome/installer/util/install_util.h"
-#include "chrome/installer/util/set_reg_value_work_item.h"
-#include "chrome/installer/util/shell_util.h"
-#include "chrome/installer/util/util_constants.h"
-#include "chrome/installer/util/work_item.h"
-#include "chrome/installer/util/work_item_list.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
-
-namespace {
-
-const wchar_t kAppListAppNameSuffix[] = L"AppList";
-
-// Helper function for ShellIntegration::GetAppId to generates profile id
-// from profile path. "profile_id" is composed of sanitized basenames of
-// user data dir and profile dir joined by a ".".
-string16 GetProfileIdFromPath(const base::FilePath& profile_path) {
- // Return empty string if profile_path is empty
- if (profile_path.empty())
- return string16();
-
- base::FilePath default_user_data_dir;
- // Return empty string if profile_path is in default user data
- // dir and is the default profile.
- if (chrome::GetDefaultUserDataDirectory(&default_user_data_dir) &&
- profile_path.DirName() == default_user_data_dir &&
- profile_path.BaseName().value() ==
- ASCIIToUTF16(chrome::kInitialProfile)) {
- return string16();
- }
-
- // Get joined basenames of user data dir and profile.
- string16 basenames = profile_path.DirName().BaseName().value() +
- L"." + profile_path.BaseName().value();
-
- string16 profile_id;
- profile_id.reserve(basenames.size());
-
- // Generate profile_id from sanitized basenames.
- for (size_t i = 0; i < basenames.length(); ++i) {
- if (IsAsciiAlpha(basenames[i]) ||
- IsAsciiDigit(basenames[i]) ||
- basenames[i] == L'.')
- profile_id += basenames[i];
- }
-
- return profile_id;
-}
-
-string16 GetAppListAppName() {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- string16 app_name(dist->GetBaseAppId());
- app_name.append(kAppListAppNameSuffix);
- return app_name;
-}
-
-// Gets expected app id for given Chrome (based on |command_line| and
-// |is_per_user_install|).
-string16 GetExpectedAppId(const CommandLine& command_line,
- bool is_per_user_install) {
- base::FilePath profile_path;
- if (command_line.HasSwitch(switches::kUserDataDir)) {
- profile_path =
- command_line.GetSwitchValuePath(switches::kUserDataDir).AppendASCII(
- chrome::kInitialProfile);
- }
-
- string16 app_name;
- if (command_line.HasSwitch(switches::kApp)) {
- app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromURL(
- GURL(command_line.GetSwitchValueASCII(switches::kApp))));
- } else if (command_line.HasSwitch(switches::kAppId)) {
- app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromExtensionId(
- command_line.GetSwitchValueASCII(switches::kAppId)));
- } else if (command_line.HasSwitch(switches::kShowAppList)) {
- app_name = GetAppListAppName();
- } else {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- app_name = ShellUtil::GetBrowserModelId(dist, is_per_user_install);
- }
-
- return ShellIntegration::GetAppModelIdForProfile(app_name, profile_path);
-}
-
-void MigrateChromiumShortcutsCallback() {
- // This should run on the file thread.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Get full path of chrome.
- base::FilePath chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &chrome_exe))
- return;
-
- // Locations to check for shortcuts migration.
- static const struct {
- int location_id;
- const wchar_t* sub_dir;
- } kLocations[] = {
- {
- base::DIR_TASKBAR_PINS,
- NULL
- }, {
- base::DIR_USER_DESKTOP,
- NULL
- }, {
- base::DIR_START_MENU,
- NULL
- }, {
- base::DIR_APP_DATA,
- L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\StartMenu"
- }
- };
-
- for (int i = 0; i < arraysize(kLocations); ++i) {
- base::FilePath path;
- if (!PathService::Get(kLocations[i].location_id, &path)) {
- NOTREACHED();
- continue;
- }
-
- if (kLocations[i].sub_dir)
- path = path.Append(kLocations[i].sub_dir);
-
- bool check_dual_mode = (kLocations[i].location_id == base::DIR_START_MENU);
- ShellIntegration::MigrateShortcutsInPathInternal(chrome_exe, path,
- check_dual_mode);
- }
-}
-
-ShellIntegration::DefaultWebClientState
- GetDefaultWebClientStateFromShellUtilDefaultState(
- ShellUtil::DefaultState default_state) {
- switch (default_state) {
- case ShellUtil::NOT_DEFAULT:
- return ShellIntegration::NOT_DEFAULT;
- case ShellUtil::IS_DEFAULT:
- return ShellIntegration::IS_DEFAULT;
- default:
- DCHECK_EQ(ShellUtil::UNKNOWN_DEFAULT, default_state);
- return ShellIntegration::UNKNOWN_DEFAULT;
- }
-}
-
-} // namespace
-
-ShellIntegration::DefaultWebClientSetPermission
- ShellIntegration::CanSetAsDefaultBrowser() {
- if (!BrowserDistribution::GetDistribution()->CanSetAsDefault())
- return SET_DEFAULT_NOT_ALLOWED;
-
- if (ShellUtil::CanMakeChromeDefaultUnattended())
- return SET_DEFAULT_UNATTENDED;
- else
- return SET_DEFAULT_INTERACTIVE;
-}
-
-bool ShellIntegration::SetAsDefaultBrowser() {
- base::FilePath chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
- LOG(ERROR) << "Error getting app exe path";
- return false;
- }
-
- // From UI currently we only allow setting default browser for current user.
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- if (!ShellUtil::MakeChromeDefault(dist, ShellUtil::CURRENT_USER,
- chrome_exe.value(), true)) {
- LOG(ERROR) << "Chrome could not be set as default browser.";
- return false;
- }
-
- VLOG(1) << "Chrome registered as default browser.";
- return true;
-}
-
-bool ShellIntegration::SetAsDefaultProtocolClient(const std::string& protocol) {
- if (protocol.empty())
- return false;
-
- base::FilePath chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
- LOG(ERROR) << "Error getting app exe path";
- return false;
- }
-
- string16 wprotocol(UTF8ToUTF16(protocol));
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- if (!ShellUtil::MakeChromeDefaultProtocolClient(dist, chrome_exe.value(),
- wprotocol)) {
- LOG(ERROR) << "Chrome could not be set as default handler for "
- << protocol << ".";
- return false;
- }
-
- VLOG(1) << "Chrome registered as default handler for " << protocol << ".";
- return true;
-}
-
-bool ShellIntegration::SetAsDefaultBrowserInteractive() {
- base::FilePath chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
- NOTREACHED() << "Error getting app exe path";
- return false;
- }
-
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- if (!ShellUtil::ShowMakeChromeDefaultSystemUI(dist, chrome_exe.value())) {
- LOG(ERROR) << "Failed to launch the set-default-browser Windows UI.";
- return false;
- }
-
- VLOG(1) << "Set-default-browser Windows UI completed.";
- return true;
-}
-
-bool ShellIntegration::SetAsDefaultProtocolClientInteractive(
- const std::string& protocol) {
- base::FilePath chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
- NOTREACHED() << "Error getting app exe path";
- return false;
- }
-
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- string16 wprotocol(UTF8ToUTF16(protocol));
- if (!ShellUtil::ShowMakeChromeDefaultProtocolClientSystemUI(
- dist, chrome_exe.value(), wprotocol)) {
- LOG(ERROR) << "Failed to launch the set-default-client Windows UI.";
- return false;
- }
-
- VLOG(1) << "Set-default-client Windows UI completed.";
- return true;
-}
-
-ShellIntegration::DefaultWebClientState ShellIntegration::GetDefaultBrowser() {
- return GetDefaultWebClientStateFromShellUtilDefaultState(
- ShellUtil::GetChromeDefaultState());
-}
-
-ShellIntegration::DefaultWebClientState
- ShellIntegration::IsDefaultProtocolClient(const std::string& protocol) {
- return GetDefaultWebClientStateFromShellUtilDefaultState(
- ShellUtil::GetChromeDefaultProtocolClientState(UTF8ToUTF16(protocol)));
-}
-
-std::string ShellIntegration::GetApplicationForProtocol(const GURL& url) {
- // TODO(calamity): this will be implemented when external_protocol_dialog is
- // refactored on windows.
- NOTREACHED();
- return std::string();
-}
-
-// There is no reliable way to say which browser is default on a machine (each
-// browser can have some of the protocols/shortcuts). So we look for only HTTP
-// protocol handler. Even this handler is located at different places in
-// registry on XP and Vista:
-// - HKCR\http\shell\open\command (XP)
-// - HKCU\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\
-// http\UserChoice (Vista)
-// This method checks if Firefox is defualt browser by checking these
-// locations and returns true if Firefox traces are found there. In case of
-// error (or if Firefox is not found)it returns the default value which
-// is false.
-bool ShellIntegration::IsFirefoxDefaultBrowser() {
- bool ff_default = false;
- if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
- string16 app_cmd;
- base::win::RegKey key(HKEY_CURRENT_USER,
- ShellUtil::kRegVistaUrlPrefs, KEY_READ);
- if (key.Valid() && (key.ReadValue(L"Progid", &app_cmd) == ERROR_SUCCESS) &&
- app_cmd == L"FirefoxURL")
- ff_default = true;
- } else {
- string16 key_path(L"http");
- key_path.append(ShellUtil::kRegShellOpen);
- base::win::RegKey key(HKEY_CLASSES_ROOT, key_path.c_str(), KEY_READ);
- string16 app_cmd;
- if (key.Valid() && (key.ReadValue(L"", &app_cmd) == ERROR_SUCCESS) &&
- string16::npos != StringToLowerASCII(app_cmd).find(L"firefox"))
- ff_default = true;
- }
- return ff_default;
-}
-
-string16 ShellIntegration::GetAppModelIdForProfile(
- const string16& app_name,
- const base::FilePath& profile_path) {
- std::vector<string16> components;
- components.push_back(app_name);
- const string16 profile_id(GetProfileIdFromPath(profile_path));
- if (!profile_id.empty())
- components.push_back(profile_id);
- return ShellUtil::BuildAppModelId(components);
-}
-
-string16 ShellIntegration::GetChromiumModelIdForProfile(
- const base::FilePath& profile_path) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- base::FilePath chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
- NOTREACHED();
- return dist->GetBaseAppId();
- }
- return GetAppModelIdForProfile(
- ShellUtil::GetBrowserModelId(
- dist, InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())),
- profile_path);
-}
-
-string16 ShellIntegration::GetAppListAppModelIdForProfile(
- const base::FilePath& profile_path) {
- return ShellIntegration::GetAppModelIdForProfile(
- GetAppListAppName(), profile_path);
-}
-
-string16 ShellIntegration::GetChromiumIconLocation() {
- // Determine the path to chrome.exe. If we can't determine what that is,
- // we have bigger fish to fry...
- base::FilePath chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
- NOTREACHED();
- return string16();
- }
-
- return ShellUtil::FormatIconLocation(
- chrome_exe.value(),
- BrowserDistribution::GetDistribution()->GetIconIndex());
-}
-
-void ShellIntegration::MigrateChromiumShortcuts() {
- if (base::win::GetVersion() < base::win::VERSION_WIN7)
- return;
-
- // This needs to happen eventually (e.g. so that the appid is fixed and the
- // run-time Chrome icon is merged with the taskbar shortcut), but this is not
- // urgent and shouldn't delay Chrome startup.
- static const int64 kMigrateChromiumShortcutsDelaySeconds = 15;
- BrowserThread::PostDelayedTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&MigrateChromiumShortcutsCallback),
- base::TimeDelta::FromSeconds(kMigrateChromiumShortcutsDelaySeconds));
-}
-
-int ShellIntegration::MigrateShortcutsInPathInternal(
- const base::FilePath& chrome_exe,
- const base::FilePath& path,
- bool check_dual_mode) {
- DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN7);
-
- // Enumerate all pinned shortcuts in the given path directly.
- file_util::FileEnumerator shortcuts_enum(
- path, false, // not recursive
- file_util::FileEnumerator::FILES, FILE_PATH_LITERAL("*.lnk"));
-
- bool is_per_user_install =
- InstallUtil::IsPerUserInstall(chrome_exe.value().c_str());
-
- int shortcuts_migrated = 0;
- base::FilePath target_path;
- string16 arguments;
- base::win::ScopedPropVariant propvariant;
- for (base::FilePath shortcut = shortcuts_enum.Next(); !shortcut.empty();
- shortcut = shortcuts_enum.Next()) {
- // TODO(gab): Use ProgramCompare instead of comparing FilePaths below once
- // it is fixed to work with FilePaths with spaces.
- if (!base::win::ResolveShortcut(shortcut, &target_path, &arguments) ||
- chrome_exe != target_path) {
- continue;
- }
- CommandLine command_line(CommandLine::FromString(base::StringPrintf(
- L"\"%ls\" %ls", target_path.value().c_str(), arguments.c_str())));
-
- // Get the expected AppId for this Chrome shortcut.
- string16 expected_app_id(
- GetExpectedAppId(command_line, is_per_user_install));
- if (expected_app_id.empty())
- continue;
-
- // Load the shortcut.
- base::win::ScopedComPtr<IShellLink> shell_link;
- base::win::ScopedComPtr<IPersistFile> persist_file;
- if (FAILED(shell_link.CreateInstance(CLSID_ShellLink, NULL,
- CLSCTX_INPROC_SERVER)) ||
- FAILED(persist_file.QueryFrom(shell_link)) ||
- FAILED(persist_file->Load(shortcut.value().c_str(), STGM_READ))) {
- DLOG(WARNING) << "Failed loading shortcut at " << shortcut.value();
- continue;
- }
-
- // Any properties that need to be updated on the shortcut will be stored in
- // |updated_properties|.
- base::win::ShortcutProperties updated_properties;
-
- // Validate the existing app id for the shortcut.
- base::win::ScopedComPtr<IPropertyStore> property_store;
- propvariant.Reset();
- if (FAILED(property_store.QueryFrom(shell_link)) ||
- property_store->GetValue(PKEY_AppUserModel_ID,
- propvariant.Receive()) != S_OK) {
- // When in doubt, prefer not updating the shortcut.
- NOTREACHED();
- continue;
- } else {
- switch (propvariant.get().vt) {
- case VT_EMPTY:
- // If there is no app_id set, set our app_id if one is expected.
- if (!expected_app_id.empty())
- updated_properties.set_app_id(expected_app_id);
- break;
- case VT_LPWSTR:
- if (expected_app_id != string16(propvariant.get().pwszVal))
- updated_properties.set_app_id(expected_app_id);
- break;
- default:
- NOTREACHED();
- continue;
- }
- }
-
- if (check_dual_mode) {
- propvariant.Reset();
- if (property_store->GetValue(PKEY_AppUserModel_IsDualMode,
- propvariant.Receive()) != S_OK) {
- // When in doubt, prefer to not update the shortcut.
- NOTREACHED();
- continue;
- } else {
- switch (propvariant.get().vt) {
- case VT_EMPTY:
- // If dual_mode is not set at all, make sure it gets set to true.
- updated_properties.set_dual_mode(true);
- break;
- case VT_BOOL:
- // If it is set to false, make sure it gets set to true as well.
- if (!propvariant.get().boolVal)
- updated_properties.set_dual_mode(true);
- break;
- default:
- NOTREACHED();
- continue;
- }
- }
- }
-
- persist_file.Release();
- shell_link.Release();
-
- // Update the shortcut if some of its properties need to be updated.
- if (updated_properties.options &&
- base::win::CreateOrUpdateShortcutLink(
- shortcut, updated_properties,
- base::win::SHORTCUT_UPDATE_EXISTING)) {
- ++shortcuts_migrated;
- }
- }
- return shortcuts_migrated;
-}
-
-base::FilePath ShellIntegration::GetStartMenuShortcut(
- const base::FilePath& chrome_exe) {
- static const int kFolderIds[] = {
- base::DIR_COMMON_START_MENU,
- base::DIR_START_MENU,
- };
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- string16 shortcut_name(dist->GetAppShortCutName());
- base::FilePath shortcut;
-
- // Check both the common and the per-user Start Menu folders for system-level
- // installs.
- size_t folder =
- InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()) ? 1 : 0;
- for (; folder < arraysize(kFolderIds); ++folder) {
- if (!PathService::Get(kFolderIds[folder], &shortcut)) {
- NOTREACHED();
- continue;
- }
-
- shortcut = shortcut.Append(shortcut_name).Append(shortcut_name +
- installer::kLnkExt);
- if (file_util::PathExists(shortcut))
- return shortcut;
- }
-
- return base::FilePath();
-}

Powered by Google App Engine
This is Rietveld 408576698