bool PluginHangUIParent::Init(const nsString& aPluginName) { if (mHangUIProcessHandle) { return false; } nsresult rv; rv = mMiniShm.Init(this, ::IsDebuggerPresent() ? INFINITE : kTimeout); NS_ENSURE_SUCCESS(rv, false); nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID)); if (!directoryService) { return false; } nsCOMPtr<nsIFile> greDir; rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir)); if (NS_FAILED(rv)) { return false; } nsAutoString path; greDir->GetPath(path); FilePath exePath(path.get()); exePath = exePath.AppendASCII(MOZ_HANGUI_PROCESS_NAME); CommandLine commandLine(exePath.value()); nsXPIDLString localizedStr; const PRUnichar* formatParams[] = { aPluginName.get() }; rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES, "PluginHangUIMessage", formatParams, localizedStr); if (NS_FAILED(rv)) { return false; } commandLine.AppendLooseValue(localizedStr.get()); const char* keys[] = { "PluginHangUITitle", "PluginHangUIWaitButton", "PluginHangUIStopButton", "DontAskAgain" }; for (unsigned int i = 0; i < ArrayLength(keys); ++i) { rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES, keys[i], localizedStr); if (NS_FAILED(rv)) { return false; } commandLine.AppendLooseValue(localizedStr.get()); } rv = GetHangUIOwnerWindowHandle(mMainWindowHandle); if (NS_FAILED(rv)) { return false; } nsAutoString hwndStr; hwndStr.AppendPrintf("%p", mMainWindowHandle); commandLine.AppendLooseValue(hwndStr.get()); ScopedHandle procHandle(::OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId())); if (!procHandle.IsValid()) { return false; } nsAutoString procHandleStr; procHandleStr.AppendPrintf("%p", procHandle.Get()); commandLine.AppendLooseValue(procHandleStr.get()); std::wstring ipcCookie; rv = mMiniShm.GetCookie(ipcCookie); if (NS_FAILED(rv)) { return false; } commandLine.AppendLooseValue(ipcCookie); mShowEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); ScopedHandle showEvent(::CreateEvent(NULL, FALSE, FALSE, NULL)); if (!showEvent.IsValid()) { return false; } mShowEvent = showEvent.Get(); STARTUPINFO startupInfo = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION processInfo = { NULL }; BOOL isProcessCreated = ::CreateProcess(exePath.value().c_str(), const_cast<wchar_t*>(commandLine.command_line_string().c_str()), nullptr, nullptr, TRUE, DETACHED_PROCESS, nullptr, nullptr, &startupInfo, &processInfo); if (isProcessCreated) { ::CloseHandle(processInfo.hThread); mHangUIProcessHandle = processInfo.hProcess; ::RegisterWaitForSingleObject(&mRegWait, processInfo.hProcess, &SOnHangUIProcessExit, this, INFINITE, WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE); ::WaitForSingleObject(mShowEvent, kTimeout); } mShowEvent = NULL; return !(!isProcessCreated); }
bool PluginHangUIParent::Init(const nsString& aPluginName) { if (mHangUIProcessHandle) { return false; } nsresult rv; rv = mMiniShm.Init(this, ::IsDebuggerPresent() ? INFINITE : mIPCTimeoutMs); NS_ENSURE_SUCCESS(rv, false); nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID)); if (!directoryService) { return false; } nsCOMPtr<nsIFile> greDir; rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir)); if (NS_FAILED(rv)) { return false; } nsAutoString path; greDir->GetPath(path); FilePath exePath(path.get()); exePath = exePath.AppendASCII(MOZ_HANGUI_PROCESS_NAME); CommandLine commandLine(exePath.value()); nsXPIDLString localizedStr; const PRUnichar* formatParams[] = { aPluginName.get() }; rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES, "PluginHangUIMessage", formatParams, localizedStr); if (NS_FAILED(rv)) { return false; } commandLine.AppendLooseValue(localizedStr.get()); const char* keys[] = { "PluginHangUITitle", "PluginHangUIWaitButton", "PluginHangUIStopButton", "DontAskAgain" }; for (unsigned int i = 0; i < ArrayLength(keys); ++i) { rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES, keys[i], localizedStr); if (NS_FAILED(rv)) { return false; } commandLine.AppendLooseValue(localizedStr.get()); } rv = GetHangUIOwnerWindowHandle(mMainWindowHandle); if (NS_FAILED(rv)) { return false; } nsAutoString hwndStr; hwndStr.AppendPrintf("%p", mMainWindowHandle); commandLine.AppendLooseValue(hwndStr.get()); ScopedHandle procHandle(::OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId())); if (!procHandle.IsValid()) { return false; } nsAutoString procHandleStr; 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"-"); } nsAutoString ipcTimeoutStr; ipcTimeoutStr.AppendInt(mIPCTimeoutMs); commandLine.AppendLooseValue(ipcTimeoutStr.get()); std::wstring ipcCookie; rv = mMiniShm.GetCookie(ipcCookie); if (NS_FAILED(rv)) { return false; } commandLine.AppendLooseValue(ipcCookie); ScopedHandle showEvent(::CreateEvent(nullptr, FALSE, FALSE, nullptr)); if (!showEvent.IsValid()) { return false; } mShowEvent = showEvent.Get(); MutexAutoLock lock(mMutex); STARTUPINFO startupInfo = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION processInfo = { nullptr }; BOOL isProcessCreated = ::CreateProcess(exePath.value().c_str(), const_cast<wchar_t*>(commandLine.command_line_string().c_str()), nullptr, nullptr, TRUE, DETACHED_PROCESS, nullptr, nullptr, &startupInfo, &processInfo); if (isProcessCreated) { ::CloseHandle(processInfo.hThread); mHangUIProcessHandle = processInfo.hProcess; ::RegisterWaitForSingleObject(&mRegWait, processInfo.hProcess, &SOnHangUIProcessExit, this, INFINITE, WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE); ::WaitForSingleObject(mShowEvent, ::IsDebuggerPresent() ? INFINITE : mIPCTimeoutMs); // 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 = nullptr; return !(!isProcessCreated); }