Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / win8 / delegate_execute / delegate_execute.cc
blob3bd1ef151b2498adedff7c32ba561b7085efcb93
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 <atlbase.h>
6 #include <atlcom.h>
7 #include <atlctl.h>
8 #include <initguid.h>
9 #include <shellapi.h>
11 #include "base/at_exit.h"
12 #include "base/command_line.h"
13 #include "base/file_util.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/process/kill.h"
16 #include "base/strings/string16.h"
17 #include "base/win/scoped_com_initializer.h"
18 #include "base/win/scoped_comptr.h"
19 #include "base/win/scoped_handle.h"
20 #include "breakpad/src/client/windows/handler/exception_handler.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/installer/util/browser_distribution.h"
23 #include "win8/delegate_execute/command_execute_impl.h"
24 #include "win8/delegate_execute/crash_server_init.h"
25 #include "win8/delegate_execute/delegate_execute_operation.h"
26 #include "win8/delegate_execute/resource.h"
28 using namespace ATL;
30 // Usually classes derived from CAtlExeModuleT, or other types of ATL
31 // COM module classes statically define their CLSID at compile time through
32 // the use of various macros, and ATL internals takes care of creating the
33 // class objects and registering them. However, we need to register the same
34 // object with different CLSIDs depending on a runtime setting, so we handle
35 // that logic here, before the main ATL message loop runs.
36 class DelegateExecuteModule
37 : public ATL::CAtlExeModuleT< DelegateExecuteModule > {
38 public :
39 typedef ATL::CAtlExeModuleT<DelegateExecuteModule> ParentClass;
40 typedef CComObject<CommandExecuteImpl> ImplType;
42 DelegateExecuteModule()
43 : registration_token_(0) {
46 HRESULT PreMessageLoop(int nShowCmd) {
47 HRESULT hr = S_OK;
48 base::string16 clsid_string;
49 GUID clsid;
50 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
51 if (!dist->GetCommandExecuteImplClsid(&clsid_string))
52 return E_FAIL;
53 hr = ::CLSIDFromString(clsid_string.c_str(), &clsid);
54 if (FAILED(hr))
55 return hr;
57 // We use the same class creation logic as ATL itself. See
58 // _ATL_OBJMAP_ENTRY::RegisterClassObject() in atlbase.h
59 hr = ImplType::_ClassFactoryCreatorClass::CreateInstance(
60 ImplType::_CreatorClass::CreateInstance, IID_IUnknown,
61 instance_.ReceiveVoid());
62 if (FAILED(hr))
63 return hr;
64 hr = ::CoRegisterClassObject(clsid, instance_, CLSCTX_LOCAL_SERVER,
65 REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &registration_token_);
66 if (FAILED(hr))
67 return hr;
69 return ParentClass::PreMessageLoop(nShowCmd);
72 HRESULT PostMessageLoop() {
73 if (registration_token_ != 0) {
74 ::CoRevokeClassObject(registration_token_);
75 registration_token_ = 0;
78 instance_.Release();
80 return ParentClass::PostMessageLoop();
83 private:
84 base::win::ScopedComPtr<IUnknown> instance_;
85 DWORD registration_token_;
88 DelegateExecuteModule _AtlModule;
90 using delegate_execute::DelegateExecuteOperation;
91 using base::win::ScopedHandle;
93 int RelaunchChrome(const DelegateExecuteOperation& operation) {
94 AtlTrace("Relaunching [%ls] with flags [%ls]\n",
95 operation.mutex().c_str(), operation.relaunch_flags().c_str());
96 ScopedHandle mutex(OpenMutexW(SYNCHRONIZE, FALSE, operation.mutex().c_str()));
97 if (mutex.IsValid()) {
98 const int kWaitSeconds = 5;
99 DWORD result = ::WaitForSingleObject(mutex, kWaitSeconds * 1000);
100 if (result == WAIT_ABANDONED) {
101 // This is the normal case. Chrome exits and windows marks the mutex as
102 // abandoned.
103 } else if (result == WAIT_OBJECT_0) {
104 // This is unexpected. Check if somebody is not closing the mutex on
105 // RelaunchChromehelper, the mutex should not be closed.
106 AtlTrace("Unexpected release of the relaunch mutex!!\n");
107 } else if (result == WAIT_TIMEOUT) {
108 // This could mean that Chrome is hung. Proceed to exterminate.
109 DWORD pid = operation.GetParentPid();
110 AtlTrace("%ds timeout. Killing Chrome %d\n", kWaitSeconds, pid);
111 base::KillProcessById(pid, 0, false);
112 } else {
113 AtlTrace("Failed to wait for relaunch mutex, result is 0x%x\n", result);
115 } else {
116 // It is possible that chrome exits so fast that the mutex is not there.
117 AtlTrace("No relaunch mutex found\n");
120 base::win::ScopedCOMInitializer com_initializer;
122 base::string16 relaunch_flags(operation.relaunch_flags());
123 SHELLEXECUTEINFO sei = { sizeof(sei) };
124 sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
125 sei.nShow = SW_SHOWNORMAL;
126 sei.lpFile = operation.shortcut().value().c_str();
127 sei.lpParameters = relaunch_flags.c_str();
129 AtlTrace(L"Relaunching Chrome via shortcut [%ls]\n", sei.lpFile);
131 if (!::ShellExecuteExW(&sei)) {
132 int error = HRESULT_FROM_WIN32(::GetLastError());
133 AtlTrace("ShellExecute returned 0x%08X\n", error);
134 return error;
136 return S_OK;
139 extern "C" int WINAPI _tWinMain(HINSTANCE , HINSTANCE, LPTSTR, int nShowCmd) {
140 scoped_ptr<google_breakpad::ExceptionHandler> breakpad =
141 delegate_execute::InitializeCrashReporting();
143 base::AtExitManager exit_manager;
144 AtlTrace("delegate_execute enter\n");
146 CommandLine::Init(0, NULL);
147 HRESULT ret_code = E_UNEXPECTED;
148 DelegateExecuteOperation operation;
149 if (operation.Init(CommandLine::ForCurrentProcess())) {
150 switch (operation.operation_type()) {
151 case DelegateExecuteOperation::DELEGATE_EXECUTE:
152 ret_code = _AtlModule.WinMain(nShowCmd);
153 break;
154 case DelegateExecuteOperation::RELAUNCH_CHROME:
155 ret_code = RelaunchChrome(operation);
156 break;
157 default:
158 NOTREACHED();
161 AtlTrace("delegate_execute exit, code = %d\n", ret_code);
162 return ret_code;