Home | History | Annotate | Download | only in win
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "cloud_print/common/win/install_utils.h"
      6 
      7 #include <windows.h>
      8 
      9 #include "base/command_line.h"
     10 #include "base/file_util.h"
     11 #include "base/file_version_info_win.h"
     12 #include "base/files/file_path.h"
     13 #include "base/path_service.h"
     14 #include "base/process/launch.h"
     15 #include "base/win/registry.h"
     16 
     17 namespace cloud_print {
     18 
     19 namespace {
     20 
     21 // Google Update related constants.
     22 const wchar_t kClientsKey[] = L"SOFTWARE\\Google\\Update\\Clients\\";
     23 const wchar_t kClientStateKey[] = L"SOFTWARE\\Google\\Update\\ClientState\\";
     24 const wchar_t* kUsageKey = L"dr";
     25 const wchar_t kVersionKey[] = L"pv";
     26 const wchar_t kNameKey[] = L"name";
     27 const DWORD kInstallerResultFailedCustomError = 1;
     28 const wchar_t kRegValueInstallerResult[] = L"InstallerResult";
     29 const wchar_t kRegValueInstallerResultUIString[] = L"InstallerResultUIString";
     30 
     31 // Uninstall related constants.
     32 const wchar_t kUninstallKey[] =
     33     L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\";
     34 const wchar_t kInstallLocation[] = L"InstallLocation";
     35 const wchar_t kUninstallString[] = L"UninstallString";
     36 const wchar_t kDisplayVersion[] = L"DisplayVersion";
     37 const wchar_t kDisplayIcon[] = L"DisplayIcon";
     38 const wchar_t kDisplayName[] = L"DisplayName";
     39 const wchar_t kPublisher[] = L"Publisher";
     40 const wchar_t kNoModify[] = L"NoModify";
     41 const wchar_t kNoRepair[] = L"NoRepair";
     42 
     43 }  // namespace
     44 
     45 
     46 void SetGoogleUpdateKeys(const base::string16& product_id,
     47                          const base::string16& product_name) {
     48   base::win::RegKey key;
     49   if (key.Create(HKEY_LOCAL_MACHINE,
     50                  (cloud_print::kClientsKey + product_id).c_str(),
     51                  KEY_SET_VALUE) != ERROR_SUCCESS) {
     52     LOG(ERROR) << "Unable to open key";
     53   }
     54 
     55   // Get the version from the resource file.
     56   base::string16 version_string;
     57   scoped_ptr<FileVersionInfo> version_info(
     58       FileVersionInfo::CreateFileVersionInfoForCurrentModule());
     59 
     60   if (version_info.get()) {
     61     FileVersionInfoWin* version_info_win =
     62         static_cast<FileVersionInfoWin*>(version_info.get());
     63     version_string = version_info_win->product_version();
     64   } else {
     65     LOG(ERROR) << "Unable to get version string";
     66     // Use a random version string so that Google Update has something to go by.
     67     version_string = L"0.0.0.99";
     68   }
     69 
     70   if (key.WriteValue(kVersionKey, version_string.c_str()) != ERROR_SUCCESS ||
     71       key.WriteValue(kNameKey, product_name.c_str()) != ERROR_SUCCESS) {
     72     LOG(ERROR) << "Unable to set registry keys";
     73   }
     74 }
     75 
     76 void SetGoogleUpdateError(const base::string16& product_id,
     77                           const base::string16& message) {
     78   LOG(ERROR) << message;
     79   base::win::RegKey key;
     80   if (key.Create(HKEY_LOCAL_MACHINE,
     81                  (cloud_print::kClientStateKey + product_id).c_str(),
     82                  KEY_SET_VALUE) != ERROR_SUCCESS) {
     83     LOG(ERROR) << "Unable to open key";
     84   }
     85 
     86   if (key.WriteValue(kRegValueInstallerResult,
     87                      kInstallerResultFailedCustomError) != ERROR_SUCCESS ||
     88       key.WriteValue(kRegValueInstallerResultUIString,
     89                      message.c_str()) != ERROR_SUCCESS) {
     90       LOG(ERROR) << "Unable to set registry keys";
     91   }
     92 }
     93 
     94 void DeleteGoogleUpdateKeys(const base::string16& product_id) {
     95   base::win::RegKey key;
     96   if (key.Open(HKEY_LOCAL_MACHINE,
     97                (cloud_print::kClientsKey + product_id).c_str(),
     98                DELETE) != ERROR_SUCCESS) {
     99     LOG(ERROR) << "Unable to open key to delete";
    100     return;
    101   }
    102   if (key.DeleteKey(L"") != ERROR_SUCCESS) {
    103     LOG(ERROR) << "Unable to delete key";
    104   }
    105 }
    106 
    107 void CreateUninstallKey(const base::string16& uninstall_id,
    108                         const base::string16& product_name,
    109                         const std::string& uninstall_switch) {
    110   // Now write the Windows Uninstall entries
    111   // Minimal error checking here since the install can continue
    112   // if this fails.
    113   base::win::RegKey key;
    114   if (key.Create(HKEY_LOCAL_MACHINE,
    115                  (cloud_print::kUninstallKey + uninstall_id).c_str(),
    116                  KEY_SET_VALUE) != ERROR_SUCCESS) {
    117     LOG(ERROR) << "Unable to open key";
    118     return;
    119   }
    120 
    121   base::FilePath unstall_binary;
    122   CHECK(PathService::Get(base::FILE_EXE, &unstall_binary));
    123 
    124   CommandLine uninstall_command(unstall_binary);
    125   uninstall_command.AppendSwitch(uninstall_switch);
    126   key.WriteValue(kUninstallString,
    127                  uninstall_command.GetCommandLineString().c_str());
    128   key.WriteValue(kInstallLocation,
    129                  unstall_binary.DirName().value().c_str());
    130 
    131   // Get the version resource.
    132   scoped_ptr<FileVersionInfo> version_info(
    133       FileVersionInfo::CreateFileVersionInfoForCurrentModule());
    134 
    135   if (version_info.get()) {
    136     FileVersionInfoWin* version_info_win =
    137         static_cast<FileVersionInfoWin*>(version_info.get());
    138     key.WriteValue(kDisplayVersion,
    139                    version_info_win->file_version().c_str());
    140     key.WriteValue(kPublisher, version_info_win->company_name().c_str());
    141   } else {
    142     LOG(ERROR) << "Unable to get version string";
    143   }
    144   key.WriteValue(kDisplayName, product_name.c_str());
    145   key.WriteValue(kDisplayIcon, unstall_binary.value().c_str());
    146   key.WriteValue(kNoModify, 1);
    147   key.WriteValue(kNoRepair, 1);
    148 }
    149 
    150 void DeleteUninstallKey(const base::string16& uninstall_id) {
    151   ::RegDeleteKey(HKEY_LOCAL_MACHINE,
    152                  (cloud_print::kUninstallKey + uninstall_id).c_str());
    153 }
    154 
    155 base::FilePath GetInstallLocation(const base::string16& uninstall_id) {
    156   base::win::RegKey key;
    157   if (key.Open(HKEY_LOCAL_MACHINE,
    158                (cloud_print::kUninstallKey + uninstall_id).c_str(),
    159                KEY_QUERY_VALUE) != ERROR_SUCCESS) {
    160     // Not installed.
    161     return base::FilePath();
    162   }
    163   base::string16 install_path_value;
    164   key.ReadValue(kInstallLocation, &install_path_value);
    165   return base::FilePath(install_path_value);
    166 }
    167 
    168 void DeleteProgramDir(const std::string& delete_switch) {
    169   base::FilePath installer_source;
    170   if (!PathService::Get(base::FILE_EXE, &installer_source))
    171     return;
    172   // Deletes only subdirs of program files.
    173   if (!IsProgramsFilesParent(installer_source))
    174     return;
    175   base::FilePath temp_path;
    176   if (!base::CreateTemporaryFile(&temp_path))
    177     return;
    178   base::CopyFile(installer_source, temp_path);
    179   base::DeleteFileAfterReboot(temp_path);
    180   CommandLine command_line(temp_path);
    181   command_line.AppendSwitchPath(delete_switch, installer_source.DirName());
    182   base::LaunchOptions options;
    183   base::ProcessHandle process_handle;
    184   if (!base::LaunchProcess(command_line, options, &process_handle)) {
    185     LOG(ERROR) << "Unable to launch child uninstall.";
    186   }
    187 }
    188 
    189 bool IsProgramsFilesParent(const base::FilePath& path) {
    190   base::FilePath program_files;
    191   if (!PathService::Get(base::DIR_PROGRAM_FILESX86, &program_files))
    192     return false;
    193   return program_files.IsParent(path);
    194 }
    195 
    196 }  // namespace cloud_print
    197 
    198