diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/installer/setup | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer/setup')
-rw-r--r-- | chrome/installer/setup/SConscript | 153 | ||||
-rw-r--r-- | chrome/installer/setup/install.cc | 269 | ||||
-rw-r--r-- | chrome/installer/setup/main.cc | 389 | ||||
-rw-r--r-- | chrome/installer/setup/setup.cc | 290 | ||||
-rw-r--r-- | chrome/installer/setup/setup.exe.manifest | 11 | ||||
-rw-r--r-- | chrome/installer/setup/setup.h | 104 | ||||
-rw-r--r-- | chrome/installer/setup/setup.ico | bin | 0 -> 766 bytes | |||
-rw-r--r-- | chrome/installer/setup/setup.rc | 82 | ||||
-rw-r--r-- | chrome/installer/setup/setup.vcproj | 130 | ||||
-rw-r--r-- | chrome/installer/setup/setup.vsprops | 30 | ||||
-rw-r--r-- | chrome/installer/setup/setup_constants.cc | 49 | ||||
-rw-r--r-- | chrome/installer/setup/setup_constants.h | 53 | ||||
-rw-r--r-- | chrome/installer/setup/setup_debug.vsprops | 8 | ||||
-rw-r--r-- | chrome/installer/setup/setup_exe_version.rc.version | 40 | ||||
-rw-r--r-- | chrome/installer/setup/setup_release.vsprops | 8 | ||||
-rw-r--r-- | chrome/installer/setup/setup_resource.h | 17 | ||||
-rw-r--r-- | chrome/installer/setup/uninstall.cc | 303 | ||||
-rw-r--r-- | chrome/installer/setup/uninstall.h | 56 |
18 files changed, 1992 insertions, 0 deletions
diff --git a/chrome/installer/setup/SConscript b/chrome/installer/setup/SConscript new file mode 100644 index 0000000..b26790f --- /dev/null +++ b/chrome/installer/setup/SConscript @@ -0,0 +1,153 @@ +# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Import('env', 'env_res')
+
+env = env.Clone()
+env_res = env_res.Clone()
+
+
+env_res.Append(
+ CPPPATH = [
+ "$TARGET_ROOT",
+ ".",
+ "#/..",
+ ],
+ RCFLAGS = [
+ ["/l", "0x409"],
+ ],
+)
+
+
+resources = [
+ env_res.RES('setup.rc'),
+ env_res.RES('../util/setup_strings.rc'),
+]
+
+
+env.Prepend(
+ CPPPATH = [
+ '../util',
+ '$TARGET_ROOT',
+ '.',
+ '#/..',
+ ],
+ LINKFLAGS = [
+ '/INCREMENTAL',
+ '/DEBUG',
+
+ '/DELAYLOAD:"dwmapi.dll"',
+ '/DELAYLOAD:"uxtheme.dll"',
+
+ '/OPT:NOWIN98',
+ '/SUBSYSTEM:WINDOWS',
+ '/MACHINE:X86',
+ '/FIXED:No',
+
+ '/safeseh',
+ '/dynamicbase',
+ '/ignore:4199',
+ '/nxcompat',
+
+ '/PDB:${TARGETS[1]}',
+ '/MAP:${TARGETS[2]}',
+ ],
+ LIBS = [
+ 'shlwapi.lib',
+
+ 'msi.lib',
+
+ 'wininet.lib',
+ 'version.lib',
+ 'msimg32.lib',
+ 'ws2_32.lib',
+ 'usp10.lib',
+ 'psapi.lib',
+ 'kernel32.lib',
+ 'user32.lib',
+ 'gdi32.lib',
+ 'winspool.lib',
+ 'comdlg32.lib',
+ 'advapi32.lib',
+ 'shell32.lib',
+ 'ole32.lib',
+ 'oleaut32.lib',
+ 'uuid.lib',
+ 'odbc32.lib',
+ 'odbccp32.lib',
+
+ 'DelayImp.lib',
+ ],
+)
+
+input_files = [
+ 'install.cc',
+ 'main.cc',
+ 'setup.cc',
+ 'setup_constants.cc',
+ 'uninstall.cc',
+]
+
+libs = [
+ '../util/util.lib',
+ '$BSPATCH_DIR/bspatch.lib',
+ '$LZMA_SDK_DIR/lzma_sdk.lib',
+ '$ICU38_DIR/icuuc.lib',
+ '$CHROME_DIR/common/common.lib',
+ '$BASE_DIR/base.lib',
+]
+
+exe = env.Program(['setup',
+ 'setup.pdb',
+ 'setup.map'],
+ resources + input_files + libs)
+i = env.Install('$TARGET_ROOT', exe)
+
+env.Alias('chrome', i)
+
+
+
+env_version = env.Clone(
+ VERSION_BAT = File('#/../chrome/tools/build/win/version.bat'),
+ CHROMEDIR = Dir('#/../chrome'),
+ PWD = Dir('.'),
+)
+
+import os
+env_version['ENV']['PROGRAMFILES'] = os.environ['PROGRAMFILES']
+env_version['ENV']['SystemDrive'] = os.environ['SystemDrive']
+env_version['ENV']['USERPROFILE'] = os.environ['USERPROFILE']
+env_version['ENV']['PATH'] = os.environ['PATH']
+
+setup_exe_version_rc = env_version.Command(
+ 'setup_exe_version.rc',
+ ['setup_exe_version.rc.version',
+ '$CHROMEDIR/VERSION',
+ '$CHROMEDIR/BRANDING'],
+ '$VERSION_BAT $SOURCE $CHROMEDIR $PWD $TARGET')
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc new file mode 100644 index 0000000..5cd0f22 --- /dev/null +++ b/chrome/installer/setup/install.cc @@ -0,0 +1,269 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <time.h> + +#include "base/file_util.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "chrome/installer/setup/setup.h" +#include "chrome/installer/setup/setup_constants.h" +#include "chrome/installer/util/copy_tree_work_item.h" +#include "chrome/installer/util/create_dir_work_item.h" +#include "chrome/installer/util/create_reg_key_work_item.h" +#include "chrome/installer/util/delete_tree_work_item.h" +#include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/logging_installer.h" +#include "chrome/installer/util/google_update_constants.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/version.h" +#include "chrome/installer/util/work_item_list.h" + +namespace { +std::wstring AppendPath(const std::wstring parent_path, + const std::wstring path) { + std::wstring new_path(parent_path); + file_util::AppendToPath(&new_path, path); + return new_path; +} + + +// This method adds work items to create (or update) Chrome uninstall entry in +// Control Panel->Add/Remove Programs list. +void AddUninstallShortcutWorkItems(HKEY reg_root, + const std::wstring& exe_path, + const std::wstring& install_path, + const std::wstring& new_version, + WorkItemList* install_list) { + std::wstring uninstall_cmd(L"\""); + uninstall_cmd.append(installer::GetInstallerPathUnderChrome(install_path, + new_version)); + file_util::AppendToPath(&uninstall_cmd, + file_util::GetFilenameFromPath(exe_path)); + uninstall_cmd.append(L"\" --"); + uninstall_cmd.append(installer_util::switches::kUninstall); + + // Create DisplayName, UninstallString and InstallLocation keys + install_list->AddCreateRegKeyWorkItem(reg_root, + installer_util::kUninstallRegPath); + install_list->AddSetRegValueWorkItem( + reg_root, + installer_util::kUninstallRegPath, + installer_util::kUninstallDisplayNameField, + installer_util::kChrome, true); + install_list->AddSetRegValueWorkItem(reg_root, + installer_util::kUninstallRegPath, + installer_util::kUninstallStringField, + uninstall_cmd, true); + install_list->AddSetRegValueWorkItem(reg_root, + installer_util::kUninstallRegPath, + L"InstallLocation", install_path, true); + + // DisplayIcon, NoModify and NoRepair + std::wstring chrome_icon = AppendPath(install_path, + installer_util::kChromeExe); + ShellUtil::GetChromeIcon(chrome_icon); + install_list->AddSetRegValueWorkItem(reg_root, + installer_util::kUninstallRegPath, + L"DisplayIcon", chrome_icon, true); + install_list->AddSetRegValueWorkItem(reg_root, + installer_util::kUninstallRegPath, + L"NoModify", 1, true); + install_list->AddSetRegValueWorkItem(reg_root, + installer_util::kUninstallRegPath, + L"NoRepair", 1, true); + + install_list->AddSetRegValueWorkItem(reg_root, + installer_util::kUninstallRegPath, + L"Publisher", + installer_util::kPublisherName, true); + install_list->AddSetRegValueWorkItem(reg_root, + installer_util::kUninstallRegPath, + L"Version", new_version.c_str(), true); + install_list->AddSetRegValueWorkItem(reg_root, + installer_util::kUninstallRegPath, + L"DisplayVersion", + new_version.c_str(), true); + time_t rawtime = time(NULL); + struct tm timeinfo = {0}; + localtime_s(&timeinfo, &rawtime); + wchar_t buffer[9]; + if (wcsftime(buffer, 9, L"%Y%m%d", &timeinfo) == 8) { + install_list->AddSetRegValueWorkItem(reg_root, + installer_util::kUninstallRegPath, + L"InstallDate", + buffer, false); + } +} + +void AddInstallerCopyTasks(const std::wstring& exe_path, + const std::wstring& archive_path, + const std::wstring& temp_path, + const std::wstring& install_path, + const std::wstring& new_version, + WorkItemList* install_list) { + std::wstring installer_dir(installer::GetInstallerPathUnderChrome( + install_path, new_version)); + install_list->AddCreateDirWorkItem(installer_dir); + + std::wstring exe_dst(installer_dir); + std::wstring archive_dst(installer_dir); + file_util::AppendToPath(&exe_dst, + file_util::GetFilenameFromPath(exe_path)); + file_util::AppendToPath(&archive_dst, + file_util::GetFilenameFromPath(archive_path)); + + install_list->AddCopyTreeWorkItem(exe_path, exe_dst, temp_path, + WorkItem::ALWAYS); + install_list->AddCopyTreeWorkItem(archive_path, archive_dst, temp_path, + WorkItem::ALWAYS); +} + + +// This method tells if we are running on 64 bit platform so that we can copy +// one extra exe. If the API call to determine 64 bit fails, we play it safe +// and return true anyway so that the executable can be copied. +bool Is64bit() { + typedef BOOL (WINAPI *WOW_FUNC)(HANDLE, PBOOL); + BOOL is64 = FALSE; + + HANDLE handle = GetCurrentProcess(); + HMODULE module = GetModuleHandle(L"kernel32.dll"); + WOW_FUNC p = reinterpret_cast<WOW_FUNC>(GetProcAddress(module, + "IsWow64Process")); + if ((p != NULL) && (!(p)(handle, &is64) || (is64 != FALSE))) { + return true; + } + + return false; +} + +} + +bool installer::InstallNewVersion(const std::wstring& exe_path, + const std::wstring& archive_path, + const std::wstring& src_path, + const std::wstring& install_path, + const std::wstring& temp_dir, + const HKEY reg_root, + const Version& new_version) { + + if (reg_root != HKEY_LOCAL_MACHINE && reg_root != HKEY_CURRENT_USER) + return false; + + scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); + // A temp directory that work items need and the actual install directory. + install_list->AddCreateDirWorkItem(temp_dir); + install_list->AddCreateDirWorkItem(install_path); + + // Browse for all the files in archive, add work items to copy them while + // handling special cases of executables. + LOG(INFO) << "Looking for Chrome installation files under " << src_path; + std::wstring root_path(src_path); + file_util::AppendToPath(&root_path, L"*"); + WIN32_FIND_DATA find_file_data; + HANDLE file_handle = FindFirstFile(root_path.c_str(), &find_file_data); + BOOL ret = TRUE; + while (ret) { + LOG(INFO) << "directory found: " << find_file_data.cFileName; + // We do not want any directories starting with '.' + if ((wcslen(find_file_data.cFileName) <= 0) || + (find_file_data.cFileName[0] == '.')) { + LOG(INFO) << "Ignoring directory found: " << find_file_data.cFileName; + } else if (_wcsicmp(find_file_data.cFileName, + installer_util::kChromeExe) == 0) { + // Special case of chrome.exe. Delete any new_chrome.exe if present + // (we will create a new one if chrome.exe is in use) and then + // copy chrome.exe. + install_list->AddDeleteTreeWorkItem( + AppendPath(install_path, installer::kChromeNewExe), std::wstring()); + install_list->AddCopyTreeWorkItem( + AppendPath(src_path, installer_util::kChromeExe), + AppendPath(install_path, installer_util::kChromeExe), + temp_dir, WorkItem::RENAME_IF_IN_USE, + AppendPath(install_path, installer::kChromeNewExe)); + } else if (_wcsicmp(find_file_data.cFileName, + installer::kWowHelperExe) == 0) { + // Special case of wow_helper.exe which is required only on 64 bit + // systems. This exe runs only for a short time when Chrome starts so + // it should not be locked most of the times and can be overwritten + // directly. + if (Is64bit()) { + install_list->AddCopyTreeWorkItem( + AppendPath(src_path, installer::kWowHelperExe), + AppendPath(install_path, installer::kWowHelperExe), + temp_dir, WorkItem::ALWAYS); + } + } else { + // In all other cases just copy the file/directory to install location. + install_list->AddCopyTreeWorkItem( + AppendPath(src_path, find_file_data.cFileName), + AppendPath(install_path, find_file_data.cFileName), + temp_dir, WorkItem::ALWAYS); // Always overwrite. + } + ret = FindNextFile(file_handle, &find_file_data); + } + FindClose(file_handle); + + // Copy installer in install directory and + // add shortcut in Control Panel->Add/Remove Programs. + AddInstallerCopyTasks(exe_path, archive_path, temp_dir, install_path, + new_version.GetString(), install_list.get()); + AddUninstallShortcutWorkItems(reg_root, exe_path, install_path, + new_version.GetString(), install_list.get()); + + // Delete any old_chrome.exe if present. + install_list->AddDeleteTreeWorkItem( + AppendPath(install_path, installer::kChromeOldExe), std::wstring()); + + // Create Google Update key (if not already present) and set the new Chrome + // version as last step. + std::wstring chrome_google_update_key = + InstallUtil::GetChromeGoogleUpdateKey(); + install_list->AddCreateRegKeyWorkItem(reg_root, chrome_google_update_key); + install_list->AddSetRegValueWorkItem(reg_root, chrome_google_update_key, + google_update::kRegNameField, + installer_util::kChrome, + false); // Don't overwrite. + install_list->AddSetRegValueWorkItem(reg_root, chrome_google_update_key, + google_update::kRegVersionField, + new_version.GetString(), + true); // overwrite version + + // Perform install operations. + if (!install_list->Do()) { + LOG(ERROR) << "install failed, roll back... "; + install_list->Rollback(); + return false; + } + + return true; +} diff --git a/chrome/installer/setup/main.cc b/chrome/installer/setup/main.cc new file mode 100644 index 0000000..233408b --- /dev/null +++ b/chrome/installer/setup/main.cc @@ -0,0 +1,389 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <string> + +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/registry.h" +#include "base/string_util.h" +#include "chrome/installer/setup/setup.h" +#include "chrome/installer/setup/setup_constants.h" +#include "chrome/installer/setup/uninstall.h" +#include "chrome/installer/util/delete_tree_work_item.h" +#include "chrome/installer/util/helper.h" +#include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/logging_installer.h" +#include "chrome/installer/util/lzma_util.h" +#include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/shell_util.h" +#include "chrome/installer/util/util_constants.h" +#include "chrome/installer/util/work_item.h" +#include "third_party/bspatch/mbspatch.h" + +namespace { + +// Checks if the current system is running Windows XP or later. We are not +// supporting Windows 2K for beta release. +bool IsWindowsXPorLater() { + OSVERSIONINFOEX osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + GetVersionEx((OSVERSIONINFO *) &osvi); + + // Windows versioning scheme doesn't seem very clear but here is what + // the code is checking as the minimum version required for Chrome: + // * Major > 5 is Vista or later so no further checks for Service Pack + // * Major = 5 && Minor > 1 is Windows Server 2003 so again no SP checks + // * Major = 5 && Minor = 1 is WinXP so check for SP1 or later + LOG(INFO) << "Windows Version: Major - " << osvi.dwMajorVersion + << " Minor - " << osvi.dwMinorVersion + << " Service Pack Major - " << osvi.wServicePackMajor + << " Service Pack Minor - " << osvi.wServicePackMinor; + if ((osvi.dwMajorVersion > 5) || // Vista or later + ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion > 1)) || // Win 2003 + ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1) && + (osvi.wServicePackMajor >= 1))) { // WinXP with SP1 + return true; + } + return false; +} + +// Applies a binary patch to existing Chrome installer archive on the system. +// Uses bspatch library. +int PatchArchiveFile(bool system_install, const std::wstring& archive_path, + const std::wstring& uncompressed_archive, + const installer::Version* installed_version) { + std::wstring existing_archive = + installer::GetChromeInstallPath(system_install); + file_util::AppendToPath(&existing_archive, + installed_version->GetString()); + file_util::AppendToPath(&existing_archive, installer::kInstallerDir); + file_util::AppendToPath(&existing_archive, installer::kChromeArchive); + + std::wstring patch_archive(archive_path); + file_util::AppendToPath(&patch_archive, installer::kChromePatchArchive); + + LOG(INFO) << "Applying patch " << patch_archive + << " to file " << existing_archive + << " and generating file " << uncompressed_archive; + return ApplyBinaryPatch(WideToUTF8(existing_archive).c_str(), + WideToUTF8(patch_archive).c_str(), + WideToUTF8(uncompressed_archive).c_str()); +} + + +// This method unpacks and uncompresses the given archive file. For Chrome +// install we are creating a uncompressed archive that contains all the files +// needed for the installer. This uncompressed archive is later compressed. +// +// This method first uncompresses archive specified by parameter "archive" +// and assumes that it will result in an uncompressed full archive file +// (chrome.7z) or uncompressed patch archive file (patch.7z). If it is patch +// archive file, the patch is applied to the old archive file that should be +// present on the system already. As the final step the new archive file +// is unpacked in the path specified by parameter "path". +DWORD UnPackArchive(const std::wstring& archive, bool system_install, + const installer::Version* installed_version, + const std::wstring& temp_path, const std::wstring& path, + bool& incremental_install) { + DWORD ret = NO_ERROR; + installer::LzmaUtil util; + // First uncompress the payload. This could be a differential + // update (patch.7z) or full archive (chrome.7z). If this uncompress fails + // return with error. + LOG(INFO) << "Opening archive " << archive; + if ((ret = util.OpenArchive(archive)) != NO_ERROR) { + LOG(ERROR) << "unable to open install archive: " << archive; + } else { + LOG(INFO) << "Uncompressing archive to path " << temp_path; + if ((ret = util.UnPack(temp_path)) != NO_ERROR) { + LOG(ERROR) << "error during uncompression: " << ret; + } + util.CloseArchive(); + } + if (ret != NO_ERROR) + return ret; + + std::wstring archive_name = file_util::GetFilenameFromPath(archive); + std::wstring uncompressed_archive(temp_path); + file_util::AppendToPath(&uncompressed_archive, installer::kChromeArchive); + // Check if this is differential update and if it is, patch it to the + // installer archive that should already be on the machine. + std::wstring prefix = installer::kChromeCompressedPatchArchivePrefix; + if ((archive_name.size() >= prefix.size()) && + (std::equal(prefix.begin(), prefix.end(), archive_name.begin(), + CaseInsensitiveCompare<wchar_t>()))) { + LOG(INFO) << "Differential patch found. Applying to existing archive."; + incremental_install = true; + if (!installed_version) { + LOG(ERROR) << "Can not use differential update when Chrome is not " + << "installed on the system."; + return 1; + } + if (PatchArchiveFile(system_install, temp_path, uncompressed_archive, + installed_version)) { + LOG(ERROR) << "Binary patching failed."; + return 1; + } + } + + // If we got the uncompressed archive, lets unpack it + LOG(INFO) << "Opening archive " << uncompressed_archive; + if ((ret = util.OpenArchive(uncompressed_archive)) != NO_ERROR) { + LOG(ERROR) << "unable to open install archive: " << + uncompressed_archive; + } else { + LOG(INFO) << "Unpacking archive to path " << path; + if ((ret = util.UnPack(path)) != NO_ERROR) { + LOG(ERROR) << "error during uncompression: " << ret; + } + util.CloseArchive(); + } + + return ret; +} + + +// Find the version of Chrome from an install source directory. +// Chrome_path should contain a complete and unpacked install package (i.e. +// a Chrome directory under which there is a version folder). +// Returns the version or NULL if no version is found. +installer::Version* GetVersionFromDir(const std::wstring& chrome_path) { + LOG(INFO) << "Looking for Chrome version folder under " << chrome_path; + std::wstring root_path(chrome_path); + file_util::AppendToPath(&root_path, L"*"); + + WIN32_FIND_DATA find_file_data; + HANDLE file_handle = FindFirstFile(root_path.c_str(), &find_file_data); + BOOL ret = TRUE; + installer::Version *version = NULL; + // Here we are assuming that the installer we have is really valid so there + // can not be two version directories. We exit as soon as we find a valid + // version directory. + while (ret) { + if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + LOG(INFO) << "directory found: " << find_file_data.cFileName; + version = + installer::Version::GetVersionFromString(find_file_data.cFileName); + if (version) break; + } + ret = FindNextFile(file_handle, &find_file_data); + } + FindClose(file_handle); + + return version; +} + +// This method checks if we need to change "ap" key in Google Update to try +// full installer as fall back method in case incremental installer fails. +// - If incremental installer fails we append a magic string ("-full"), if +// it is not present already, so that Google Update server next time will send +// full installer to update Chrome on the local machine +// - If we are currently running full installer, we remove this magic +// string (if it is present) regardless of whether installer failed or not. +// There is no fall-back for full installer :) +void ResetGoogleUpdateApKey(bool system_install, bool incremental_install, + installer_util::InstallStatus install_status) { + HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + + RegKey key; + std::wstring ap_key_value; + std::wstring chrome_google_update_state_key( + google_update::kRegPathClientState); + chrome_google_update_state_key.append(L"\\"); + chrome_google_update_state_key.append(google_update::kChromeGuid); + if (!key.Open(reg_root, chrome_google_update_state_key.c_str(), + KEY_ALL_ACCESS) || !key.ReadValue(google_update::kRegApFieldName, + &ap_key_value)) { + LOG(INFO) << "Application key not found. Returning without changing it."; + key.Close(); + return; + } + + std::wstring new_value = InstallUtil::GetNewGoogleUpdateApKey( + incremental_install, install_status, ap_key_value); + if ((new_value.compare(ap_key_value) != 0) && + !key.WriteValue(google_update::kRegApFieldName, new_value.c_str())) { + LOG(ERROR) << "Failed to write value " << new_value + << " to the registry field " << google_update::kRegApFieldName; + } + key.Close(); +} +} // namespace + + +int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, + wchar_t* command_line, int show_command) { + CommandLine parsed_command_line; + installer::InitInstallerLogging(parsed_command_line); + + // Check to make sure current system is WinXP or later. If not, log + // error message and get out. + if (!IsWindowsXPorLater()) { + LOG(ERROR) << "Chrome only supports Windows XP or later"; + return installer_util::OS_NOT_SUPPORTED; + } + + // Initialize COM for use later. + if (CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) != S_OK) { + LOG(ERROR) << "COM initialization failed."; + return installer_util::OS_ERROR; + } + + bool system_install = + parsed_command_line.HasSwitch(installer_util::switches::kSystemInstall); + LOG(INFO) << "system install is " << system_install; + + // Check the existing version installed. + scoped_ptr<installer::Version> + installed_version(InstallUtil::GetChromeVersion(system_install)); + if (installed_version.get()) { + LOG(INFO) << "version on the system: " << installed_version->GetString(); + } + + // If --register-chrome-browser option is specified, register all + // Chrome protocol/file associations as well as register it as a valid + // browser for StarMenu->Internet shortcut. This option should only + // be used when setup.exe is launched with admin rights. We do not + // make any user specific changes in this option. + if (parsed_command_line.HasSwitch( + installer_util::switches::kRegisterChromeBrowser)) { + std::wstring chrome_exe(parsed_command_line.GetSwitchValue( + installer_util::switches::kRegisterChromeBrowser)); + return ShellUtil::AddChromeToSetAccessDefaults(chrome_exe, true); + } + + installer_util::InstallStatus install_status = installer_util::UNKNOWN_STATUS; + if (parsed_command_line.HasSwitch(installer_util::switches::kUninstall)) { + bool remove_all = true; + if (parsed_command_line.HasSwitch( + installer_util::switches::kDoNotRemoveSharedItems)) + remove_all = false; + // If --uninstall option is given, uninstall chrome + LOG(INFO) << "Uninstalling Chome"; + if (!installed_version.get()) { + LOG(ERROR) << "No Chrome installation found for uninstall"; + install_status = installer_util::CHROME_NOT_INSTALLED; + } else { + install_status = installer_setup::UninstallChrome( + parsed_command_line.program(), system_install, + *installed_version, remove_all); + } + } else { + // If --uninstall option is not specified, we assume it is install case. + // For install the default location for chrome.packed.7z is in current + // folder, so get that value first. + std::wstring archive_path = + file_util::GetDirectoryFromPath(parsed_command_line.program()); + file_util::AppendToPath(&archive_path, + std::wstring(installer::kChromeCompressedArchive)); + // If --install-archive is given, get the user specified value + if (parsed_command_line.HasSwitch( + installer_util::switches::kInstallArchive)) { + archive_path = parsed_command_line.GetSwitchValue( + installer_util::switches::kInstallArchive); + } + LOG(INFO) << "Archive found to install Chrome " << archive_path; + + // Create a temp folder where we will unpack Chrome archive. If it fails, + // then we are doomed so return immediately and no cleanup is required. + std::wstring install_temp_path; + if (!file_util::CreateNewTempDirectory(std::wstring(L"chrome_"), + &install_temp_path)) { + LOG(ERROR) << "can not create temporary path"; + return installer_util::TEMP_DIR_FAILED; + } + LOG(INFO) << "created path " << install_temp_path; + std::wstring unpack_path(install_temp_path); + file_util::AppendToPath(&unpack_path, + std::wstring(installer::kInstallSourceDir)); + + bool incremental_install = false; + if (UnPackArchive(archive_path, system_install, installed_version.get(), + install_temp_path, unpack_path, incremental_install)) { + install_status = installer_util::UNCOMPRESSION_FAILED; + } else { + LOG(INFO) << "unpacked to " << unpack_path; + std::wstring src_path(unpack_path); + file_util::AppendToPath(&src_path, + std::wstring(installer::kInstallSourceChromeDir)); + scoped_ptr<installer::Version> + installer_version(GetVersionFromDir(src_path)); + if (!installer_version.get()) { + LOG(ERROR) << "didn't find any valid version in installer"; + install_status = installer_util::INVALID_ARCHIVE; + } else { + LOG(INFO) << "version to be installed: " << + installer_version->GetString(); + if (installed_version.get() && + installed_version->IsHigherThan(installer_version.get())) { + LOG(ERROR) << "Higher version is already installed."; + install_status = installer_util::HIGHER_VERSION_EXISTS; + } else { + // We want to keep uncompressed archive (chrome.7z) that we get after + // uncompressing and binary patching. Get the location for this file. + std::wstring archive_to_copy(install_temp_path); + file_util::AppendToPath(&archive_to_copy, + std::wstring(installer::kChromeArchive)); + install_status = installer::InstallOrUpdateChrome( + parsed_command_line.program(), archive_to_copy, + install_temp_path, system_install, + *installer_version, installed_version.get()); + if (install_status == installer_util::FIRST_INSTALL_SUCCESS) { + LOG(INFO) << "First install successful. Launching Chrome."; + installer::LaunchChrome(system_install); + } + } + } + } + + // Delete install temporary directory. + LOG(INFO) << "Deleting temporary directory " << install_temp_path; + scoped_ptr<DeleteTreeWorkItem> delete_tree( + WorkItem::CreateDeleteTreeWorkItem(install_temp_path, + std::wstring())); + delete_tree->Do(); + + ResetGoogleUpdateApKey(system_install, incremental_install, install_status); + + // TBD: The previous installs/updates may leave some temporary files + // that were not deleted when the installs/updates exited, probably due + // to a crash. Try delete those temporary files again? + } + + CoUninitialize(); + if (InstallUtil::InstallSuccessful(install_status)) + return 0; // For Google Update's benefit we need to return 0 for success + // cases. + else + return install_status; +} diff --git a/chrome/installer/setup/setup.cc b/chrome/installer/setup/setup.cc new file mode 100644 index 0000000..7452f10 --- /dev/null +++ b/chrome/installer/setup/setup.cc @@ -0,0 +1,290 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <shlobj.h> + +#include "chrome/installer/setup/setup.h" + +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/registry.h" +#include "base/string_util.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/installer/setup/setup_constants.h" +#include "chrome/installer/util/create_reg_key_work_item.h" +#include "chrome/installer/util/l10n_string_util.h" +#include "chrome/installer/util/logging_installer.h" +#include "chrome/installer/util/helper.h" +#include "chrome/installer/util/shell_util.h" +#include "chrome/installer/util/util_constants.h" +#include "chrome/installer/util/version.h" +#include "chrome/installer/util/work_item_list.h" + +#include "setup_strings.h" + +namespace { + +void AddChromeToMediaPlayerList() { + std::wstring reg_path(installer::kMediaPlayerRegPath); + // registry paths can also be appended like file system path + file_util::AppendToPath(®_path, installer_util::kChromeExe); + LOG(INFO) << "Adding Chrome to Media player list at " << reg_path; + scoped_ptr<WorkItem> work_item(WorkItem::CreateCreateRegKeyWorkItem( + HKEY_LOCAL_MACHINE, reg_path)); + + // if the operation fails we log the error but still continue + if (!work_item.get()->Do()) + LOG(ERROR) << "Couldn't add Chrome to media player inclusion list."; + +} + +// If we ever rename Chrome shortcuts under Windows Start menu, this +// function deletes any of the old Chrome shortcuts if they exist. This +// function will probably contain hard coded names of old shortcuts as they +// will not longer be used anywhere else. +// Method returns true if it finds and deletes successfully any old shortcut, +// in all other cases it returns false. +bool DeleteOldShortcuts(const std::wstring shortcut_path) { + // Check for the existence of shortcuts when they were still created under + // Start->Programs->Chrome (as opposed to Start->Programs->Google Chrome). + std::wstring shortcut_folder(shortcut_path); + file_util::AppendToPath(&shortcut_folder, L"Chrome"); + if (file_util::PathExists(shortcut_folder)) { + LOG(INFO) << "Old shortcut path " << shortcut_folder << " exists."; + return file_util::Delete(shortcut_folder, true); + } + return false; +} + +// Update shortcuts that are created by chrome.exe during first run, but +// we take care of updating them in case the location of chrome.exe changes. +void UpdateChromeExeShortcuts(const std::wstring& chrome_exe) { + std::wstring desktop_shortcut, ql_shortcut, shortcut_name; + if (!ShellUtil::GetQuickLaunchPath(&ql_shortcut) || + !ShellUtil::GetDesktopPath(&desktop_shortcut) || + !ShellUtil::GetChromeShortcutName(&shortcut_name)) + return; + // Migrate the old shortcuts from Chrome.lnk to the localized name. + std::wstring old_ql_shortcut = ql_shortcut; + file_util::AppendToPath(&old_ql_shortcut, L"Chrome.lnk"); + file_util::AppendToPath(&ql_shortcut, shortcut_name); + std::wstring old_desktop_shortcut = desktop_shortcut; + file_util::AppendToPath(&old_desktop_shortcut, L"Chrome.lnk"); + file_util::AppendToPath(&desktop_shortcut, shortcut_name); + + if (file_util::Move(old_ql_shortcut, ql_shortcut)) { + // Notify the Windows Shell that we renamed the file so it can remove the + // old icon. It's safe to not cehck for MAX_PATH because file_util::Move + // does the check for us. + SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATH, old_ql_shortcut.c_str(), + ql_shortcut.c_str()); + } + if (file_util::Move(old_desktop_shortcut, desktop_shortcut)) { + SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATH, old_desktop_shortcut.c_str(), + desktop_shortcut.c_str()); + } + + // Go ahead and update the shortcuts if they exist. + ShellUtil::UpdateChromeShortcut(chrome_exe, ql_shortcut, false); + ShellUtil::UpdateChromeShortcut(chrome_exe, desktop_shortcut, false); +} + +// This method creates Chrome shortcuts in Start->Programs for all users or +// only for current user depending on whether it is system wide install or +// user only install. +// +// If first_install is true, it creates shortcuts for launching and +// uninstalling chrome. +// If first_install is false, the function only updates the shortcut for +// uninstalling chrome. According to +// http://blogs.msdn.com/oldnewthing/archive/2005/11/24/496690.aspx, +// updating uninstall shortcut should not trigger Windows "new application +// installed" notification. +// +// If the shortcuts do not exist, the function does not recreate them during +// update. +bool CreateOrUpdateChromeShortcuts(const std::wstring& exe_path, + bool system_install, + installer_util::InstallStatus install_status, + const std::wstring& install_path, + const std::wstring& new_version) { + std::wstring shortcut_path; + int dir_enum = (system_install) ? base::DIR_COMMON_START_MENU : + base::DIR_START_MENU; + if (!PathService::Get(dir_enum, &shortcut_path)) { + LOG(ERROR) << "Failed to get location for shortcut."; + return false; + } + + // Check for existence of old shortcuts + bool old_shortcuts_existed = DeleteOldShortcuts(shortcut_path); + + // The location of Start->Programs->Google Chrome folder + const std::wstring& product_name = + installer_util::GetLocalizedString(IDS_PRODUCT_NAME_BASE); + file_util::AppendToPath(&shortcut_path, product_name); + + // Create/update Chrome link (points to chrome.exe) & Uninstall Chrome link + // (which points to setup.exe) under this folder only if: + // - This is a new install or install repair + // OR + // - The shortcut already exists in case of updates (user may have deleted + // shortcuts since our install. So on updates we only update if shortcut + // already exists) + bool ret1 = true; + std::wstring chrome_link(shortcut_path); // Chrome link (launches Chrome) + file_util::AppendToPath(&chrome_link, product_name + L".lnk"); + std::wstring chrome_exe(install_path); // Chrome link target + file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe); + + if ((install_status == installer_util::FIRST_INSTALL_SUCCESS) || + (install_status == installer_util::INSTALL_REPAIRED) || + (old_shortcuts_existed)) { + if (!file_util::PathExists(shortcut_path)) + file_util::CreateDirectoryW(shortcut_path); + + LOG(INFO) << "Creating shortcut to " << chrome_exe << " at " << chrome_link; + ShellUtil::UpdateChromeShortcut(chrome_exe, chrome_link, true); + } else if (file_util::PathExists(chrome_link)) { + LOG(INFO) << "Updating shortcut at " << chrome_link + << " to point to " << chrome_exe; + ShellUtil::UpdateChromeShortcut(chrome_exe, chrome_link, false); + } + + // Create/update uninstall link + bool ret2 = true; + std::wstring uninstall_link(shortcut_path); // Uninstall Chrome link + + file_util::AppendToPath(&uninstall_link, + installer_util::GetLocalizedString(IDS_UNINSTALL_CHROME_BASE) + L".lnk"); + if ((install_status == installer_util::FIRST_INSTALL_SUCCESS) || + (install_status == installer_util::INSTALL_REPAIRED) || + (old_shortcuts_existed) || + (file_util::PathExists(uninstall_link))) { + if (!file_util::PathExists(shortcut_path)) + file_util::CreateDirectoryW(shortcut_path); + std::wstring setup_exe(installer::GetInstallerPathUnderChrome(install_path, + new_version)); + file_util::AppendToPath(&setup_exe, + file_util::GetFilenameFromPath(exe_path)); + std::wstring arguments(L" --"); + arguments.append(installer_util::switches::kUninstall); + LOG(INFO) << "Creating/updating uninstall link at " << uninstall_link; + ret2 = file_util::CreateShortcutLink(setup_exe.c_str(), + uninstall_link.c_str(), + install_path.c_str(), + arguments.c_str(), + NULL, + setup_exe.c_str(), + 0); + } + + // Update Desktop and Quick Launch shortcuts (only if they already exist) + UpdateChromeExeShortcuts(chrome_exe); + + return ret1 && ret2; +} +} // namespace + + +std::wstring installer::GetInstallerPathUnderChrome( + const std::wstring& install_path, const std::wstring& new_version) { + std::wstring installer_path(install_path); + file_util::AppendToPath(&installer_path, new_version); + file_util::AppendToPath(&installer_path, installer::kInstallerDir); + return installer_path; +} + + +installer_util::InstallStatus installer::InstallOrUpdateChrome( + const std::wstring& exe_path, const std::wstring& archive_path, + const std::wstring& install_temp_path, bool system_install, + const Version& new_version, const Version* installed_version) { + + std::wstring install_path(GetChromeInstallPath(system_install)); + if (install_path.empty()) { + LOG(ERROR) << "Couldn't get installation destination path"; + return installer_util::INSTALL_FAILED; + } else { + LOG(INFO) << "install destination path: " << install_path; + } + + std::wstring src_path(install_temp_path); + file_util::AppendToPath(&src_path, std::wstring(kInstallSourceDir)); + file_util::AppendToPath(&src_path, std::wstring(kInstallSourceChromeDir)); + + HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + bool install_success = InstallNewVersion(exe_path, archive_path, src_path, + install_path, install_temp_path, reg_root, new_version); + + installer_util::InstallStatus result; + if (!install_success) { + LOG(ERROR) << "Install failed."; + result = installer_util::INSTALL_FAILED; + } else { + if (!installed_version) { + LOG(INFO) << "First install of version " << new_version.GetString(); + result = installer_util::FIRST_INSTALL_SUCCESS; + } else if (new_version.GetString() == installed_version->GetString()) { + LOG(INFO) << "Install repaired of version " << new_version.GetString(); + result = installer_util::INSTALL_REPAIRED; + } else if (new_version.IsHigherThan(installed_version)) { + LOG(INFO) << "Version updated to " << new_version.GetString(); + result = installer_util::NEW_VERSION_UPDATED; + } else { + NOTREACHED(); + } + + if (!CreateOrUpdateChromeShortcuts(exe_path, system_install, result, + install_path, new_version.GetString())) + LOG(WARNING) << "Failed to create/update start menu shortcut."; + + std::wstring chrome_exe(install_path); + file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe); + if (result == installer_util::FIRST_INSTALL_SUCCESS || + result == installer_util::INSTALL_REPAIRED) { + // Try to add Chrome to Media Player shim inclusion list. We don't do any + // error checking here because this operation will fail if user doesn't + // have admin rights and we want to ignore the error. + AddChromeToMediaPlayerList(); + + // We try to register Chrome as a valid browser on local machine. This + // will work only if current user has admin rights. + LOG(INFO) << "Registering Chrome as browser"; + ShellUtil::RegisterStatus ret = + ShellUtil::AddChromeToSetAccessDefaults(chrome_exe, true); + LOG(ERROR) << "Return status of Chrome browser registration " << ret; + } else { + UpdateChromeExeShortcuts(chrome_exe); + RemoveOldVersionDirs(install_path, new_version.GetString()); + } + } + + return result; +} diff --git a/chrome/installer/setup/setup.exe.manifest b/chrome/installer/setup/setup.exe.manifest new file mode 100644 index 0000000..28469a3 --- /dev/null +++ b/chrome/installer/setup/setup.exe.manifest @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+ <ms_asmv2:security>
+ <ms_asmv2:requestedPrivileges>
+ <ms_asmv2:requestedExecutionLevel level="asInvoker">
+ </ms_asmv2:requestedExecutionLevel>
+ </ms_asmv2:requestedPrivileges>
+ </ms_asmv2:security>
+ </ms_asmv2:trustInfo>
+</assembly>
diff --git a/chrome/installer/setup/setup.h b/chrome/installer/setup/setup.h new file mode 100644 index 0000000..0f3ebc5 --- /dev/null +++ b/chrome/installer/setup/setup.h @@ -0,0 +1,104 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file contains the specification of setup main functions. + +#ifndef CHROME_INSTALLER_SETUP_SETUP_H__ +#define CHROME_INSTALLER_SETUP_SETUP_H__ + +#include <string> +#include <windows.h> + +#include "chrome/installer/util/util_constants.h" +#include "chrome/installer/util/version.h" + +namespace installer { +// Get path to the installer under Chrome version folder +// (for example <path>\Google\Chrome\<Version>\installer) +std::wstring GetInstallerPathUnderChrome(const std::wstring& install_path, + const std::wstring& new_version); + +// This function installs or updates a new version of Chrome. It returns +// install status (failed, new_install, updated etc). +// +// exe_path: Path to the executable (setup.exe) as it will be copied +// to Chrome install folder after install is complete +// archive_path: Path to the archive (chrome.7z) as it will be copied +// to Chrome install folder after install is complete +// install_temp_path: working directory used during install/update. It should +// also has a sub dir source that contains a complete +// and unpacked Chrome package. +// system_install: if true, the function performs a system wide install/update. +// Otherwise it installs/updates Chrome for the current user. +// new_version: new Chrome version that needs to be installed +// installed_version: currently installed version of Chrome, if any, or +// NULL otherwise +// +// Note: since caller unpacks Chrome to install_temp_path\source, the caller +// is responsible for cleaning up install_temp_path. +installer_util::InstallStatus InstallOrUpdateChrome( + const std::wstring& exe_path, const std::wstring& archive_path, + const std::wstring& install_temp_path, bool system_install, + const Version& new_version, const Version* installed_version); + +// This function installs a new version of Chrome to the specified location. +// It returns true if install was successful and false in case of an error. +// +// exe_path: Path to the executable (setup.exe) as it will be copied +// to Chrome install folder after install is complete +// archive_path: Path to the archive (chrome.7z) as it will be copied +// to Chrome install folder after install is complete +// src_path: the path that contains a complete and unpacked Chrome package +// to be installed. +// install_path: the destination path for Chrome to be installed to. This +// path does not need to exist. +// temp_dir: the path of working directory used during installation. This path +// does not need to exist. +// reg_root: the root of registry where the function applies settings for the +// new Chrome version. It should be either HKLM or HKCU. +// new_version: new Chrome version that needs to be installed +// +// This function makes best effort to do installation in a transactional +// manner. If failed it tries to rollback all changes on the file system +// and registry. For example, if install_path exists before calling the +// function, it rolls back all new file and directory changes under +// install_path. If install_path does not exist before calling the function +// (typical new install), the function creates install_path during install +// and removes the whole directory during rollback. +bool InstallNewVersion(const std::wstring& exe_path, + const std::wstring& archive_path, + const std::wstring& src_path, + const std::wstring& install_path, + const std::wstring& temp_dir, + const HKEY reg_root, + const Version& new_version); + +} + +#endif // CHROME_INSTALLER_SETUP_SETUP_H__ diff --git a/chrome/installer/setup/setup.ico b/chrome/installer/setup/setup.ico Binary files differnew file mode 100644 index 0000000..5ecfcbd --- /dev/null +++ b/chrome/installer/setup/setup.ico diff --git a/chrome/installer/setup/setup.rc b/chrome/installer/setup/setup.rc new file mode 100644 index 0000000..2423a76 --- /dev/null +++ b/chrome/installer/setup/setup.rc @@ -0,0 +1,82 @@ +// Microsoft Visual C++ generated resource script. +// +#include "setup_resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "setup_resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#include ""setup_exe_version.rc""\r\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_SETUP ICON "setup.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_UNINSTALL_SURVEY_URL "http://go/chromeuninstall?hl=$1&contact_type=uninstall" +END + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "setup_exe_version.rc" + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/chrome/installer/setup/setup.vcproj b/chrome/installer/setup/setup.vcproj new file mode 100644 index 0000000..e6c6abf --- /dev/null +++ b/chrome/installer/setup/setup.vcproj @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="setup" + ProjectGUID="{21C76E6E-8B38-44D6-8148-B589C13B9554}" + RootNamespace="setup" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + <ToolFile + RelativePath="..\..\tools\build\win\version.rules" + /> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\setup_debug.vsprops;..\util\using_util.vsprops;..\util\prebuild\util_prebuild.vsprops" + > + <Tool + Name="Version" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCManifestTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + ConfigurationType="1" + InheritedPropertySheets=".\setup_release.vsprops;..\util\using_util.vsprops;..\util\prebuild\util_prebuild.vsprops" + > + <Tool + Name="Version" + /> + <Tool + Name="VCCLCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCLinkerTool" + /> + <Tool + Name="VCManifestTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="resources" + > + <File + RelativePath=".\setup_resource.h" + > + </File> + <File + RelativePath=".\setup.ico" + > + </File> + <File + RelativePath=".\setup.rc" + > + </File> + <File + RelativePath=".\setup_exe_version.rc.version" + > + </File> + <File + RelativePath="$(IntDir)\..\util_prebuild\setup_strings.h" + > + </File> + <File + RelativePath="$(IntDir)\..\util_prebuild\setup_strings.rc" + > + </File> + </Filter> + <File + RelativePath=".\install.cc" + > + </File> + <File + RelativePath=".\main.cc" + > + </File> + <File + RelativePath=".\setup.cc" + > + </File> + <File + RelativePath=".\setup.h" + > + </File> + <File + RelativePath=".\setup_constants.cc" + > + </File> + <File + RelativePath=".\setup_constants.h" + > + </File> + <File + RelativePath=".\uninstall.cc" + > + </File> + <File + RelativePath=".\uninstall.h" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/chrome/installer/setup/setup.vsprops b/chrome/installer/setup/setup.vsprops new file mode 100644 index 0000000..53258e4 --- /dev/null +++ b/chrome/installer/setup/setup.vsprops @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="setup" + InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="$(OutDir);$(IntDir)" + EnableIntrinsicFunctions="true" + BasicRuntimeChecks="0" + BufferSecurityCheck="false" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="msi.lib" + GenerateMapFile="true" + SubSystem="2" + OptimizeForWindows98="1" + /> + <Tool + Name="VCResourceCompilerTool" + AdditionalIncludeDirectories="$(OutDir);$(IntDir)" + /> + <Tool + Name="VCManifestTool" + AdditionalManifestFiles="$(SolutionDir)installer\setup\setup.exe.manifest" + /> +</VisualStudioPropertySheet> diff --git a/chrome/installer/setup/setup_constants.cc b/chrome/installer/setup/setup_constants.cc new file mode 100644 index 0000000..3397836 --- /dev/null +++ b/chrome/installer/setup/setup_constants.cc @@ -0,0 +1,49 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "chrome/installer/setup/setup_constants.h" + +namespace installer { +// Elements that makes up install target path. +const wchar_t kChromeOldExe[] = L"old_chrome.exe"; +const wchar_t kChromeNewExe[] = L"new_chrome.exe"; +const wchar_t kWowHelperExe[] = L"wow_helper.exe"; +const wchar_t kChromeArchive[] = L"chrome.7z"; +const wchar_t kChromePatchArchive[] = L"patch.7z"; +const wchar_t kChromeCompressedArchive[] = L"chrome.packed.7z"; +const wchar_t kChromeCompressedPatchArchivePrefix[] = L"patch"; + +// Sub directory of install source package under install temporary directory. +const wchar_t kInstallSourceDir[] = L"source"; +const wchar_t kInstallSourceChromeDir[] = L"Chrome-bin"; + +const wchar_t kInstallerDir[] = L"Installer"; + +const wchar_t kMediaPlayerRegPath[] = L"Software\\Microsoft\\MediaPlayer\\ShimInclusionList"; +} // namespace installer diff --git a/chrome/installer/setup/setup_constants.h b/chrome/installer/setup/setup_constants.h new file mode 100644 index 0000000..7e4bc48 --- /dev/null +++ b/chrome/installer/setup/setup_constants.h @@ -0,0 +1,53 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Defines all the command-line switches used by Chrome installer. + +#ifndef CHROME_INSTALLER_SETUP_SETUP_CONSTANTS_H__ +#define CHROME_INSTALLER_SETUP_SETUP_CONSTANTS_H__ + +namespace installer { + +extern const wchar_t kChromeOldExe[]; +extern const wchar_t kChromeNewExe[]; +extern const wchar_t kWowHelperExe[]; +extern const wchar_t kChromeArchive[]; +extern const wchar_t kChromePatchArchive[]; +extern const wchar_t kChromeCompressedArchive[]; +extern const wchar_t kChromeCompressedPatchArchivePrefix[]; + +extern const wchar_t kInstallSourceDir[]; +extern const wchar_t kInstallSourceChromeDir[]; + +extern const wchar_t kInstallerDir[]; + +extern const wchar_t kMediaPlayerRegPath[]; +} // namespace installer + +#endif // CHROME_INSTALLER_SETUP_SETUP_CONSTANTS_H__ diff --git a/chrome/installer/setup/setup_debug.vsprops b/chrome/installer/setup/setup_debug.vsprops new file mode 100644 index 0000000..873c6f1 --- /dev/null +++ b/chrome/installer/setup/setup_debug.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="setup_debug" + InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;.\setup.vsprops" + > +</VisualStudioPropertySheet> diff --git a/chrome/installer/setup/setup_exe_version.rc.version b/chrome/installer/setup/setup_exe_version.rc.version new file mode 100644 index 0000000..5c41cf0 --- /dev/null +++ b/chrome/installer/setup/setup_exe_version.rc.version @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @MAJOR@,@MINOR@,@BUILD@,@PATCH@ + PRODUCTVERSION @MAJOR@,@MINOR@,@BUILD@,@PATCH@ + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "@COMPANY_FULLNAME@" + VALUE "FileDescription", "@PRODUCT_FULLNAME@" + VALUE "FileVersion", "@MAJOR@.@MINOR@.@BUILD@.@PATCH@" + VALUE "InternalName", "setup" + VALUE "LegalCopyright", "@COPYRIGHT@" + VALUE "ProductName", "@PRODUCT_FULLNAME@" + VALUE "ProductVersion", "@MAJOR@.@MINOR@.@BUILD@.@PATCH@" + VALUE "CompanyShortName", "@COMPANY_SHORTNAME@" + VALUE "ProductShortName", "@PRODUCT_SHORTNAME@" + VALUE "LastChange", "@LASTCHANGE@" + VALUE "Official Build", "@OFFICIAL_BUILD@" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/chrome/installer/setup/setup_release.vsprops b/chrome/installer/setup/setup_release.vsprops new file mode 100644 index 0000000..ee6094c --- /dev/null +++ b/chrome/installer/setup/setup_release.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="setup_release" + InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;.\setup.vsprops" + > +</VisualStudioPropertySheet> diff --git a/chrome/installer/setup/setup_resource.h b/chrome/installer/setup/setup_resource.h new file mode 100644 index 0000000..6915d21 --- /dev/null +++ b/chrome/installer/setup/setup_resource.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by setup.rc +// +#define IDI_SETUP 101 +#define IDS_UNINSTALL_SURVEY_URL 102 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc new file mode 100644 index 0000000..9403a8a --- /dev/null +++ b/chrome/installer/setup/uninstall.cc @@ -0,0 +1,303 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file defines the methods useful for uninstalling Chrome. + +#include "chrome/installer/setup/uninstall.h" + +#include <atlbase.h> +#include <windows.h> +#include <msi.h> + +#include "base/file_util.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 "base/wmi_util.h" +#include "chrome/app/google_update_settings.h" +#include "chrome/app/result_codes.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/installer/setup/setup_constants.h" +#include "chrome/installer/util/helper.h" +#include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/l10n_string_util.h" +#include "chrome/installer/util/logging_installer.h" +#include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/shell_util.h" +#include "chrome/installer/util/util_constants.h" +#include "chrome/installer/util/version.h" + +#include "setup_resource.h" +#include "setup_strings.h" + +namespace { + +// This method deletes Chrome shortcut folder from Windows Start menu. It +// checks system_uninstall to see if the shortcut is in all users start menu +// or current user start menu. +void DeleteChromeShortcut(bool system_uninstall) { + std::wstring shortcut_path; + if (system_uninstall) { + PathService::Get(base::DIR_COMMON_START_MENU, &shortcut_path); + } else { + PathService::Get(base::DIR_START_MENU, &shortcut_path); + } + if (shortcut_path.empty()) { + LOG(ERROR) << "failed to get location for shortcut"; + } else { + file_util::AppendToPath(&shortcut_path, + installer_util::GetLocalizedString(IDS_PRODUCT_NAME_BASE)); + LOG(INFO) << "Deleting shortcut " << shortcut_path; + if (!file_util::Delete(shortcut_path, true)) + LOG(ERROR) << "Failed to delete folder: " << shortcut_path; + } +} + +// This method tries to delete a registry key and logs an error message +// in case of failure. It returns true if deletion is successful, +// otherwise false. +bool DeleteRegistryKey(RegKey& key, const std::wstring& key_path) { + LOG(INFO) << "Deleting registry key " << key_path; + if (!key.DeleteKey(key_path.c_str())) { + LOG(ERROR) << "Failed to delete registry key: " << key_path + << " and the error is " << InstallUtil::FormatLastWin32Error(); + return false; + } + return true; +} + +// This method tries to delete a registry value and logs an error message +// in case of failure. It returns true if deletion is successful, +// otherwise false. +bool DeleteRegistryValue(HKEY reg_root, const std::wstring& key_path, + const std::wstring& value_name) { + RegKey key(reg_root, key_path.c_str(), KEY_ALL_ACCESS); + LOG(INFO) << "Deleting registry value " << value_name; + if (!key.DeleteValue(value_name.c_str())) { + LOG(ERROR) << "Failed to delete registry value: " << value_name + << " and the error is " << InstallUtil::FormatLastWin32Error(); + return false; + } + return true; +} + +// This method checks if Chrome is currently running or if the user has +// cancelled the uninstall operation by clicking Cancel on the confirmation +// box that Chrome pops up. +installer_util::InstallStatus IsChromeActiveOrUserCancelled( + bool system_uninstall) { + static const std::wstring kCmdLineOptions(L" --uninstall"); + static const int32 kTimeOutMs = 30000; + int32 exit_code = ResultCodes::NORMAL_EXIT; + bool is_timeout = false; + + // We ignore all other errors such as whether launching chrome fails, + // whether chrome returns UNINSTALL_ERROR, etc. + LOG(INFO) << "Launching Chrome to do uninstall tasks."; + if (installer::LaunchChromeAndWaitForResult(system_uninstall, + kCmdLineOptions, + kTimeOutMs, + &exit_code, + &is_timeout)) { + if (is_timeout || exit_code == ResultCodes::UNINSTALL_CHROME_ALIVE) { + LOG(ERROR) << "Can't uninstall when chrome is still running"; + return installer_util::CHROME_RUNNING; + } else if (exit_code == ResultCodes::UNINSTALL_USER_CANCEL) { + LOG(INFO) << "User cancelled uninstall operation"; + return installer_util::UNINSTALL_CANCELLED; + } else if (exit_code == ResultCodes::UNINSTALL_ERROR) { + LOG(ERROR) << "chrome.exe reported error while uninstalling."; + return installer_util::UNINSTALL_FAILED; + } + } + + return installer_util::UNINSTALL_CONFIRMED; +} + +// Read the URL from the resource file and substitute the locale parameter +// with whatever Google Update tells us is the locale. In case we fail to find +// the locale, we use US English. +std::wstring GetUninstallSurveyUrl() { + const ATLSTRINGRESOURCEIMAGE* image = AtlGetStringResourceImage( + _AtlBaseModule.GetModuleInstance(), IDS_UNINSTALL_SURVEY_URL); + DCHECK(image); + std::wstring url = std::wstring(image->achString, image->nLength); + DCHECK(!url.empty()); + + std::wstring language; + if (!GoogleUpdateSettings::GetLanguage(&language)) + language = L"en-US"; // Default to US English. + + return ReplaceStringPlaceholders(url.c_str(), language.c_str(), NULL); +} + +// This method launches an uninstall survey and is called at the end of +// uninstall process. We are not doing any error checking here as it is +// not critical to have this survey. If we fail to launch it, we just +// ignore it silently. +void LaunchUninstallSurvey(const installer::Version& installed_version) { + // Send the Chrome version and OS version as params to the form. + // It would be nice to send the locale, too, but I don't see an + // easy way to get that in the existing code. It's something we + // can add later, if needed. + // We depend on installed_version.GetString() not having spaces or other + // characters that need escaping: 0.2.13.4. Should that change, we will + // need to escape the string before using it in a URL. + const std::wstring kVersionParam = L"crversion"; + const std::wstring kVersion = installed_version.GetString(); + const std::wstring kOSParam = L"os"; + std::wstring os_version = L"na"; + OSVERSIONINFO version_info; + version_info.dwOSVersionInfoSize = sizeof version_info; + if (GetVersionEx(&version_info)) { + os_version = StringPrintf(L"%d.%d.%d", + version_info.dwMajorVersion, + version_info.dwMinorVersion, + version_info.dwBuildNumber); + } + + std::wstring iexplore; + if (!PathService::Get(base::DIR_PROGRAM_FILES, &iexplore)) + return; + + file_util::AppendToPath(&iexplore, L"Internet Explorer"); + file_util::AppendToPath(&iexplore, L"iexplore.exe"); + + std::wstring command = iexplore + L" " + GetUninstallSurveyUrl() + L"&" + + kVersionParam + L"=" + kVersion + L"&" + kOSParam + L"=" + os_version; + int pid = 0; + WMIProcessUtil::Launch(command, &pid); +} + +// Uninstall Chrome specific Gears. First we find Gears MSI ProductId (that +// changes with every new version of Gears) using Gears MSI UpgradeCode (that +// does not change) and then uninstall Gears using API. +void UninstallGears() { + wchar_t product[39]; // GUID + '\0' + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); // Don't show any UI to user. + for (int i = 0; MsiEnumRelatedProducts(google_update::kGearsUpgradeCode, 0, i, + product) != ERROR_NO_MORE_ITEMS; ++i) { + LOG(INFO) << "Uninstalling Gears - " << product; + unsigned int ret = MsiConfigureProduct(product, INSTALLLEVEL_MAXIMUM, + INSTALLSTATE_ABSENT); + if (ret != ERROR_SUCCESS) + LOG(ERROR) << "Failed to uninstall Gears " << product + << " because of error " << ret; + } +} + +} // namespace + + +installer_util::InstallStatus installer_setup::UninstallChrome( + const std::wstring& exe_path, bool system_uninstall, + const installer::Version& installed_version, bool remove_all) { + installer_util::InstallStatus status = + IsChromeActiveOrUserCancelled(system_uninstall); + if (status == installer_util::CHROME_RUNNING || + status == installer_util::UNINSTALL_CANCELLED) + return status; + + // Uninstall Gears first. + UninstallGears(); + + // Chrome is not in use so lets uninstall Chrome by deleting various files + // and registry entries. Here we will just make best effort and keep going + // in case of errors. + // First delete shortcut from Start->Programs. + DeleteChromeShortcut(system_uninstall); + + // Delete the registry keys (Uninstall key and Google Update update key). + HKEY reg_root = system_uninstall ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + RegKey key(reg_root, L"", KEY_ALL_ACCESS); + DeleteRegistryKey(key, installer_util::kUninstallRegPath); + DeleteRegistryKey(key, InstallUtil::GetChromeGoogleUpdateKey()); + + // Delete Software\Classes\ChromeHTML, + // Software\Clients\StartMenuInternet\chrome.exe and + // Software\RegisteredApplications\Chrome + std::wstring html_prog_id(ShellUtil::kRegClasses); + file_util::AppendToPath(&html_prog_id, ShellUtil::kChromeHTMLProgId); + DeleteRegistryKey(key, html_prog_id); + + std::wstring set_access_key(ShellUtil::kRegStartMenuInternet); + file_util::AppendToPath(&set_access_key, installer_util::kChromeExe); + DeleteRegistryKey(key, set_access_key); + + DeleteRegistryValue(reg_root, ShellUtil::kRegRegisteredApplications, + installer_util::kApplicationName); + key.Close(); + + // Delete shared registry keys as well (these require admin rights) if + // remove_all option is specified. + if (remove_all) { + RegKey hklm_key(HKEY_LOCAL_MACHINE, L"", KEY_ALL_ACCESS); + DeleteRegistryKey(hklm_key, set_access_key); + DeleteRegistryKey(hklm_key, html_prog_id); + DeleteRegistryValue(HKEY_LOCAL_MACHINE, + ShellUtil::kRegRegisteredApplications, + installer_util::kApplicationName); + + // Delete media player registry key that exists only in HKLM. + std::wstring reg_path(installer::kMediaPlayerRegPath); + file_util::AppendToPath(®_path, installer_util::kChromeExe); + DeleteRegistryKey(hklm_key, reg_path); + hklm_key.Close(); + } + + // Finally delete all the files from Chrome folder after moving setup.exe + // to a temp location. + std::wstring install_path(installer::GetChromeInstallPath(system_uninstall)); + if (install_path.empty()) { + LOG(ERROR) << "Couldn't get installation destination path"; + // Nothing else we could do for uninstall, so we return. + return installer_util::UNINSTALL_FAILED; + } else { + LOG(INFO) << "install destination path: " << install_path; + } + + std::wstring setup_exe(install_path); + file_util::AppendToPath(&setup_exe, installed_version.GetString()); + file_util::AppendToPath(&setup_exe, installer::kInstallerDir); + file_util::AppendToPath(&setup_exe, file_util::GetFilenameFromPath(exe_path)); + + std::wstring temp_file; + file_util::CreateTemporaryFileName(&temp_file); + file_util::Move(setup_exe, temp_file); + + LOG(INFO) << "Deleting install path " << install_path; + if (!file_util::Delete(install_path, true)) + LOG(ERROR) << "Failed to delete folder: " << install_path; + + LOG(INFO) << "Uninstallation complete. Launching Uninstall survey."; + LaunchUninstallSurvey(installed_version); + return installer_util::UNINSTALL_SUCCESSFUL; +} diff --git a/chrome/installer/setup/uninstall.h b/chrome/installer/setup/uninstall.h new file mode 100644 index 0000000..9308859 --- /dev/null +++ b/chrome/installer/setup/uninstall.h @@ -0,0 +1,56 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file declares Chrome uninstall related functions. + +#ifndef CHROME_INSTALLER_SETUP_UNINSTALL_H__ +#define CHROME_INSTALLER_SETUP_UNINSTALL_H__ + +#include <string> + +#include "chrome/installer/util/util_constants.h" +#include "chrome/installer/util/version.h" + +namespace installer_setup { +// This function uninstalls Chrome. +// +// exe_path: Path to the executable (setup.exe) as it will be copied +// to temp folder before deleting Chrome folder. +// system_uninstall: if true, the function uninstalls Chrome installed system +// wise. otherwise, it uninstalls Chrome installed for the +// current user. +// installed_version: currently installed version of Chrome. +// remove_all: Remove all shared files, registry entries as well. +installer_util::InstallStatus UninstallChrome( + const std::wstring& exe_path, bool system_uninstall, + const installer::Version& installed_version, bool remove_all); + +} // namespace installer_setup + +#endif // CHROME_INSTALLER_SETUP_UNINSTALL_H__ |