1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // chrome_tab.cc : Implementation of DLL Exports.
7 // Need to include this before the ATL headers below.
8 #include "chrome_frame/chrome_tab.h"
10 #include <atlsecurity.h>
13 #include "base/at_exit.h"
14 #include "base/basictypes.h"
15 #include "base/command_line.h"
16 #include "base/file_util.h"
17 #include "base/file_version_info.h"
18 #include "base/logging.h"
19 #include "base/logging_win.h"
20 #include "base/path_service.h"
21 #include "base/process/launch.h"
22 #include "base/strings/string16.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_piece.h"
25 #include "base/strings/string_util.h"
26 #include "base/strings/sys_string_conversions.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/win/registry.h"
29 #include "base/win/windows_version.h"
30 #include "chrome/common/chrome_constants.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/installer/util/google_update_settings.h"
33 #include "chrome_frame/bho.h"
34 #include "chrome_frame/chrome_active_document.h"
35 #include "chrome_frame/chrome_frame_activex.h"
36 #include "chrome_frame/chrome_frame_automation.h"
37 #include "chrome_frame/chrome_frame_reporting.h"
38 #include "chrome_frame/chrome_launcher_utils.h"
39 #include "chrome_frame/chrome_protocol.h"
40 #include "chrome_frame/dll_redirector.h"
41 #include "chrome_frame/exception_barrier.h"
42 #include "chrome_frame/pin_module.h"
43 #include "chrome_frame/resource.h"
44 #include "chrome_frame/utils.h"
45 #include "components/variations/entropy_provider.h"
46 #include "grit/chrome_frame_resources.h"
47 #include "url/url_util.h"
49 #if _ATL_VER >= 0x0C00
50 // This was removed between the VS2010 version and the VS2013 version, and
51 // the unsuffixed version was repurposed to mean 'S'.
52 #define UpdateRegistryFromResourceS UpdateRegistryFromResource
55 using base::win::RegKey
;
59 const wchar_t kInternetSettings
[] =
60 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
62 const wchar_t kProtocolHandlers
[] =
63 L
"Software\\Classes\\Protocols\\Handler";
65 const wchar_t kRunOnce
[] =
66 L
"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
68 const wchar_t kRunKeyName
[] = L
"ChromeFrameHelper";
70 const wchar_t kChromeFrameHelperExe
[] = L
"chrome_frame_helper.exe";
71 const wchar_t kChromeFrameHelperStartupArg
[] = L
"--startup";
73 // Window class and window names.
74 // TODO(robertshield): These and other constants need to be refactored into
75 // a common chrome_frame_constants.h|cc and built into a separate lib
76 // (either chrome_frame_utils or make another one).
77 const wchar_t kChromeFrameHelperWindowClassName
[] =
78 L
"ChromeFrameHelperWindowClass";
79 const wchar_t kChromeFrameHelperWindowName
[] =
80 L
"ChromeFrameHelperWindowName";
82 // {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
83 const GUID kChromeFrameProvider
=
84 { 0x562bfc3, 0x2550, 0x45b4,
85 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
87 const wchar_t kPostPlatformUAKey
[] =
88 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
89 L
"User Agent\\Post Platform";
90 const wchar_t kChromeFramePrefix
[] = L
"chromeframe/";
92 // See comments in DllGetClassObject.
93 LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr
= NULL
;
95 // This function has the side effect of initializing an unprotected
96 // vector pointer inside GoogleUrl. If this is called during DLL loading,
97 // it has the effect of avoiding an initialization race on that pointer.
98 // TODO(siggi): fix GoogleUrl.
99 void InitGoogleUrl() {
100 static const char kDummyUrl
[] = "http://www.google.com";
102 url_util::IsStandard(kDummyUrl
,
103 url_parse::MakeRange(0, arraysize(kDummyUrl
)));
106 class ChromeTabModule
: public CAtlDllModuleT
<ChromeTabModule
> {
108 typedef CAtlDllModuleT
<ChromeTabModule
> ParentClass
;
110 ChromeTabModule() : do_system_registration_(true), crash_reporting_(NULL
) {}
112 DECLARE_LIBID(LIBID_ChromeTabLib
)
113 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CHROMETAB
,
114 "{FD9B1B31-F4D8-436A-8F4F-D3C2E36733D3}")
116 // Override to add our SYSTIME binary value to registry scripts.
117 // See chrome_frame_activex.rgs for usage.
118 virtual HRESULT
AddCommonRGSReplacements(IRegistrarBase
* registrar
) throw() {
119 HRESULT hr
= ParentClass::AddCommonRGSReplacements(registrar
);
122 SYSTEMTIME local_time
;
123 ::GetSystemTime(&local_time
);
124 std::string
hex(base::HexEncode(&local_time
, sizeof(local_time
)));
125 base::StringPiece
sp_hex(hex
);
126 hr
= registrar
->AddReplacement(L
"SYSTIME",
127 base::SysNativeMBToWide(sp_hex
).c_str());
128 DCHECK(SUCCEEDED(hr
));
132 base::FilePath app_path
=
133 chrome_launcher::GetChromeExecutablePath().DirName();
134 hr
= registrar
->AddReplacement(L
"CHROME_APPPATH",
135 app_path
.value().c_str());
136 DCHECK(SUCCEEDED(hr
));
140 hr
= registrar
->AddReplacement(L
"CHROME_APPNAME",
141 chrome::kBrowserProcessExecutableName
);
142 DCHECK(SUCCEEDED(hr
));
144 // Fill in VERSION from the VERSIONINFO stored in the DLL's resources.
145 scoped_ptr
<FileVersionInfo
> module_version_info(
146 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
147 DCHECK(module_version_info
!= NULL
);
148 std::wstring
file_version(module_version_info
->file_version());
149 hr
= registrar
->AddReplacement(L
"VERSION", file_version
.c_str());
150 DCHECK(SUCCEEDED(hr
));
154 // Add the directory of chrome_launcher.exe. This will be the same
155 // as the directory for the current DLL.
156 std::wstring module_dir
;
157 base::FilePath module_path
;
158 if (PathService::Get(base::FILE_MODULE
, &module_path
)) {
159 module_dir
= module_path
.DirName().value();
163 hr
= registrar
->AddReplacement(L
"CHROME_LAUNCHER_APPPATH",
165 DCHECK(SUCCEEDED(hr
));
169 // Add the filename of chrome_launcher.exe
170 hr
= registrar
->AddReplacement(L
"CHROME_LAUNCHER_APPNAME",
171 chrome_launcher::kLauncherExeBaseName
);
172 DCHECK(SUCCEEDED(hr
));
176 // Add the registry hive to use.
177 // Note: This is ugly as hell. I'd rather use the pMapEntries parameter
178 // to CAtlModule::UpdateRegistryFromResource, unfortunately we have a
179 // few components that are registered by calling their
180 // static T::UpdateRegistry() methods directly, which doesn't allow
181 // pMapEntries to be passed through :-(
182 if (do_system_registration_
) {
183 hr
= registrar
->AddReplacement(L
"HIVE", L
"HKLM");
185 hr
= registrar
->AddReplacement(L
"HIVE", L
"HKCU");
187 DCHECK(SUCCEEDED(hr
));
191 // Add the Chrome Frame CLSID.
192 wchar_t cf_clsid
[64];
193 StringFromGUID2(CLSID_ChromeFrame
, &cf_clsid
[0], arraysize(cf_clsid
));
194 hr
= registrar
->AddReplacement(L
"CHROME_FRAME_CLSID", &cf_clsid
[0]);
200 // The module is "locked" when an object takes a reference on it. The first
201 // time it is locked, take a reference on crash reporting to bind its lifetime
203 virtual LONG
Lock() throw() {
204 LONG result
= ParentClass::Lock();
206 DCHECK_EQ(crash_reporting_
,
207 static_cast<chrome_frame::ScopedCrashReporting
*>(NULL
));
208 crash_reporting_
= new chrome_frame::ScopedCrashReporting();
213 // The module is "unlocked" when an object that had a reference on it is
214 // destroyed. The last time it is unlocked, release the reference on crash
216 virtual LONG
Unlock() throw() {
217 LONG result
= ParentClass::Unlock();
219 DCHECK_NE(crash_reporting_
,
220 static_cast<chrome_frame::ScopedCrashReporting
*>(NULL
));
221 delete crash_reporting_
;
222 crash_reporting_
= NULL
;
227 // See comments in AddCommonRGSReplacements
228 bool do_system_registration_
;
231 // A scoper created when the module is initially locked and destroyed when it
232 // is finally unlocked. This is not a scoped_ptr since that could cause
233 // reporting to shut down at exit, which would lead to problems with the
235 chrome_frame::ScopedCrashReporting
* crash_reporting_
;
238 ChromeTabModule _AtlModule
;
240 base::AtExitManager
* g_exit_manager
= NULL
;
242 HRESULT
RefreshElevationPolicy() {
243 const wchar_t kIEFrameDll
[] = L
"ieframe.dll";
244 const char kIERefreshPolicy
[] = "IERefreshElevationPolicy";
245 HRESULT hr
= E_NOTIMPL
;
247 // Stick an SEH in the chain to prevent the VEH from picking up on first
248 // chance exceptions caused by loading ieframe.dll. Use the vanilla
249 // ExceptionBarrier to report any exceptions that do make their way to us
251 ExceptionBarrier barrier
;
253 HMODULE ieframe_module
= LoadLibrary(kIEFrameDll
);
254 if (ieframe_module
) {
255 typedef HRESULT (__stdcall
*IERefreshPolicy
)();
256 IERefreshPolicy ie_refresh_policy
= reinterpret_cast<IERefreshPolicy
>(
257 GetProcAddress(ieframe_module
, kIERefreshPolicy
));
259 if (ie_refresh_policy
) {
260 hr
= ie_refresh_policy();
262 hr
= HRESULT_FROM_WIN32(GetLastError());
265 FreeLibrary(ieframe_module
);
267 hr
= HRESULT_FROM_WIN32(GetLastError());
273 // Experimental boot prefetch optimization for Chrome Frame
275 // If chrome is warmed up during a single reboot, it gets paged
276 // in for subsequent reboots and the cold startup times essentially
277 // look like warm times thereafter! The 'warm up' is done by
278 // setting up a 'RunOnce' key during DLLRegisterServer of
279 // npchrome_frame.dll.
281 // This works because chrome prefetch becomes part of boot
282 // prefetch file ntosboot-b00dfaad.pf and paged in on subsequent
283 // reboots. As long as the sytem does not undergo significant
284 // memory pressure those pages remain in memory and we get pretty
285 // amazing startup times, down to about 300 ms from 1200 ms
288 // - Whether chrome frame is used or not, there's a read penalty
289 // (1200-300 =) 900 ms for every boot.
290 // - Heavy system memory usage after reboot will nullify the benefits
291 // but the user will still pay the cost.
292 // - Overall the time saved will always be less than total time spent
294 // - We are not sure when the chrome 'warm up' will age out from the
295 // boot prefetch file.
297 // The idea here is to try this out on chrome frame dev channel
298 // and see if it produces a significant drift in startup numbers.
299 HRESULT
SetupRunOnce() {
300 HRESULT result
= E_FAIL
;
302 string16 channel_name
;
303 if (base::win::GetVersion() < base::win::VERSION_VISTA
&&
304 GoogleUpdateSettings::GetChromeChannelAndModifiers(true, &channel_name
)) {
305 std::transform(channel_name
.begin(), channel_name
.end(),
306 channel_name
.begin(), tolower
);
307 // Use this only for the dev channel.
308 if (channel_name
.find(L
"dev") != string16::npos
) {
309 HKEY hive
= HKEY_CURRENT_USER
;
310 if (IsSystemProcess()) {
311 // For system installs, our updates will be running as SYSTEM which
312 // makes writing to a RunOnce key under HKCU not so terribly useful.
313 hive
= HKEY_LOCAL_MACHINE
;
317 LONG ret
= run_once
.Create(hive
, kRunOnce
, KEY_READ
| KEY_WRITE
);
318 if (ret
== ERROR_SUCCESS
) {
319 CommandLine
run_once_cmd(chrome_launcher::GetChromeExecutablePath());
320 run_once_cmd
.AppendSwitchASCII(switches::kAutomationClientChannelID
,
322 run_once_cmd
.AppendSwitch(switches::kChromeFrame
);
323 ret
= run_once
.WriteValue(L
"A",
324 run_once_cmd
.GetCommandLineString().c_str());
326 result
= HRESULT_FROM_WIN32(ret
);
331 // We're on a non-XP version of Windows or on a stable channel. Nothing
339 // Helper method called for user-level installs where we don't have admin
340 // permissions. Starts up the long running process and registers it to get it
341 // started at next boot.
342 HRESULT
SetupUserLevelHelper() {
345 // Remove existing run-at-startup entry.
346 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER
, kRunKeyName
);
348 // Build the chrome_frame_helper command line.
349 base::FilePath module_path
;
350 base::FilePath helper_path
;
351 if (PathService::Get(base::FILE_MODULE
, &module_path
)) {
352 module_path
= module_path
.DirName();
353 helper_path
= module_path
.Append(kChromeFrameHelperExe
);
354 if (!base::PathExists(helper_path
)) {
355 // If we can't find the helper in the current directory, try looking
356 // one up (this is the layout in the build output folder).
357 module_path
= module_path
.DirName();
358 helper_path
= module_path
.Append(kChromeFrameHelperExe
);
359 DCHECK(base::PathExists(helper_path
)) <<
360 "Could not find chrome_frame_helper.exe.";
363 // Find window handle of existing instance.
364 HWND old_window
= FindWindow(kChromeFrameHelperWindowClassName
,
365 kChromeFrameHelperWindowName
);
367 if (base::PathExists(helper_path
)) {
368 std::wstring
helper_path_cmd(L
"\"");
369 helper_path_cmd
+= helper_path
.value();
370 helper_path_cmd
+= L
"\" ";
371 helper_path_cmd
+= kChromeFrameHelperStartupArg
;
373 // Add new run-at-startup entry.
374 if (!base::win::AddCommandToAutoRun(HKEY_CURRENT_USER
, kRunKeyName
,
377 LOG(ERROR
) << "Could not add helper process to auto run key.";
380 // Start new instance.
381 base::LaunchOptions options
;
382 options
.start_hidden
= true;
383 bool launched
= base::LaunchProcess(helper_path
.value(), options
, NULL
);
386 PLOG(DFATAL
) << "Could not launch helper process.";
389 // Kill old instance using window handle.
390 if (IsWindow(old_window
)) {
391 BOOL result
= PostMessage(old_window
, WM_CLOSE
, 0, 0);
393 PLOG(ERROR
) << "Failed to post close message to old helper process: ";
397 hr
= HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
407 // To delete the user agent, set value to NULL.
408 // The is_system parameter indicates whether this is a per machine or a per
409 // user installation.
410 HRESULT
SetChromeFrameUA(bool is_system
, const wchar_t* value
) {
412 HKEY parent_hive
= is_system
? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
;
415 LONG reg_result
= ua_key
.Create(parent_hive
, kPostPlatformUAKey
,
416 KEY_READ
| KEY_WRITE
);
417 if (reg_result
== ERROR_SUCCESS
) {
418 // Make sure that we unregister ChromeFrame UA strings registered previously
419 wchar_t value_name
[MAX_PATH
+ 1] = {};
420 wchar_t value_data
[MAX_PATH
+ 1] = {};
422 DWORD value_index
= 0;
423 while (value_index
< ua_key
.GetValueCount()) {
424 DWORD name_size
= arraysize(value_name
);
425 DWORD value_size
= arraysize(value_data
);
427 LRESULT ret
= ::RegEnumValue(ua_key
.Handle(), value_index
, value_name
,
428 &name_size
, NULL
, &type
,
429 reinterpret_cast<BYTE
*>(value_data
),
431 if (ret
== ERROR_SUCCESS
) {
432 if (StartsWith(value_name
, kChromeFramePrefix
, false)) {
433 ua_key
.DeleteValue(value_name
);
442 std::wstring chrome_frame_ua_value_name
= kChromeFramePrefix
;
443 chrome_frame_ua_value_name
+= GetCurrentModuleVersion();
445 ua_key
.WriteValue(chrome_frame_ua_value_name
.c_str(), value
);
449 DLOG(ERROR
) << __FUNCTION__
<< ": " << kPostPlatformUAKey
450 << ", error code = " << reg_result
;
451 hr
= HRESULT_FROM_WIN32(reg_result
);
456 class SecurityDescBackup
{
458 explicit SecurityDescBackup(const std::wstring
& backup_key
)
459 : backup_key_name_(backup_key
) {}
460 ~SecurityDescBackup() {}
462 // Save given security descriptor to the backup key.
463 bool SaveSecurity(const CSecurityDesc
& sd
) {
465 if (!sd
.ToString(&str
))
468 RegKey
backup_key(HKEY_LOCAL_MACHINE
, backup_key_name_
.c_str(),
469 KEY_READ
| KEY_WRITE
);
470 if (backup_key
.Valid()) {
471 return backup_key
.WriteValue(NULL
, str
.GetString()) == ERROR_SUCCESS
;
477 // Restore security descriptor from backup key to given key name.
478 bool RestoreSecurity(const wchar_t* key_name
) {
480 if (!ReadBackupKey(&sddl
))
483 // Create security descriptor from string.
485 if (!sd
.FromString(sddl
.c_str()))
489 // Restore DACL and Owner of the key from saved security descriptor.
495 DWORD error
= ::SetNamedSecurityInfo(const_cast<wchar_t*>(key_name
),
496 SE_REGISTRY_KEY
, OWNER_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
497 const_cast<SID
*>(owner
.GetPSID()), NULL
,
498 const_cast<ACL
*>(dacl
.GetPACL()), NULL
);
501 return (error
== ERROR_SUCCESS
);
505 // Read SDDL string from backup key
506 bool ReadBackupKey(std::wstring
* sddl
) {
507 RegKey
backup_key(HKEY_LOCAL_MACHINE
, backup_key_name_
.c_str(), KEY_READ
);
508 if (!backup_key
.Valid())
512 DWORD reg_type
= REG_NONE
;
513 if (backup_key
.ReadValue(NULL
, NULL
, &len
, ®_type
) != ERROR_SUCCESS
)
515 DCHECK_EQ(0u, len
% sizeof(wchar_t));
517 if ((len
== 0) || (reg_type
!= REG_SZ
))
520 size_t wchar_count
= 1 + len
/ sizeof(wchar_t);
521 if (backup_key
.ReadValue(NULL
, WriteInto(sddl
, wchar_count
), &len
,
522 ®_type
) != ERROR_SUCCESS
) {
529 void DeleteBackupKey() {
530 ::RegDeleteKey(HKEY_LOCAL_MACHINE
, backup_key_name_
.c_str());
533 std::wstring backup_key_name_
;
536 struct TokenWithPrivileges
{
537 TokenWithPrivileges() {
538 token_
.GetEffectiveToken(TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
);
539 token_
.GetUser(&user_
);
542 ~TokenWithPrivileges() {
543 token_
.EnableDisablePrivileges(take_ownership_
);
544 token_
.EnableDisablePrivileges(restore_
);
547 bool EnablePrivileges() {
548 if (take_ownership_
.GetCount() == 0)
549 if (!token_
.EnablePrivilege(L
"SeTakeOwnershipPrivilege",
553 if (restore_
.GetCount() == 0)
554 if (!token_
.EnablePrivilege(L
"SeRestorePrivilege", &restore_
))
560 const CSid
& GetUser() const {
566 CTokenPrivileges take_ownership_
;
567 CTokenPrivileges restore_
;
571 const wchar_t* const kMimeHandlerKeyValues
[] = {
572 L
"ChromeTab.ChromeActiveDocument",
573 L
"ChromeTab.ChromeActiveDocument.1",
576 // Returns true if the values are present or absent in |root_key|'s Secure Mime
577 // Handlers key based on |for_installed|. Returns false if the values are not as
578 // expected or if an error occurred.
579 bool MimeHandlerKeyIsConfigured(bool for_install
, HKEY root_key
) {
580 string16
key_name(kInternetSettings
);
581 key_name
.append(L
"\\Secure Mime Handlers");
582 RegKey
key(root_key
, key_name
.c_str(), KEY_QUERY_VALUE
);
586 for (size_t i
= 0; i
< arraysize(kMimeHandlerKeyValues
); ++i
) {
588 LONG result
= key
.ReadValueDW(kMimeHandlerKeyValues
[i
], &value
);
590 if (result
!= ERROR_SUCCESS
|| value
!= 1)
593 if (result
!= ERROR_FILE_NOT_FOUND
)
600 HRESULT
SetOrDeleteMimeHandlerKey(bool set
, HKEY root_key
) {
601 string16
key_name(kInternetSettings
);
602 key_name
.append(L
"\\Secure Mime Handlers");
603 RegKey
key(root_key
, key_name
.c_str(), KEY_SET_VALUE
);
607 HRESULT result
= S_OK
;
608 for (size_t i
= 0; i
< arraysize(kMimeHandlerKeyValues
); ++i
) {
609 LONG intermediate
= set
?
610 key
.WriteValue(kMimeHandlerKeyValues
[i
], 1) :
611 key
.DeleteValue(kMimeHandlerKeyValues
[i
]);
612 if (intermediate
!= ERROR_SUCCESS
&& result
== S_OK
)
613 result
= HRESULT_FROM_WIN32(intermediate
);
619 // Pin crash reporting by leaking a reference.
620 ignore_result(new chrome_frame::ScopedCrashReporting());
623 // Chrome Frame registration functions.
624 //-----------------------------------------------------------------------------
625 HRESULT
RegisterSecuredMimeHandler(bool enable
, bool is_system
) {
626 if (MimeHandlerKeyIsConfigured(enable
, HKEY_LOCAL_MACHINE
))
629 return SetOrDeleteMimeHandlerKey(enable
, HKEY_CURRENT_USER
);
630 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
631 return SetOrDeleteMimeHandlerKey(enable
, HKEY_LOCAL_MACHINE
);
633 std::wstring mime_key
= kInternetSettings
;
634 mime_key
.append(L
"\\Secure Mime Handlers");
635 std::wstring backup_key
= kInternetSettings
;
636 backup_key
.append(L
"\\__backup_SMH__");
637 std::wstring object_name
= L
"MACHINE\\";
638 object_name
.append(mime_key
);
640 TokenWithPrivileges token_
;
641 if (!token_
.EnablePrivileges())
642 return E_ACCESSDENIED
;
644 // If there is a backup key - something bad happened; try to restore
645 // security on "Secure Mime Handlers" from the backup.
646 SecurityDescBackup
backup(backup_key
);
647 backup
.RestoreSecurity(object_name
.c_str());
649 // Read old security descriptor of the Mime key first.
651 if (!AtlGetSecurityDescriptor(object_name
.c_str(), SE_REGISTRY_KEY
, &sd
)) {
655 backup
.SaveSecurity(sd
);
658 if (AtlSetOwnerSid(object_name
.c_str(), SE_REGISTRY_KEY
, token_
.GetUser())) {
661 sd
.GetDacl(&new_dacl
);
662 new_dacl
.AddAllowedAce(token_
.GetUser(), GENERIC_WRITE
| GENERIC_READ
);
663 if (AtlSetDacl(object_name
.c_str(), SE_REGISTRY_KEY
, new_dacl
)) {
664 hr
= SetOrDeleteMimeHandlerKey(enable
, HKEY_LOCAL_MACHINE
);
668 backup
.RestoreSecurity(object_name
.c_str());
672 HRESULT
RegisterActiveDoc(bool reg
, bool is_system
) {
673 // We have to call the static T::UpdateRegistry function instead of
674 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEDOC, reg)
675 // because there is specific OLEMISC replacement.
676 return ChromeActiveDocument::UpdateRegistry(reg
);
679 HRESULT
RegisterActiveX(bool reg
, bool is_system
) {
680 // We have to call the static T::UpdateRegistry function instead of
681 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEX, reg)
682 // because there is specific OLEMISC replacement.
683 return ChromeFrameActivex::UpdateRegistry(reg
);
686 HRESULT
RegisterElevationPolicy(bool reg
, bool is_system
) {
688 if (base::win::GetVersion() >= base::win::VERSION_VISTA
) {
689 // Register the elevation policy. This must succeed for Chrome Frame to
690 // be able launch Chrome when running in low-integrity IE.
691 hr
= _AtlModule
.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ELEVATION
, reg
);
693 // Ignore failures since old versions of IE 7 (e.g., 7.0.6000.16386, which
694 // shipped with Vista RTM) do not export IERefreshElevationPolicy.
695 RefreshElevationPolicy();
701 HRESULT
RegisterProtocol(bool reg
, bool is_system
) {
702 return _AtlModule
.UpdateRegistryFromResourceS(IDR_CHROMEPROTOCOL
, reg
);
705 HRESULT
RegisterBhoClsid(bool reg
, bool is_system
) {
706 return Bho::UpdateRegistry(reg
);
709 HRESULT
RegisterBhoIE(bool reg
, bool is_system
) {
711 return _AtlModule
.UpdateRegistryFromResourceS(IDR_REGISTER_BHO
, reg
);
714 // Setup the long running process:
715 return SetupUserLevelHelper();
717 // Unschedule the user-level helper. Note that we don't kill it here
718 // so that during updates we don't have a time window with no running
719 // helper. Uninstalls and updates will explicitly kill the helper from
720 // within the installer. Unregister existing run-at-startup entry.
721 return base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER
,
722 kRunKeyName
) ? S_OK
: E_FAIL
;
727 HRESULT
RegisterTypeLib(bool reg
, bool is_system
) {
728 if (reg
&& !is_system
) {
729 // Enables the RegisterTypeLib Function function to override default
730 // registry mappings under Windows Vista Service Pack 1 (SP1),
731 // Windows Server 2008, and later operating system versions
732 typedef void (WINAPI
* OaEnablePerUserTypeLibReg
)(void);
733 OaEnablePerUserTypeLibReg per_user_typelib_func
=
734 reinterpret_cast<OaEnablePerUserTypeLibReg
>(
735 GetProcAddress(GetModuleHandle(L
"oleaut32.dll"),
736 "OaEnablePerUserTLibRegistration"));
737 if (per_user_typelib_func
) {
738 (*per_user_typelib_func
)();
742 UtilRegisterTypeLib(_AtlComModule
.m_hInstTypeLib
,
744 UtilUnRegisterTypeLib(_AtlComModule
.m_hInstTypeLib
,
748 HRESULT
RegisterLegacyNPAPICleanup(bool reg
, bool is_system
) {
750 _AtlModule
.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI
, reg
);
751 UtilRemovePersistentNPAPIMarker();
757 HRESULT
RegisterAppId(bool reg
, bool is_system
) {
758 return _AtlModule
.UpdateRegistryAppId(reg
);
761 HRESULT
RegisterUserAgent(bool reg
, bool is_system
) {
763 return SetChromeFrameUA(is_system
, L
"1");
765 return SetChromeFrameUA(is_system
, NULL
);
769 enum RegistrationStepId
{
770 kStepSecuredMimeHandler
= 0,
773 kStepElevationPolicy
= 3,
776 kStepBhoRegistration
= 6,
777 kStepRegisterTypeLib
= 7,
778 kStepNpapiCleanup
= 8,
784 enum RegistrationFlags
{
787 GCF_PROTOCOL
= 0x0004,
789 BHO_REGISTRATION
= 0x0010,
795 // Mux the failure step into the hresult. We take only the first four bits
796 // and stick those into the top four bits of the facility code. We also set the
797 // Customer bit to be polite. Graphically, we write our error code to the
798 // bits marked with ^:
799 // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
800 // 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
801 // +---+-+-+-----------------------+-------------------------------+
802 // |Sev|C|R| Facility | Code |
803 // +---+-+-+-----------------------+-------------------------------+
805 // See http://msdn.microsoft.com/en-us/library/cc231198(PROT.10).aspx for
806 // more details on HRESULTS.
808 // The resulting error can be extracted by:
809 // error_code = (fiddled_hr & 0x07800000) >> 23
810 HRESULT
MuxErrorIntoHRESULT(HRESULT hr
, int error_code
) {
811 DCHECK_GE(error_code
, 0);
812 DCHECK_LT(error_code
, kStepEnd
);
813 COMPILE_ASSERT(kStepEnd
<= 0xF, update_error_muxing_too_many_steps
);
815 // Check that our four desired bits are clear.
816 // 0xF87FFFFF == 11111000011111111111111111111111
817 DCHECK_EQ(static_cast<HRESULT
>(hr
& 0xF87FFFFF), hr
);
819 HRESULT fiddled_hr
= ((error_code
& 0xF) << 23) | hr
;
820 fiddled_hr
|= 1 << 29; // Set the customer bit.
825 HRESULT
CustomRegistration(uint16 reg_flags
, bool reg
, bool is_system
) {
826 if (reg
&& (reg_flags
& (ACTIVEDOC
| ACTIVEX
)))
827 reg_flags
|= (TYPELIB
| GCF_PROTOCOL
);
829 // Set the flag that gets checked in AddCommonRGSReplacements before doing
830 // registration work.
831 _AtlModule
.do_system_registration_
= is_system
;
833 typedef HRESULT (*RegistrationFn
)(bool reg
, bool is_system
);
834 struct RegistrationStep
{
835 RegistrationStepId id
;
839 static const RegistrationStep registration_steps
[] = {
840 { kStepSecuredMimeHandler
, ACTIVEDOC
, &RegisterSecuredMimeHandler
},
841 { kStepActiveDoc
, ACTIVEDOC
, &RegisterActiveDoc
},
842 { kStepActiveX
, ACTIVEX
, &RegisterActiveX
},
843 { kStepElevationPolicy
, (ACTIVEDOC
| ACTIVEX
), &RegisterElevationPolicy
},
844 { kStepProtocol
, GCF_PROTOCOL
, &RegisterProtocol
},
845 { kStepBhoClsid
, BHO_CLSID
, &RegisterBhoClsid
},
846 { kStepBhoRegistration
, BHO_REGISTRATION
, &RegisterBhoIE
},
847 { kStepRegisterTypeLib
, TYPELIB
, &RegisterTypeLib
},
848 { kStepNpapiCleanup
, ALL
, &RegisterLegacyNPAPICleanup
},
849 { kStepAppId
, ALL
, &RegisterAppId
},
850 { kStepUserAgent
, ALL
, &RegisterUserAgent
}
855 bool rollback
= false;
856 int failure_step
= 0;
857 HRESULT step_hr
= S_OK
;
858 for (int step
= 0; step
< arraysize(registration_steps
); ++step
) {
859 if ((reg_flags
& registration_steps
[step
].condition
) != 0) {
860 step_hr
= registration_steps
[step
].func(reg
, is_system
);
861 if (FAILED(step_hr
)) {
862 // Store only the first failing HRESULT with the step value muxed in.
864 hr
= MuxErrorIntoHRESULT(step_hr
, step
);
867 // On registration if a step fails, we abort and rollback.
879 // Rollback the failing action and all preceding ones.
880 for (int step
= failure_step
; step
>= 0; --step
) {
881 registration_steps
[step
].func(!reg
, is_system
);
891 extern "C" BOOL WINAPI
DllMain(HINSTANCE instance
,
894 UNREFERENCED_PARAMETER(instance
);
895 if (reason
== DLL_PROCESS_ATTACH
) {
896 #if _ATL_VER < 0x0C00 && !defined(NDEBUG)
897 // Silence traces from the ATL registrar to reduce the log noise.
898 ATL::CTrace::s_trace
.ChangeCategory(atlTraceRegistrar
, 0,
899 ATLTRACESTATUS_DISABLED
);
903 g_exit_manager
= new base::AtExitManager();
904 CommandLine::Init(0, NULL
);
905 logging::LoggingSettings settings
;
906 settings
.logging_dest
= logging::LOG_TO_SYSTEM_DEBUG_LOG
;
907 logging::InitLogging(settings
);
909 // Log the same items as Chrome.
910 logging::SetLogItems(true, // enable_process_id
911 true, // enable_thread_id
912 false, // enable_timestamp
913 true); // enable_tickcount
915 DllRedirector
* dll_redirector
= DllRedirector::GetInstance();
916 DCHECK(dll_redirector
);
918 if (!dll_redirector
->RegisterAsFirstCFModule()) {
919 // Someone else was here first, try and get a pointer to their
920 // DllGetClassObject export:
921 g_dll_get_class_object_redir_ptr
=
922 dll_redirector
->GetDllGetClassObjectPtr();
923 DCHECK(g_dll_get_class_object_redir_ptr
!= NULL
)
924 << "Found CF module with no DllGetClassObject export.";
927 // Enable trace control and transport through event tracing for Windows.
928 logging::LogEventProvider::Initialize(kChromeFrameProvider
);
930 // Set a callback so that crash reporting can be pinned when the module is
932 chrome_frame::SetPinModuleCallback(&OnPinModule
);
933 } else if (reason
== DLL_PROCESS_DETACH
) {
934 DllRedirector
* dll_redirector
= DllRedirector::GetInstance();
935 DCHECK(dll_redirector
);
936 dll_redirector
->UnregisterAsFirstCFModule();
938 g_patch_helper
.UnpatchIfNeeded();
940 delete g_exit_manager
;
941 g_exit_manager
= NULL
;
943 return _AtlModule
.DllMain(reason
, reserved
);
946 // Used to determine whether the DLL can be unloaded by OLE
947 STDAPI
DllCanUnloadNow() {
948 return _AtlModule
.DllCanUnloadNow();
951 // Returns a class factory to create an object of the requested type
952 STDAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
* ppv
) {
953 chrome_frame::ScopedCrashReporting crash_reporting
;
955 // IE 11+ are unsupported.
956 if (GetIEVersion() > IE_10
) {
957 return CLASS_E_CLASSNOTAVAILABLE
;
960 // If we found another module present when we were loaded, then delegate to
962 if (g_dll_get_class_object_redir_ptr
) {
963 return g_dll_get_class_object_redir_ptr(rclsid
, riid
, ppv
);
966 // Enable sniffing and switching only if asked for BHO
967 // (we use BHO to get loaded in IE).
968 if (rclsid
== CLSID_ChromeFrameBHO
) {
969 g_patch_helper
.InitializeAndPatchProtocolsIfNeeded();
972 return _AtlModule
.DllGetClassObject(rclsid
, riid
, ppv
);
975 // DllRegisterServer - Adds entries to the system registry
976 STDAPI
DllRegisterServer() {
977 chrome_frame::ScopedCrashReporting crash_reporting
;
978 uint16 flags
= ACTIVEX
| ACTIVEDOC
| TYPELIB
| GCF_PROTOCOL
|
979 BHO_CLSID
| BHO_REGISTRATION
;
981 HRESULT hr
= CustomRegistration(flags
, true, true);
989 // DllUnregisterServer - Removes entries from the system registry
990 STDAPI
DllUnregisterServer() {
991 chrome_frame::ScopedCrashReporting crash_reporting
;
992 HRESULT hr
= CustomRegistration(ALL
, false, true);
996 // DllRegisterUserServer - Adds entries to the HKCU hive in the registry.
997 STDAPI
DllRegisterUserServer() {
998 chrome_frame::ScopedCrashReporting crash_reporting
;
999 UINT flags
= ACTIVEX
| ACTIVEDOC
| TYPELIB
| GCF_PROTOCOL
|
1000 BHO_CLSID
| BHO_REGISTRATION
;
1002 HRESULT hr
= CustomRegistration(flags
, TRUE
, false);
1003 if (SUCCEEDED(hr
)) {
1010 // DllUnregisterUserServer - Removes entries from the HKCU hive in the registry.
1011 STDAPI
DllUnregisterUserServer() {
1012 chrome_frame::ScopedCrashReporting crash_reporting
;
1013 HRESULT hr
= CustomRegistration(ALL
, FALSE
, false);
1017 // Object entries go here instead of with each object, so that we can move
1018 // the objects to a lib. Also reduces magic.
1019 OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO
, Bho
)
1020 OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument
), ChromeActiveDocument
)
1021 OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame
), ChromeFrameActivex
)
1022 OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol
), ChromeProtocol
)