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

Unified Diff: chrome_frame/chrome_tab.cc

Issue 7824010: Make Chrome Frame registration and unregistration more robust. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 3 months 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
Index: chrome_frame/chrome_tab.cc
===================================================================
--- chrome_frame/chrome_tab.cc (revision 98956)
+++ chrome_frame/chrome_tab.cc (working copy)
@@ -15,6 +15,7 @@
#include "base/file_version_info.h"
#include "base/logging.h"
#include "base/logging_win.h"
+#include "base/memory/scoped_vector.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "base/string_piece.h"
@@ -191,7 +192,7 @@
ChromeTabModule _AtlModule;
base::AtExitManager* g_exit_manager = NULL;
-bool RegisterSecuredMimeHandler(bool enable, bool is_system); // forward
+HRESULT RegisterSecuredMimeHandler(bool enable, bool is_system); // forward
// DLL Entry Point
extern "C" BOOL WINAPI DllMain(HINSTANCE instance,
@@ -348,7 +349,9 @@
// Helper method called for user-level installs where we don't have admin
// permissions. Starts up the long running process and registers it to get it
// started at next boot.
-void SetupUserLevelHelper() {
+HRESULT SetupUserLevelHelper() {
+ HRESULT hr = S_OK;
+
// Remove existing run-at-startup entry.
base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kRunKeyName);
@@ -366,42 +369,48 @@
DCHECK(file_util::PathExists(helper_path)) <<
"Could not find chrome_frame_helper.exe.";
}
- } else {
- NOTREACHED();
- }
- // Find window handle of existing instance.
- HWND old_window = FindWindow(kChromeFrameHelperWindowClassName,
- kChromeFrameHelperWindowName);
+ // Find window handle of existing instance.
+ HWND old_window = FindWindow(kChromeFrameHelperWindowClassName,
+ kChromeFrameHelperWindowName);
- if (file_util::PathExists(helper_path)) {
- std::wstring helper_path_cmd(L"\"");
- helper_path_cmd += helper_path.value();
- helper_path_cmd += L"\" ";
- helper_path_cmd += kChromeFrameHelperStartupArg;
+ if (file_util::PathExists(helper_path)) {
+ std::wstring helper_path_cmd(L"\"");
+ helper_path_cmd += helper_path.value();
+ helper_path_cmd += L"\" ";
+ helper_path_cmd += kChromeFrameHelperStartupArg;
- // Add new run-at-startup entry.
- base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, kRunKeyName,
- helper_path_cmd);
+ // Add new run-at-startup entry.
+ base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, kRunKeyName,
grt (UTC plus 2) 2011/09/06 14:56:55 if this fails, installation will continue but GCF
robertshield 2011/09/06 20:23:42 Nope, we now fail on this as well.
+ helper_path_cmd);
- // Start new instance.
- base::LaunchOptions options;
- options.start_hidden = true;
- bool launched = base::LaunchProcess(helper_path.value(), options, NULL);
- if (!launched) {
- NOTREACHED();
- LOG(ERROR) << "Could not launch helper process.";
- }
+ // Start new instance.
+ base::LaunchOptions options;
+ options.start_hidden = true;
+ bool launched = base::LaunchProcess(helper_path.value(), options, NULL);
+ if (!launched) {
+ hr = E_FAIL;
grt (UTC plus 2) 2011/09/06 14:56:55 this will now cause installation to fail and rollb
robertshield 2011/09/06 20:23:42 Yes, this is desired. New IE instances will not re
+ NOTREACHED();
+ LOG(ERROR) << "Could not launch helper process.";
grt (UTC plus 2) 2011/09/06 14:56:55 Do you think the last-error code might be useful h
robertshield 2011/09/06 20:23:42 So changed, although sadly this won't show up in t
grt (UTC plus 2) 2011/09/07 15:00:48 frown. so the logging stuff in DllMain is a noop
robertshield 2011/09/07 17:58:11 As far as I can tell, this is the case. It may be
+ }
- // Kill old instance using window handle.
- if (IsWindow(old_window)) {
- BOOL result = PostMessage(old_window, WM_CLOSE, 0, 0);
- if (!result) {
- LOG(ERROR) << "Failed to post close message to old helper process: "
- << GetLastError();
+ // Kill old instance using window handle.
+ if (IsWindow(old_window)) {
+ BOOL result = PostMessage(old_window, WM_CLOSE, 0, 0);
+ if (!result) {
+ LOG(ERROR) << "Failed to post close message to old helper process: "
grt (UTC plus 2) 2011/09/06 14:56:55 PLOG and remove GetLastError
robertshield 2011/09/06 20:23:42 Done.
+ << GetLastError();
+ }
}
+ } else {
+ hr = ERROR_FILE_NOT_FOUND;
grt (UTC plus 2) 2011/09/06 14:56:55 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
robertshield 2011/09/06 20:23:42 Done.
}
+ } else {
+ hr = E_UNEXPECTED;
+ NOTREACHED();
}
+
+ return hr;
}
@@ -479,6 +488,119 @@
return hr;
}
grt (UTC plus 2) 2011/09/06 14:56:55 consider adding a comment indicating that what fol
robertshield 2011/09/06 20:23:42 Done.
+HRESULT RegisterActiveDoc(bool reg, bool is_system) {
+ // We have to call the static T::UpdateRegistry function instead of
+ // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEDOC, reg)
+ // because there is specific OLEMISC replacement.
+ return ChromeActiveDocument::UpdateRegistry(reg);
+}
+
+HRESULT RegisterActiveX(bool reg, bool is_system) {
+ // We have to call the static T::UpdateRegistry function instead of
+ // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEX, reg)
+ // because there is specific OLEMISC replacement.
+ return ChromeFrameActivex::UpdateRegistry(reg);
+}
+
+HRESULT RegisterElevationPolicy(bool reg, bool is_system) {
+ if (reg && base::win::GetVersion() >= base::win::VERSION_VISTA) {
+ // Register the elevation policy. We do this only for developer
+ // convenience as the installer is really responsible for doing this.
grt (UTC plus 2) 2011/09/06 14:56:55 This comment says that the installer is responsibl
robertshield 2011/09/06 20:23:42 It does, in fact, do it. See install_worker.cc, Ad
+ // Because of that, we do not unregister this policy and just leave that
+ // up to the installer. Also we do not gate registration on this
+ // succeeding.
+ _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ELEVATION,
+ reg);
+ RefreshElevationPolicy();
+ }
+ return S_OK;
+}
+
+HRESULT RegisterProtocol(bool reg, bool is_system) {
+ return _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEPROTOCOL, reg);
+}
+
+HRESULT RegisterBhoClsid(bool reg, bool is_system) {
+ return Bho::UpdateRegistry(reg);
+}
+
+HRESULT RegisterBhoIE(bool reg, bool is_system) {
+ if (is_system) {
+ return _AtlModule.UpdateRegistryFromResourceS(IDR_REGISTER_BHO, reg);
+ } else {
+ if (reg) {
+ // Setup the long running process:
+ return SetupUserLevelHelper();
+ } else {
+ // Unschedule the user-level helper. Note that we don't kill it here
+ // so that during updates we don't have a time window with no running
+ // helper. Uninstalls and updates will explicitly kill the helper from
+ // within the installer. Unregister existing run-at-startup entry.
+ return base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER,
grt (UTC plus 2) 2011/09/06 14:56:55 return base::win::Remove...(...) ? S_OK : E_FAIL;
robertshield 2011/09/06 20:23:42 Done.
+ kRunKeyName);
+ }
+ }
+}
+
+HRESULT RegisterTypeLib(bool reg, bool is_system) {
+ if (reg && !is_system) {
+ // Enables the RegisterTypeLib Function function to override default
+ // registry mappings under Windows Vista Service Pack 1 (SP1),
+ // Windows Server 2008, and later operating system versions
+ typedef void (WINAPI* OaEnablePerUserTypeLibReg)(void);
+ OaEnablePerUserTypeLibReg per_user_typelib_func =
+ reinterpret_cast<OaEnablePerUserTypeLibReg>(
+ GetProcAddress(GetModuleHandle(L"oleaut32.dll"),
+ "OaEnablePerUserTLibRegistration"));
+ if (per_user_typelib_func) {
+ (*per_user_typelib_func)();
+ }
+ }
+ return reg ?
+ UtilRegisterTypeLib(_AtlComModule.m_hInstTypeLib,
+ NULL, !is_system) :
+ UtilUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib,
+ NULL, !is_system);
+}
+
+HRESULT RegisterLegacyNPAPICleanup(bool reg, bool is_system) {
+ if (!reg) {
+ _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, reg);
+ UtilRemovePersistentNPAPIMarker();
+ }
+ // Ignore failures.
+ return S_OK;
+}
+
grt (UTC plus 2) 2011/09/06 14:56:55 remove extra newline
robertshield 2011/09/06 20:23:42 Done.
+
+HRESULT RegisterAppId(bool reg, bool is_system) {
+ return _AtlModule.UpdateRegistryAppId(reg);
+}
+
grt (UTC plus 2) 2011/09/06 14:56:55 remove extra newline
robertshield 2011/09/06 20:23:42 Done.
+
+HRESULT RegisterUserAgent(bool reg, bool is_system) {
+ if (reg) {
+ return SetChromeFrameUA(is_system, L"1");
+ } else {
+ return SetChromeFrameUA(is_system, NULL);
+ }
+}
+
+enum RegistrationSteps {
grt (UTC plus 2) 2011/09/06 14:56:55 nit: make this singular since an instance of the t
robertshield 2011/09/06 20:23:42 Done.
+ kStepSecuredMimeHandler = 0,
+ kStepActiveDoc = 1,
+ kStepActiveX = 2,
+ kStepElevationPolicy = 3,
+ kStepProtocol = 4,
+ kStepBhoClsid = 5,
+ kStepBhoRegistration = 6,
+ kStepRegisterTypeLib = 7,
+ kStepNpapiCleanup = 8,
+ kStepAppId = 9,
+ kStepUserAgent = 10,
+ kStepEnd = 11
+};
+
enum RegistrationFlags {
ACTIVEX = 0x0001,
ACTIVEDOC = 0x0002,
@@ -490,116 +612,95 @@
ALL = 0xFFFF
};
-STDAPI CustomRegistration(UINT reg_flags, BOOL reg, bool is_system) {
- UINT flags = reg_flags;
+// Mux the failure step into the hresult. We take only the first four bits
+// and stick those into the top four bits of the facility code. We also set the
+// Customer bit to be polite. Graphically, we write our error code to the
+// bits marked with ^:
+// | 1 2 3 |
+// |0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1|
+// |S|R|C|N|X|Facility |Code |
+// ^ ^ ^ ^ ^
+// See http://msdn.microsoft.com/en-us/library/cc231198(PROT.10).aspx for
+// more details on HRESULTS.
+//
+// The resulting error can be extracted by:
+// error_code = (fiddled_hr & 0x07800000) >> 23
+HRESULT MuxErrorIntoHRESULT(HRESULT hr, int error_code) {
+ DCHECK_GE(error_code, 0);
+ DCHECK_LT(error_code, kStepEnd);
+ COMPILE_ASSERT(kStepEnd <= 0xF, update_error_muxing_too_many_steps);
- if (reg && (flags & (ACTIVEDOC | ACTIVEX)))
- flags |= (TYPELIB | GCF_PROTOCOL);
+ // Check that our four desired bits are clear.
+ // 0xF87FFFFF == 11111000011111111111111111111111
+ DCHECK_EQ(static_cast<HRESULT>(hr & 0xF87FFFFF), hr);
- HRESULT hr = S_OK;
+ HRESULT fiddled_hr = ((error_code & 0xF) << 23) | hr;
+ fiddled_hr |= 1 << 29; // Set the customer bit.
+ return fiddled_hr;
+}
+
+HRESULT CustomRegistration(uint16 reg_flags, bool reg, bool is_system) {
+ if (reg && (reg_flags & (ACTIVEDOC | ACTIVEX)))
+ reg_flags |= (TYPELIB | GCF_PROTOCOL);
+
// Set the flag that gets checked in AddCommonRGSReplacements before doing
// registration work.
_AtlModule.do_system_registration_ = is_system;
- if ((hr == S_OK) && (flags & ACTIVEDOC)) {
- // Don't fail to unregister if we can't undo the secure mime
- // handler registration. This was observed getting hit during
- // uninstallation.
- if (!RegisterSecuredMimeHandler(reg ? true : false, is_system) && reg)
- return E_FAIL;
- hr = ChromeActiveDocument::UpdateRegistry(reg);
- }
+ typedef HRESULT (*RegistrationFn)(bool reg, bool is_system);
+ struct RegistrationStep {
+ int id;
grt (UTC plus 2) 2011/09/06 14:56:55 how about RegistrationStepId rather than int? thi
robertshield 2011/09/06 20:23:42 Done.
+ uint32 condition;
grt (UTC plus 2) 2011/09/06 14:56:55 since reg_flags is a uint16, should this be, too?
robertshield 2011/09/06 20:23:42 Done.
+ RegistrationFn func;
+ };
+ static const RegistrationStep registration_steps[] = {
+ { kStepSecuredMimeHandler, ACTIVEDOC, &RegisterSecuredMimeHandler },
+ { kStepActiveDoc, ACTIVEDOC, &RegisterActiveDoc },
+ { kStepActiveX, ACTIVEX, &RegisterActiveX },
+ { kStepElevationPolicy, (ACTIVEDOC | ACTIVEX), &RegisterElevationPolicy },
+ { kStepProtocol, GCF_PROTOCOL, &RegisterProtocol },
+ { kStepBhoClsid, BHO_CLSID, &RegisterBhoClsid },
+ { kStepBhoRegistration, BHO_REGISTRATION, &RegisterBhoIE },
+ { kStepRegisterTypeLib, TYPELIB, &RegisterTypeLib },
+ { kStepNpapiCleanup, ALL, &RegisterLegacyNPAPICleanup },
+ { kStepAppId, ALL, &RegisterAppId },
+ { kStepUserAgent, ALL, &RegisterUserAgent }
+ };
- if ((hr == S_OK) && (flags & ACTIVEX)) {
- // We have to call the static T::UpdateRegistry function instead of
- // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEX, reg)
- // because there is specific OLEMISC replacement.
- hr = ChromeFrameActivex::UpdateRegistry(reg);
- }
-
- // Register the elevation policy. We do this only for developer convenience
- // as the installer is really responsible for doing this.
- // Because of that, we do not unregister this policy and just leave that up
- // to the installer.
- if (hr == S_OK && (flags & (ACTIVEDOC | ACTIVEX)) && reg) {
- _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ELEVATION, reg);
- RefreshElevationPolicy();
- }
-
- if ((hr == S_OK) && (flags & GCF_PROTOCOL)) {
- hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEPROTOCOL, reg);
- }
-
- if ((hr == S_OK) && (flags & BHO_CLSID)) {
- hr = Bho::UpdateRegistry(reg);
- }
-
- if ((hr == S_OK) && (flags & BHO_REGISTRATION)) {
- if (is_system) {
- _AtlModule.UpdateRegistryFromResourceS(IDR_REGISTER_BHO, reg);
- } else {
- if (reg) {
- // Setup the long running process:
- SetupUserLevelHelper();
- } else {
- // Unschedule the user-level helper. Note that we don't kill it here so
- // that during updates we don't have a time window with no running
- // helper. Uninstalls and updates will explicitly kill the helper from
- // within the installer. Unregister existing run-at-startup entry.
- base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kRunKeyName);
+ HRESULT hr = S_OK;
+ bool rollback = false;
+ int failure_step = 0;
+ for (int step = 0; step < arraysize(registration_steps); ++step) {
+ if ((reg_flags & registration_steps[step].condition) != 0) {
+ hr = registration_steps[step].func(reg, is_system);
+ if (FAILED(hr) && reg) {
+ rollback = true;
+ failure_step = step;
+ break;
}
}
}
- if ((hr == S_OK) && (flags & TYPELIB)) {
- if (reg && !is_system) {
- // Enables the RegisterTypeLib Function function to override default
- // registry mappings under Windows Vista Service Pack 1 (SP1),
- // Windows Server 2008, and later operating system versions
- typedef void (WINAPI* OaEnablePerUserTypeLibReg)(void);
- OaEnablePerUserTypeLibReg per_user_typelib_func =
- reinterpret_cast<OaEnablePerUserTypeLibReg>(
- GetProcAddress(GetModuleHandle(L"oleaut32.dll"),
- "OaEnablePerUserTLibRegistration"));
- if (per_user_typelib_func) {
- (*per_user_typelib_func)();
- }
+ if (rollback) {
+ DCHECK(reg);
+ // Rollback the failing action and all preceding ones.
+ for (int rollback_step = failure_step;
grt (UTC plus 2) 2011/09/06 14:56:55 how about reusing "step" so this doesn't need so m
robertshield 2011/09/06 20:23:42 Done.
+ rollback_step >= 0;
+ --rollback_step) {
+ registration_steps[rollback_step].func(!reg, is_system);
}
- hr = (reg)?
- UtilRegisterTypeLib(_AtlComModule.m_hInstTypeLib, NULL, !is_system) :
- UtilUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib, NULL, !is_system);
}
- // Unconditionally remove NPAPI registration when unregistering any component.
- if ((hr == S_OK) && !reg) {
- // Ignore failures.
- _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, reg);
- UtilRemovePersistentNPAPIMarker();
- }
-
- if (hr == S_OK) {
- hr = _AtlModule.UpdateRegistryAppId(reg);
- }
-
- if (hr == S_OK) {
- if (reg) {
- hr = SetChromeFrameUA(is_system, L"1");
- } else {
- hr = SetChromeFrameUA(is_system, NULL);
- }
- }
- return hr;
+ return MuxErrorIntoHRESULT(hr, failure_step);
}
-
-
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer() {
- UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
- BHO_CLSID | BHO_REGISTRATION;
+ uint16 flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
+ BHO_CLSID | BHO_REGISTRATION;
- HRESULT hr = CustomRegistration(flags, TRUE, true);
+ HRESULT hr = CustomRegistration(flags, true, true);
if (SUCCEEDED(hr)) {
SetupRunOnce();
}
@@ -609,11 +710,11 @@
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer() {
- HRESULT hr = CustomRegistration(ALL, FALSE, true);
+ HRESULT hr = CustomRegistration(ALL, false, true);
return hr;
}
-// DllRegisterServer - Adds entries to the HKCU hive in the registry
+// DllRegisterUserServer - Adds entries to the HKCU hive in the registry.
STDAPI DllRegisterUserServer() {
UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
BHO_CLSID | BHO_REGISTRATION;
@@ -626,7 +727,7 @@
return hr;
}
-// DllRegisterServer - Removes entries from the HKCU hive in the registry.
+// DllUnregisterUserServer - Removes entries from the HKCU hive in the registry.
STDAPI DllUnregisterUserServer() {
HRESULT hr = CustomRegistration(ALL, FALSE, false);
return hr;
@@ -746,7 +847,7 @@
CSid user_;
};
-static bool SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) {
+static HRESULT SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) {
grt (UTC plus 2) 2011/09/06 14:56:55 nit: move this (and the above classes) into the un
robertshield 2011/09/06 20:23:42 Done.
std::wstring key_name = kInternetSettings;
key_name.append(L"\\Secure Mime Handlers");
RegKey key(root_key, key_name.c_str(), KEY_READ | KEY_WRITE);
@@ -763,10 +864,11 @@
result2 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument.1");
}
- return (result2 == ERROR_SUCCESS) && (result2 == ERROR_SUCCESS);
+ return result1 != ERROR_SUCCESS ? HRESULT_FROM_WIN32(result1) :
+ HRESULT_FROM_WIN32(result2);
}
-bool RegisterSecuredMimeHandler(bool enable, bool is_system) {
+HRESULT RegisterSecuredMimeHandler(bool enable, bool is_system) {
grt (UTC plus 2) 2011/09/06 14:56:55 nit: move this so that it lives with the other reg
robertshield 2011/09/06 20:23:42 Done.
if (!is_system) {
return SetOrDeleteMimeHandlerKey(enable, HKEY_CURRENT_USER);
} else if (base::win::GetVersion() < base::win::VERSION_VISTA) {
@@ -782,7 +884,7 @@
TokenWithPrivileges token_;
if (!token_.EnablePrivileges())
- return false;
+ return E_ACCESSDENIED;
// If there is a backup key - something bad happened; try to restore
// security on "Secure Mime Handlers" from the backup.
@@ -792,11 +894,11 @@
// Read old security descriptor of the Mime key first.
CSecurityDesc sd;
if (!AtlGetSecurityDescriptor(object_name.c_str(), SE_REGISTRY_KEY, &sd)) {
- return false;
+ return E_FAIL;
}
backup.SaveSecurity(sd);
- bool result = false;
+ HRESULT hr = E_FAIL;
// set new owner
if (AtlSetOwnerSid(object_name.c_str(), SE_REGISTRY_KEY, token_.GetUser())) {
// set new dacl
@@ -804,10 +906,10 @@
sd.GetDacl(&new_dacl);
new_dacl.AddAllowedAce(token_.GetUser(), GENERIC_WRITE | GENERIC_READ);
if (AtlSetDacl(object_name.c_str(), SE_REGISTRY_KEY, new_dacl)) {
- result = SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
+ hr = SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
}
}
backup.RestoreSecurity(object_name.c_str());
- return result;
+ return hr;
}
« chrome/installer/util/self_reg_work_item.cc ('K') | « chrome/installer/util/self_reg_work_item.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698