Allows webview to access extension resources.
[chromium-blink-merge.git] / win8 / delegate_execute / delegate_execute.cc
blob986911cf8948fa844dbd418ac342266db33dd7eb
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/files/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 "base/win/windows_version.h"
21 #include "breakpad/src/client/windows/handler/exception_handler.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/installer/util/browser_distribution.h"
24 #include "win8/delegate_execute/command_execute_impl.h"
25 #include "win8/delegate_execute/crash_server_init.h"
26 #include "win8/delegate_execute/delegate_execute_operation.h"
27 #include "win8/delegate_execute/resource.h"
29 using namespace ATL;
31 // Usually classes derived from CAtlExeModuleT, or other types of ATL
32 // COM module classes statically define their CLSID at compile time through
33 // the use of various macros, and ATL internals takes care of creating the
34 // class objects and registering them. However, we need to register the same
35 // object with different CLSIDs depending on a runtime setting, so we handle
36 // that logic here, before the main ATL message loop runs.
37 class DelegateExecuteModule
38 : public ATL::CAtlExeModuleT< DelegateExecuteModule > {
39 public :
40 typedef ATL::CAtlExeModuleT<DelegateExecuteModule> ParentClass;
41 typedef CComObject<CommandExecuteImpl> ImplType;
43 DelegateExecuteModule()
44 : registration_token_(0) {
47 HRESULT PreMessageLoop(int nShowCmd) {
48 HRESULT hr = S_OK;
49 base::string16 clsid_string;
50 GUID clsid;
51 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
52 if (!dist->GetCommandExecuteImplClsid(&clsid_string))
53 return E_FAIL;
54 hr = ::CLSIDFromString(clsid_string.c_str(), &clsid);
55 if (FAILED(hr))
56 return hr;
58 // We use the same class creation logic as ATL itself. See
59 // _ATL_OBJMAP_ENTRY::RegisterClassObject() in atlbase.h
60 hr = ImplType::_ClassFactoryCreatorClass::CreateInstance(
61 ImplType::_CreatorClass::CreateInstance, IID_IUnknown,
62 instance_.ReceiveVoid());
63 if (FAILED(hr))
64 return hr;
65 hr = ::CoRegisterClassObject(clsid, instance_, CLSCTX_LOCAL_SERVER,
66 REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &registration_token_);
67 if (FAILED(hr))
68 return hr;
70 return ParentClass::PreMessageLoop(nShowCmd);
73 HRESULT PostMessageLoop() {
74 if (registration_token_ != 0) {
75 ::CoRevokeClassObject(registration_token_);
76 registration_token_ = 0;
79 instance_.Release();
81 return ParentClass::PostMessageLoop();
84 private:
85 base::win::ScopedComPtr<IUnknown> instance_;
86 DWORD registration_token_;
89 DelegateExecuteModule _AtlModule;
91 using delegate_execute::DelegateExecuteOperation;
92 using base::win::ScopedHandle;
94 int RelaunchChrome(const DelegateExecuteOperation& operation) {
95 AtlTrace("Relaunching [%ls] with flags [%ls]\n",
96 operation.mutex().c_str(), operation.relaunch_flags().c_str());
97 ScopedHandle mutex(OpenMutexW(SYNCHRONIZE, FALSE, operation.mutex().c_str()));
98 if (mutex.IsValid()) {
99 const int kWaitSeconds = 5;
100 DWORD result = ::WaitForSingleObject(mutex, kWaitSeconds * 1000);
101 if (result == WAIT_ABANDONED) {
102 // This is the normal case. Chrome exits and windows marks the mutex as
103 // abandoned.
104 } else if (result == WAIT_OBJECT_0) {
105 // This is unexpected. Check if somebody is not closing the mutex on
106 // RelaunchChromehelper, the mutex should not be closed.
107 AtlTrace("Unexpected release of the relaunch mutex!!\n");
108 } else if (result == WAIT_TIMEOUT) {
109 // This could mean that Chrome is hung. Proceed to exterminate.
110 DWORD pid = operation.GetParentPid();
111 AtlTrace("%ds timeout. Killing Chrome %d\n", kWaitSeconds, pid);
112 base::KillProcessById(pid, 0, false);
113 } else {
114 AtlTrace("Failed to wait for relaunch mutex, result is 0x%x\n", result);
116 } else {
117 // It is possible that chrome exits so fast that the mutex is not there.
118 AtlTrace("No relaunch mutex found\n");
121 // On Windows 8+ to launch Chrome we rely on Windows to use the
122 // IExecuteCommand interface exposed by delegate_execute to launch Chrome
123 // into Windows 8 metro mode or desktop.
124 // On Windows 7 we don't use delegate_execute and instead use plain vanilla
125 // ShellExecute to launch Chrome into ASH or desktop.
126 if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
127 base::win::ScopedCOMInitializer com_initializer;
129 base::string16 relaunch_flags(operation.relaunch_flags());
130 SHELLEXECUTEINFO sei = { sizeof(sei) };
131 sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
132 sei.nShow = SW_SHOWNORMAL;
133 sei.lpFile = operation.shortcut().value().c_str();
134 sei.lpParameters = relaunch_flags.c_str();
136 AtlTrace(L"Relaunching Chrome via shortcut [%ls]\n", sei.lpFile);
138 if (!::ShellExecuteExW(&sei)) {
139 int error = HRESULT_FROM_WIN32(::GetLastError());
140 AtlTrace("ShellExecute returned 0x%08X\n", error);
141 return error;
143 } else {
144 base::FilePath chrome_exe_path;
145 bool found_exe = CommandExecuteImpl::FindChromeExe(&chrome_exe_path);
146 DCHECK(found_exe);
147 if (found_exe) {
148 bool launch_ash = CommandLine::ForCurrentProcess()->HasSwitch(
149 switches::kForceImmersive);
150 if (launch_ash) {
151 AtlTrace(L"Relaunching Chrome into Windows ASH on Windows 7\n");
152 } else {
153 AtlTrace(L"Relaunching Chrome into Desktop From ASH on Windows 7\n");
155 SHELLEXECUTEINFO sei = { sizeof(sei) };
156 sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
157 sei.nShow = SW_SHOWNORMAL;
158 // No point in using the shortcut if we are launching into ASH as any
159 // additonal command line switches specified in the shortcut will be
160 // ignored. This is because we don't have a good way to send the command
161 // line switches from the viewer to the browser process.
162 sei.lpFile = (launch_ash || operation.shortcut().empty()) ?
163 chrome_exe_path.value().c_str() :
164 operation.shortcut().value().c_str();
165 sei.lpParameters =
166 launch_ash ? L"-ServerName:DefaultBrowserServer" : NULL;
167 if (!::ShellExecuteExW(&sei)) {
168 int error = HRESULT_FROM_WIN32(::GetLastError());
169 AtlTrace("ShellExecute returned 0x%08X\n", error);
170 return error;
174 return S_OK;
177 extern "C" int WINAPI _tWinMain(HINSTANCE , HINSTANCE, LPTSTR, int nShowCmd) {
178 scoped_ptr<google_breakpad::ExceptionHandler> breakpad =
179 delegate_execute::InitializeCrashReporting();
181 base::AtExitManager exit_manager;
182 AtlTrace("delegate_execute enter\n");
184 CommandLine::Init(0, NULL);
185 HRESULT ret_code = E_UNEXPECTED;
186 DelegateExecuteOperation operation;
187 if (operation.Init(CommandLine::ForCurrentProcess())) {
188 switch (operation.operation_type()) {
189 case DelegateExecuteOperation::DELEGATE_EXECUTE:
190 ret_code = _AtlModule.WinMain(nShowCmd);
191 break;
192 case DelegateExecuteOperation::RELAUNCH_CHROME:
193 ret_code = RelaunchChrome(operation);
194 break;
195 default:
196 NOTREACHED();
199 AtlTrace("delegate_execute exit, code = %d\n", ret_code);
200 return ret_code;