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