• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SetGoogleUpdateKeys(const base::string16 & product_id,const base::string16 & product_name)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 
SetGoogleUpdateError(const base::string16 & product_id,const base::string16 & message)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 
SetGoogleUpdateError(const base::string16 & product_id,HRESULT hr)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 
DeleteGoogleUpdateKeys(const base::string16 & product_id)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 
CreateUninstallKey(const base::string16 & uninstall_id,const base::string16 & product_name,const std::string & uninstall_switch)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 
DeleteUninstallKey(const base::string16 & uninstall_id)173 void DeleteUninstallKey(const base::string16& uninstall_id) {
174   ::RegDeleteKey(HKEY_LOCAL_MACHINE,
175                  (cloud_print::kUninstallKey + uninstall_id).c_str());
176 }
177 
GetInstallLocation(const base::string16 & uninstall_id)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 
DeleteProgramDir(const std::string & delete_switch)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 
IsProgramsFilesParent(const base::FilePath & path)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