blob: e8bd45b7bb6be86360f1c484b880e9caf3a5ef0d [file] [log] [blame]
// 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/installer/launcher_support/chrome_launcher_support.h"
#include <windows.h>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/strings/string16.h"
#include "base/win/registry.h"
namespace chrome_launcher_support {
namespace {
// TODO(huangs) Refactor the constants:
const wchar_t kInstallationRegKey[] =
// Copied from
const wchar_t kBinariesAppGuid[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
// Copied from
const wchar_t kBrowserAppGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
// Copied frome
const wchar_t kSxSBrowserAppGuid[] = L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";
const wchar_t kInstallationRegKey[] = L"Software\\Chromium";
// Copied from
const wchar_t kChromeExe[] = L"chrome.exe";
const wchar_t kUninstallStringField[] = L"UninstallString";
// Reads a string value from the specified product's registry key. Returns true
// iff the value is present and successfully read.
bool GetClientStateValue(InstallationLevel level,
const wchar_t* app_guid,
const wchar_t* value_name,
base::string16* value) {
HKEY root_key = (level == USER_LEVEL_INSTALLATION) ?
base::string16 subkey(kInstallationRegKey);
if (app_guid)
subkey.append(1, L'\\').append(app_guid);
base::win::RegKey reg_key;
// Google Update always uses 32bit hive.
if (reg_key.Open(root_key, subkey.c_str(),
if (reg_key.ReadValue(value_name, value) == ERROR_SUCCESS) {
return true;
return false;
// Reads the path to setup.exe from the value "UninstallString" within the
// specified product's registry key. Returns an empty FilePath if an error
// occurs or the product is not installed at the specified level.
base::FilePath GetSetupExeFromRegistry(InstallationLevel level,
const wchar_t* app_guid) {
base::string16 uninstall;
if (GetClientStateValue(level, app_guid, kUninstallStringField, &uninstall)) {
base::FilePath setup_exe_path(uninstall);
if (base::PathExists(setup_exe_path))
return setup_exe_path;
return base::FilePath();
// Returns the path to an existing setup.exe at the specified level, if it can
// be found via the registry.
base::FilePath GetSetupExeForInstallationLevel(InstallationLevel level) {
base::FilePath setup_exe_path;
// Look in the registry for Chrome Binaries first.
setup_exe_path = GetSetupExeFromRegistry(level, kBinariesAppGuid);
// If the above fails, look in the registry for Chrome next.
if (setup_exe_path.empty())
setup_exe_path = GetSetupExeFromRegistry(level, kBrowserAppGuid);
// If we fail again, then setup_exe_path would be empty.
// For Chromium, there are no GUIDs. Just look in the Chromium registry key.
setup_exe_path = GetSetupExeFromRegistry(level, nullptr);
return setup_exe_path;
// Returns the path to an installed |exe_file| (e.g. chrome.exe) at the
// specified level, given |setup_exe_path| from the registry. Returns empty
// base::FilePath if none found, or if |setup_exe_path| is empty.
base::FilePath FindExeRelativeToSetupExe(const base::FilePath setup_exe_path,
const wchar_t* exe_file) {
if (!setup_exe_path.empty()) {
// The uninstall path contains the path to setup.exe, which is two levels
// down from |exe_file|. Move up two levels (plus one to drop the file
// name) and look for chrome.exe from there.
base::FilePath exe_path(
if (base::PathExists(exe_path))
return exe_path;
// By way of mild future proofing, look up one to see if there's a
// |exe_file| in the version directory
exe_path = setup_exe_path.DirName().DirName().Append(exe_file);
if (base::PathExists(exe_path))
return exe_path;
return base::FilePath();
} // namespace
base::FilePath GetChromePathForInstallationLevel(InstallationLevel level,
bool is_sxs) {
if (is_sxs) {
return FindExeRelativeToSetupExe(
GetSetupExeFromRegistry(level, kSxSBrowserAppGuid), kChromeExe);
// There is no SxS build for Chromium.
return base::FilePath();
} else {
return FindExeRelativeToSetupExe(GetSetupExeForInstallationLevel(level),
base::FilePath GetAnyChromePath(bool is_sxs) {
base::FilePath path;
path = GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION, is_sxs);
if (path.empty())
path = GetChromePathForInstallationLevel(USER_LEVEL_INSTALLATION, is_sxs);
return path;
} // namespace chrome_launcher_support