author | Brian R. Bondy <netzen@gmail.com> |
Tue, 10 Sep 2013 10:24:56 -0400 | |
changeset 146350 | 2cf4ecefa258051a4aa87580a936a00e215cdb08 |
parent 146349 | 225eb3f0434917485a84874148a5a2cb9063fc95 |
child 146351 | f8f04499e62a0acc9801655d35c3ca844e1322dc |
push id | 25255 |
push user | bbondy@mozilla.com |
push date | Tue, 10 Sep 2013 14:25:16 +0000 |
treeherder | mozilla-central@4d152d0220be [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jimm |
bugs | 882142 |
milestone | 26.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/metro/shell/commandexecutehandler/CEHHelper.cpp +++ b/browser/metro/shell/commandexecutehandler/CEHHelper.cpp @@ -1,14 +1,15 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "CEHHelper.h" +#include <tlhelp32.h> #ifdef SHOW_CONSOLE #include <io.h> // _open_osfhandle #endif HANDLE sCon; LPCWSTR metroDX10Available = L"MetroD3DAvailable"; @@ -53,16 +54,63 @@ SetupConsole() int fd = _open_osfhandle(reinterpret_cast<intptr_t>(sCon), 0); fp = _fdopen(fd, "w"); *stdout = *fp; setvbuf(stdout, nullptr, _IONBF, 0); } #endif bool +IsImmersiveProcessDynamic(HANDLE process) +{ + HMODULE user32DLL = LoadLibraryW(L"user32.dll"); + if (!user32DLL) { + return false; + } + + typedef BOOL (WINAPI* IsImmersiveProcessFunc)(HANDLE process); + IsImmersiveProcessFunc IsImmersiveProcessPtr = + (IsImmersiveProcessFunc)GetProcAddress(user32DLL, + "IsImmersiveProcess"); + if (!IsImmersiveProcessPtr) { + FreeLibrary(user32DLL); + return false; + } + + BOOL bImmersiveProcess = IsImmersiveProcessPtr(process); + FreeLibrary(user32DLL); + return bImmersiveProcess; +} + +bool +IsImmersiveProcessRunning(const wchar_t *processName) +{ + bool exists = false; + PROCESSENTRY32W entry; + entry.dwSize = sizeof(PROCESSENTRY32W); + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); + + if (Process32First(snapshot, &entry)) { + while (!exists && Process32Next(snapshot, &entry)) { + if (!_wcsicmp(entry.szExeFile, processName)) { + HANDLE process = OpenProcess(GENERIC_READ, FALSE, entry.th32ProcessID); + if (IsImmersiveProcessDynamic(process)) { + exists = true; + } + CloseHandle(process); + } + } + } + + CloseHandle(snapshot); + return exists; +} + +bool IsDX10Available() { DWORD isDX10Available; if (GetDWORDRegKey(metroDX10Available, isDX10Available)) { return isDX10Available; } HMODULE dxgiModule = LoadLibraryA("dxgi.dll");
--- a/browser/metro/shell/commandexecutehandler/CEHHelper.h +++ b/browser/metro/shell/commandexecutehandler/CEHHelper.h @@ -22,8 +22,10 @@ void Log(const wchar_t *fmt, ...); #if defined(SHOW_CONSOLE) void SetupConsole(); #endif bool IsDX10Available(); bool GetDWORDRegKey(LPCWSTR name, DWORD &value); bool SetDWORDRegKey(LPCWSTR name, DWORD value); +bool IsImmersiveProcessDynamic(HANDLE process); +bool IsImmersiveProcessRunning(const wchar_t *processName);
--- a/browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp +++ b/browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp @@ -28,19 +28,27 @@ // Heartbeat timer duration used while waiting for an incoming request. #define HEARTBEAT_MSEC 1000 // Total number of heartbeats we wait before giving up and shutting down. #define REQUEST_WAIT_TIMEOUT 30 // Pulled from desktop browser's shell #define APP_REG_NAME L"Firefox" +// If we have a restart request, attempt to wait up to RESTART_WAIT_TIMEOUT +// until the previous instance closes. We don't want to wait too long +// because the browser could appear to randomly start for the user. We want +// it to also be long enough so the browser has time to close. +#define RESTART_WAIT_PER_RETRY 50 +#define RESTART_WAIT_TIMEOUT 38000 + static const WCHAR* kFirefoxExe = L"firefox.exe"; static const WCHAR* kMetroFirefoxExe = L"firefox.exe"; static const WCHAR* kDefaultMetroBrowserIDPathKey = L"FirefoxURL"; +static const WCHAR* kMetroRestartCmdLine = L"--metro-restart"; static bool GetDefaultBrowserPath(CStringW& aPathBuffer); /* * Retrieve our module dir path. * * @aPathBuffer Buffer to fill */ @@ -90,16 +98,17 @@ public: CExecuteCommandVerb() : mRef(1), mShellItemArray(nullptr), mUnkSite(nullptr), mTargetIsFileSystemLink(false), mTargetIsDefaultBrowser(false), mTargetIsBrowser(false), mIsDesktopRequest(true), + mIsRestartMetroRequest(false), mRequestMet(false) { } bool RequestMet() { return mRequestMet; } long RefCount() { return mRef; } // IUnknown @@ -135,17 +144,22 @@ public: { mKeyState = aKeyState; return S_OK; } IFACEMETHODIMP SetParameters(PCWSTR aParameters) { Log(L"SetParameters: '%s'", aParameters); - mParameters = aParameters; + + if (_wcsicmp(aParameters, kMetroRestartCmdLine) == 0) { + mIsRestartMetroRequest = true; + } else { + mParameters = aParameters; + } return S_OK; } IFACEMETHODIMP SetPosition(POINT aPoint) { return S_OK; } IFACEMETHODIMP SetShowWindow(int aShowFlag) { return S_OK; } @@ -396,16 +410,17 @@ private: CStringW mVerb; CStringW mTarget; CStringW mParameters; bool mTargetIsFileSystemLink; bool mTargetIsDefaultBrowser; bool mTargetIsBrowser; DWORD mKeyState; bool mIsDesktopRequest; + bool mIsRestartMetroRequest; bool mRequestMet; }; /* * Retrieve the current default browser's path. * * @aPathBuffer Buffer to fill */ @@ -431,30 +446,25 @@ static bool GetDefaultBrowserPath(CStrin } /* * Retrieve the app model id of the firefox metro browser. * * @aPathBuffer Buffer to fill * @aCharLength Length of buffer to fill in characters */ -static bool GetDefaultBrowserAppModelID(WCHAR* aIDBuffer, - long aCharLength) +template <size_t N> +static bool GetDefaultBrowserAppModelID(WCHAR (&aIDBuffer)[N]) { - if (!aIDBuffer || aCharLength <= 0) - return false; - - memset(aIDBuffer, 0, (sizeof(WCHAR)*aCharLength)); - HKEY key; if (RegOpenKeyExW(HKEY_CLASSES_ROOT, kDefaultMetroBrowserIDPathKey, 0, KEY_READ, &key) != ERROR_SUCCESS) { return false; } - DWORD len = aCharLength * sizeof(WCHAR); + DWORD len = sizeof(aIDBuffer); memset(aIDBuffer, 0, len); if (RegQueryValueExW(key, L"AppUserModelID", nullptr, nullptr, (LPBYTE)aIDBuffer, &len) != ERROR_SUCCESS || !len) { RegCloseKey(key); return false; } RegCloseKey(key); return true; @@ -612,79 +622,132 @@ class AutoSetRequestMet public: explicit AutoSetRequestMet(bool* aFlag) : mFlag(aFlag) {} ~AutoSetRequestMet() { if (mFlag) *mFlag = true; } private: bool* mFlag; }; +static HRESULT +PrepareActivationManager(CComPtr<IApplicationActivationManager> &activateMgr) +{ + HRESULT hr = activateMgr.CoCreateInstance(CLSID_ApplicationActivationManager, NULL, CLSCTX_LOCAL_SERVER); + if (FAILED(hr)) { + Log(L"CoCreateInstance failed, launching on desktop."); + return E_FAIL; + } + + // Hand off focus rights to the out-of-process activation server. Without + // this the metro interface won't launch. + hr = CoAllowSetForegroundWindow(activateMgr, nullptr); + if (FAILED(hr)) { + Log(L"CoAllowSetForegroundWindow result %X", hr); + return E_FAIL; + } + + return S_OK; +} + +DWORD WINAPI +DelayedExecuteThread(LPVOID param) +{ + Log(L"Starting delayed execute thread..."); + bool &bRequestMet(*(bool*)param); + AutoSetRequestMet asrm(&bRequestMet); + + CoInitialize(NULL); + + CComPtr<IApplicationActivationManager> activateMgr; + if (FAILED(PrepareActivationManager(activateMgr))) { + Log(L"Warning: Could not prepare activation manager"); + } + + size_t currentWaitTime = 0; + while(currentWaitTime < RESTART_WAIT_TIMEOUT) { + if (!IsImmersiveProcessRunning(kMetroFirefoxExe)) + break; + currentWaitTime += RESTART_WAIT_PER_RETRY; + Sleep(RESTART_WAIT_PER_RETRY); + } + + Log(L"Done waiting, getting app ID"); + // Activate the application as long as we can obtian the appModelID + WCHAR appModelID[256]; + if (GetDefaultBrowserAppModelID(appModelID)) { + Log(L"Activating application"); + DWORD processID; + HRESULT hr = activateMgr->ActivateApplication(appModelID, L"", AO_NONE, &processID); + if (SUCCEEDED(hr)) { + Log(L"Activate application succeeded"); + } else { + Log(L"Activate application failed! (%x)", hr); + } + } + + CoUninitialize(); + return 0; +} + IFACEMETHODIMP CExecuteCommandVerb::Execute() { Log(L"Execute()"); + if (!mTarget.GetLength()) { + // We shut down when this flips to true + mRequestMet = true; + return E_FAIL; + } + + if (mIsRestartMetroRequest) { + HANDLE thread = CreateThread(NULL, 0, DelayedExecuteThread, &mRequestMet, 0, NULL); + CloseHandle(thread); + return S_OK; + } + // We shut down when this flips to true AutoSetRequestMet asrm(&mRequestMet); - if (!mTarget.GetLength()) { - return E_FAIL; - } - // Launch on the desktop if (mIsDesktopRequest) { LaunchDesktopBrowser(); return S_OK; } - // Launch into Metro - IApplicationActivationManager* activateMgr = nullptr; - DWORD processID; - if (FAILED(CoCreateInstance(CLSID_ApplicationActivationManager, nullptr, - CLSCTX_LOCAL_SERVER, - IID_IApplicationActivationManager, - (void**)&activateMgr))) { - Log(L"CoCreateInstance failed, launching on desktop."); - LaunchDesktopBrowser(); - return S_OK; + CComPtr<IApplicationActivationManager> activateMgr; + if (!PrepareActivationManager(activateMgr)) { + LaunchDesktopBrowser(); + return S_OK; } - + HRESULT hr; WCHAR appModelID[256]; - if (!GetDefaultBrowserAppModelID(appModelID, (sizeof(appModelID)/sizeof(WCHAR)))) { + if (!GetDefaultBrowserAppModelID(appModelID)) { Log(L"GetDefaultBrowserAppModelID failed, launching on desktop."); - activateMgr->Release(); LaunchDesktopBrowser(); return S_OK; } - // Hand off focus rights to the out-of-process activation server. Without - // this the metro interface won't launch. - hr = CoAllowSetForegroundWindow(activateMgr, nullptr); - if (FAILED(hr)) { - Log(L"CoAllowSetForegroundWindow result %X", hr); - activateMgr->Release(); - return false; - } - Log(L"Metro Launch: verb:%s appid:%s params:%s", mVerb, appModelID, mTarget); + // shortcuts to the application + DWORD processID; if (mTargetIsDefaultBrowser) { hr = activateMgr->ActivateApplication(appModelID, L"", AO_NONE, &processID); Log(L"ActivateApplication result %X", hr); // files } else if (mTargetIsFileSystemLink) { hr = activateMgr->ActivateForFile(appModelID, mShellItemArray, mVerb, &processID); Log(L"ActivateForFile result %X", hr); // protocols } else { hr = activateMgr->ActivateForProtocol(appModelID, mShellItemArray, &processID); Log(L"ActivateForProtocol result %X", hr); } - activateMgr->Release(); return S_OK; } class ClassFactory : public IClassFactory { public: ClassFactory(IUnknown *punkObject); ~ClassFactory();