summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/installer/util/self_reg_work_item.cc29
-rw-r--r--chrome_frame/chrome_tab.cc687
2 files changed, 423 insertions, 293 deletions
diff --git a/chrome/installer/util/self_reg_work_item.cc b/chrome/installer/util/self_reg_work_item.cc
index 79e4cc3..70f1853 100644
--- a/chrome/installer/util/self_reg_work_item.cc
+++ b/chrome/installer/util/self_reg_work_item.cc
@@ -27,6 +27,26 @@ SelfRegWorkItem::SelfRegWorkItem(const std::wstring& dll_path,
SelfRegWorkItem::~SelfRegWorkItem() {
}
+// This is designed to unmux error codes that may be shoe-horned in to HRESULT
+// return codes by ORing a number into the top four bits of the facility code
+// Any number thus found will be returned in |error_code|. The "cleaned"
+// HRESULT is then returned.
+//
+// This only has an effect if the customer bit is set in the HRESULT, if it is
+// not set then *error_code will be unchanged and the original HRESULT is
+// returned.
+//
+// Note that this will do the wrong thing for high-valued facility codes.
+HRESULT UnMuxHRESULTErrorCode(HRESULT hr, int* error_code) {
+ DCHECK(error_code);
+ if (hr & (1 << 29)) {
+ *error_code = (hr & 0x07800000) >> 23;
+ return hr & 0xF87FFFFF;
+ }
+
+ return hr;
+}
+
bool SelfRegWorkItem::RegisterDll(bool do_register) {
VLOG(1) << "COM " << (do_register ? "registration of " : "unregistration of ")
<< dll_path_;
@@ -52,9 +72,12 @@ bool SelfRegWorkItem::RegisterDll(bool do_register) {
HRESULT hr = register_server_func();
success = SUCCEEDED(hr);
if (!success) {
- PLOG(ERROR) << "Failed to " << (do_register ? "register" : "unregister")
- << " DLL at " << dll_path_.c_str() <<
- base::StringPrintf(" 0x%08X", hr);
+ int error_code = 0;
+ HRESULT unmuxed_hr = UnMuxHRESULTErrorCode(hr, &error_code);
+ LOG(ERROR) << "Failed to " << (do_register ? "register" : "unregister")
+ << " DLL at " << dll_path_.c_str() << ", hr="
+ << base::StringPrintf(" 0x%08X", unmuxed_hr) << ", code="
+ << error_code;
}
} else {
LOG(ERROR) << "COM registration export function not found";
diff --git a/chrome_frame/chrome_tab.cc b/chrome_frame/chrome_tab.cc
index b77d94e..7b80394 100644
--- a/chrome_frame/chrome_tab.cc
+++ b/chrome_frame/chrome_tab.cc
@@ -52,11 +52,6 @@ void InitGoogleUrl() {
url_util::IsStandard(kDummyUrl,
url_parse::MakeRange(0, arraysize(kDummyUrl)));
}
-}
-
-static const wchar_t kBhoRegistryPath[] =
- L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"
- L"\\Browser Helper Objects";
const wchar_t kInternetSettings[] =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
@@ -86,13 +81,10 @@ static const GUID kChromeFrameProvider =
{ 0x562bfc3, 0x2550, 0x45b4,
{ 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
-// Object entries go here instead of with each object, so that we can move
-// the objects to a lib. Also reduces magic.
-OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho)
-OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument)
-OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex)
-OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol)
-
+const wchar_t kPostPlatformUAKey[] =
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
+ L"User Agent\\Post Platform";
+const wchar_t kChromeFramePrefix[] = L"chromeframe/";
// See comments in DllGetClassObject.
LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr = NULL;
@@ -191,61 +183,7 @@ class ChromeTabModule : public CAtlDllModuleT<ChromeTabModule> {
ChromeTabModule _AtlModule;
base::AtExitManager* g_exit_manager = NULL;
-bool RegisterSecuredMimeHandler(bool enable, bool is_system); // forward
-
-// DLL Entry Point
-extern "C" BOOL WINAPI DllMain(HINSTANCE instance,
- DWORD reason,
- LPVOID reserved) {
- UNREFERENCED_PARAMETER(instance);
- if (reason == DLL_PROCESS_ATTACH) {
-#ifndef NDEBUG
- // Silence traces from the ATL registrar to reduce the log noise.
- ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0,
- ATLTRACESTATUS_DISABLED);
-#endif
- InitGoogleUrl();
-
- g_exit_manager = new base::AtExitManager();
- CommandLine::Init(0, NULL);
- InitializeCrashReporting();
- logging::InitLogging(
- NULL,
- logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
- logging::LOCK_LOG_FILE,
- logging::DELETE_OLD_LOG_FILE,
- logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
-
- DllRedirector* dll_redirector = DllRedirector::GetInstance();
- DCHECK(dll_redirector);
-
- if (!dll_redirector->RegisterAsFirstCFModule()) {
- // Someone else was here first, try and get a pointer to their
- // DllGetClassObject export:
- g_dll_get_class_object_redir_ptr =
- dll_redirector->GetDllGetClassObjectPtr();
- DCHECK(g_dll_get_class_object_redir_ptr != NULL)
- << "Found CF module with no DllGetClassObject export.";
- }
-
- // Enable ETW logging.
- logging::LogEventProvider::Initialize(kChromeFrameProvider);
- } else if (reason == DLL_PROCESS_DETACH) {
- DllRedirector* dll_redirector = DllRedirector::GetInstance();
- DCHECK(dll_redirector);
- dll_redirector->UnregisterAsFirstCFModule();
- g_patch_helper.UnpatchIfNeeded();
- delete g_exit_manager;
- g_exit_manager = NULL;
- ShutdownCrashReporting();
- }
- return _AtlModule.DllMain(reason, reserved);
-}
-
-#ifdef _MANAGED
-#pragma managed(pop)
-#endif
HRESULT RefreshElevationPolicy() {
const wchar_t kIEFrameDll[] = L"ieframe.dll";
@@ -348,7 +286,9 @@ HRESULT SetupRunOnce() {
// 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,72 +306,51 @@ void SetupUserLevelHelper() {
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);
-
- 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);
-
- // 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.";
- }
- // 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();
+ // 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;
+
+ // Add new run-at-startup entry.
+ if (!base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, kRunKeyName,
+ helper_path_cmd)) {
+ hr = E_FAIL;
+ LOG(ERROR) << "Could not add helper process to auto run key.";
}
- }
- }
-}
+ // Start new instance.
+ base::LaunchOptions options;
+ options.start_hidden = true;
+ bool launched = base::LaunchProcess(helper_path.value(), options, NULL);
+ if (!launched) {
+ hr = E_FAIL;
+ PLOG(DFATAL) << "Could not launch helper process.";
+ }
-// Used to determine whether the DLL can be unloaded by OLE
-STDAPI DllCanUnloadNow() {
- return _AtlModule.DllCanUnloadNow();
-}
-
-// Returns a class factory to create an object of the requested type
-STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
- // If we found another module present when we were loaded, then delegate to
- // that:
- if (g_dll_get_class_object_redir_ptr) {
- return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv);
- }
-
- // Enable sniffing and switching only if asked for BHO
- // (we use BHO to get loaded in IE).
- if (rclsid == CLSID_ChromeFrameBHO) {
- g_patch_helper.InitializeAndPatchProtocolsIfNeeded();
+ // Kill old instance using window handle.
+ if (IsWindow(old_window)) {
+ BOOL result = PostMessage(old_window, WM_CLOSE, 0, 0);
+ if (!result) {
+ PLOG(ERROR) << "Failed to post close message to old helper process: ";
+ }
+ }
+ } else {
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+ } else {
+ hr = E_UNEXPECTED;
+ NOTREACHED();
}
- return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
+ return hr;
}
-const wchar_t kPostPlatformUAKey[] =
- L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
- L"User Agent\\Post Platform";
-const wchar_t kChromeFramePrefix[] = L"chromeframe/";
-
// To delete the user agent, set value to NULL.
// The is_system parameter indicates whether this is a per machine or a per
// user installation.
@@ -440,8 +359,9 @@ HRESULT SetChromeFrameUA(bool is_system, const wchar_t* value) {
HKEY parent_hive = is_system ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
RegKey ua_key;
- if (ua_key.Create(parent_hive, kPostPlatformUAKey,
- KEY_READ | KEY_WRITE) == ERROR_SUCCESS) {
+ LONG reg_result = ua_key.Create(parent_hive, kPostPlatformUAKey,
+ KEY_READ | KEY_WRITE);
+ if (reg_result == ERROR_SUCCESS) {
// Make sure that we unregister ChromeFrame UA strings registered previously
wchar_t value_name[MAX_PATH + 1] = {};
wchar_t value_data[MAX_PATH + 1] = {};
@@ -473,165 +393,13 @@ HRESULT SetChromeFrameUA(bool is_system, const wchar_t* value) {
}
hr = S_OK;
} else {
- DLOG(ERROR) << __FUNCTION__ << ": " << kPostPlatformUAKey;
- hr = E_UNEXPECTED;
+ DLOG(ERROR) << __FUNCTION__ << ": " << kPostPlatformUAKey
+ << ", error code = " << reg_result;
+ hr = HRESULT_FROM_WIN32(reg_result);
}
return hr;
}
-enum RegistrationFlags {
- ACTIVEX = 0x0001,
- ACTIVEDOC = 0x0002,
- GCF_PROTOCOL = 0x0004,
- BHO_CLSID = 0x0008,
- BHO_REGISTRATION = 0x0010,
- TYPELIB = 0x0020,
-
- ALL = 0xFFFF
-};
-
-STDAPI CustomRegistration(UINT reg_flags, BOOL reg, bool is_system) {
- UINT flags = reg_flags;
-
- if (reg && (flags & (ACTIVEDOC | ACTIVEX)))
- flags |= (TYPELIB | GCF_PROTOCOL);
-
- HRESULT hr = S_OK;
-
- // 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);
- }
-
- 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);
- }
- }
- }
-
- 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)();
- }
- }
- 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;
-}
-
-
-
-// DllRegisterServer - Adds entries to the system registry
-STDAPI DllRegisterServer() {
- UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
- BHO_CLSID | BHO_REGISTRATION;
-
- HRESULT hr = CustomRegistration(flags, TRUE, true);
- if (SUCCEEDED(hr)) {
- SetupRunOnce();
- }
-
- return hr;
-}
-
-// DllUnregisterServer - Removes entries from the system registry
-STDAPI DllUnregisterServer() {
- HRESULT hr = CustomRegistration(ALL, FALSE, true);
- return hr;
-}
-
-// DllRegisterServer - Adds entries to the HKCU hive in the registry
-STDAPI DllRegisterUserServer() {
- UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
- BHO_CLSID | BHO_REGISTRATION;
-
- HRESULT hr = CustomRegistration(flags, TRUE, false);
- if (SUCCEEDED(hr)) {
- SetupRunOnce();
- }
-
- return hr;
-}
-
-// DllRegisterServer - Removes entries from the HKCU hive in the registry.
-STDAPI DllUnregisterUserServer() {
- HRESULT hr = CustomRegistration(ALL, FALSE, false);
- return hr;
-}
-
class SecurityDescBackup {
public:
explicit SecurityDescBackup(const std::wstring& backup_key)
@@ -746,7 +514,7 @@ struct TokenWithPrivileges {
CSid user_;
};
-static bool SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) {
+HRESULT SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) {
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 +531,13 @@ static bool SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) {
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) {
+// Chrome Frame registration functions.
+//-----------------------------------------------------------------------------
+HRESULT RegisterSecuredMimeHandler(bool enable, bool is_system) {
if (!is_system) {
return SetOrDeleteMimeHandlerKey(enable, HKEY_CURRENT_USER);
} else if (base::win::GetVersion() < base::win::VERSION_VISTA) {
@@ -782,7 +553,7 @@ bool RegisterSecuredMimeHandler(bool enable, bool is_system) {
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 +563,11 @@ bool RegisterSecuredMimeHandler(bool enable, bool is_system) {
// 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 +575,346 @@ bool RegisterSecuredMimeHandler(bool enable, bool is_system) {
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;
+}
+
+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) {
+ HRESULT hr = S_OK;
+ if (reg && base::win::GetVersion() >= base::win::VERSION_VISTA) {
+ // Register the elevation policy. This must succeed for Chrome Frame to
+ // be able launch Chrome when running in low-integrity IE.
+ // Note that this is not done on unregistration, the installer will
+ // explicitly remove the policy on uninstall.
+ hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ELEVATION,
+ reg);
+ if (SUCCEEDED(hr)) {
+ hr = RefreshElevationPolicy();
+ }
+ }
+ return hr;
+}
+
+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,
+ kRunKeyName) ? S_OK : E_FAIL;
+ }
+ }
+}
+
+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;
+}
+
+HRESULT RegisterAppId(bool reg, bool is_system) {
+ return _AtlModule.UpdateRegistryAppId(reg);
+}
+
+HRESULT RegisterUserAgent(bool reg, bool is_system) {
+ if (reg) {
+ return SetChromeFrameUA(is_system, L"1");
+ } else {
+ return SetChromeFrameUA(is_system, NULL);
+ }
+}
+
+enum RegistrationStepId {
+ 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,
+ GCF_PROTOCOL = 0x0004,
+ BHO_CLSID = 0x0008,
+ BHO_REGISTRATION = 0x0010,
+ TYPELIB = 0x0020,
+
+ ALL = 0xFFFF
+};
+
+// 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 ^:
+// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+// +---+-+-+-----------------------+-------------------------------+
+// |Sev|C|R| 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);
+
+ // Check that our four desired bits are clear.
+ // 0xF87FFFFF == 11111000011111111111111111111111
+ DCHECK_EQ(static_cast<HRESULT>(hr & 0xF87FFFFF), hr);
+
+ 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;
+
+ typedef HRESULT (*RegistrationFn)(bool reg, bool is_system);
+ struct RegistrationStep {
+ RegistrationStepId id;
+ uint16 condition;
+ 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 }
+ };
+
+ HRESULT hr = S_OK;
+
+ bool rollback = false;
+ int failure_step = 0;
+ HRESULT step_hr = S_OK;
+ for (int step = 0; step < arraysize(registration_steps); ++step) {
+ if ((reg_flags & registration_steps[step].condition) != 0) {
+ step_hr = registration_steps[step].func(reg, is_system);
+ if (FAILED(step_hr)) {
+ // Store only the first failing HRESULT with the step value muxed in.
+ if (hr == S_OK) {
+ hr = MuxErrorIntoHRESULT(step_hr, step);
+ }
+
+ // On registration if a step fails, we abort and rollback.
+ if (reg) {
+ rollback = true;
+ failure_step = step;
+ break;
+ }
+ }
+ }
+ }
+
+ if (rollback) {
+ DCHECK(reg);
+ // Rollback the failing action and all preceding ones.
+ for (int step = failure_step; step >= 0; --step) {
+ registration_steps[step].func(!reg, is_system);
+ }
+ }
+
+ return hr;
+}
+
+} // namespace
+
+// DLL Entry Point
+extern "C" BOOL WINAPI DllMain(HINSTANCE instance,
+ DWORD reason,
+ LPVOID reserved) {
+ UNREFERENCED_PARAMETER(instance);
+ if (reason == DLL_PROCESS_ATTACH) {
+#ifndef NDEBUG
+ // Silence traces from the ATL registrar to reduce the log noise.
+ ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0,
+ ATLTRACESTATUS_DISABLED);
+#endif
+ InitGoogleUrl();
+
+ g_exit_manager = new base::AtExitManager();
+ CommandLine::Init(0, NULL);
+ InitializeCrashReporting();
+ logging::InitLogging(
+ NULL,
+ logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
+ logging::LOCK_LOG_FILE,
+ logging::DELETE_OLD_LOG_FILE,
+ logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
+
+ DllRedirector* dll_redirector = DllRedirector::GetInstance();
+ DCHECK(dll_redirector);
+
+ if (!dll_redirector->RegisterAsFirstCFModule()) {
+ // Someone else was here first, try and get a pointer to their
+ // DllGetClassObject export:
+ g_dll_get_class_object_redir_ptr =
+ dll_redirector->GetDllGetClassObjectPtr();
+ DCHECK(g_dll_get_class_object_redir_ptr != NULL)
+ << "Found CF module with no DllGetClassObject export.";
+ }
+
+ // Enable ETW logging.
+ logging::LogEventProvider::Initialize(kChromeFrameProvider);
+ } else if (reason == DLL_PROCESS_DETACH) {
+ DllRedirector* dll_redirector = DllRedirector::GetInstance();
+ DCHECK(dll_redirector);
+
+ dll_redirector->UnregisterAsFirstCFModule();
+ g_patch_helper.UnpatchIfNeeded();
+ delete g_exit_manager;
+ g_exit_manager = NULL;
+ ShutdownCrashReporting();
+ }
+ return _AtlModule.DllMain(reason, reserved);
+}
+
+// Used to determine whether the DLL can be unloaded by OLE
+STDAPI DllCanUnloadNow() {
+ return _AtlModule.DllCanUnloadNow();
}
+
+// Returns a class factory to create an object of the requested type
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
+ // If we found another module present when we were loaded, then delegate to
+ // that:
+ if (g_dll_get_class_object_redir_ptr) {
+ return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv);
+ }
+
+ // Enable sniffing and switching only if asked for BHO
+ // (we use BHO to get loaded in IE).
+ if (rclsid == CLSID_ChromeFrameBHO) {
+ g_patch_helper.InitializeAndPatchProtocolsIfNeeded();
+ }
+
+ return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
+}
+
+// DllRegisterServer - Adds entries to the system registry
+STDAPI DllRegisterServer() {
+ uint16 flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
+ BHO_CLSID | BHO_REGISTRATION;
+
+ HRESULT hr = CustomRegistration(flags, true, true);
+ if (SUCCEEDED(hr)) {
+ SetupRunOnce();
+ }
+
+ return hr;
+}
+
+// DllUnregisterServer - Removes entries from the system registry
+STDAPI DllUnregisterServer() {
+ HRESULT hr = CustomRegistration(ALL, false, true);
+ return hr;
+}
+
+// DllRegisterUserServer - Adds entries to the HKCU hive in the registry.
+STDAPI DllRegisterUserServer() {
+ UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
+ BHO_CLSID | BHO_REGISTRATION;
+
+ HRESULT hr = CustomRegistration(flags, TRUE, false);
+ if (SUCCEEDED(hr)) {
+ SetupRunOnce();
+ }
+
+ return hr;
+}
+
+// DllUnregisterUserServer - Removes entries from the HKCU hive in the registry.
+STDAPI DllUnregisterUserServer() {
+ HRESULT hr = CustomRegistration(ALL, FALSE, false);
+ return hr;
+}
+
+// Object entries go here instead of with each object, so that we can move
+// the objects to a lib. Also reduces magic.
+OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho)
+OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument)
+OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex)
+OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol)