Bug 834127 - Make Plugin Hang UI dialog unowned. r=bsmedberg

This commit is contained in:
Aaron Klotz 2013-02-14 18:03:05 -05:00
parent 0e5dbfff3e
commit f5026d4a7a
3 changed files with 59 additions and 13 deletions

View File

@ -16,10 +16,13 @@
#include "nsIFile.h"
#include "nsIProperties.h"
#include "nsIWindowMediator.h"
#include "nsIWinTaskbar.h"
#include "nsServiceManagerUtils.h"
#include "WidgetUtils.h"
#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
using base::ProcessHandle;
using mozilla::widget::WidgetUtils;
@ -65,7 +68,7 @@ private:
namespace mozilla {
namespace plugins {
const DWORD PluginHangUIParent::kTimeout = 5000U;
const DWORD PluginHangUIParent::kTimeout = 30000U;
PluginHangUIParent::PluginHangUIParent(PluginModuleParent* aModule,
const int32_t aHangUITimeoutPref)
@ -190,6 +193,23 @@ PluginHangUIParent::Init(const nsString& aPluginName)
procHandleStr.AppendPrintf("%p", procHandle.Get());
commandLine.AppendLooseValue(procHandleStr.get());
// On Win7+, pass the application user model to the child, so it can
// register with it. This insures windows created by the Hang UI
// properly group with the parent app on the Win7 taskbar.
nsCOMPtr<nsIWinTaskbar> taskbarInfo = do_GetService(NS_TASKBAR_CONTRACTID);
if (taskbarInfo) {
bool isSupported = false;
taskbarInfo->GetAvailable(&isSupported);
nsAutoString appId;
if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
commandLine.AppendLooseValue(appId.get());
} else {
commandLine.AppendLooseValue(L"-");
}
} else {
commandLine.AppendLooseValue(L"-");
}
std::wstring ipcCookie;
rv = mMiniShm.GetCookie(ipcCookie);
if (NS_FAILED(rv)) {
@ -197,7 +217,6 @@ PluginHangUIParent::Init(const nsString& aPluginName)
}
commandLine.AppendLooseValue(ipcCookie);
mShowEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
ScopedHandle showEvent(::CreateEvent(NULL, FALSE, FALSE, NULL));
if (!showEvent.IsValid()) {
return false;
@ -225,7 +244,14 @@ PluginHangUIParent::Init(const nsString& aPluginName)
this,
INFINITE,
WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE);
::WaitForSingleObject(mShowEvent, kTimeout);
::WaitForSingleObject(mShowEvent, ::IsDebuggerPresent() ? INFINITE
: kTimeout);
// Setting this to true even if we time out on mShowEvent. This timeout
// typically occurs when the machine is thrashing so badly that
// plugin-hang-ui.exe is taking a while to start. If we didn't set
// this to true, Firefox would keep spawning additional plugin-hang-ui
// processes, which is not what we want.
mIsShowing = true;
}
mShowEvent = NULL;
return !(!isProcessCreated);
@ -356,8 +382,7 @@ PluginHangUIParent::OnMiniShmConnect(MiniShmBase* aMiniShmObj)
return;
}
cmd->mCode = PluginHangUICommand::HANGUI_CMD_SHOW;
mIsShowing = NS_SUCCEEDED(aMiniShmObj->Send());
if (mIsShowing) {
if (NS_SUCCEEDED(aMiniShmObj->Send())) {
mShowTicks = GetTickCount();
}
::SetEvent(mShowEvent);

View File

@ -18,7 +18,7 @@ namespace mozilla {
namespace plugins {
PluginHangUIChild* PluginHangUIChild::sSelf = nullptr;
const int PluginHangUIChild::kExpectedMinimumArgc = 9;
const int PluginHangUIChild::kExpectedMinimumArgc = 10;
const DWORD PluginHangUIChild::kProcessTimeout = 1200000U;
const DWORD PluginHangUIChild::kShmTimeout = 5000U;
@ -68,6 +68,18 @@ PluginHangUIChild::Init(int aArgc, wchar_t* aArgv[])
if (!issProc) {
return false;
}
// Only set the App User Model ID if it's present in the args
if (wcscmp(aArgv[++i], L"-")) {
HMODULE shell32 = LoadLibrary(L"shell32.dll");
if (shell32) {
SETAPPUSERMODELID fSetAppUserModelID = (SETAPPUSERMODELID)
GetProcAddress(shell32, "SetCurrentProcessExplicitAppUserModelID");
if (fSetAppUserModelID) {
fSetAppUserModelID(aArgv[i]);
}
FreeLibrary(shell32);
}
}
nsresult rv = mMiniShm.Init(this,
std::wstring(aArgv[++i]),
@ -119,10 +131,6 @@ PluginHangUIChild::HangUIDlgProc(HWND aDlgHandle, UINT aMsgCode, WPARAM aWParam,
mDlgHandle = aDlgHandle;
switch (aMsgCode) {
case WM_INITDIALOG: {
// Disentangle our input queue from the hung Firefox process
AttachThreadInput(GetCurrentThreadId(),
GetWindowThreadProcessId(mParentWindow, nullptr),
FALSE);
// Register a wait on the Firefox process so that we will be informed
// if it dies while the dialog is showing
RegisterWaitForSingleObject(&mRegWaitProcess,
@ -141,11 +149,13 @@ PluginHangUIChild::HangUIDlgProc(HWND aDlgHandle, UINT aMsgCode, WPARAM aWParam,
if (icon) {
SendDlgItemMessage(aDlgHandle, IDC_DLGICON, STM_SETICON, (WPARAM)icon, 0);
}
EnableWindow(mParentWindow, FALSE);
return TRUE;
}
case WM_CLOSE: {
mResponseBits |= HANGUI_USER_RESPONSE_CANCEL;
EndDialog(aDlgHandle, 0);
SetWindowLongPtr(aDlgHandle, DWLP_MSGRESULT, 0);
return TRUE;
}
case WM_COMMAND: {
@ -154,6 +164,7 @@ PluginHangUIChild::HangUIDlgProc(HWND aDlgHandle, UINT aMsgCode, WPARAM aWParam,
if (HIWORD(aWParam) == BN_CLICKED) {
mResponseBits |= HANGUI_USER_RESPONSE_CONTINUE;
EndDialog(aDlgHandle, 1);
SetWindowLongPtr(aDlgHandle, DWLP_MSGRESULT, 0);
return TRUE;
}
break;
@ -161,6 +172,7 @@ PluginHangUIChild::HangUIDlgProc(HWND aDlgHandle, UINT aMsgCode, WPARAM aWParam,
if (HIWORD(aWParam) == BN_CLICKED) {
mResponseBits |= HANGUI_USER_RESPONSE_STOP;
EndDialog(aDlgHandle, 1);
SetWindowLongPtr(aDlgHandle, DWLP_MSGRESULT, 0);
return TRUE;
}
break;
@ -173,16 +185,23 @@ PluginHangUIChild::HangUIDlgProc(HWND aDlgHandle, UINT aMsgCode, WPARAM aWParam,
mResponseBits &=
~static_cast<DWORD>(HANGUI_USER_RESPONSE_DONT_SHOW_AGAIN);
}
SetWindowLongPtr(aDlgHandle, DWLP_MSGRESULT, 0);
return TRUE;
}
break;
default:
break;
}
return FALSE;
break;
}
case WM_DESTROY: {
EnableWindow(mParentWindow, TRUE);
break;
}
default:
return FALSE;
break;
}
return FALSE;
}
// static
@ -207,7 +226,7 @@ PluginHangUIChild::Show()
{
INT_PTR dlgResult = DialogBox(GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_HANGUIDLG),
mParentWindow,
NULL,
&SHangUIDlgProc);
mDlgHandle = NULL;
assert(dlgResult != -1);

View File

@ -99,6 +99,8 @@ private:
static const DWORD kProcessTimeout;
static const DWORD kShmTimeout;
typedef HRESULT (WINAPI *SETAPPUSERMODELID)(PCWSTR);
DISALLOW_COPY_AND_ASSIGN(PluginHangUIChild);
};