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 #include "build/intsafe_workaround.h"
13 #include "base/at_exit.h"
14 #include "base/command_line.h"
15 #include "base/file_util.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/process/kill.h"
18 #include "base/strings/string16.h"
19 #include "base/win/scoped_com_initializer.h"
20 #include "base/win/scoped_comptr.h"
21 #include "base/win/scoped_handle.h"
22 #include "breakpad/src/client/windows/handler/exception_handler.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/installer/util/browser_distribution.h"
25 #include "win8/delegate_execute/command_execute_impl.h"
26 #include "win8/delegate_execute/crash_server_init.h"
27 #include "win8/delegate_execute/delegate_execute_operation.h"
28 #include "win8/delegate_execute/resource.h"
32 // Usually classes derived from CAtlExeModuleT, or other types of ATL
33 // COM module classes statically define their CLSID at compile time through
34 // the use of various macros, and ATL internals takes care of creating the
35 // class objects and registering them. However, we need to register the same
36 // object with different CLSIDs depending on a runtime setting, so we handle
37 // that logic here, before the main ATL message loop runs.
38 class DelegateExecuteModule
39 : public ATL::CAtlExeModuleT
< DelegateExecuteModule
> {
41 typedef ATL::CAtlExeModuleT
<DelegateExecuteModule
> ParentClass
;
42 typedef CComObject
<CommandExecuteImpl
> ImplType
;
44 DelegateExecuteModule()
45 : registration_token_(0) {
48 HRESULT
PreMessageLoop(int nShowCmd
) {
50 string16 clsid_string
;
52 BrowserDistribution
* dist
= BrowserDistribution::GetDistribution();
53 if (!dist
->GetCommandExecuteImplClsid(&clsid_string
))
55 hr
= ::CLSIDFromString(clsid_string
.c_str(), &clsid
);
59 // We use the same class creation logic as ATL itself. See
60 // _ATL_OBJMAP_ENTRY::RegisterClassObject() in atlbase.h
61 hr
= ImplType::_ClassFactoryCreatorClass::CreateInstance(
62 ImplType::_CreatorClass::CreateInstance
, IID_IUnknown
,
63 instance_
.ReceiveVoid());
66 hr
= ::CoRegisterClassObject(clsid
, instance_
, CLSCTX_LOCAL_SERVER
,
67 REGCLS_MULTIPLEUSE
| REGCLS_SUSPENDED
, ®istration_token_
);
71 return ParentClass::PreMessageLoop(nShowCmd
);
74 HRESULT
PostMessageLoop() {
75 if (registration_token_
!= 0) {
76 ::CoRevokeClassObject(registration_token_
);
77 registration_token_
= 0;
82 return ParentClass::PostMessageLoop();
86 base::win::ScopedComPtr
<IUnknown
> instance_
;
87 DWORD registration_token_
;
90 DelegateExecuteModule _AtlModule
;
92 using delegate_execute::DelegateExecuteOperation
;
93 using base::win::ScopedHandle
;
95 int RelaunchChrome(const DelegateExecuteOperation
& operation
) {
96 AtlTrace("Relaunching [%ls] with flags [%s]\n",
97 operation
.mutex().c_str(), operation
.relaunch_flags());
98 ScopedHandle
mutex(OpenMutexW(SYNCHRONIZE
, FALSE
, operation
.mutex().c_str()));
99 if (mutex
.IsValid()) {
100 const int kWaitSeconds
= 5;
101 DWORD result
= ::WaitForSingleObject(mutex
, kWaitSeconds
* 1000);
102 if (result
== WAIT_ABANDONED
) {
103 // This is the normal case. Chrome exits and windows marks the mutex as
105 } else if (result
== WAIT_OBJECT_0
) {
106 // This is unexpected. Check if somebody is not closing the mutex on
107 // RelaunchChromehelper, the mutex should not be closed.
108 AtlTrace("Unexpected release of the relaunch mutex!!\n");
109 } else if (result
== WAIT_TIMEOUT
) {
110 // This could mean that Chrome is hung. Proceed to exterminate.
111 DWORD pid
= operation
.GetParentPid();
112 AtlTrace("%ds timeout. Killing Chrome %d\n", kWaitSeconds
, pid
);
113 base::KillProcessById(pid
, 0, false);
115 AtlTrace("Failed to wait for relaunch mutex, result is 0x%x\n", result
);
118 // It is possible that chrome exits so fast that the mutex is not there.
119 AtlTrace("No relaunch mutex found\n");
122 base::win::ScopedCOMInitializer com_initializer
;
124 string16
relaunch_flags(operation
.relaunch_flags());
125 SHELLEXECUTEINFO sei
= { sizeof(sei
) };
126 sei
.fMask
= SEE_MASK_FLAG_LOG_USAGE
;
127 sei
.nShow
= SW_SHOWNORMAL
;
128 sei
.lpFile
= operation
.shortcut().value().c_str();
129 sei
.lpParameters
= relaunch_flags
.c_str();
131 AtlTrace(L
"Relaunching Chrome via shortcut [%ls]\n", sei
.lpFile
);
133 if (!::ShellExecuteExW(&sei
)) {
134 int error
= HRESULT_FROM_WIN32(::GetLastError());
135 AtlTrace("ShellExecute returned 0x%08X\n", error
);
141 extern "C" int WINAPI
_tWinMain(HINSTANCE
, HINSTANCE
, LPTSTR
, int nShowCmd
) {
142 scoped_ptr
<google_breakpad::ExceptionHandler
> breakpad
=
143 delegate_execute::InitializeCrashReporting();
145 base::AtExitManager exit_manager
;
146 AtlTrace("delegate_execute enter\n");
148 CommandLine::Init(0, NULL
);
149 HRESULT ret_code
= E_UNEXPECTED
;
150 DelegateExecuteOperation operation
;
151 if (operation
.Init(CommandLine::ForCurrentProcess())) {
152 switch (operation
.operation_type()) {
153 case DelegateExecuteOperation::DELEGATE_EXECUTE
:
154 ret_code
= _AtlModule
.WinMain(nShowCmd
);
156 case DelegateExecuteOperation::RELAUNCH_CHROME
:
157 ret_code
= RelaunchChrome(operation
);
163 AtlTrace("delegate_execute exit, code = %d\n", ret_code
);