#include "base/bind.h"
#include "base/command_line.h"
-#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/md5.h"
#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/master_preferences_constants.h"
#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/work_item.h"
#include "installer_util_strings.h" // NOLINT
}
COMPILE_ASSERT(sizeof(base::MD5Digest) == 16, size_of_MD5_not_as_expected_);
base::MD5Digest md5_digest;
- std::string user_sid_ascii(UTF16ToASCII(user_sid));
+ std::string user_sid_ascii(base::UTF16ToASCII(user_sid));
base::MD5Sum(user_sid_ascii.c_str(), user_sid_ascii.length(), &md5_digest);
const base::string16 base32_md5(
ShellUtil::ByteArrayToBase32(md5_digest.a, arraysize(md5_digest.a)));
LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM,
};
+ // Details about a Windows application, to be entered into the registry for
+ // the purpose of file associations.
+ struct ApplicationInfo {
+ ApplicationInfo() : file_type_icon_index(0), application_icon_index(0) {}
+
+ // The ProgId used by Windows for file associations with this application.
+ // Must not be empty or start with a '.'.
+ base::string16 prog_id;
+ // The friendly name, and the path of the icon that will be used for files
+ // of these types when associated with this application by default. (They
+ // are NOT the name/icon that will represent the application under the Open
+ // With menu.)
+ base::string16 file_type_name;
+ // TODO(mgiuca): |file_type_icon_path| should be a base::FilePath.
+ base::string16 file_type_icon_path;
+ int file_type_icon_index;
+ // The command to execute when opening a file via this association. It
+ // should contain "%1" (to tell Windows to pass the filename as an
+ // argument).
+ // TODO(mgiuca): |command_line| should be a base::CommandLine.
+ base::string16 command_line;
+ // The AppUserModelId used by Windows 8 for this application. Distinct from
+ // |prog_id|.
+ base::string16 app_id;
+
+ // User-visible details about this application. Any of these may be empty.
+ base::string16 application_name;
+ // TODO(mgiuca): |application_icon_path| should be a base::FilePath.
+ base::string16 application_icon_path;
+ int application_icon_index;
+ base::string16 application_description;
+ base::string16 publisher_name;
+
+ // The CLSID for the application's DelegateExecute handler. May be empty.
+ base::string16 delegate_clsid;
+ };
+
// Returns the Windows browser client registration key for Chrome. For
// example: "Software\Clients\StartMenuInternet\Chromium[.user]". Strictly
// speaking, we should use the name of the executable (e.g., "chrome.exe"),
// This method returns a list of all the registry entries that
// are needed to register this installation's ProgId and AppId.
// These entries need to be registered in HKLM prior to Win8.
- static void GetProgIdEntries(BrowserDistribution* dist,
- const base::string16& chrome_exe,
- const base::string16& suffix,
- ScopedVector<RegistryEntry>* entries) {
- base::string16 icon_path(
- ShellUtil::FormatIconLocation(
- chrome_exe,
- dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)));
- base::string16 open_cmd(ShellUtil::GetChromeShellOpenCmd(chrome_exe));
+ static void GetChromeProgIdEntries(BrowserDistribution* dist,
+ const base::string16& chrome_exe,
+ const base::string16& suffix,
+ ScopedVector<RegistryEntry>* entries) {
+ int chrome_icon_index =
+ dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME);
+
+ ApplicationInfo app_info;
+ app_info.prog_id = GetBrowserProgId(suffix);
+ app_info.file_type_name = dist->GetBrowserProgIdDesc();
+ // File types associated with Chrome are just given the Chrome icon.
+ app_info.file_type_icon_path = chrome_exe;
+ app_info.file_type_icon_index = chrome_icon_index;
+ app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
+ // For user-level installs: entries for the app id will be in HKCU; thus we
+ // do not need a suffix on those entries.
+ app_info.app_id = ShellUtil::GetBrowserModelId(
+ dist, InstallUtil::IsPerUserInstall(chrome_exe.c_str()));
+
+ // The command to execute when opening this application via the Metro UI.
base::string16 delegate_command(
ShellUtil::GetChromeDelegateCommand(chrome_exe));
- // For user-level installs: entries for the app id and DelegateExecute verb
- // handler will be in HKCU; thus we do not need a suffix on those entries.
- base::string16 app_id(
- ShellUtil::GetBrowserModelId(
- dist, InstallUtil::IsPerUserInstall(chrome_exe.c_str())));
- base::string16 delegate_guid;
bool set_delegate_execute =
IsChromeMetroSupported() &&
- dist->GetCommandExecuteImplClsid(&delegate_guid);
+ dist->GetCommandExecuteImplClsid(&app_info.delegate_clsid);
- // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8.
+ // TODO(grt): http://crbug.com/75152 Write a reference to a localized
+ // resource for name, description, and company.
+ app_info.application_name = dist->GetDisplayName();
+ app_info.application_icon_path = chrome_exe;
+ app_info.application_icon_index = chrome_icon_index;
+ app_info.application_description = dist->GetAppDescription();
+ app_info.publisher_name = dist->GetPublisherName();
+
+ GetProgIdEntries(app_info, entries);
+
+ // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. This is
+ // only needed for registring a web browser, not for general associations.
if (set_delegate_execute) {
base::string16 model_id_shell(ShellUtil::kRegClasses);
model_id_shell.push_back(base::FilePath::kSeparators[0]);
- model_id_shell.append(app_id);
+ model_id_shell.append(app_info.app_id);
model_id_shell.append(ShellUtil::kRegExePath);
model_id_shell.append(ShellUtil::kRegShellPath);
// <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command
entries->push_back(new RegistryEntry(sub_path, delegate_command));
entries->push_back(new RegistryEntry(
- sub_path, ShellUtil::kRegDelegateExecute, delegate_guid));
+ sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid));
}
}
+ }
+
+ // Gets the registry entries to register an application in the Windows
+ // registry. |app_info| provides all of the information needed.
+ static void GetProgIdEntries(const ApplicationInfo& app_info,
+ ScopedVector<RegistryEntry>* entries) {
+ // Basic sanity checks.
+ DCHECK(!app_info.prog_id.empty());
+ DCHECK_NE(L'.', app_info.prog_id[0]);
// File association ProgId
- base::string16 chrome_html_prog_id(ShellUtil::kRegClasses);
- chrome_html_prog_id.push_back(base::FilePath::kSeparators[0]);
- chrome_html_prog_id.append(GetBrowserProgId(suffix));
- entries->push_back(new RegistryEntry(
- chrome_html_prog_id, dist->GetBrowserProgIdDesc()));
+ base::string16 prog_id_path(ShellUtil::kRegClasses);
+ prog_id_path.push_back(base::FilePath::kSeparators[0]);
+ prog_id_path.append(app_info.prog_id);
+ entries->push_back(
+ new RegistryEntry(prog_id_path, app_info.file_type_name));
entries->push_back(new RegistryEntry(
- chrome_html_prog_id, ShellUtil::kRegUrlProtocol, L""));
+ prog_id_path + ShellUtil::kRegDefaultIcon,
+ ShellUtil::FormatIconLocation(app_info.file_type_icon_path,
+ app_info.file_type_icon_index)));
entries->push_back(new RegistryEntry(
- chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path));
- entries->push_back(new RegistryEntry(
- chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd));
- if (set_delegate_execute) {
- entries->push_back(new RegistryEntry(
- chrome_html_prog_id + ShellUtil::kRegShellOpen,
- ShellUtil::kRegDelegateExecute, delegate_guid));
+ prog_id_path + ShellUtil::kRegShellOpen, app_info.command_line));
+ if (!app_info.delegate_clsid.empty()) {
+ entries->push_back(
+ new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen,
+ ShellUtil::kRegDelegateExecute,
+ app_info.delegate_clsid));
}
// The following entries are required as of Windows 8, but do not
// depend on the DelegateExecute verb handler being set.
if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
- entries->push_back(new RegistryEntry(
- chrome_html_prog_id, ShellUtil::kRegAppUserModelId, app_id));
+ if (!app_info.app_id.empty()) {
+ entries->push_back(new RegistryEntry(
+ prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
+ }
- // Add \Software\Classes\ChromeHTML\Application entries
- base::string16 chrome_application(chrome_html_prog_id +
- ShellUtil::kRegApplication);
- entries->push_back(new RegistryEntry(
- chrome_application, ShellUtil::kRegAppUserModelId, app_id));
- entries->push_back(new RegistryEntry(
- chrome_application, ShellUtil::kRegApplicationIcon, icon_path));
- // TODO(grt): http://crbug.com/75152 Write a reference to a localized
- // resource for name, description, and company.
- entries->push_back(new RegistryEntry(
- chrome_application, ShellUtil::kRegApplicationName,
- dist->GetDisplayName()));
- entries->push_back(new RegistryEntry(
- chrome_application, ShellUtil::kRegApplicationDescription,
- dist->GetAppDescription()));
- entries->push_back(new RegistryEntry(
- chrome_application, ShellUtil::kRegApplicationCompany,
- dist->GetPublisherName()));
+ // Add \Software\Classes\<prog_id>\Application entries
+ base::string16 application_path(prog_id_path +
+ ShellUtil::kRegApplication);
+ if (!app_info.app_id.empty()) {
+ entries->push_back(new RegistryEntry(
+ application_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
+ }
+ if (!app_info.application_icon_path.empty()) {
+ entries->push_back(new RegistryEntry(
+ application_path,
+ ShellUtil::kRegApplicationIcon,
+ ShellUtil::FormatIconLocation(app_info.application_icon_path,
+ app_info.application_icon_index)));
+ }
+ if (!app_info.application_name.empty()) {
+ entries->push_back(new RegistryEntry(application_path,
+ ShellUtil::kRegApplicationName,
+ app_info.application_name));
+ }
+ if (!app_info.application_description.empty()) {
+ entries->push_back(
+ new RegistryEntry(application_path,
+ ShellUtil::kRegApplicationDescription,
+ app_info.application_description));
+ }
+ if (!app_info.publisher_name.empty()) {
+ entries->push_back(new RegistryEntry(application_path,
+ ShellUtil::kRegApplicationCompany,
+ app_info.publisher_name));
+ }
}
}
// - File Associations
// http://msdn.microsoft.com/en-us/library/bb166549
// These entries need to be registered in HKLM prior to Win8.
- static void GetAppRegistrationEntries(const base::string16& chrome_exe,
- const base::string16& suffix,
- ScopedVector<RegistryEntry>* entries) {
+ static void GetChromeAppRegistrationEntries(
+ const base::string16& chrome_exe,
+ const base::string16& suffix,
+ ScopedVector<RegistryEntry>* entries) {
const base::FilePath chrome_path(chrome_exe);
base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey);
app_path_key.push_back(base::FilePath::kSeparators[0]);
const base::string16 html_prog_id(GetBrowserProgId(suffix));
for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
- base::string16 key(ShellUtil::kRegClasses);
- key.push_back(base::FilePath::kSeparators[0]);
- key.append(ShellUtil::kPotentialFileAssociations[i]);
- key.push_back(base::FilePath::kSeparators[0]);
- key.append(ShellUtil::kRegOpenWithProgids);
- entries->push_back(
- new RegistryEntry(key, html_prog_id, base::string16()));
+ GetAppExtRegistrationEntries(
+ html_prog_id, ShellUtil::kPotentialFileAssociations[i], entries);
+ }
+ }
+
+ // Gets the registry entries to register an application as a handler for a
+ // particular file extension. |prog_id| is the ProgId used by Windows for the
+ // application. |ext| is the file extension, which must begin with a '.'.
+ static void GetAppExtRegistrationEntries(
+ const base::string16& prog_id,
+ const base::string16& ext,
+ ScopedVector<RegistryEntry>* entries) {
+ // In HKEY_CURRENT_USER\Software\Classes\EXT\OpenWithProgids, create an
+ // empty value with this class's ProgId.
+ base::string16 key_name(ShellUtil::kRegClasses);
+ key_name.push_back(base::FilePath::kSeparators[0]);
+ key_name.append(ext);
+ key_name.push_back(base::FilePath::kSeparators[0]);
+ key_name.append(ShellUtil::kRegOpenWithProgids);
+ entries->push_back(new RegistryEntry(key_name, prog_id, base::string16()));
+ }
+
+ // Gets the registry entries to register an application as the default handler
+ // for a particular file extension. |prog_id| is the ProgId used by Windows
+ // for the application. |ext| is the file extension, which must begin with a
+ // '.'. If |overwrite_existing|, always sets the default handler; otherwise
+ // only sets if there is no existing default.
+ //
+ // This has no effect on Windows 8. Windows 8 ignores the default and lets the
+ // user choose. If there is only one handler for a file, it will automatically
+ // become the default. Otherwise, the first time the user opens a file, they
+ // are presented with the dialog to set the default handler. (This is roughly
+ // equivalent to being called with |overwrite_existing| false.)
+ static void GetAppDefaultRegistrationEntries(
+ const base::string16& prog_id,
+ const base::string16& ext,
+ bool overwrite_existing,
+ ScopedVector<RegistryEntry>* entries) {
+ // Set the default value of HKEY_CURRENT_USER\Software\Classes\EXT to this
+ // class's name.
+ base::string16 key_name(ShellUtil::kRegClasses);
+ key_name.push_back(base::FilePath::kSeparators[0]);
+ key_name.append(ext);
+ scoped_ptr<RegistryEntry> default_association(
+ new RegistryEntry(key_name, prog_id));
+ if (overwrite_existing ||
+ !default_association->KeyExistsInRegistry(
+ RegistryEntry::LOOK_IN_HKCU)) {
+ entries->push_back(default_association.release());
}
}
// so IE, explorer and other apps will route it to our handler.
// <root hkey>\Software\Classes\<protocol>\URL Protocol
entries->push_back(new RegistryEntry(url_key,
- ShellUtil::kRegUrlProtocol, L""));
+ ShellUtil::kRegUrlProtocol, base::string16()));
// <root hkey>\Software\Classes\<protocol>\DefaultIcon
base::string16 icon_key = url_key + ShellUtil::kRegDefaultIcon;
// <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec
base::string16 dde_key = url_key + L"\\shell\\open\\ddeexec";
- entries->push_back(new RegistryEntry(dde_key, L""));
+ entries->push_back(new RegistryEntry(dde_key, base::string16()));
// <root hkey>\Software\Classes\<protocol>\shell\@
base::string16 protocol_shell_key = url_key + ShellUtil::kRegShellPath;
// File extension associations.
base::string16 html_prog_id(GetBrowserProgId(suffix));
for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) {
- base::string16 ext_key(ShellUtil::kRegClasses);
- ext_key.push_back(base::FilePath::kSeparators[0]);
- ext_key.append(ShellUtil::kDefaultFileAssociations[i]);
- entries->push_back(new RegistryEntry(ext_key, html_prog_id));
+ GetAppDefaultRegistrationEntries(
+ html_prog_id, ShellUtil::kDefaultFileAssociations[i], true, entries);
}
// Protocols associations.
// Generate work_item tasks required to create current registry entry and
// add them to the given work item list.
void AddToWorkItemList(HKEY root, WorkItemList *items) const {
- items->AddCreateRegKeyWorkItem(root, key_path_);
+ items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default);
if (is_string_) {
- items->AddSetRegValueWorkItem(root, key_path_, name_, value_, true);
+ items->AddSetRegValueWorkItem(
+ root, key_path_, WorkItem::kWow64Default, name_, value_, true);
} else {
- items->AddSetRegValueWorkItem(root, key_path_, name_, int_value_, true);
+ items->AddSetRegValueWorkItem(
+ root, key_path_, WorkItem::kWow64Default, name_, int_value_, true);
}
}
return status == SAME_VALUE;
}
+ // Checks if the current registry entry exists in \|key_path_|\|name_|,
+ // regardless of value. Same lookup rules as ExistsInRegistry.
+ // Unlike ExistsInRegistry, this returns true if some other value is present
+ // with the same key.
+ bool KeyExistsInRegistry(uint32 look_for_in) const {
+ DCHECK(look_for_in);
+
+ RegistryStatus status = DOES_NOT_EXIST;
+ if (look_for_in & LOOK_IN_HKCU)
+ status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER);
+ if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM))
+ status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE);
+ return status != DOES_NOT_EXIST;
+ }
+
private:
// States this RegistryKey can be in compared to the registry.
enum RegistryStatus {
if (is_string_) {
base::string16 read_value;
found = key.ReadValue(name_.c_str(), &read_value) == ERROR_SUCCESS;
- correct_value = read_value.size() == value_.size() &&
- std::equal(value_.begin(), value_.end(), read_value.begin(),
- base::CaseInsensitiveCompare<wchar_t>());
+ if (found) {
+ correct_value = read_value.size() == value_.size() &&
+ std::equal(value_.begin(), value_.end(), read_value.begin(),
+ base::CaseInsensitiveCompare<wchar_t>());
+ }
} else {
DWORD read_value;
found = key.ReadValueDW(name_.c_str(), &read_value) == ERROR_SUCCESS;
- correct_value = read_value == int_value_;
+ if (found)
+ correct_value = read_value == int_value_;
}
return found ?
(correct_value ? SAME_VALUE : DIFFERENT_VALUE) : DOES_NOT_EXIST;
const base::string16& suffix,
uint32 look_for_in) {
ScopedVector<RegistryEntry> entries;
- RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, &entries);
+ RegistryEntry::GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries);
RegistryEntry::GetShellIntegrationEntries(dist, chrome_exe, suffix, &entries);
- RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix, &entries);
+ RegistryEntry::GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries);
return AreEntriesRegistered(entries, look_for_in);
}
if (!base::PathExists(exe_path)) {
HKEY reg_root = InstallUtil::IsPerUserInstall(chrome_exe.c_str()) ?
HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
- RegKey key(reg_root, dist->GetUninstallRegPath().c_str(), KEY_READ);
+ RegKey key(reg_root,
+ dist->GetUninstallRegPath().c_str(),
+ KEY_READ | KEY_WOW64_32KEY);
base::string16 uninstall_string;
key.ReadValue(installer::kUninstallStringField, &uninstall_string);
CommandLine command_line = CommandLine::FromString(uninstall_string);
run_verb_key.append(ShellUtil::kRegShellPath);
run_verb_key.push_back(base::FilePath::kSeparators[0]);
run_verb_key.append(ShellUtil::kRegVerbRun);
- InstallUtil::DeleteRegistryKey(root_key, run_verb_key);
+ InstallUtil::DeleteRegistryKey(root_key, run_verb_key,
+ WorkItem::kWow64Default);
}
}
// did not perform validation on the ProgID registered as the current default.
// As a result, stale ProgIDs could be returned, leading to false positives.
ShellUtil::DefaultState ProbeCurrentDefaultHandlers(
+ const base::FilePath& chrome_exe,
const wchar_t* const* protocols,
size_t num_protocols) {
base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
return ShellUtil::UNKNOWN_DEFAULT;
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- base::FilePath chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
- NOTREACHED();
- return ShellUtil::UNKNOWN_DEFAULT;
- }
base::string16 prog_id(dist->GetBrowserProgIdPrefix());
prog_id += ShellUtil::GetCurrentInstallationSuffix(dist, chrome_exe.value());
// Probe using IApplicationAssociationRegistration::QueryAppIsDefault (Vista and
// Windows 7); see ProbeProtocolHandlers.
ShellUtil::DefaultState ProbeAppIsDefaultHandlers(
+ const base::FilePath& chrome_exe,
const wchar_t* const* protocols,
size_t num_protocols) {
base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
return ShellUtil::UNKNOWN_DEFAULT;
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- base::FilePath chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
- NOTREACHED();
- return ShellUtil::UNKNOWN_DEFAULT;
- }
base::string16 app_name(
ShellUtil::GetApplicationName(dist, chrome_exe.value()));
// Probe the current commands registered to handle the shell "open" verb for
// |protocols| (Windows XP); see ProbeProtocolHandlers.
ShellUtil::DefaultState ProbeOpenCommandHandlers(
+ const base::FilePath& chrome_exe,
const wchar_t* const* protocols,
size_t num_protocols) {
- // Get the path to the current exe (Chrome).
- base::FilePath app_path;
- if (!PathService::Get(base::FILE_EXE, &app_path)) {
- LOG(ERROR) << "Error getting app exe path";
- return ShellUtil::UNKNOWN_DEFAULT;
- }
-
// Get its short (8.3) form.
base::string16 short_app_path;
- if (!ShortNameFromPath(app_path, &short_app_path))
+ if (!ShortNameFromPath(chrome_exe, &short_app_path))
return ShellUtil::UNKNOWN_DEFAULT;
const HKEY root_key = HKEY_CLASSES_ROOT;
// Chrome is the default handler for |protocols|. Returns IS_DEFAULT
// only if Chrome is the default for all specified protocols.
ShellUtil::DefaultState ProbeProtocolHandlers(
+ const base::FilePath& chrome_exe,
const wchar_t* const* protocols,
size_t num_protocols) {
+#if DCHECK_IS_ON
DCHECK(!num_protocols || protocols);
- if (DCHECK_IS_ON()) {
- for (size_t i = 0; i < num_protocols; ++i)
- DCHECK(protocols[i] && *protocols[i]);
- }
+ for (size_t i = 0; i < num_protocols; ++i)
+ DCHECK(protocols[i] && *protocols[i]);
+#endif
const base::win::Version windows_version = base::win::GetVersion();
if (windows_version >= base::win::VERSION_WIN8)
- return ProbeCurrentDefaultHandlers(protocols, num_protocols);
+ return ProbeCurrentDefaultHandlers(chrome_exe, protocols, num_protocols);
else if (windows_version >= base::win::VERSION_VISTA)
- return ProbeAppIsDefaultHandlers(protocols, num_protocols);
+ return ProbeAppIsDefaultHandlers(chrome_exe, protocols, num_protocols);
- return ProbeOpenCommandHandlers(protocols, num_protocols);
+ return ProbeOpenCommandHandlers(chrome_exe, protocols, num_protocols);
}
// (Windows 8+) Finds and stores an app shortcuts folder path in *|path|.
ShellUtil::ShellChange level,
const scoped_refptr<ShellUtil::SharedCancellationFlag>& cancel) {
DCHECK(!shortcut_operation.is_null());
+
+ // There is no system-level Quick Launch shortcut folder.
+ if (level == ShellUtil::SYSTEM_LEVEL &&
+ location == ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH) {
+ return true;
+ }
+
base::FilePath shortcut_folder;
if (!ShellUtil::GetShortcutPath(location, dist, level, &shortcut_folder)) {
LOG(WARNING) << "Cannot find path at location " << location;
base::DIR_COMMON_DESKTOP;
break;
case SHORTCUT_LOCATION_QUICK_LAUNCH:
- dir_key = (level == CURRENT_USER) ? base::DIR_USER_QUICK_LAUNCH :
- base::DIR_DEFAULT_USER_QUICK_LAUNCH;
+ // There is no support for a system-level Quick Launch shortcut.
+ DCHECK_EQ(level, CURRENT_USER);
+ dir_key = base::DIR_USER_QUICK_LAUNCH;
break;
case SHORTCUT_LOCATION_START_MENU_ROOT:
dir_key = (level == CURRENT_USER) ? base::DIR_START_MENU :
base::FilePath user_shortcut_path;
base::FilePath system_shortcut_path;
- if (!GetShortcutPath(location, dist, SYSTEM_LEVEL, &system_shortcut_path)) {
+ if (location == SHORTCUT_LOCATION_QUICK_LAUNCH) {
+ // There is no system-level shortcut for Quick Launch.
+ DCHECK_EQ(properties.level, CURRENT_USER);
+ } else if (!GetShortcutPath(
+ location, dist, SYSTEM_LEVEL, &system_shortcut_path)) {
NOTREACHED();
return false;
}
// Install the system-level shortcut if requested.
chosen_path = &system_shortcut_path;
} else if (operation != SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL ||
+ system_shortcut_path.empty() ||
!base::PathExists(system_shortcut_path)) {
// Otherwise install the user-level shortcut, unless the system-level
// variant of this shortcut is present on the machine and |operation| states
}
}
// No spaces are allowed in the AppUserModelId according to MSDN.
- base::ReplaceChars(app_id, L" ", L"_", &app_id);
+ base::ReplaceChars(app_id, base::ASCIIToUTF16(" "), base::ASCIIToUTF16("_"),
+ &app_id);
return app_id;
}
ShellUtil::DefaultState ShellUtil::GetChromeDefaultState() {
+ base::FilePath app_path;
+ if (!PathService::Get(base::FILE_EXE, &app_path)) {
+ NOTREACHED();
+ return ShellUtil::UNKNOWN_DEFAULT;
+ }
+
+ return GetChromeDefaultStateFromPath(app_path);
+}
+
+ShellUtil::DefaultState ShellUtil::GetChromeDefaultStateFromPath(
+ const base::FilePath& chrome_exe) {
BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
if (distribution->GetDefaultBrowserControlPolicy() ==
BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
// flag. There is doubtless some other key we can hook into to cause "Repair"
// to show up in Add/Remove programs for us.
static const wchar_t* const kChromeProtocols[] = { L"http", L"https" };
- return ProbeProtocolHandlers(kChromeProtocols, arraysize(kChromeProtocols));
+ return ProbeProtocolHandlers(chrome_exe,
+ kChromeProtocols,
+ arraysize(kChromeProtocols));
}
ShellUtil::DefaultState ShellUtil::GetChromeDefaultProtocolClientState(
if (protocol.empty())
return UNKNOWN_DEFAULT;
+ base::FilePath chrome_exe;
+ if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
+ NOTREACHED();
+ return ShellUtil::UNKNOWN_DEFAULT;
+ }
+
const wchar_t* const protocols[] = { protocol.c_str() };
- return ProbeProtocolHandlers(protocols, arraysize(protocols));
+ return ProbeProtocolHandlers(chrome_exe,
+ protocols,
+ arraysize(protocols));
}
// static
// an admin.
ScopedVector<RegistryEntry> progid_and_appreg_entries;
ScopedVector<RegistryEntry> shell_entries;
- RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix,
- &progid_and_appreg_entries);
- RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix,
- &progid_and_appreg_entries);
+ RegistryEntry::GetChromeProgIdEntries(
+ dist, chrome_exe, suffix, &progid_and_appreg_entries);
+ RegistryEntry::GetChromeAppRegistrationEntries(
+ chrome_exe, suffix, &progid_and_appreg_entries);
RegistryEntry::GetShellIntegrationEntries(
dist, chrome_exe, suffix, &shell_entries);
result = (AddRegistryEntries(root, progid_and_appreg_entries) &&
AddRegistryEntries(root, shell_entries));
} else if (elevate_if_not_admin &&
- base::win::GetVersion() >= base::win::VERSION_VISTA &&
- ElevateAndRegisterChrome(dist, chrome_exe, suffix, L"")) {
+ base::win::GetVersion() >= base::win::VERSION_VISTA &&
+ ElevateAndRegisterChrome(dist, chrome_exe, suffix, base::string16())) {
// If the user is not an admin and OS is between Vista and Windows 7
// inclusively, try to elevate and register. This is only intended for
// user-level installs as system-level installs should always be run with
// If we got to this point then all we can do is create ProgId and basic app
// registrations under HKCU.
ScopedVector<RegistryEntry> entries;
- RegistryEntry::GetProgIdEntries(
+ RegistryEntry::GetChromeProgIdEntries(
dist, chrome_exe, base::string16(), &entries);
// Prefer to use |suffix|; unless Chrome's ProgIds are already registered
// with no suffix (as per the old registration style): in which case some
if (!AreEntriesRegistered(entries, RegistryEntry::LOOK_IN_HKCU)) {
if (!suffix.empty()) {
entries.clear();
- RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, &entries);
- RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix, &entries);
+ RegistryEntry::GetChromeProgIdEntries(
+ dist, chrome_exe, suffix, &entries);
+ RegistryEntry::GetChromeAppRegistrationEntries(
+ chrome_exe, suffix, &entries);
}
result = AddRegistryEntries(HKEY_CURRENT_USER, entries);
} else {
// thus needs to be done after the above check for the unsuffixed
// registration).
entries.clear();
- RegistryEntry::GetAppRegistrationEntries(chrome_exe, base::string16(),
- &entries);
+ RegistryEntry::GetChromeAppRegistrationEntries(
+ chrome_exe, base::string16(), &entries);
result = AddRegistryEntries(HKEY_CURRENT_USER, entries);
}
}
DCHECK_EQ(ret.length(), encoded_length);
return ret;
}
+
+// static
+bool ShellUtil::AddFileAssociations(
+ const base::string16& prog_id,
+ const base::CommandLine& command_line,
+ const base::string16& file_type_name,
+ const base::FilePath& icon_path,
+ const std::set<base::string16>& file_extensions) {
+ ScopedVector<RegistryEntry> entries;
+
+ // Create a class for this app.
+ RegistryEntry::ApplicationInfo app_info;
+ app_info.prog_id = prog_id;
+ app_info.file_type_name = file_type_name;
+ app_info.file_type_icon_path = icon_path.value();
+ app_info.file_type_icon_index = 0;
+ app_info.command_line = command_line.GetCommandLineStringWithPlaceholders();
+ RegistryEntry::GetProgIdEntries(app_info, &entries);
+
+ // Associate each extension that the app can handle with the class. Set this
+ // app as the default handler if and only if there is no existing default.
+ for (std::set<base::string16>::const_iterator it = file_extensions.begin();
+ it != file_extensions.end();
+ ++it) {
+ // Do not allow empty file extensions, or extensions beginning with a '.'.
+ DCHECK(!it->empty());
+ DCHECK_NE(L'.', (*it)[0]);
+ base::string16 ext(1, L'.');
+ ext.append(*it);
+ RegistryEntry::GetAppExtRegistrationEntries(prog_id, ext, &entries);
+
+ // Regstering as the default will have no effect on Windows 8 (see
+ // documentation for GetAppDefaultRegistrationEntries). However, if our app
+ // is the only handler, it will automatically become the default, so the
+ // same effect is achieved.
+ RegistryEntry::GetAppDefaultRegistrationEntries(
+ prog_id, ext, false, &entries);
+ }
+
+ return AddRegistryEntries(HKEY_CURRENT_USER, entries);
+}
+
+// static
+bool ShellUtil::DeleteFileAssociations(const base::string16& prog_id) {
+ // Delete the key HKEY_CURRENT_USER\Software\Classes\PROGID.
+ base::string16 key_path(ShellUtil::kRegClasses);
+ key_path.push_back(base::FilePath::kSeparators[0]);
+ key_path.append(prog_id);
+ return InstallUtil::DeleteRegistryKey(
+ HKEY_CURRENT_USER, key_path, WorkItem::kWow64Default);
+
+ // TODO(mgiuca): Remove the extension association entries. This requires that
+ // the extensions associated with a particular prog_id are stored in that
+ // prog_id's key.
+}