- add sources.
[platform/framework/web/crosswalk.git] / src / win8 / delegate_execute / delegate_execute.cc
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.
4
5 #include "build/intsafe_workaround.h"
6
7 #include <atlbase.h>
8 #include <atlcom.h>
9 #include <atlctl.h>
10 #include <initguid.h>
11 #include <shellapi.h>
12
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"
29
30 using namespace ATL;
31
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 > {
40  public :
41   typedef ATL::CAtlExeModuleT<DelegateExecuteModule> ParentClass;
42   typedef CComObject<CommandExecuteImpl> ImplType;
43
44   DelegateExecuteModule()
45       : registration_token_(0) {
46   }
47
48   HRESULT PreMessageLoop(int nShowCmd) {
49     HRESULT hr = S_OK;
50     string16 clsid_string;
51     GUID clsid;
52     BrowserDistribution* dist = BrowserDistribution::GetDistribution();
53     if (!dist->GetCommandExecuteImplClsid(&clsid_string))
54       return E_FAIL;
55     hr = ::CLSIDFromString(clsid_string.c_str(), &clsid);
56     if (FAILED(hr))
57       return hr;
58
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());
64     if (FAILED(hr))
65       return hr;
66     hr = ::CoRegisterClassObject(clsid, instance_, CLSCTX_LOCAL_SERVER,
67         REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &registration_token_);
68     if (FAILED(hr))
69       return hr;
70
71     return ParentClass::PreMessageLoop(nShowCmd);
72   }
73
74   HRESULT PostMessageLoop() {
75     if (registration_token_ != 0) {
76       ::CoRevokeClassObject(registration_token_);
77       registration_token_ = 0;
78     }
79
80     instance_.Release();
81
82     return ParentClass::PostMessageLoop();
83   }
84
85  private:
86   base::win::ScopedComPtr<IUnknown> instance_;
87   DWORD registration_token_;
88 };
89
90 DelegateExecuteModule _AtlModule;
91
92 using delegate_execute::DelegateExecuteOperation;
93 using base::win::ScopedHandle;
94
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
104       // abandoned.
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);
114     } else {
115       AtlTrace("Failed to wait for relaunch mutex, result is 0x%x\n", result);
116     }
117   } else {
118     // It is possible that chrome exits so fast that the mutex is not there.
119     AtlTrace("No relaunch mutex found\n");
120   }
121
122   base::win::ScopedCOMInitializer com_initializer;
123
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();
130
131   AtlTrace(L"Relaunching Chrome via shortcut [%ls]\n", sei.lpFile);
132
133   if (!::ShellExecuteExW(&sei)) {
134     int error = HRESULT_FROM_WIN32(::GetLastError());
135     AtlTrace("ShellExecute returned 0x%08X\n", error);
136     return error;
137   }
138   return S_OK;
139 }
140
141 extern "C" int WINAPI _tWinMain(HINSTANCE , HINSTANCE, LPTSTR, int nShowCmd) {
142   scoped_ptr<google_breakpad::ExceptionHandler> breakpad =
143       delegate_execute::InitializeCrashReporting();
144
145   base::AtExitManager exit_manager;
146   AtlTrace("delegate_execute enter\n");
147
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);
155         break;
156       case DelegateExecuteOperation::RELAUNCH_CHROME:
157         ret_code = RelaunchChrome(operation);
158         break;
159       default:
160         NOTREACHED();
161     }
162   }
163   AtlTrace("delegate_execute exit, code = %d\n", ret_code);
164   return ret_code;
165 }