OLD | NEW |
---|---|
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2009 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 appropiate flags. | 9 // 2) run the real installer (setup.exe) with appropiate flags. |
10 // | 10 // |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
120 return false; | 120 return false; |
121 | 121 |
122 for (int i = 0; start_str[i] != L'\0'; ++i) { | 122 for (int i = 0; start_str[i] != L'\0'; ++i) { |
123 if (!EqualASCIICharI(str[i], start_str[i])) | 123 if (!EqualASCIICharI(str[i], start_str[i])) |
124 return false; | 124 return false; |
125 } | 125 } |
126 | 126 |
127 return true; | 127 return true; |
128 } | 128 } |
129 | 129 |
130 // Helper function to read a REG_SZ value from the registry. Returns | |
131 // ERROR_SUCCESS, ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error. | |
132 // |size| is the size of |value| in wchar_t units. |value| is guaranteed to be | |
133 // null-terminated when ERROR_SUCCESS is returned. | |
134 LONG ReadValueFromRegistry(HKEY key, const wchar_t* value_name, wchar_t* value, | |
tommi (sloooow) - chröme
2010/12/16 06:32:25
nice
| |
135 size_t size) { | |
136 DWORD type; | |
137 DWORD byte_length = static_cast<DWORD>(size * sizeof(wchar_t)); | |
138 LONG result = ::RegQueryValueEx(key, value_name, NULL, &type, | |
139 reinterpret_cast<LPBYTE>(value), | |
tommi (sloooow) - chröme
2010/12/16 06:32:25
nit: styleguide prefers BYTE* over LPBYTE iirc
grt (UTC plus 2)
2010/12/16 17:36:34
Done.
| |
140 &byte_length); | |
141 if (result == ERROR_SUCCESS) { | |
142 if (type != REG_SZ) { | |
143 result = ERROR_NOT_SUPPORTED; | |
144 } else if (byte_length == 0) { | |
145 *value = L'\0'; | |
146 } else if (value[byte_length/sizeof(wchar_t) - 1] != L'\0') { | |
147 if (byte_length / sizeof(wchar_t) < size) | |
tommi (sloooow) - chröme
2010/12/16 06:32:25
nit: use () for readability
grt (UTC plus 2)
2010/12/16 17:36:34
Done.
| |
148 value[byte_length / sizeof(wchar_t)] = L'\0'; | |
149 else | |
150 result = ERROR_MORE_DATA; | |
151 } | |
152 } | |
153 return result; | |
154 } | |
155 | |
130 // Helper function to read a value from registry. Returns true if value | 156 // Helper function to read a value from registry. Returns true if value |
131 // is read successfully and stored in parameter value. Returns false otherwise. | 157 // is read successfully and stored in parameter value. Returns false otherwise. |
158 // |size| is measured in wchar_t units. | |
132 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, | 159 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, |
133 const wchar_t *value_name, wchar_t *value, | 160 const wchar_t *value_name, wchar_t *value, |
134 size_t size) { | 161 size_t size) { |
162 bool result = false; | |
135 HKEY key; | 163 HKEY key; |
136 if ((::RegOpenKeyEx(root_key, sub_key, NULL, | 164 if (::RegOpenKeyEx(root_key, sub_key, NULL, |
137 KEY_READ, &key) == ERROR_SUCCESS) && | 165 KEY_READ, &key) == ERROR_SUCCESS) { |
138 (::RegQueryValueEx(key, value_name, NULL, NULL, | 166 result = |
139 reinterpret_cast<LPBYTE>(value), | 167 (ReadValueFromRegistry(key, value_name, value, size) == ERROR_SUCCESS); |
140 reinterpret_cast<LPDWORD>(&size)) == ERROR_SUCCESS)) { | |
141 ::RegCloseKey(key); | 168 ::RegCloseKey(key); |
142 return true; | |
143 } | 169 } |
144 return false; | 170 return result; |
145 } | 171 } |
146 | 172 |
147 // This function sets the flag in registry to indicate that Google Update | 173 // Opens the Google Update ClientState key for a product. |
148 // should try full installer next time. If the current installer works, this | 174 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, |
149 // flag is cleared by setup.exe at the end of install. The flag will by default | 175 HKEY* key) { |
150 // be written to HKCU, but if --system-level is included in the command line, | 176 wchar_t client_state_key[128]; |
151 // it will be written to HKLM instead. | 177 |
152 void SetFullInstallerFlag() { | 178 return SafeStrCopy(client_state_key, _countof(client_state_key), |
153 HKEY key; | 179 kApRegistryKeyBase) && |
154 wchar_t ap_registry_key[128]; | 180 SafeStrCat(client_state_key, _countof(client_state_key), app_guid) && |
181 (::RegOpenKeyEx(root_key, client_state_key, NULL, access, key) == | |
182 ERROR_SUCCESS); | |
183 } | |
184 | |
185 // TODO(grt): Write a unit test for this that uses registry virtualization. | |
186 void SetFullInstallerFlagHelper(int args_num, const wchar_t* const* args) { | |
187 bool multi_install = false; | |
188 HKEY key = NULL; | |
155 const wchar_t* app_guid = google_update::kAppGuid; | 189 const wchar_t* app_guid = google_update::kAppGuid; |
156 HKEY root_key = HKEY_CURRENT_USER; | 190 HKEY root_key = HKEY_CURRENT_USER; |
191 wchar_t value[128]; | |
192 LONG ret; | |
157 | 193 |
158 int args_num; | |
159 wchar_t* cmd_line = ::GetCommandLine(); | |
160 wchar_t** args = ::CommandLineToArgvW(cmd_line, &args_num); | |
161 for (int i = 1; i < args_num; ++i) { | 194 for (int i = 1; i < args_num; ++i) { |
162 if (0 == ::lstrcmpi(args[i], L"--chrome-sxs")) | 195 if (0 == ::lstrcmpi(args[i], L"--chrome-sxs")) |
163 app_guid = google_update::kSxSAppGuid; | 196 app_guid = google_update::kSxSAppGuid; |
164 else if (0 == ::lstrcmpi(args[i], L"--chrome-frame")) | 197 else if (0 == ::lstrcmpi(args[i], L"--chrome-frame")) |
165 app_guid = google_update::kChromeFrameAppGuid; | 198 app_guid = google_update::kChromeFrameAppGuid; |
199 else if (0 == ::lstrcmpi(args[i], L"--multi-install")) | |
200 multi_install = true; | |
166 else if (0 == ::lstrcmpi(args[i], L"--system-level")) | 201 else if (0 == ::lstrcmpi(args[i], L"--system-level")) |
167 root_key = HKEY_LOCAL_MACHINE; | 202 root_key = HKEY_LOCAL_MACHINE; |
168 } | 203 } |
169 | 204 |
170 if (!SafeStrCopy(ap_registry_key, _countof(ap_registry_key), | 205 // When multi_install is true, we are potentially: |
171 kApRegistryKeyBase) || | 206 // 1. Performing a multi-install of some product(s) on a clean machine. |
172 !SafeStrCat(ap_registry_key, _countof(ap_registry_key), | 207 // Neither the product(s) nor the multi-installer will have a ClientState |
173 app_guid)) { | 208 // key in the registry, so there is nothing to be done. |
174 return; | 209 // 2. Upgrading an existing multi-install. The multi-installer will have a |
210 // ClientState key in the registry. Only it need be modified. | |
211 // 3. Migrating a single-install into a multi-install. The product will have | |
212 // a ClientState key in the registry. Only it need be modified. | |
213 // To handle all cases, we inspect the product's ClientState to see if it | |
214 // exists and its "ap" value does not contain "-multi". This is case 3, so we | |
215 // modify the product's ClientState. Otherwise, we check the | |
216 // multi-installer's ClientState and modify it if it exists. | |
217 if (multi_install) { | |
218 if (OpenClientStateKey(root_key, app_guid, KEY_READ | KEY_SET_VALUE, | |
219 &key)) { | |
220 // The app is installed. See if it's a single-install. | |
221 ret = ReadValueFromRegistry(key, kApRegistryValueName, value, | |
222 _countof(value)); | |
223 if (ret != ERROR_FILE_NOT_FOUND && | |
224 (ret != ERROR_SUCCESS || StrStr(value, kMultiInstallTag) != NULL)) { | |
225 // Error or case 2: add "-full" to the multi-installer's value. | |
226 ::RegCloseKey(key); | |
tommi (sloooow) - chröme
2010/12/16 06:32:25
it's almost worth it to write a poor man's RegKey
grt (UTC plus 2)
2010/12/16 17:36:34
I was thinking along the same lines in the shower
| |
227 key = NULL; | |
228 app_guid = google_update::kMultiInstallAppGuid; | |
229 } // else case 3: add "-full" to this value. | |
230 } else { | |
231 // case 1 or 2: add "-full" to the multi-installer's value. | |
232 key = NULL; | |
233 app_guid = google_update::kMultiInstallAppGuid; | |
234 } | |
175 } | 235 } |
176 if (::RegOpenKeyEx(root_key, ap_registry_key, NULL, | |
177 KEY_READ | KEY_SET_VALUE, &key) != ERROR_SUCCESS) | |
178 return; | |
179 | 236 |
180 wchar_t value[128]; | 237 if (key == NULL) { |
181 size_t size = _countof(value); | 238 if (!OpenClientStateKey(root_key, app_guid, KEY_READ | KEY_SET_VALUE, &key)) |
182 size_t buf_size = size; | 239 return; |
183 LONG ret = ::RegQueryValueEx(key, kApRegistryValueName, NULL, NULL, | 240 |
184 reinterpret_cast<LPBYTE>(value), | 241 ret = ReadValueFromRegistry(key, kApRegistryValueName, value, |
185 reinterpret_cast<LPDWORD>(&size)); | 242 _countof(value)); |
243 } | |
186 | 244 |
187 // The conditions below are handling two cases: | 245 // The conditions below are handling two cases: |
188 // 1. When ap key is present, we want to make sure it doesn't already end | 246 // 1. When ap key is present, we want to make sure it doesn't already end |
189 // in -full and then append -full to it. | 247 // in -full and then append -full to it. |
190 // 2. When ap key is missing, we are going to create it with value -full. | 248 // 2. When ap key is missing, we are going to create it with value -full. |
191 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { | 249 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { |
192 if (ret == ERROR_FILE_NOT_FOUND) | 250 if (ret == ERROR_FILE_NOT_FOUND) |
193 value[0] = L'\0'; | 251 value[0] = L'\0'; |
194 | 252 |
195 if (!StrEndsWith(value, kFullInstallerSuffix) && | 253 if (!StrEndsWith(value, kFullInstallerSuffix) && |
196 (SafeStrCat(value, buf_size, kFullInstallerSuffix))) | 254 (SafeStrCat(value, _countof(value), kFullInstallerSuffix))) |
197 ::RegSetValueEx(key, kApRegistryValueName, 0, REG_SZ, | 255 ::RegSetValueEx(key, kApRegistryValueName, 0, REG_SZ, |
198 reinterpret_cast<LPBYTE>(value), | 256 reinterpret_cast<LPBYTE>(value), |
199 lstrlen(value) * sizeof(wchar_t)); | 257 (lstrlen(value) + 1) * sizeof(wchar_t)); |
200 } | 258 } |
201 | 259 |
202 ::RegCloseKey(key); | 260 ::RegCloseKey(key); |
203 } | 261 } |
204 | 262 |
263 // This function sets the flag in registry to indicate that Google Update | |
264 // should try full installer next time. If the current installer works, this | |
265 // flag is cleared by setup.exe at the end of install. The flag will by default | |
266 // be written to HKCU, but if --system-level is included in the command line, | |
267 // it will be written to HKLM instead. | |
268 void SetFullInstallerFlag() { | |
269 int args_num; | |
270 wchar_t* cmd_line = ::GetCommandLine(); | |
271 wchar_t** args = ::CommandLineToArgvW(cmd_line, &args_num); | |
272 | |
273 SetFullInstallerFlagHelper(args_num, args); | |
274 | |
275 ::LocalFree(args); | |
276 } | |
277 | |
205 // Gets the setup.exe path from Registry by looking the value of Uninstall | 278 // Gets the setup.exe path from Registry by looking the value of Uninstall |
206 // string, strips the arguments for uninstall and returns only the full path | 279 // string, strips the arguments for uninstall and returns only the full path |
207 // to setup.exe. | 280 // to setup.exe. |size| is measured in wchar_t units. |
208 bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) { | 281 bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) { |
209 if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey, | 282 if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey, |
210 kUninstallRegistryValueName, path, size)) { | 283 kUninstallRegistryValueName, path, size)) { |
211 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kUninstallRegistryKey, | 284 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kUninstallRegistryKey, |
212 kUninstallRegistryValueName, path, size)) { | 285 kUninstallRegistryValueName, path, size)) { |
213 return false; | 286 return false; |
214 } | 287 } |
215 } | 288 } |
216 wchar_t *tmp = StrStr(path, L" --"); | 289 wchar_t *tmp = StrStr(path, L" --"); |
217 if (tmp) { | 290 if (tmp) { |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
541 wchar_t archive_path[MAX_PATH] = {0}; | 614 wchar_t archive_path[MAX_PATH] = {0}; |
542 wchar_t setup_path[MAX_PATH] = {0}; | 615 wchar_t setup_path[MAX_PATH] = {0}; |
543 if (!UnpackBinaryResources(module, base_path, archive_path, MAX_PATH, | 616 if (!UnpackBinaryResources(module, base_path, archive_path, MAX_PATH, |
544 setup_path, MAX_PATH)) | 617 setup_path, MAX_PATH)) |
545 return 102; | 618 return 102; |
546 | 619 |
547 int exit_code = 103; | 620 int exit_code = 103; |
548 if (!RunSetup(archive_path, setup_path, &exit_code)) | 621 if (!RunSetup(archive_path, setup_path, &exit_code)) |
549 return exit_code; | 622 return exit_code; |
550 | 623 |
551 wchar_t value[4]; | 624 wchar_t value[2]; |
552 if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, | 625 if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, |
553 kCleanupRegistryValueName, value, 4)) || | 626 kCleanupRegistryValueName, value, |
627 _countof(value))) || | |
554 (value[0] != L'0')) | 628 (value[0] != L'0')) |
555 DeleteExtractedFiles(base_path, archive_path, setup_path); | 629 DeleteExtractedFiles(base_path, archive_path, setup_path); |
556 | 630 |
557 return exit_code; | 631 return exit_code; |
558 } | 632 } |
559 } // namespace mini_installer | 633 } // namespace mini_installer |
560 | 634 |
561 | 635 |
562 int MainEntryPoint() { | 636 int MainEntryPoint() { |
563 int result = mini_installer::WMain(::GetModuleHandle(NULL)); | 637 int result = mini_installer::WMain(::GetModuleHandle(NULL)); |
564 ::ExitProcess(result); | 638 ::ExitProcess(result); |
565 } | 639 } |
OLD | NEW |