// Copyright (c) 2006-2008 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. // // See the corresponding header file for description of the functions in this // file. #include "chrome/installer/util/install_util.h" #include #include #include #include "base/command_line.h" #include "base/file_util.h" #include "base/logging.h" #include "base/path_service.h" #include "base/registry.h" #include "base/scoped_ptr.h" #include "base/string_util.h" #include "base/win_util.h" #include "chrome/common/json_value_serializer.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/google_update_constants.h" #include "chrome/installer/util/l10n_string_util.h" #include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/util_constants.h" #include "chrome/installer/util/work_item_list.h" bool InstallUtil::ExecuteExeAsAdmin(const std::wstring& exe, const std::wstring& params, DWORD* exit_code) { SHELLEXECUTEINFO info = {0}; info.cbSize = sizeof(SHELLEXECUTEINFO); info.fMask = SEE_MASK_NOCLOSEPROCESS; info.lpVerb = L"runas"; info.lpFile = exe.c_str(); info.lpParameters = params.c_str(); info.nShow = SW_SHOW; if (::ShellExecuteEx(&info) == FALSE) return false; ::WaitForSingleObject(info.hProcess, INFINITE); DWORD ret_val = 0; if (!::GetExitCodeProcess(info.hProcess, &ret_val)) return false; if (exit_code) *exit_code = ret_val; return true; } std::wstring InstallUtil::GetChromeUninstallCmd(bool system_install) { HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; BrowserDistribution* dist = BrowserDistribution::GetDistribution(); RegKey key(root, dist->GetUninstallRegPath().c_str()); std::wstring uninstall_cmd; key.ReadValue(installer_util::kUninstallStringField, &uninstall_cmd); return uninstall_cmd; } installer::Version* InstallUtil::GetChromeVersion(bool system_install) { RegKey key; std::wstring version_str; HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; BrowserDistribution* dist = BrowserDistribution::GetDistribution(); if (!key.Open(reg_root, dist->GetVersionKey().c_str(), KEY_READ) || !key.ReadValue(google_update::kRegVersionField, &version_str)) { LOG(INFO) << "No existing Chrome install found."; key.Close(); return NULL; } key.Close(); LOG(INFO) << "Existing Chrome version found " << version_str; return installer::Version::GetVersionFromString(version_str); } bool InstallUtil::IsOSSupported() { int major, minor; win_util::WinVersion version = win_util::GetWinVersion(); win_util::GetServicePackLevel(&major, &minor); // We do not support Win2K or older, or XP without service pack 2. LOG(INFO) << "Windows Version: " << version << ", Service Pack: " << major << "." << minor; if ((version > win_util::WINVERSION_XP) || (version == win_util::WINVERSION_XP && major >= 2)) { return true; } return false; } void InstallUtil::WriteInstallerResult(bool system_install, installer_util::InstallStatus status, int string_resource_id, const std::wstring* const launch_cmd) { HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; BrowserDistribution* dist = BrowserDistribution::GetDistribution(); std::wstring key = dist->GetStateKey(); int installer_result = (dist->GetInstallReturnCode(status) == 0) ? 0 : 1; scoped_ptr install_list(WorkItem::CreateWorkItemList()); install_list->AddCreateRegKeyWorkItem(root, key); install_list->AddSetRegValueWorkItem(root, key, L"InstallerResult", installer_result, true); install_list->AddSetRegValueWorkItem(root, key, L"InstallerError", status, true); if (string_resource_id != 0) { std::wstring msg = installer_util::GetLocalizedString(string_resource_id); install_list->AddSetRegValueWorkItem(root, key, L"InstallerResultUIString", msg, true); } if (launch_cmd != NULL && !launch_cmd->empty()) { install_list->AddSetRegValueWorkItem(root, key, L"InstallerSuccessLaunchCmdLine", *launch_cmd, true); } if (!install_list->Do()) LOG(ERROR) << "Failed to record installer error information in registry."; } bool InstallUtil::IsPerUserInstall(const wchar_t* const exe_path) { wchar_t program_files_path[MAX_PATH] = {0}; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, program_files_path))) { return !StartsWith(exe_path, program_files_path, false); } else { NOTREACHED(); } return true; } bool InstallUtil::IsChromeFrameProcess() { CommandLine* command_line = CommandLine::ForCurrentProcess(); DCHECK(command_line) << "IsChromeFrameProcess() called before ComamandLine::Init()"; FilePath module_path; PathService::Get(base::FILE_MODULE, &module_path); std::wstring module_name(module_path.BaseName().value()); scoped_ptr prefs(installer_util::GetInstallPreferences( *command_line)); DCHECK(prefs.get()); bool is_cf = false; installer_util::GetDistroBooleanPreference(prefs.get(), installer_util::master_preferences::kChromeFrame, &is_cf); // Also assume this to be a ChromeFrame process if we are running inside // the Chrome Frame DLL. return is_cf || module_name == installer_util::kChromeFrameDll; } bool InstallUtil::IsChromeSxSProcess() { CommandLine* command_line = CommandLine::ForCurrentProcess(); CHECK(command_line); if (command_line->HasSwitch(installer_util::switches::kChromeSxS)) return true; // Also return true if we are running from Chrome SxS installed path. FilePath exe_dir; PathService::Get(base::DIR_EXE, &exe_dir); std::wstring chrome_sxs_dir(installer_util::kGoogleChromeInstallSubDir2); chrome_sxs_dir.append(installer_util::kSxSSuffix); return FilePath::CompareEqualIgnoreCase(exe_dir.BaseName().value(), installer_util::kInstallBinaryDir) && FilePath::CompareEqualIgnoreCase(exe_dir.DirName().BaseName().value(), chrome_sxs_dir); } bool InstallUtil::IsMSIProcess(bool system_level) { // Initialize the static msi flags. static bool is_msi_ = false; static bool msi_checked_ = false; CommandLine* command_line = CommandLine::ForCurrentProcess(); CHECK(command_line); if (!msi_checked_) { msi_checked_ = true; scoped_ptr prefs(installer_util::GetInstallPreferences( *command_line)); DCHECK(prefs.get()); bool is_msi = false; installer_util::GetDistroBooleanPreference(prefs.get(), installer_util::master_preferences::kMsi, &is_msi); if (!is_msi) { // We didn't find it in the preferences, try looking in the registry. HKEY reg_root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; RegKey key; DWORD msi_value; BrowserDistribution* dist = BrowserDistribution::GetDistribution(); DCHECK(dist); bool success = false; std::wstring reg_key(dist->GetStateKey()); if (key.Open(reg_root, reg_key.c_str(), KEY_READ | KEY_WRITE)) { if (key.ReadValueDW(google_update::kRegMSIField, &msi_value)) { is_msi = (msi_value == 1); } } } is_msi_ = is_msi; } return is_msi_; } bool InstallUtil::SetMSIMarker(bool system_level, bool set) { BrowserDistribution* dist = BrowserDistribution::GetDistribution(); DCHECK(dist); std::wstring client_state_path(dist->GetStateKey()); bool success = false; HKEY reg_root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; RegKey client_state_key; if (client_state_key.Open(reg_root, client_state_path.c_str(), KEY_READ | KEY_WRITE)) { DWORD msi_value = set ? 1 : 0; if (client_state_key.WriteValue(google_update::kRegMSIField, msi_value)) { success = true; } else { LOG(ERROR) << "Could not write msi value to client state key."; } } else { LOG(ERROR) << "Could not open client state key!"; } return success; } bool InstallUtil::BuildDLLRegistrationList(const std::wstring& install_path, const wchar_t** const dll_names, int dll_names_count, bool do_register, WorkItemList* registration_list) { DCHECK(NULL != registration_list); bool success = true; for (int i = 0; i < dll_names_count; i++) { std::wstring dll_file_path(install_path); file_util::AppendToPath(&dll_file_path, dll_names[i]); success = registration_list->AddSelfRegWorkItem(dll_file_path, do_register) && success; } return (dll_names_count > 0) && success; }