OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // mini_installer.exe is the first exe that is run when chrome is being | 5 // mini_installer.exe is the first exe that is run when chrome is being |
6 // installed or upgraded. It is designed to be extremely small (~5KB with no | 6 // installed or upgraded. It is designed to be extremely small (~5KB with no |
7 // extra resources linked) and it has two main jobs: | 7 // extra resources linked) and it has two main jobs: |
8 // 1) unpack the resources (possibly decompressing some) | 8 // 1) unpack the resources (possibly decompressing some) |
9 // 2) run the real installer (setup.exe) with appropriate flags. | 9 // 2) run the real installer (setup.exe) with appropriate flags. |
10 // | 10 // |
(...skipping 14 matching lines...) Expand all Loading... |
25 #include <shellapi.h> | 25 #include <shellapi.h> |
26 #include <stdlib.h> | 26 #include <stdlib.h> |
27 | 27 |
28 #include "chrome/installer/mini_installer/appid.h" | 28 #include "chrome/installer/mini_installer/appid.h" |
29 #include "chrome/installer/mini_installer/configuration.h" | 29 #include "chrome/installer/mini_installer/configuration.h" |
30 #include "chrome/installer/mini_installer/decompress.h" | 30 #include "chrome/installer/mini_installer/decompress.h" |
31 #include "chrome/installer/mini_installer/exit_code.h" | 31 #include "chrome/installer/mini_installer/exit_code.h" |
32 #include "chrome/installer/mini_installer/mini_installer_constants.h" | 32 #include "chrome/installer/mini_installer/mini_installer_constants.h" |
33 #include "chrome/installer/mini_installer/mini_string.h" | 33 #include "chrome/installer/mini_installer/mini_string.h" |
34 #include "chrome/installer/mini_installer/pe_resource.h" | 34 #include "chrome/installer/mini_installer/pe_resource.h" |
| 35 #include "chrome/installer/mini_installer/regkey.h" |
35 | 36 |
36 namespace mini_installer { | 37 namespace mini_installer { |
37 | 38 |
38 typedef DWORD ProcessExitCode; | |
39 typedef StackString<MAX_PATH> PathString; | 39 typedef StackString<MAX_PATH> PathString; |
40 typedef StackString<MAX_PATH * 4> CommandString; | 40 typedef StackString<MAX_PATH * 4> CommandString; |
41 | 41 |
| 42 struct ProcessExitResult { |
| 43 DWORD exit_code; |
| 44 DWORD windows_error; |
| 45 |
| 46 explicit ProcessExitResult(DWORD exit) : exit_code(exit), windows_error(0) {} |
| 47 ProcessExitResult(DWORD exit, DWORD win) |
| 48 : exit_code(exit), windows_error(win) { |
| 49 } |
| 50 |
| 51 bool IsSuccess() { |
| 52 return exit_code == SUCCESS_EXIT_CODE; |
| 53 } |
| 54 }; |
| 55 |
42 // This structure passes data back and forth for the processing | 56 // This structure passes data back and forth for the processing |
43 // of resource callbacks. | 57 // of resource callbacks. |
44 struct Context { | 58 struct Context { |
45 // Input to the call back method. Specifies the dir to save resources. | 59 // Input to the call back method. Specifies the dir to save resources. |
46 const wchar_t* base_path; | 60 const wchar_t* base_path; |
47 // First output from call back method. Full path of Chrome archive. | 61 // First output from call back method. Full path of Chrome archive. |
48 PathString* chrome_resource_path; | 62 PathString* chrome_resource_path; |
49 // Second output from call back method. Full path of Setup archive/exe. | 63 // Second output from call back method. Full path of Setup archive/exe. |
50 PathString* setup_resource_path; | 64 PathString* setup_resource_path; |
51 }; | 65 }; |
52 | 66 |
53 // A helper class used to manipulate the Windows registry. Typically, members | |
54 // return Windows last-error codes a la the Win32 registry API. | |
55 class RegKey { | |
56 public: | |
57 RegKey() : key_(NULL) { } | |
58 ~RegKey() { Close(); } | |
59 | 67 |
60 // Opens the key named |sub_key| with given |access| rights. Returns | 68 // Opens the Google Update ClientState key for the current install |
61 // ERROR_SUCCESS or some other error. | 69 // configuration. This includes locating the correct key in the face of |
62 LONG Open(HKEY key, const wchar_t* sub_key, REGSAM access); | 70 // multi-install. The flag will by default be written to HKCU, but if |
| 71 // --system-level is included in the command line, it will be written to |
| 72 // HKLM instead. |
| 73 bool OpenInstallStateKey(const Configuration& configuration, RegKey* key) { |
| 74 const HKEY root_key = |
| 75 configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
| 76 const wchar_t* app_guid = configuration.chrome_app_guid(); |
| 77 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; |
| 78 LONG ret = ERROR_SUCCESS; |
63 | 79 |
64 // Returns true if a key is open. | 80 return OpenClientStateKey(root_key, app_guid, key_access, key); |
65 bool is_valid() const { return key_ != NULL; } | |
66 | |
67 // Read a REG_SZ value from the registry into the memory indicated by |value| | |
68 // (of |value_size| wchar_t units). Returns ERROR_SUCCESS, | |
69 // ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error. |value| is | |
70 // guaranteed to be null-terminated on success. | |
71 LONG ReadValue(const wchar_t* value_name, | |
72 wchar_t* value, | |
73 size_t value_size) const; | |
74 | |
75 // Write a REG_SZ value to the registry. |value| must be null-terminated. | |
76 // Returns ERROR_SUCCESS or an error code. | |
77 LONG WriteValue(const wchar_t* value_name, const wchar_t* value); | |
78 | |
79 // Closes the key if it was open. | |
80 void Close(); | |
81 | |
82 private: | |
83 RegKey(const RegKey&); | |
84 RegKey& operator=(const RegKey&); | |
85 | |
86 HKEY key_; | |
87 }; // class RegKey | |
88 | |
89 LONG RegKey::Open(HKEY key, const wchar_t* sub_key, REGSAM access) { | |
90 Close(); | |
91 return ::RegOpenKeyEx(key, sub_key, NULL, access, &key_); | |
92 } | 81 } |
93 | 82 |
94 LONG RegKey::ReadValue(const wchar_t* value_name, | 83 // Writes install results into registry where it is read by Google Update. |
95 wchar_t* value, | 84 // Don't write anything if there is already a result present, likely |
96 size_t value_size) const { | 85 // written by setup.exe. |
97 DWORD type; | 86 void WriteInstallResults(const Configuration& configuration, |
98 DWORD byte_length = static_cast<DWORD>(value_size * sizeof(wchar_t)); | 87 ProcessExitResult result) { |
99 LONG result = ::RegQueryValueEx(key_, value_name, NULL, &type, | 88 #if defined(GOOGLE_CHROME_BUILD) |
100 reinterpret_cast<BYTE*>(value), | 89 // Calls to setup.exe will write a "success" result if everything was good |
101 &byte_length); | 90 // so we don't need to write anything from here. |
102 if (result == ERROR_SUCCESS) { | 91 if (result.IsSuccess()) |
103 if (type != REG_SZ) { | 92 return; |
104 result = ERROR_NOT_SUPPORTED; | 93 |
105 } else if (byte_length == 0) { | 94 RegKey key; |
106 *value = L'\0'; | 95 DWORD value; |
107 } else if (value[byte_length/sizeof(wchar_t) - 1] != L'\0') { | 96 if (OpenInstallStateKey(configuration, &key)) { |
108 if ((byte_length / sizeof(wchar_t)) < value_size) | 97 if (key.ReadDWValue(kInstallerResultRegistryValue, &value) |
109 value[byte_length / sizeof(wchar_t)] = L'\0'; | 98 != ERROR_SUCCESS || value == 0) { |
110 else | 99 key.WriteDWValue(kInstallerResultRegistryValue, |
111 result = ERROR_MORE_DATA; | 100 result.exit_code ? 1 /* FAILED_CUSTOM_ERROR */ |
| 101 : 0 /* SUCCESS */); |
| 102 key.WriteDWValue(kInstallerErrorRegistryValue, result.exit_code); |
| 103 key.WriteDWValue(kInstallerExtraCode1RegistryValue, result.windows_error); |
112 } | 104 } |
| 105 key.Close(); |
113 } | 106 } |
114 return result; | 107 #endif |
115 } | |
116 | |
117 LONG RegKey::WriteValue(const wchar_t* value_name, const wchar_t* value) { | |
118 return ::RegSetValueEx(key_, value_name, 0, REG_SZ, | |
119 reinterpret_cast<const BYTE*>(value), | |
120 (lstrlen(value) + 1) * sizeof(wchar_t)); | |
121 } | |
122 | |
123 void RegKey::Close() { | |
124 if (key_ != NULL) { | |
125 ::RegCloseKey(key_); | |
126 key_ = NULL; | |
127 } | |
128 } | |
129 | |
130 // Helper function to read a value from registry. Returns true if value | |
131 // is read successfully and stored in parameter value. Returns false otherwise. | |
132 // |size| is measured in wchar_t units. | |
133 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, | |
134 const wchar_t *value_name, wchar_t *value, | |
135 size_t size) { | |
136 RegKey key; | |
137 | |
138 if (key.Open(root_key, sub_key, KEY_QUERY_VALUE) == ERROR_SUCCESS && | |
139 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) { | |
140 return true; | |
141 } | |
142 return false; | |
143 } | |
144 | |
145 // Opens the Google Update ClientState key for a product. This finds only | |
146 // registry entries for Chrome; it does not support the Chromium registry | |
147 // layout. | |
148 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, | |
149 RegKey* key) { | |
150 PathString client_state_key; | |
151 return client_state_key.assign(kClientStateKeyBase) && | |
152 client_state_key.append(app_guid) && | |
153 (key->Open(root_key, | |
154 client_state_key.get(), | |
155 access | KEY_WOW64_32KEY) == ERROR_SUCCESS); | |
156 } | 108 } |
157 | 109 |
158 // This function sets the flag in registry to indicate that Google Update | 110 // This function sets the flag in registry to indicate that Google Update |
159 // should try full installer next time. If the current installer works, this | 111 // should try full installer next time. If the current installer works, this |
160 // flag is cleared by setup.exe at the end of install. The flag will by default | 112 // flag is cleared by setup.exe at the end of install. |
161 // be written to HKCU, but if --system-level is included in the command line, | |
162 // it will be written to HKLM instead. | |
163 // TODO(grt): Write a unit test for this that uses registry virtualization. | |
164 void SetInstallerFlags(const Configuration& configuration) { | 113 void SetInstallerFlags(const Configuration& configuration) { |
165 RegKey key; | 114 RegKey key; |
166 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; | |
167 const HKEY root_key = | |
168 configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
169 // This is ignored if multi-install is true. | |
170 const wchar_t* app_guid = | |
171 configuration.has_chrome_frame() ? | |
172 google_update::kChromeFrameAppGuid : | |
173 configuration.chrome_app_guid(); | |
174 StackString<128> value; | 115 StackString<128> value; |
175 LONG ret = ERROR_SUCCESS; | 116 LONG ret = ERROR_SUCCESS; |
176 | 117 |
177 // When multi_install is true, we are potentially: | 118 if (!OpenInstallStateKey(configuration, &key)) |
178 // 1. Performing a multi-install of some product(s) on a clean machine. | 119 return; |
179 // Neither the product(s) nor the multi-installer will have a ClientState | |
180 // key in the registry, so there is nothing to be done. | |
181 // 2. Upgrading an existing multi-install. The multi-installer will have a | |
182 // ClientState key in the registry. Only it need be modified. | |
183 // 3. Migrating a single-install into a multi-install. The product will have | |
184 // a ClientState key in the registry. Only it need be modified. | |
185 // To handle all cases, we inspect the product's ClientState to see if it | |
186 // exists and its "ap" value does not contain "-multi". This is case 3, so we | |
187 // modify the product's ClientState. Otherwise, we check the | |
188 // multi-installer's ClientState and modify it if it exists. | |
189 if (configuration.is_multi_install()) { | |
190 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) { | |
191 // The product has a client state key. See if it's a single-install. | |
192 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity()); | |
193 if (ret != ERROR_FILE_NOT_FOUND && | |
194 (ret != ERROR_SUCCESS || | |
195 FindTagInStr(value.get(), kMultiInstallTag, NULL))) { | |
196 // Error or case 2: modify the multi-installer's value. | |
197 key.Close(); | |
198 app_guid = google_update::kMultiInstallAppGuid; | |
199 } // else case 3: modify this value. | |
200 } else { | |
201 // case 1 or 2: modify the multi-installer's value. | |
202 key.Close(); | |
203 app_guid = google_update::kMultiInstallAppGuid; | |
204 } | |
205 } | |
206 | 120 |
207 if (!key.is_valid()) { | 121 ret = key.ReadSZValue(kApRegistryValue, value.get(), value.capacity()); |
208 if (!OpenClientStateKey(root_key, app_guid, key_access, &key)) | |
209 return; | |
210 | |
211 value.clear(); | |
212 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity()); | |
213 } | |
214 | 122 |
215 // The conditions below are handling two cases: | 123 // The conditions below are handling two cases: |
216 // 1. When ap value is present, we want to add the required tag only if it is | 124 // 1. When ap value is present, we want to add the required tag only if it is |
217 // not present. | 125 // not present. |
218 // 2. When ap value is missing, we are going to create it with the required | 126 // 2. When ap value is missing, we are going to create it with the required |
219 // tag. | 127 // tag. |
220 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { | 128 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { |
221 if (ret == ERROR_FILE_NOT_FOUND) | 129 if (ret == ERROR_FILE_NOT_FOUND) |
222 value.clear(); | 130 value.clear(); |
223 | 131 |
224 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && | 132 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && |
225 value.append(kFullInstallerSuffix)) { | 133 value.append(kFullInstallerSuffix)) { |
226 key.WriteValue(kApRegistryValue, value.get()); | 134 key.WriteSZValue(kApRegistryValue, value.get()); |
227 } | 135 } |
228 } | 136 } |
229 } | 137 } |
230 | 138 |
231 // Gets the setup.exe path from Registry by looking at the value of Uninstall | 139 // Gets the setup.exe path from Registry by looking at the value of Uninstall |
232 // string. |size| is measured in wchar_t units. | 140 // string. |size| is measured in wchar_t units. |
233 ProcessExitCode GetSetupExePathForAppGuid(bool system_level, | 141 ProcessExitResult GetSetupExePathForAppGuid(bool system_level, |
234 const wchar_t* app_guid, | 142 const wchar_t* app_guid, |
235 const wchar_t* previous_version, | 143 const wchar_t* previous_version, |
236 wchar_t* path, | 144 wchar_t* path, |
237 size_t size) { | 145 size_t size) { |
238 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | 146 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
239 RegKey key; | 147 RegKey key; |
240 if (!OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key) || | 148 if (!OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key)) |
241 (key.ReadValue(kUninstallRegistryValue, path, size) != ERROR_SUCCESS)) { | 149 return ProcessExitResult(UNABLE_TO_FIND_REGISTRY_KEY); |
242 return UNABLE_TO_FIND_REGISTRY_KEY; | 150 DWORD result = key.ReadSZValue(kUninstallRegistryValue, path, size); |
243 } | 151 if (result != ERROR_SUCCESS) |
| 152 return ProcessExitResult(UNABLE_TO_FIND_REGISTRY_KEY, result); |
244 | 153 |
245 // Check that the path to the existing installer includes the expected | 154 // Check that the path to the existing installer includes the expected |
246 // version number. It's not necessary for accuracy to verify before/after | 155 // version number. It's not necessary for accuracy to verify before/after |
247 // delimiters. | 156 // delimiters. |
248 if (!SearchStringI(path, previous_version)) | 157 if (!SearchStringI(path, previous_version)) |
249 return PATCH_NOT_FOR_INSTALLED_VERSION; | 158 return ProcessExitResult(PATCH_NOT_FOR_INSTALLED_VERSION); |
250 | 159 |
251 return SUCCESS_EXIT_CODE; | 160 return ProcessExitResult(SUCCESS_EXIT_CODE); |
252 } | 161 } |
253 | 162 |
254 // Gets the path to setup.exe of the previous version. The overall path is found | 163 // Gets the path to setup.exe of the previous version. The overall path is found |
255 // in the Uninstall string in the registry. A previous version number specified | 164 // in the Uninstall string in the registry. A previous version number specified |
256 // in |configuration| is used if available. |size| is measured in wchar_t units. | 165 // in |configuration| is used if available. |size| is measured in wchar_t units. |
257 ProcessExitCode GetPreviousSetupExePath(const Configuration& configuration, | 166 ProcessExitResult GetPreviousSetupExePath(const Configuration& configuration, |
258 wchar_t* path, | 167 wchar_t* path, |
259 size_t size) { | 168 size_t size) { |
260 bool system_level = configuration.is_system_level(); | 169 bool system_level = configuration.is_system_level(); |
261 const wchar_t* previous_version = configuration.previous_version(); | 170 const wchar_t* previous_version = configuration.previous_version(); |
262 ProcessExitCode exit_code = GENERIC_ERROR; | 171 ProcessExitResult exit_code = ProcessExitResult(GENERIC_ERROR); |
263 | 172 |
264 // If this is a multi install, first try looking in the binaries for the path. | 173 // If this is a multi install, first try looking in the binaries for the path. |
265 if (configuration.is_multi_install()) { | 174 if (configuration.is_multi_install()) { |
266 exit_code = GetSetupExePathForAppGuid( | 175 exit_code = GetSetupExePathForAppGuid( |
267 system_level, google_update::kMultiInstallAppGuid, previous_version, | 176 system_level, google_update::kMultiInstallAppGuid, previous_version, |
268 path, size); | 177 path, size); |
269 } | 178 } |
270 | 179 |
271 // Failing that, look in Chrome Frame's client state key if --chrome-frame was | 180 // Failing that, look in Chrome Frame's client state key if --chrome-frame was |
272 // specified. | 181 // specified. |
273 if (exit_code != SUCCESS_EXIT_CODE && configuration.has_chrome_frame()) { | 182 if (!exit_code.IsSuccess() && configuration.has_chrome_frame()) { |
274 exit_code = GetSetupExePathForAppGuid( | 183 exit_code = GetSetupExePathForAppGuid( |
275 system_level, google_update::kChromeFrameAppGuid, previous_version, | 184 system_level, google_update::kChromeFrameAppGuid, previous_version, |
276 path, size); | 185 path, size); |
277 } | 186 } |
278 | 187 |
279 // Make a last-ditch effort to look in the Chrome client state key. | 188 // Make a last-ditch effort to look in the Chrome client state key. |
280 if (exit_code != SUCCESS_EXIT_CODE) { | 189 if (!exit_code.IsSuccess()) { |
281 exit_code = GetSetupExePathForAppGuid( | 190 exit_code = GetSetupExePathForAppGuid( |
282 system_level, configuration.chrome_app_guid(), previous_version, | 191 system_level, configuration.chrome_app_guid(), previous_version, |
283 path, size); | 192 path, size); |
284 } | 193 } |
285 | 194 |
286 return exit_code; | 195 return exit_code; |
287 } | 196 } |
288 | 197 |
289 // Calls CreateProcess with good default parameters and waits for the process to | 198 // Calls CreateProcess with good default parameters and waits for the process to |
290 // terminate returning the process exit code. |exit_code|, if non-NULL, is | 199 // terminate returning the process exit code. |exit_code|, if non-NULL, is |
291 // populated with the process exit code. | 200 // populated with the process exit code. |
292 ProcessExitCode RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) { | 201 ProcessExitResult RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) { |
293 STARTUPINFOW si = {sizeof(si)}; | 202 STARTUPINFOW si = {sizeof(si)}; |
294 PROCESS_INFORMATION pi = {0}; | 203 PROCESS_INFORMATION pi = {0}; |
295 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, | 204 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, |
296 NULL, NULL, &si, &pi)) { | 205 NULL, NULL, &si, &pi)) { |
297 return COULD_NOT_CREATE_PROCESS; | 206 return ProcessExitResult(COULD_NOT_CREATE_PROCESS, ::GetLastError()); |
298 } | 207 } |
299 | 208 |
300 ::CloseHandle(pi.hThread); | 209 ::CloseHandle(pi.hThread); |
301 | 210 |
302 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; | 211 DWORD exit_code = SUCCESS_EXIT_CODE; |
303 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); | 212 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); |
304 if (WAIT_OBJECT_0 != wr || !::GetExitCodeProcess(pi.hProcess, &exit_code)) | 213 if (WAIT_OBJECT_0 != wr || !::GetExitCodeProcess(pi.hProcess, &exit_code)) { |
305 exit_code = WAIT_FOR_PROCESS_FAILED; | 214 // Note: We've assumed that WAIT_OBJCT_0 != wr means a failure. The call |
| 215 // could return a different object but since we never spawn more than one |
| 216 // sub-process at a time that case should never happen. |
| 217 return ProcessExitResult(WAIT_FOR_PROCESS_FAILED, ::GetLastError()); |
| 218 } |
306 | 219 |
307 ::CloseHandle(pi.hProcess); | 220 ::CloseHandle(pi.hProcess); |
308 | 221 |
309 return exit_code; | 222 return ProcessExitResult(exit_code); |
310 } | 223 } |
311 | 224 |
312 // Appends any command line params passed to mini_installer to the given buffer | 225 // Appends any command line params passed to mini_installer to the given buffer |
313 // so that they can be passed on to setup.exe. | 226 // so that they can be passed on to setup.exe. |
314 // |buffer| is unchanged in case of error. | 227 // |buffer| is unchanged in case of error. |
315 void AppendCommandLineFlags(const Configuration& configuration, | 228 void AppendCommandLineFlags(const Configuration& configuration, |
316 CommandString* buffer) { | 229 CommandString* buffer) { |
317 PathString full_exe_path; | 230 PathString full_exe_path; |
318 size_t len = ::GetModuleFileName(NULL, full_exe_path.get(), | 231 size_t len = ::GetModuleFileName(NULL, full_exe_path.get(), |
319 full_exe_path.capacity()); | 232 full_exe_path.capacity()); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 // can come in one of three possible forms: | 334 // can come in one of three possible forms: |
422 // - Resource type 'B7', compressed using LZMA (*.7z) | 335 // - Resource type 'B7', compressed using LZMA (*.7z) |
423 // - Resource type 'BL', compressed using LZ (*.ex_) | 336 // - Resource type 'BL', compressed using LZ (*.ex_) |
424 // - Resource type 'BN', uncompressed (*.exe) | 337 // - Resource type 'BN', uncompressed (*.exe) |
425 // If setup.exe is present in more than one form, the precedence order is | 338 // If setup.exe is present in more than one form, the precedence order is |
426 // BN < BL < B7 | 339 // BN < BL < B7 |
427 // For more details see chrome/tools/build/win/create_installer_archive.py. | 340 // For more details see chrome/tools/build/win/create_installer_archive.py. |
428 // For component builds (where setup.ex_ is always used), all files stored as | 341 // For component builds (where setup.ex_ is always used), all files stored as |
429 // uncompressed 'BN' resources are also extracted. This is generally the set of | 342 // uncompressed 'BN' resources are also extracted. This is generally the set of |
430 // DLLs/resources needed by setup.exe to run. | 343 // DLLs/resources needed by setup.exe to run. |
431 ProcessExitCode UnpackBinaryResources(const Configuration& configuration, | 344 ProcessExitResult UnpackBinaryResources(const Configuration& configuration, |
432 HMODULE module, const wchar_t* base_path, | 345 HMODULE module, const wchar_t* base_path, |
433 PathString* archive_path, | 346 PathString* archive_path, |
434 PathString* setup_path) { | 347 PathString* setup_path) { |
435 // Generate the setup.exe path where we patch/uncompress setup resource. | 348 // Generate the setup.exe path where we patch/uncompress setup resource. |
436 PathString setup_dest_path; | 349 PathString setup_dest_path; |
437 if (!setup_dest_path.assign(base_path) || | 350 if (!setup_dest_path.assign(base_path) || |
438 !setup_dest_path.append(kSetupExe)) | 351 !setup_dest_path.append(kSetupExe)) |
439 return PATH_STRING_OVERFLOW; | 352 return ProcessExitResult(PATH_STRING_OVERFLOW); |
440 | 353 |
441 // Prepare the input to OnResourceFound method that needs a location where | 354 // Prepare the input to OnResourceFound method that needs a location where |
442 // it will write all the resources. | 355 // it will write all the resources. |
443 Context context = { | 356 Context context = { |
444 base_path, | 357 base_path, |
445 archive_path, | 358 archive_path, |
446 setup_path, | 359 setup_path, |
447 }; | 360 }; |
448 | 361 |
449 // Get the resources of type 'B7' (7zip archive). | 362 // Get the resources of type 'B7' (7zip archive). |
450 // We need a chrome archive to do the installation. So if there | 363 // We need a chrome archive to do the installation. So if there |
451 // is a problem in fetching B7 resource, just return an error. | 364 // is a problem in fetching B7 resource, just return an error. |
452 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, | 365 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, |
453 reinterpret_cast<LONG_PTR>(&context)) || | 366 reinterpret_cast<LONG_PTR>(&context))) { |
454 archive_path->length() == 0) | 367 return ProcessExitResult(UNABLE_TO_EXTRACT_CHROME_ARCHIVE, |
455 return UNABLE_TO_EXTRACT_CHROME_ARCHIVE; | 368 ::GetLastError()); |
| 369 } |
| 370 if (archive_path->length() == 0) { |
| 371 return ProcessExitResult(UNABLE_TO_EXTRACT_CHROME_ARCHIVE); |
| 372 } |
456 | 373 |
457 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; | 374 ProcessExitResult exit_code = ProcessExitResult(SUCCESS_EXIT_CODE); |
458 | 375 |
459 // If we found setup 'B7' resource (used for differential updates), handle | 376 // If we found setup 'B7' resource (used for differential updates), handle |
460 // it. Note that this is only for Chrome; Chromium installs are always | 377 // it. Note that this is only for Chrome; Chromium installs are always |
461 // "full" installs. | 378 // "full" installs. |
462 if (setup_path->length() > 0) { | 379 if (setup_path->length() > 0) { |
463 CommandString cmd_line; | 380 CommandString cmd_line; |
464 PathString exe_path; | 381 PathString exe_path; |
465 // Get the path to setup.exe first. | 382 // Get the path to setup.exe first. |
466 exit_code = GetPreviousSetupExePath(configuration, exe_path.get(), | 383 exit_code = GetPreviousSetupExePath(configuration, exe_path.get(), |
467 exe_path.capacity()); | 384 exe_path.capacity()); |
468 if (exit_code == SUCCESS_EXIT_CODE) { | 385 if (exit_code.IsSuccess()) { |
469 if (!cmd_line.append(exe_path.get()) || | 386 if (!cmd_line.append(exe_path.get()) || |
470 !cmd_line.append(L" --") || | 387 !cmd_line.append(L" --") || |
471 !cmd_line.append(kCmdUpdateSetupExe) || | 388 !cmd_line.append(kCmdUpdateSetupExe) || |
472 !cmd_line.append(L"=\"") || | 389 !cmd_line.append(L"=\"") || |
473 !cmd_line.append(setup_path->get()) || | 390 !cmd_line.append(setup_path->get()) || |
474 !cmd_line.append(L"\" --") || | 391 !cmd_line.append(L"\" --") || |
475 !cmd_line.append(kCmdNewSetupExe) || | 392 !cmd_line.append(kCmdNewSetupExe) || |
476 !cmd_line.append(L"=\"") || | 393 !cmd_line.append(L"=\"") || |
477 !cmd_line.append(setup_dest_path.get()) || | 394 !cmd_line.append(setup_dest_path.get()) || |
478 !cmd_line.append(L"\"")) { | 395 !cmd_line.append(L"\"")) { |
479 exit_code = COMMAND_STRING_OVERFLOW; | 396 exit_code = ProcessExitResult(COMMAND_STRING_OVERFLOW); |
480 } | 397 } |
481 } | 398 } |
482 | 399 |
483 // Get any command line option specified for mini_installer and pass them | 400 // Get any command line option specified for mini_installer and pass them |
484 // on to setup.exe. This is important since switches such as | 401 // on to setup.exe. This is important since switches such as |
485 // --multi-install and --chrome-frame affect where setup.exe will write | 402 // --multi-install and --chrome-frame affect where setup.exe will write |
486 // installer results for consumption by Google Update. | 403 // installer results for consumption by Google Update. |
487 AppendCommandLineFlags(configuration, &cmd_line); | 404 AppendCommandLineFlags(configuration, &cmd_line); |
488 | 405 |
489 if (exit_code == SUCCESS_EXIT_CODE) | 406 if (exit_code.IsSuccess()) |
490 exit_code = RunProcessAndWait(exe_path.get(), cmd_line.get()); | 407 exit_code = RunProcessAndWait(exe_path.get(), cmd_line.get()); |
491 | 408 |
492 if (exit_code != SUCCESS_EXIT_CODE) | 409 if (!exit_code.IsSuccess()) |
493 DeleteFile(setup_path->get()); | 410 DeleteFile(setup_path->get()); |
494 else if (!setup_path->assign(setup_dest_path.get())) | 411 else if (!setup_path->assign(setup_dest_path.get())) |
495 exit_code = PATH_STRING_OVERFLOW; | 412 exit_code = ProcessExitResult(PATH_STRING_OVERFLOW); |
496 | 413 |
497 return exit_code; | 414 return exit_code; |
498 } | 415 } |
499 | 416 |
500 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' | 417 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' |
501 // (compressed setup). | 418 // (compressed setup). |
502 if (!::EnumResourceNames(module, kLZCResourceType, OnResourceFound, | 419 if (!::EnumResourceNames(module, kLZCResourceType, OnResourceFound, |
503 reinterpret_cast<LONG_PTR>(&context)) && | 420 reinterpret_cast<LONG_PTR>(&context)) && |
504 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) | 421 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) { |
505 return UNABLE_TO_EXTRACT_SETUP_B7; | 422 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP_B7, ::GetLastError()); |
| 423 } |
506 | 424 |
507 if (setup_path->length() > 0) { | 425 if (setup_path->length() > 0) { |
508 // Uncompress LZ compressed resource. Setup is packed with 'MSCF' | 426 // Uncompress LZ compressed resource. Setup is packed with 'MSCF' |
509 // as opposed to old DOS way of 'SZDD'. Hence we don't use LZCopy. | 427 // as opposed to old DOS way of 'SZDD'. Hence we don't use LZCopy. |
510 bool success = mini_installer::Expand(setup_path->get(), | 428 bool success = mini_installer::Expand(setup_path->get(), |
511 setup_dest_path.get()); | 429 setup_dest_path.get()); |
512 ::DeleteFile(setup_path->get()); | 430 ::DeleteFile(setup_path->get()); |
513 if (success) { | 431 if (success) { |
514 if (!setup_path->assign(setup_dest_path.get())) { | 432 if (!setup_path->assign(setup_dest_path.get())) { |
515 ::DeleteFile(setup_dest_path.get()); | 433 ::DeleteFile(setup_dest_path.get()); |
516 exit_code = PATH_STRING_OVERFLOW; | 434 exit_code = ProcessExitResult(PATH_STRING_OVERFLOW); |
517 } | 435 } |
518 } else { | 436 } else { |
519 exit_code = UNABLE_TO_EXTRACT_SETUP_EXE; | 437 exit_code = ProcessExitResult(UNABLE_TO_EXTRACT_SETUP_EXE); |
520 } | 438 } |
521 | 439 |
522 #if defined(COMPONENT_BUILD) | 440 #if defined(COMPONENT_BUILD) |
523 // Extract the (uncompressed) modules required by setup.exe. | 441 // Extract the (uncompressed) modules required by setup.exe. |
524 if (!::EnumResourceNames(module, kBinResourceType, WriteResourceToDirectory, | 442 if (!::EnumResourceNames(module, kBinResourceType, WriteResourceToDirectory, |
525 reinterpret_cast<LONG_PTR>(base_path))) | 443 reinterpret_cast<LONG_PTR>(base_path))) { |
526 return UNABLE_TO_EXTRACT_SETUP; | 444 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP, ::GetLastError()); |
| 445 } |
527 #endif | 446 #endif |
528 | 447 |
529 return exit_code; | 448 return exit_code; |
530 } | 449 } |
531 | 450 |
532 // setup.exe still not found. So finally check if it was sent as 'BN' | 451 // setup.exe still not found. So finally check if it was sent as 'BN' |
533 // (uncompressed setup). | 452 // (uncompressed setup). |
534 // TODO(tommi): We don't need BN anymore so let's remove it (and remove | 453 // TODO(tommi): We don't need BN anymore so let's remove it (and remove |
535 // it from create_installer_archive.py). | 454 // it from create_installer_archive.py). |
536 if (!::EnumResourceNames(module, kBinResourceType, OnResourceFound, | 455 if (!::EnumResourceNames(module, kBinResourceType, OnResourceFound, |
537 reinterpret_cast<LONG_PTR>(&context)) && | 456 reinterpret_cast<LONG_PTR>(&context)) && |
538 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) | 457 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) { |
539 return UNABLE_TO_EXTRACT_SETUP_BN; | 458 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP_BN, ::GetLastError()); |
| 459 } |
540 | 460 |
541 if (setup_path->length() > 0) { | 461 if (setup_path->length() > 0) { |
542 if (setup_path->comparei(setup_dest_path.get()) != 0) { | 462 if (setup_path->comparei(setup_dest_path.get()) != 0) { |
543 if (!::MoveFileEx(setup_path->get(), setup_dest_path.get(), | 463 if (!::MoveFileEx(setup_path->get(), setup_dest_path.get(), |
544 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) { | 464 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) { |
545 ::DeleteFile(setup_path->get()); | 465 ::DeleteFile(setup_path->get()); |
546 setup_path->clear(); | 466 setup_path->clear(); |
547 } else if (!setup_path->assign(setup_dest_path.get())) { | 467 } else if (!setup_path->assign(setup_dest_path.get())) { |
548 ::DeleteFile(setup_dest_path.get()); | 468 ::DeleteFile(setup_dest_path.get()); |
549 } | 469 } |
550 } | 470 } |
551 } | 471 } |
552 | 472 |
553 if (setup_path->length() == 0) | 473 if (setup_path->length() == 0) |
554 exit_code = UNABLE_TO_EXTRACT_SETUP; | 474 exit_code = ProcessExitResult(UNABLE_TO_EXTRACT_SETUP); |
555 | 475 |
556 return exit_code; | 476 return exit_code; |
557 } | 477 } |
558 | 478 |
559 // Executes setup.exe, waits for it to finish and returns the exit code. | 479 // Executes setup.exe, waits for it to finish and returns the exit code. |
560 ProcessExitCode RunSetup(const Configuration& configuration, | 480 ProcessExitResult RunSetup(const Configuration& configuration, |
561 const wchar_t* archive_path, | 481 const wchar_t* archive_path, |
562 const wchar_t* setup_path) { | 482 const wchar_t* setup_path) { |
563 // There could be three full paths in the command line for setup.exe (path | 483 // There could be three full paths in the command line for setup.exe (path |
564 // to exe itself, path to archive and path to log file), so we declare | 484 // to exe itself, path to archive and path to log file), so we declare |
565 // total size as three + one additional to hold command line options. | 485 // total size as three + one additional to hold command line options. |
566 CommandString cmd_line; | 486 CommandString cmd_line; |
567 | 487 |
568 // Get the path to setup.exe first. | 488 // Get the path to setup.exe first. |
569 if (::lstrlen(setup_path) > 0) { | 489 if (::lstrlen(setup_path) > 0) { |
570 if (!cmd_line.assign(L"\"") || | 490 if (!cmd_line.assign(L"\"") || |
571 !cmd_line.append(setup_path) || | 491 !cmd_line.append(setup_path) || |
572 !cmd_line.append(L"\"")) | 492 !cmd_line.append(L"\"")) |
573 return COMMAND_STRING_OVERFLOW; | 493 return ProcessExitResult(COMMAND_STRING_OVERFLOW); |
574 } else { | 494 } else { |
575 ProcessExitCode exit_code = GetPreviousSetupExePath( | 495 ProcessExitResult exit_code = GetPreviousSetupExePath( |
576 configuration, cmd_line.get(), cmd_line.capacity()); | 496 configuration, cmd_line.get(), cmd_line.capacity()); |
577 if (exit_code != SUCCESS_EXIT_CODE) | 497 if (!exit_code.IsSuccess()) |
578 return exit_code; | 498 return exit_code; |
579 } | 499 } |
580 | 500 |
581 // Append the command line param for chrome archive file. | 501 // Append the command line param for chrome archive file. |
582 if (!cmd_line.append(L" --") || | 502 if (!cmd_line.append(L" --") || |
583 #if defined(COMPONENT_BUILD) | 503 #if defined(COMPONENT_BUILD) |
584 // For faster developer turnaround, the component build generates | 504 // For faster developer turnaround, the component build generates |
585 // uncompressed archives. | 505 // uncompressed archives. |
586 !cmd_line.append(kCmdUncompressedArchive) || | 506 !cmd_line.append(kCmdUncompressedArchive) || |
587 #else | 507 #else |
588 !cmd_line.append(kCmdInstallArchive) || | 508 !cmd_line.append(kCmdInstallArchive) || |
589 #endif | 509 #endif |
590 !cmd_line.append(L"=\"") || | 510 !cmd_line.append(L"=\"") || |
591 !cmd_line.append(archive_path) || | 511 !cmd_line.append(archive_path) || |
592 !cmd_line.append(L"\"")) | 512 !cmd_line.append(L"\"")) |
593 return COMMAND_STRING_OVERFLOW; | 513 return ProcessExitResult(COMMAND_STRING_OVERFLOW); |
594 | 514 |
595 // Append the command line param for chrome previous version. | 515 // Append the command line param for chrome previous version. |
596 if (configuration.previous_version() && | 516 if (configuration.previous_version() && |
597 (!cmd_line.append(L" --") || | 517 (!cmd_line.append(L" --") || |
598 !cmd_line.append(kCmdPreviousVersion) || | 518 !cmd_line.append(kCmdPreviousVersion) || |
599 !cmd_line.append(L"=\"") || | 519 !cmd_line.append(L"=\"") || |
600 !cmd_line.append(configuration.previous_version()) || | 520 !cmd_line.append(configuration.previous_version()) || |
601 !cmd_line.append(L"\""))) { | 521 !cmd_line.append(L"\""))) { |
602 return COMMAND_STRING_OVERFLOW; | 522 return ProcessExitResult(COMMAND_STRING_OVERFLOW); |
603 } | 523 } |
604 | 524 |
605 // Get any command line option specified for mini_installer and pass them | 525 // Get any command line option specified for mini_installer and pass them |
606 // on to setup.exe | 526 // on to setup.exe |
607 AppendCommandLineFlags(configuration, &cmd_line); | 527 AppendCommandLineFlags(configuration, &cmd_line); |
608 | 528 |
609 return RunProcessAndWait(NULL, cmd_line.get()); | 529 return RunProcessAndWait(NULL, cmd_line.get()); |
610 } | 530 } |
611 | 531 |
612 // Deletes given files and working dir. | 532 // Deletes given files and working dir. |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
798 for (int i = 0; i < _countof(kDirectoryPrefixes); ++i) { | 718 for (int i = 0; i < _countof(kDirectoryPrefixes); ++i) { |
799 DeleteDirectoriesWithPrefix(temp.get(), kDirectoryPrefixes[i]); | 719 DeleteDirectoriesWithPrefix(temp.get(), kDirectoryPrefixes[i]); |
800 } | 720 } |
801 } | 721 } |
802 | 722 |
803 // Checks the command line for specific mini installer flags. | 723 // Checks the command line for specific mini installer flags. |
804 // If the function returns true, the command line has been processed and all | 724 // If the function returns true, the command line has been processed and all |
805 // required actions taken. The installer must exit and return the returned | 725 // required actions taken. The installer must exit and return the returned |
806 // |exit_code|. | 726 // |exit_code|. |
807 bool ProcessNonInstallOperations(const Configuration& configuration, | 727 bool ProcessNonInstallOperations(const Configuration& configuration, |
808 ProcessExitCode* exit_code) { | 728 ProcessExitResult* exit_code) { |
809 switch (configuration.operation()) { | 729 switch (configuration.operation()) { |
810 case Configuration::CLEANUP: | 730 case Configuration::CLEANUP: |
811 // Cleanup has already taken place in DeleteOldChromeTempDirectories at | 731 // Cleanup has already taken place in DeleteOldChromeTempDirectories at |
812 // this point, so just tell our caller to exit early. | 732 // this point, so just tell our caller to exit early. |
813 *exit_code = SUCCESS_EXIT_CODE; | 733 *exit_code = ProcessExitResult(SUCCESS_EXIT_CODE); |
814 return true; | 734 return true; |
815 | 735 |
816 default: | 736 default: |
817 return false; | 737 return false; |
818 } | 738 } |
819 } | 739 } |
820 | 740 |
821 // Returns true if we should delete the temp files we create (default). | 741 // Returns true if we should delete the temp files we create (default). |
822 // Returns false iff the user has manually created a ChromeInstallerCleanup | 742 // Returns false iff the user has manually created a ChromeInstallerCleanup |
823 // string value in the registry under HKCU\\Software\\[Google|Chromium] | 743 // string value in the registry under HKCU\\Software\\[Google|Chromium] |
824 // and set its value to "0". That explicitly forbids the mini installer from | 744 // and set its value to "0". That explicitly forbids the mini installer from |
825 // deleting these files. | 745 // deleting these files. |
826 // Support for this has been publicly mentioned in troubleshooting tips so | 746 // Support for this has been publicly mentioned in troubleshooting tips so |
827 // we continue to support it. | 747 // we continue to support it. |
828 bool ShouldDeleteExtractedFiles() { | 748 bool ShouldDeleteExtractedFiles() { |
829 wchar_t value[2] = {0}; | 749 wchar_t value[2] = {0}; |
830 if (ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, | 750 if (RegKey::ReadSZValue(HKEY_CURRENT_USER, kCleanupRegistryKey, |
831 kCleanupRegistryValue, value, _countof(value)) && | 751 kCleanupRegistryValue, value, _countof(value)) && |
832 value[0] == L'0') { | 752 value[0] == L'0') { |
833 return false; | 753 return false; |
834 } | 754 } |
835 | 755 |
836 return true; | 756 return true; |
837 } | 757 } |
838 | 758 |
839 // Main function. First gets a working dir, unpacks the resources and finally | 759 // Main function. First gets a working dir, unpacks the resources and finally |
840 // executes setup.exe to do the install/upgrade. | 760 // executes setup.exe to do the install/upgrade. |
841 ProcessExitCode WMain(HMODULE module) { | 761 ProcessExitResult WMain(HMODULE module) { |
842 // Always start with deleting potential leftovers from previous installations. | 762 // Always start with deleting potential leftovers from previous installations. |
843 // This can make the difference between success and failure. We've seen | 763 // This can make the difference between success and failure. We've seen |
844 // many installations out in the field fail due to out of disk space problems | 764 // many installations out in the field fail due to out of disk space problems |
845 // so this could buy us some space. | 765 // so this could buy us some space. |
846 DeleteOldChromeTempDirectories(); | 766 DeleteOldChromeTempDirectories(); |
847 | 767 |
848 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; | 768 ProcessExitResult exit_code = ProcessExitResult(SUCCESS_EXIT_CODE); |
849 | 769 |
850 // Parse configuration from the command line and resources. | 770 // Parse configuration from the command line and resources. |
851 Configuration configuration; | 771 Configuration configuration; |
852 if (!configuration.Initialize(module)) | 772 if (!configuration.Initialize(module)) |
853 return GENERIC_INITIALIZATION_FAILURE; | 773 return ProcessExitResult(GENERIC_INITIALIZATION_FAILURE); |
854 | 774 |
855 // If the --cleanup switch was specified on the command line, then that means | 775 // If the --cleanup switch was specified on the command line, then that means |
856 // we should only do the cleanup and then exit. | 776 // we should only do the cleanup and then exit. |
857 if (ProcessNonInstallOperations(configuration, &exit_code)) | 777 if (ProcessNonInstallOperations(configuration, &exit_code)) |
858 return exit_code; | 778 return exit_code; |
859 | 779 |
860 // First get a path where we can extract payload | 780 // First get a path where we can extract payload |
861 PathString base_path; | 781 PathString base_path; |
862 if (!GetWorkDir(module, &base_path)) | 782 if (!GetWorkDir(module, &base_path)) |
863 return UNABLE_TO_GET_WORK_DIRECTORY; | 783 return ProcessExitResult(UNABLE_TO_GET_WORK_DIRECTORY); |
864 | 784 |
865 #if defined(GOOGLE_CHROME_BUILD) | 785 #if defined(GOOGLE_CHROME_BUILD) |
866 // Set the magic suffix in registry to try full installer next time. We ignore | 786 // Set the magic suffix in registry to try full installer next time. We ignore |
867 // any errors here and we try to set the suffix for user level unless | 787 // any errors here and we try to set the suffix for user level unless |
868 // --system-level is on the command line in which case we set it for system | 788 // --system-level is on the command line in which case we set it for system |
869 // level instead. This only applies to the Google Chrome distribution. | 789 // level instead. This only applies to the Google Chrome distribution. |
870 SetInstallerFlags(configuration); | 790 SetInstallerFlags(configuration); |
871 #endif | 791 #endif |
872 | 792 |
873 PathString archive_path; | 793 PathString archive_path; |
874 PathString setup_path; | 794 PathString setup_path; |
875 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), | 795 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), |
876 &archive_path, &setup_path); | 796 &archive_path, &setup_path); |
877 | 797 |
878 // While unpacking the binaries, we paged in a whole bunch of memory that | 798 // While unpacking the binaries, we paged in a whole bunch of memory that |
879 // we don't need anymore. Let's give it back to the pool before running | 799 // we don't need anymore. Let's give it back to the pool before running |
880 // setup. | 800 // setup. |
881 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); | 801 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); |
882 | 802 |
883 if (exit_code == SUCCESS_EXIT_CODE) | 803 if (exit_code.IsSuccess()) |
884 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); | 804 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); |
885 | 805 |
886 if (ShouldDeleteExtractedFiles()) | 806 if (ShouldDeleteExtractedFiles()) |
887 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); | 807 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); |
888 | 808 |
| 809 WriteInstallResults(configuration, exit_code); |
889 return exit_code; | 810 return exit_code; |
890 } | 811 } |
891 | 812 |
892 } // namespace mini_installer | 813 } // namespace mini_installer |
893 | 814 |
894 int MainEntryPoint() { | 815 int MainEntryPoint() { |
895 mini_installer::ProcessExitCode result = | 816 mini_installer::ProcessExitResult result = |
896 mini_installer::WMain(::GetModuleHandle(NULL)); | 817 mini_installer::WMain(::GetModuleHandle(NULL)); |
897 ::ExitProcess(result); | 818 |
| 819 ::ExitProcess(result.exit_code); |
898 } | 820 } |
899 | 821 |
900 // VC Express editions don't come with the memset CRT obj file and linking to | 822 // VC Express editions don't come with the memset CRT obj file and linking to |
901 // the obj files between versions becomes a bit problematic. Therefore, | 823 // the obj files between versions becomes a bit problematic. Therefore, |
902 // simply implement memset. | 824 // simply implement memset. |
903 // | 825 // |
904 // This also avoids having to explicitly set the __sse2_available hack when | 826 // This also avoids having to explicitly set the __sse2_available hack when |
905 // linking with both the x64 and x86 obj files which is required when not | 827 // linking with both the x64 and x86 obj files which is required when not |
906 // linking with the std C lib in certain instances (including Chromium) with | 828 // linking with the std C lib in certain instances (including Chromium) with |
907 // MSVC. __sse2_available determines whether to use SSE2 intructions with | 829 // MSVC. __sse2_available determines whether to use SSE2 intructions with |
908 // std C lib routines, and is set by MSVC's std C lib implementation normally. | 830 // std C lib routines, and is set by MSVC's std C lib implementation normally. |
909 extern "C" { | 831 extern "C" { |
910 #pragma function(memset) | 832 #pragma function(memset) |
911 void* memset(void* dest, int c, size_t count) { | 833 void* memset(void* dest, int c, size_t count) { |
912 void* start = dest; | 834 void* start = dest; |
913 while (count--) { | 835 while (count--) { |
914 *reinterpret_cast<char*>(dest) = static_cast<char>(c); | 836 *reinterpret_cast<char*>(dest) = static_cast<char>(c); |
915 dest = reinterpret_cast<char*>(dest) + 1; | 837 dest = reinterpret_cast<char*>(dest) + 1; |
916 } | 838 } |
917 return start; | 839 return start; |
918 } | 840 } |
919 } // extern "C" | 841 } // extern "C" |
OLD | NEW |