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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/installer/mini_installer/mini_installer.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/installer/mini_installer/mini_installer.cc
===================================================================
--- chrome/installer/mini_installer/mini_installer.cc (revision 69281)
+++ chrome/installer/mini_installer/mini_installer.cc (working copy)
@@ -127,63 +127,121 @@
return true;
}
+// Helper function to read a REG_SZ value from the registry. Returns
+// ERROR_SUCCESS, ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error.
+// |size| is the size of |value| in wchar_t units. |value| is guaranteed to be
+// null-terminated when ERROR_SUCCESS is returned.
+LONG ReadValueFromRegistry(HKEY key, const wchar_t* value_name, wchar_t* value,
tommi (sloooow) - chröme 2010/12/16 06:32:25 nice
+ size_t size) {
+ DWORD type;
+ DWORD byte_length = static_cast<DWORD>(size * sizeof(wchar_t));
+ LONG result = ::RegQueryValueEx(key, value_name, NULL, &type,
+ 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.
+ &byte_length);
+ if (result == ERROR_SUCCESS) {
+ if (type != REG_SZ) {
+ result = ERROR_NOT_SUPPORTED;
+ } else if (byte_length == 0) {
+ *value = L'\0';
+ } else if (value[byte_length/sizeof(wchar_t) - 1] != L'\0') {
+ 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.
+ value[byte_length / sizeof(wchar_t)] = L'\0';
+ else
+ result = ERROR_MORE_DATA;
+ }
+ }
+ return result;
+}
+
// Helper function to read a value from registry. Returns true if value
// is read successfully and stored in parameter value. Returns false otherwise.
+// |size| is measured in wchar_t units.
bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key,
const wchar_t *value_name, wchar_t *value,
size_t size) {
+ bool result = false;
HKEY key;
- if ((::RegOpenKeyEx(root_key, sub_key, NULL,
- KEY_READ, &key) == ERROR_SUCCESS) &&
- (::RegQueryValueEx(key, value_name, NULL, NULL,
- reinterpret_cast<LPBYTE>(value),
- reinterpret_cast<LPDWORD>(&size)) == ERROR_SUCCESS)) {
+ if (::RegOpenKeyEx(root_key, sub_key, NULL,
+ KEY_READ, &key) == ERROR_SUCCESS) {
+ result =
+ (ReadValueFromRegistry(key, value_name, value, size) == ERROR_SUCCESS);
::RegCloseKey(key);
- return true;
}
- return false;
+ return result;
}
-// This function sets the flag in registry to indicate that Google Update
-// should try full installer next time. If the current installer works, this
-// flag is cleared by setup.exe at the end of install. The flag will by default
-// be written to HKCU, but if --system-level is included in the command line,
-// it will be written to HKLM instead.
-void SetFullInstallerFlag() {
- HKEY key;
- wchar_t ap_registry_key[128];
+// Opens the Google Update ClientState key for a product.
+bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access,
+ HKEY* key) {
+ wchar_t client_state_key[128];
+
+ return SafeStrCopy(client_state_key, _countof(client_state_key),
+ kApRegistryKeyBase) &&
+ SafeStrCat(client_state_key, _countof(client_state_key), app_guid) &&
+ (::RegOpenKeyEx(root_key, client_state_key, NULL, access, key) ==
+ ERROR_SUCCESS);
+}
+
+// TODO(grt): Write a unit test for this that uses registry virtualization.
+void SetFullInstallerFlagHelper(int args_num, const wchar_t* const* args) {
+ bool multi_install = false;
+ HKEY key = NULL;
const wchar_t* app_guid = google_update::kAppGuid;
HKEY root_key = HKEY_CURRENT_USER;
+ wchar_t value[128];
+ LONG ret;
- int args_num;
- wchar_t* cmd_line = ::GetCommandLine();
- wchar_t** args = ::CommandLineToArgvW(cmd_line, &args_num);
for (int i = 1; i < args_num; ++i) {
if (0 == ::lstrcmpi(args[i], L"--chrome-sxs"))
app_guid = google_update::kSxSAppGuid;
else if (0 == ::lstrcmpi(args[i], L"--chrome-frame"))
app_guid = google_update::kChromeFrameAppGuid;
+ else if (0 == ::lstrcmpi(args[i], L"--multi-install"))
+ multi_install = true;
else if (0 == ::lstrcmpi(args[i], L"--system-level"))
root_key = HKEY_LOCAL_MACHINE;
}
- if (!SafeStrCopy(ap_registry_key, _countof(ap_registry_key),
- kApRegistryKeyBase) ||
- !SafeStrCat(ap_registry_key, _countof(ap_registry_key),
- app_guid)) {
- return;
+ // When multi_install is true, we are potentially:
+ // 1. Performing a multi-install of some product(s) on a clean machine.
+ // Neither the product(s) nor the multi-installer will have a ClientState
+ // key in the registry, so there is nothing to be done.
+ // 2. Upgrading an existing multi-install. The multi-installer will have a
+ // ClientState key in the registry. Only it need be modified.
+ // 3. Migrating a single-install into a multi-install. The product will have
+ // a ClientState key in the registry. Only it need be modified.
+ // To handle all cases, we inspect the product's ClientState to see if it
+ // exists and its "ap" value does not contain "-multi". This is case 3, so we
+ // modify the product's ClientState. Otherwise, we check the
+ // multi-installer's ClientState and modify it if it exists.
+ if (multi_install) {
+ if (OpenClientStateKey(root_key, app_guid, KEY_READ | KEY_SET_VALUE,
+ &key)) {
+ // The app is installed. See if it's a single-install.
+ ret = ReadValueFromRegistry(key, kApRegistryValueName, value,
+ _countof(value));
+ if (ret != ERROR_FILE_NOT_FOUND &&
+ (ret != ERROR_SUCCESS || StrStr(value, kMultiInstallTag) != NULL)) {
+ // Error or case 2: add "-full" to the multi-installer's value.
+ ::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
+ key = NULL;
+ app_guid = google_update::kMultiInstallAppGuid;
+ } // else case 3: add "-full" to this value.
+ } else {
+ // case 1 or 2: add "-full" to the multi-installer's value.
+ key = NULL;
+ app_guid = google_update::kMultiInstallAppGuid;
+ }
}
- if (::RegOpenKeyEx(root_key, ap_registry_key, NULL,
- KEY_READ | KEY_SET_VALUE, &key) != ERROR_SUCCESS)
- return;
- wchar_t value[128];
- size_t size = _countof(value);
- size_t buf_size = size;
- LONG ret = ::RegQueryValueEx(key, kApRegistryValueName, NULL, NULL,
- reinterpret_cast<LPBYTE>(value),
- reinterpret_cast<LPDWORD>(&size));
+ if (key == NULL) {
+ if (!OpenClientStateKey(root_key, app_guid, KEY_READ | KEY_SET_VALUE, &key))
+ return;
+ ret = ReadValueFromRegistry(key, kApRegistryValueName, value,
+ _countof(value));
+ }
+
// The conditions below are handling two cases:
// 1. When ap key is present, we want to make sure it doesn't already end
// in -full and then append -full to it.
@@ -193,18 +251,33 @@
value[0] = L'\0';
if (!StrEndsWith(value, kFullInstallerSuffix) &&
- (SafeStrCat(value, buf_size, kFullInstallerSuffix)))
+ (SafeStrCat(value, _countof(value), kFullInstallerSuffix)))
::RegSetValueEx(key, kApRegistryValueName, 0, REG_SZ,
reinterpret_cast<LPBYTE>(value),
- lstrlen(value) * sizeof(wchar_t));
+ (lstrlen(value) + 1) * sizeof(wchar_t));
}
::RegCloseKey(key);
}
+// This function sets the flag in registry to indicate that Google Update
+// should try full installer next time. If the current installer works, this
+// flag is cleared by setup.exe at the end of install. The flag will by default
+// be written to HKCU, but if --system-level is included in the command line,
+// it will be written to HKLM instead.
+void SetFullInstallerFlag() {
+ int args_num;
+ wchar_t* cmd_line = ::GetCommandLine();
+ wchar_t** args = ::CommandLineToArgvW(cmd_line, &args_num);
+
+ SetFullInstallerFlagHelper(args_num, args);
+
+ ::LocalFree(args);
+}
+
// Gets the setup.exe path from Registry by looking the value of Uninstall
// string, strips the arguments for uninstall and returns only the full path
-// to setup.exe.
+// to setup.exe. |size| is measured in wchar_t units.
bool GetSetupExePathFromRegistry(wchar_t *path, size_t size) {
if (!ReadValueFromRegistry(HKEY_CURRENT_USER, kUninstallRegistryKey,
kUninstallRegistryValueName, path, size)) {
@@ -548,9 +621,10 @@
if (!RunSetup(archive_path, setup_path, &exit_code))
return exit_code;
- wchar_t value[4];
+ wchar_t value[2];
if ((!ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey,
- kCleanupRegistryValueName, value, 4)) ||
+ kCleanupRegistryValueName, value,
+ _countof(value))) ||
(value[0] != L'0'))
DeleteExtractedFiles(base_path, archive_path, setup_path);
« 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