15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "build/intsafe_workaround.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <atlbase.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <atlcom.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <atlctl.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <initguid.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shellapi.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/at_exit.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
17bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/kill.h"
187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string16.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_com_initializer.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "breakpad/src/client/windows/handler/exception_handler.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/delegate_execute/command_execute_impl.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/delegate_execute/crash_server_init.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/delegate_execute/delegate_execute_operation.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/delegate_execute/resource.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace ATL;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DelegateExecuteModule
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public ATL::CAtlExeModuleT< DelegateExecuteModule > {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public :
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef ATL::CAtlExeModuleT<DelegateExecuteModule> ParentClass;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT RegisterServer(BOOL reg_type_lib) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ParentClass::RegisterServer(FALSE);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AtlTrace(L"In %hs\n", __FUNCTION__);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    wchar_t delegate_execute_clsid[MAX_PATH] = {0};
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!StringFromGUID2(__uuidof(CommandExecuteImpl), delegate_execute_clsid,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         ARRAYSIZE(delegate_execute_clsid))) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ATLASSERT(false);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return E_FAIL;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = registrar->AddReplacement(L"DELEGATE_EXECUTE_CLSID",
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   delegate_execute_clsid);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ATLASSERT(SUCCEEDED(hr));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DelegateExecuteModule _AtlModule;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using delegate_execute::DelegateExecuteOperation;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::ScopedHandle;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int RelaunchChrome(const DelegateExecuteOperation& operation) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AtlTrace("Relaunching [%ls] with flags [%s]\n",
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           operation.mutex().c_str(), operation.relaunch_flags());
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHandle mutex(OpenMutexW(SYNCHRONIZE, FALSE, operation.mutex().c_str()));
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (mutex.IsValid()) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int kWaitSeconds = 5;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD result = ::WaitForSingleObject(mutex, kWaitSeconds * 1000);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result == WAIT_ABANDONED) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is the normal case. Chrome exits and windows marks the mutex as
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // abandoned.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (result == WAIT_OBJECT_0) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is unexpected. Check if somebody is not closing the mutex on
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // RelaunchChromehelper, the mutex should not be closed.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AtlTrace("Unexpected release of the relaunch mutex!!\n");
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (result == WAIT_TIMEOUT) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This could mean that Chrome is hung. Proceed to exterminate.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DWORD pid = operation.GetParentPid();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AtlTrace("%ds timeout. Killing Chrome %d\n", kWaitSeconds, pid);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::KillProcessById(pid, 0, false);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AtlTrace("Failed to wait for relaunch mutex, result is 0x%x\n", result);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // It is possible that chrome exits so fast that the mutex is not there.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AtlTrace("No relaunch mutex found\n");
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedCOMInitializer com_initializer;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 relaunch_flags(operation.relaunch_flags());
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHELLEXECUTEINFO sei = { sizeof(sei) };
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sei.nShow = SW_SHOWNORMAL;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sei.lpFile = operation.shortcut().value().c_str();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sei.lpParameters = relaunch_flags.c_str();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AtlTrace(L"Relaunching Chrome via shortcut [%ls]\n", sei.lpFile);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!::ShellExecuteExW(&sei)) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int error = HRESULT_FROM_WIN32(::GetLastError());
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AtlTrace("ShellExecute returned 0x%08X\n", error);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return error;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" int WINAPI _tWinMain(HINSTANCE , HINSTANCE, LPTSTR, int nShowCmd) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<google_breakpad::ExceptionHandler> breakpad =
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delegate_execute::InitializeCrashReporting();
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AtExitManager exit_manager;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AtlTrace("delegate_execute enter\n");
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine::Init(0, NULL);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT ret_code = E_UNEXPECTED;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DelegateExecuteOperation operation;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (operation.Init(CommandLine::ForCurrentProcess())) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (operation.operation_type()) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case DelegateExecuteOperation::DELEGATE_EXECUTE:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret_code = _AtlModule.WinMain(nShowCmd);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case DelegateExecuteOperation::RELAUNCH_CHROME:
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret_code = RelaunchChrome(operation);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AtlTrace("delegate_execute exit, code = %d\n", ret_code);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret_code;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
135