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

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
« no previous file with comments | « chrome/installer/mini_installer/mini_installer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 // First output from call back method. Full path of Chrome archive. 49 // First output from call back method. Full path of Chrome archive.
50 wchar_t* chrome_resource_path; 50 wchar_t* chrome_resource_path;
51 // Size of chrome_resource_path buffer 51 // Size of chrome_resource_path buffer
52 size_t chrome_resource_path_size; 52 size_t chrome_resource_path_size;
53 // Second output from call back method. Full path of Setup archive/exe. 53 // Second output from call back method. Full path of Setup archive/exe.
54 wchar_t* setup_resource_path; 54 wchar_t* setup_resource_path;
55 // Size of setup_resource_path buffer 55 // Size of setup_resource_path buffer
56 size_t setup_resource_path_size; 56 size_t setup_resource_path_size;
57 }; 57 };
58 58
59 // A helper class used to manipulate the Windows registry. Typically, members
60 // return Windows last-error codes a la the Win32 registry API.
61 class RegKey {
62 public:
63 RegKey() : key_(NULL) { }
64 ~RegKey() { Close(); }
65
66 // Opens the key named |sub_key| with given |access| rights. Returns
67 // ERROR_SUCCESS or some other error.
68 LONG Open(HKEY key, const wchar_t* sub_key, REGSAM access);
69
70 // Returns true if the is open.
71 bool IsOpen() const { return key_ != NULL; }
72
73 // Read a REG_SZ value from the registry into the memory indicated by |value|
74 // (of |value_size| wchar_t units). Returns ERROR_SUCCESS,
75 // ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error. |value| is
76 // guaranteed to be null-terminated on success.
77 LONG ReadValue(const wchar_t* value_name,
78 wchar_t* value,
79 size_t value_size) const;
tommi (sloooow) - chröme 2010/12/16 17:52:47 ah how I wish chrome's regkey would return the act
80
81 // Write a REG_SZ value to the registry. |value| must be null-terminated.
82 // Returns ERROR_SUCCESS or an error code.
83 LONG WriteValue(const wchar_t* value_name, const wchar_t* value);
84
85 // Closes the key if it was open.
86 void Close();
87
88 private:
89 RegKey(const RegKey&);
90 RegKey& operator=(const RegKey&);
91
92 HKEY key_;
93 }; // class RegKey
94
95 LONG RegKey::Open(HKEY key, const wchar_t* sub_key, REGSAM access) {
96 Close();
97 return ::RegOpenKeyEx(key, sub_key, NULL, access, &key_);
98 }
99
100 LONG RegKey::ReadValue(const wchar_t* value_name,
101 wchar_t* value,
102 size_t value_size) const {
103 DWORD type;
104 DWORD byte_length = static_cast<DWORD>(value_size * sizeof(wchar_t));
105 LONG result = ::RegQueryValueEx(key_, value_name, NULL, &type,
106 reinterpret_cast<BYTE*>(value),
107 &byte_length);
108 if (result == ERROR_SUCCESS) {
109 if (type != REG_SZ) {
110 result = ERROR_NOT_SUPPORTED;
111 } else if (byte_length == 0) {
112 *value = L'\0';
113 } else if (value[byte_length/sizeof(wchar_t) - 1] != L'\0') {
114 if ((byte_length / sizeof(wchar_t)) < value_size)
115 value[byte_length / sizeof(wchar_t)] = L'\0';
116 else
117 result = ERROR_MORE_DATA;
118 }
119 }
120 return result;
121 }
122
123 LONG RegKey::WriteValue(const wchar_t* value_name, const wchar_t* value) {
124 return ::RegSetValueEx(key_, value_name, 0, REG_SZ,
125 reinterpret_cast<const BYTE*>(value),
126 (lstrlen(value) + 1) * sizeof(wchar_t));
127 }
128
129 void RegKey::Close() {
130 if (key_ != NULL) {
131 ::RegCloseKey(key_);
132 key_ = NULL;
133 }
134 }
135
59 // Returns true if the given two ASCII characters are same (ignoring case). 136 // Returns true if the given two ASCII characters are same (ignoring case).
60 bool EqualASCIICharI(wchar_t a, wchar_t b) { 137 bool EqualASCIICharI(wchar_t a, wchar_t b) {
61 if (a >= L'A' && a <= L'Z') 138 if (a >= L'A' && a <= L'Z')
62 a = a + (L'a' - L'A'); 139 a = a + (L'a' - L'A');
63 if (b >= L'A' && b <= L'Z') 140 if (b >= L'A' && b <= L'Z')
64 b = b + (L'a' - L'A'); 141 b = b + (L'a' - L'A');
65 return (a == b); 142 return (a == b);
66 } 143 }
67 144
68 // Takes the path to file and returns a pointer to the filename component. For 145 // Takes the path to file and returns a pointer to the filename component. For
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 for (int i = 0; start_str[i] != L'\0'; ++i) { 199 for (int i = 0; start_str[i] != L'\0'; ++i) {
123 if (!EqualASCIICharI(str[i], start_str[i])) 200 if (!EqualASCIICharI(str[i], start_str[i]))
124 return false; 201 return false;
125 } 202 }
126 203
127 return true; 204 return true;
128 } 205 }
129 206
130 // Helper function to read a value from registry. Returns true if value 207 // Helper function to read a value from registry. Returns true if value
131 // is read successfully and stored in parameter value. Returns false otherwise. 208 // is read successfully and stored in parameter value. Returns false otherwise.
209 // |size| is measured in wchar_t units.
132 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, 210 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key,
133 const wchar_t *value_name, wchar_t *value, 211 const wchar_t *value_name, wchar_t *value,
134 size_t size) { 212 size_t size) {
135 HKEY key; 213 RegKey key;
136 if ((::RegOpenKeyEx(root_key, sub_key, NULL, 214
137 KEY_READ, &key) == ERROR_SUCCESS) && 215 if (key.Open(root_key, sub_key, KEY_QUERY_VALUE) == ERROR_SUCCESS &&
138 (::RegQueryValueEx(key, value_name, NULL, NULL, 216 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) {
139 reinterpret_cast<LPBYTE>(value),
140 reinterpret_cast<LPDWORD>(&size)) == ERROR_SUCCESS)) {
141 ::RegCloseKey(key);
142 return true; 217 return true;
143 } 218 }
144 return false; 219 return false;
145 } 220 }
146 221
147 // This function sets the flag in registry to indicate that Google Update 222 // Opens the Google Update ClientState key for a product.
148 // should try full installer next time. If the current installer works, this 223 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 224 RegKey* key) {
150 // be written to HKCU, but if --system-level is included in the command line, 225 wchar_t client_state_key[128];
151 // it will be written to HKLM instead. 226
152 void SetFullInstallerFlag() { 227 return SafeStrCopy(client_state_key, _countof(client_state_key),
153 HKEY key; 228 kApRegistryKeyBase) &&
154 wchar_t ap_registry_key[128]; 229 SafeStrCat(client_state_key, _countof(client_state_key), app_guid) &&
230 (key->Open(root_key, client_state_key, access) == ERROR_SUCCESS);
231 }
232
233 // TODO(grt): Write a unit test for this that uses registry virtualization.
234 void SetFullInstallerFlagHelper(int args_num, const wchar_t* const* args) {
235 bool multi_install = false;
236 RegKey key;
237 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE;
155 const wchar_t* app_guid = google_update::kAppGuid; 238 const wchar_t* app_guid = google_update::kAppGuid;
156 HKEY root_key = HKEY_CURRENT_USER; 239 HKEY root_key = HKEY_CURRENT_USER;
240 wchar_t value[128];
241 LONG ret;
157 242
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) { 243 for (int i = 1; i < args_num; ++i) {
162 if (0 == ::lstrcmpi(args[i], L"--chrome-sxs")) 244 if (0 == ::lstrcmpi(args[i], L"--chrome-sxs"))
163 app_guid = google_update::kSxSAppGuid; 245 app_guid = google_update::kSxSAppGuid;
164 else if (0 == ::lstrcmpi(args[i], L"--chrome-frame")) 246 else if (0 == ::lstrcmpi(args[i], L"--chrome-frame"))
165 app_guid = google_update::kChromeFrameAppGuid; 247 app_guid = google_update::kChromeFrameAppGuid;
248 else if (0 == ::lstrcmpi(args[i], L"--multi-install"))
249 multi_install = true;
166 else if (0 == ::lstrcmpi(args[i], L"--system-level")) 250 else if (0 == ::lstrcmpi(args[i], L"--system-level"))
167 root_key = HKEY_LOCAL_MACHINE; 251 root_key = HKEY_LOCAL_MACHINE;
168 } 252 }
169 253
170 if (!SafeStrCopy(ap_registry_key, _countof(ap_registry_key), 254 // When multi_install is true, we are potentially:
171 kApRegistryKeyBase) || 255 // 1. Performing a multi-install of some product(s) on a clean machine.
172 !SafeStrCat(ap_registry_key, _countof(ap_registry_key), 256 // Neither the product(s) nor the multi-installer will have a ClientState
173 app_guid)) { 257 // key in the registry, so there is nothing to be done.
174 return; 258 // 2. Upgrading an existing multi-install. The multi-installer will have a
259 // ClientState key in the registry. Only it need be modified.
260 // 3. Migrating a single-install into a multi-install. The product will have
261 // a ClientState key in the registry. Only it need be modified.
262 // To handle all cases, we inspect the product's ClientState to see if it
263 // exists and its "ap" value does not contain "-multi". This is case 3, so we
264 // modify the product's ClientState. Otherwise, we check the
265 // multi-installer's ClientState and modify it if it exists.
266 if (multi_install) {
267 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) {
268 // The app is installed. See if it's a single-install.
269 ret = key.ReadValue(kApRegistryValueName, value, _countof(value));
270 if (ret != ERROR_FILE_NOT_FOUND &&
271 (ret != ERROR_SUCCESS || StrStr(value, kMultiInstallTag) != NULL)) {
272 // Error or case 2: add "-full" to the multi-installer's value.
273 key.Close();
274 app_guid = google_update::kMultiInstallAppGuid;
275 } // else case 3: add "-full" to this value.
276 } else {
277 // case 1 or 2: add "-full" to the multi-installer's value.
278 key.Close();
279 app_guid = google_update::kMultiInstallAppGuid;
280 }
175 } 281 }
176 if (::RegOpenKeyEx(root_key, ap_registry_key, NULL,
177 KEY_READ | KEY_SET_VALUE, &key) != ERROR_SUCCESS)
178 return;
179 282
180 wchar_t value[128]; 283 if (!key.IsOpen()) {
181 size_t size = _countof(value); 284 if (!OpenClientStateKey(root_key, app_guid, key_access, &key))
182 size_t buf_size = size; 285 return;
183 LONG ret = ::RegQueryValueEx(key, kApRegistryValueName, NULL, NULL, 286
184 reinterpret_cast<LPBYTE>(value), 287 ret = key.ReadValue(kApRegistryValueName, value, _countof(value));
185 reinterpret_cast<LPDWORD>(&size)); 288 }
186 289
187 // The conditions below are handling two cases: 290 // The conditions below are handling two cases:
188 // 1. When ap key is present, we want to make sure it doesn't already end 291 // 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. 292 // in -full and then append -full to it.
190 // 2. When ap key is missing, we are going to create it with value -full. 293 // 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)) { 294 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) {
192 if (ret == ERROR_FILE_NOT_FOUND) 295 if (ret == ERROR_FILE_NOT_FOUND)
193 value[0] = L'\0'; 296 value[0] = L'\0';
194 297
195 if (!StrEndsWith(value, kFullInstallerSuffix) && 298 if (!StrEndsWith(value, kFullInstallerSuffix) &&
196 (SafeStrCat(value, buf_size, kFullInstallerSuffix))) 299 (SafeStrCat(value, _countof(value), kFullInstallerSuffix)))
197 ::RegSetValueEx(key, kApRegistryValueName, 0, REG_SZ, 300 key.WriteValue(kApRegistryValueName, value);
198 reinterpret_cast<LPBYTE>(value),
199 lstrlen(value) * sizeof(wchar_t));
200 } 301 }
302 }
201 303
202 ::RegCloseKey(key); 304 // This function sets the flag in registry to indicate that Google Update
305 // should try full installer next time. If the current installer works, this
306 // flag is cleared by setup.exe at the end of install. The flag will by default
307 // be written to HKCU, but if --system-level is included in the command line,
308 // it will be written to HKLM instead.
309 void SetFullInstallerFlag() {
310 int args_num;
311 wchar_t* cmd_line = ::GetCommandLine();
312 wchar_t** args = ::CommandLineToArgvW(cmd_line, &args_num);
313
314 SetFullInstallerFlagHelper(args_num, args);
315
316 ::LocalFree(args);
203 } 317 }
204 318
205 // Gets the setup.exe path from Registry by looking the value of Uninstall 319 // 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 320 // string, strips the arguments for uninstall and returns only the full path
207 // to setup.exe. 321 // to setup.exe. |size| is measured in wchar_t units.
208 bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) { 322 bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) {
209 if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey, 323 if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey,
210 kUninstallRegistryValueName, path, size)) { 324 kUninstallRegistryValueName, path, size)) {
211 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kUninstallRegistryKey, 325 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kUninstallRegistryKey,
212 kUninstallRegistryValueName, path, size)) { 326 kUninstallRegistryValueName, path, size)) {
213 return false; 327 return false;
214 } 328 }
215 } 329 }
216 wchar_t *tmp = StrStr(path, L" --"); 330 wchar_t *tmp = StrStr(path, L" --");
217 if (tmp) { 331 if (tmp) {
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 wchar_t archive_path[MAX_PATH] = {0}; 655 wchar_t archive_path[MAX_PATH] = {0};
542 wchar_t setup_path[MAX_PATH] = {0}; 656 wchar_t setup_path[MAX_PATH] = {0};
543 if (!UnpackBinaryResources(module, base_path, archive_path, MAX_PATH, 657 if (!UnpackBinaryResources(module, base_path, archive_path, MAX_PATH,
544 setup_path, MAX_PATH)) 658 setup_path, MAX_PATH))
545 return 102; 659 return 102;
546 660
547 int exit_code = 103; 661 int exit_code = 103;
548 if (!RunSetup(archive_path, setup_path, &exit_code)) 662 if (!RunSetup(archive_path, setup_path, &exit_code))
549 return exit_code; 663 return exit_code;
550 664
551 wchar_t value[4]; 665 wchar_t value[2];
552 if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, 666 if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey,
553 kCleanupRegistryValueName, value, 4)) || 667 kCleanupRegistryValueName, value,
668 _countof(value))) ||
554 (value[0] != L'0')) 669 (value[0] != L'0'))
555 DeleteExtractedFiles(base_path, archive_path, setup_path); 670 DeleteExtractedFiles(base_path, archive_path, setup_path);
556 671
557 return exit_code; 672 return exit_code;
558 } 673 }
559 } // namespace mini_installer 674 } // namespace mini_installer
560 675
561 676
562 int MainEntryPoint() { 677 int MainEntryPoint() {
563 int result = mini_installer::WMain(::GetModuleHandle(NULL)); 678 int result = mini_installer::WMain(::GetModuleHandle(NULL));
564 ::ExitProcess(result); 679 ::ExitProcess(result);
565 } 680 }
OLDNEW
« no previous file with comments | « chrome/installer/mini_installer/mini_installer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698