Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: chrome/installer/mini_installer/mini_installer.cc

Issue 5875003: Add support for --multi-install to mini_installer, fixed a memory leak, and r... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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 // Function to check if a string (specified by str) contains another string
131 // (specified by sub_str).
132 bool StrContains(const wchar_t* str, const wchar_t *sub_str) {
tommi (sloooow) - chröme 2010/12/15 20:15:43 Use StrStr[I] instead? wchar_t * -> wchar_t*
robertshield 2010/12/15 20:25:45 delete me (me as in this function, not me as in Ro
grt (UTC plus 2) 2010/12/16 05:59:13 Replaced with a call to StrStr, thanks.
grt (UTC plus 2) 2010/12/16 05:59:13 Done.
133 if (str == NULL || sub_str == NULL)
134 return false;
135
136 for (const wchar_t* scan_str = str; *scan_str != L'\0'; ++scan_str) {
137 if (StrStartsWith(scan_str, sub_str))
138 return true;
139 }
140 return false;
141 }
142
130 // Helper function to read a value from registry. Returns true if value 143 // Helper function to read a value from registry. Returns true if value
131 // is read successfully and stored in parameter value. Returns false otherwise. 144 // is read successfully and stored in parameter value. Returns false otherwise.
132 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, 145 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key,
133 const wchar_t *value_name, wchar_t *value, 146 const wchar_t *value_name, wchar_t *value,
134 size_t size) { 147 size_t size) {
135 HKEY key; 148 HKEY key;
136 if ((::RegOpenKeyEx(root_key, sub_key, NULL, 149 if ((::RegOpenKeyEx(root_key, sub_key, NULL,
137 KEY_READ, &key) == ERROR_SUCCESS) && 150 KEY_READ, &key) == ERROR_SUCCESS) &&
138 (::RegQueryValueEx(key, value_name, NULL, NULL, 151 (::RegQueryValueEx(key, value_name, NULL, NULL,
139 reinterpret_cast<LPBYTE>(value), 152 reinterpret_cast<LPBYTE>(value),
140 reinterpret_cast<LPDWORD>(&size)) == ERROR_SUCCESS)) { 153 reinterpret_cast<LPDWORD>(&size)) == ERROR_SUCCESS)) {
141 ::RegCloseKey(key); 154 ::RegCloseKey(key);
142 return true; 155 return true;
143 } 156 }
144 return false; 157 return false;
145 } 158 }
146 159
147 // This function sets the flag in registry to indicate that Google Update 160 // Opens the Google Update ClientState key for a product.
148 // should try full installer next time. If the current installer works, this 161 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 162 HKEY* key) {
150 // be written to HKCU, but if --system-level is included in the command line, 163 wchar_t client_state_key[128];
151 // it will be written to HKLM instead. 164
152 void SetFullInstallerFlag() { 165 return SafeStrCopy(client_state_key, _countof(client_state_key),
tommi (sloooow) - chröme 2010/12/15 20:15:43 chrome code typically uses arraysize(). Can we us
grt (UTC plus 2) 2010/12/16 05:59:13 No due to dependency issues.
153 HKEY key; 166 kApRegistryKeyBase) &&
154 wchar_t ap_registry_key[128]; 167 SafeStrCat(client_state_key, _countof(client_state_key), app_guid) &&
168 ::RegOpenKeyEx(root_key, client_state_key, NULL, access, key) ==
169 ERROR_SUCCESS;
robertshield 2010/12/15 20:25:45 For readability, please include () around the last
grt (UTC plus 2) 2010/12/16 05:59:13 Done.
170 }
171
172 // TODO(grt): Write a unit test for this that uses registry virtualization.
173 void SetFullInstallerFlagHelper(int args_num, const wchar_t* const* args) {
174 bool multi_install = false;
175 HKEY key = 0;
155 const wchar_t* app_guid = google_update::kAppGuid; 176 const wchar_t* app_guid = google_update::kAppGuid;
156 HKEY root_key = HKEY_CURRENT_USER; 177 HKEY root_key = HKEY_CURRENT_USER;
178 wchar_t value[128];
tommi (sloooow) - chröme 2010/12/15 20:17:28 zero initialize
grt (UTC plus 2) 2010/12/16 05:59:13 The old code didn't, so I'm inclined not to add it
179 DWORD size = UINT_MAX;
180 LONG ret;
157 181
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) { 182 for (int i = 1; i < args_num; ++i) {
162 if (0 == ::lstrcmpi(args[i], L"--chrome-sxs")) 183 if (0 == ::lstrcmpi(args[i], L"--chrome-sxs"))
163 app_guid = google_update::kSxSAppGuid; 184 app_guid = google_update::kSxSAppGuid;
164 else if (0 == ::lstrcmpi(args[i], L"--chrome-frame")) 185 else if (0 == ::lstrcmpi(args[i], L"--chrome-frame"))
165 app_guid = google_update::kChromeFrameAppGuid; 186 app_guid = google_update::kChromeFrameAppGuid;
187 else if (0 == ::lstrcmpi(args[i], L"--multi-install"))
188 multi_install = true;
166 else if (0 == ::lstrcmpi(args[i], L"--system-level")) 189 else if (0 == ::lstrcmpi(args[i], L"--system-level"))
167 root_key = HKEY_LOCAL_MACHINE; 190 root_key = HKEY_LOCAL_MACHINE;
168 } 191 }
169 192
170 if (!SafeStrCopy(ap_registry_key, _countof(ap_registry_key), 193 // When multi_install is true, we are potentially:
171 kApRegistryKeyBase) || 194 // 1. Performing a multi-install of some product(s) on a clean machine.
172 !SafeStrCat(ap_registry_key, _countof(ap_registry_key), 195 // Neither the product(s) nor the multi-installer will have a ClientState
173 app_guid)) { 196 // key in the registry, so there is nothing to be done.
174 return; 197 // 2. Upgrading an existing multi-install. The multi-installer will have a
198 // ClientState key in the registry. Only it need be modified.
199 // 3. Migrating a single-install into a multi-install. The product will have
200 // a ClientState key in the registry. Only it need be modified.
tommi (sloooow) - chröme 2010/12/15 20:15:43 is there a 4? : Two products are installed, one i
grt (UTC plus 2) 2010/12/16 05:59:13 In this case, the single will only be migrated whe
201 // To handle all cases, we inspect the product's ClientState to see if it
202 // exists and its "ap" value does not contain "-multi". This is case 3, so we
203 // modify the product's ClientState. Otherwise, we check the
204 // multi-installer's ClientState and modify it if it exists.
205 if (multi_install) {
206 if (OpenClientStateKey(root_key, app_guid, KEY_READ | KEY_SET_VALUE,
207 &key)) {
208 // The app is installed. See if it's a single-install.
209 size = _countof(value);
210 ret = ::RegQueryValueEx(key, kApRegistryValueName, NULL, NULL,
211 reinterpret_cast<LPBYTE>(value), &size);
212 if (ret == ERROR_FILE_NOT_FOUND) {
213 // case 3: add "-full" to this value.
214 *value = L'\0';
215 } else if (ret != ERROR_SUCCESS || StrContains(value, kMultiInstallTag)) {
216 // Error or case 2: add "-full" to the multi-installer's value.
217 ::RegCloseKey(key);
218 key = 0;
219 app_guid = google_update::kMultiInstallAppGuid;
220 } // else case 3: add "-full" to this value.
221 } else {
222 // case 1 or 2: add "-full" to the multi-installer's value.
223 key = 0;
224 app_guid = google_update::kMultiInstallAppGuid;
225 }
175 } 226 }
176 if (::RegOpenKeyEx(root_key, ap_registry_key, NULL,
177 KEY_READ | KEY_SET_VALUE, &key) != ERROR_SUCCESS)
178 return;
179 227
180 wchar_t value[128]; 228 if (key == 0) {
tommi (sloooow) - chröme 2010/12/15 20:15:43 key == NULL
grt (UTC plus 2) 2010/12/16 05:59:13 Done.
181 size_t size = _countof(value); 229 if (!OpenClientStateKey(root_key, app_guid, KEY_READ | KEY_SET_VALUE, &key))
182 size_t buf_size = size; 230 return;
183 LONG ret = ::RegQueryValueEx(key, kApRegistryValueName, NULL, NULL, 231
184 reinterpret_cast<LPBYTE>(value), 232 size = _countof(value);
185 reinterpret_cast<LPDWORD>(&size)); 233 ret = ::RegQueryValueEx(key, kApRegistryValueName, NULL, NULL,
234 reinterpret_cast<LPBYTE>(value),
235 reinterpret_cast<LPDWORD>(&size));
236 }
186 237
187 // The conditions below are handling two cases: 238 // The conditions below are handling two cases:
188 // 1. When ap key is present, we want to make sure it doesn't already end 239 // 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. 240 // in -full and then append -full to it.
190 // 2. When ap key is missing, we are going to create it with value -full. 241 // 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)) { 242 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) {
192 if (ret == ERROR_FILE_NOT_FOUND) 243 if (ret == ERROR_FILE_NOT_FOUND)
193 value[0] = L'\0'; 244 value[0] = L'\0';
194 245
195 if (!StrEndsWith(value, kFullInstallerSuffix) && 246 if (!StrEndsWith(value, kFullInstallerSuffix) &&
196 (SafeStrCat(value, buf_size, kFullInstallerSuffix))) 247 (SafeStrCat(value, _countof(value), kFullInstallerSuffix)))
197 ::RegSetValueEx(key, kApRegistryValueName, 0, REG_SZ, 248 ::RegSetValueEx(key, kApRegistryValueName, 0, REG_SZ,
198 reinterpret_cast<LPBYTE>(value), 249 reinterpret_cast<LPBYTE>(value),
199 lstrlen(value) * sizeof(wchar_t)); 250 lstrlen(value) * sizeof(wchar_t));
200 } 251 }
201 252
202 ::RegCloseKey(key); 253 ::RegCloseKey(key);
203 } 254 }
204 255
256 // This function sets the flag in registry to indicate that Google Update
257 // should try full installer next time. If the current installer works, this
258 // flag is cleared by setup.exe at the end of install. The flag will by default
259 // be written to HKCU, but if --system-level is included in the command line,
260 // it will be written to HKLM instead.
261 void SetFullInstallerFlag() {
262 int args_num;
263 wchar_t* cmd_line = ::GetCommandLine();
264 wchar_t** args = ::CommandLineToArgvW(cmd_line, &args_num);
265
266 SetFullInstallerFlagHelper(args_num, args);
267
268 ::LocalFree(args);
269 }
270
205 // Gets the setup.exe path from Registry by looking the value of Uninstall 271 // 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 272 // string, strips the arguments for uninstall and returns only the full path
207 // to setup.exe. 273 // to setup.exe.
208 bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) { 274 bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) {
209 if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey, 275 if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey,
210 kUninstallRegistryValueName, path, size)) { 276 kUninstallRegistryValueName, path, size)) {
211 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kUninstallRegistryKey, 277 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kUninstallRegistryKey,
212 kUninstallRegistryValueName, path, size)) { 278 kUninstallRegistryValueName, path, size)) {
213 return false; 279 return false;
214 } 280 }
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
556 622
557 return exit_code; 623 return exit_code;
558 } 624 }
559 } // namespace mini_installer 625 } // namespace mini_installer
560 626
561 627
562 int MainEntryPoint() { 628 int MainEntryPoint() {
563 int result = mini_installer::WMain(::GetModuleHandle(NULL)); 629 int result = mini_installer::WMain(::GetModuleHandle(NULL));
564 ::ExitProcess(result); 630 ::ExitProcess(result);
565 } 631 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698