/** * Deletes an auto-dereference pool. * The function will dereference any objects * currently in the pool. If a pool other than * the current pool is passed to the function, * an exception is raised. * * \param AutoPool The auto-dereference pool to delete. */ __mayRaise VOID PhDeleteAutoPool( __inout PPH_AUTO_POOL AutoPool ) { PhDrainAutoPool(AutoPool); if (PhpGetCurrentAutoPool() != AutoPool) PhRaiseStatus(STATUS_UNSUCCESSFUL); // Remove the pool from the stack. PhpSetCurrentAutoPool(AutoPool->NextPool); // Free the dynamic array if it hasn't been freed yet. if (AutoPool->DynamicObjects) PhFree(AutoPool->DynamicObjects); REF_STAT_UP(RefAutoPoolsDestroyed); }
static NTSTATUS WindowThreadStart( __in PVOID Parameter ) { PH_AUTO_POOL autoPool; BOOL result; MSG message; PhInitializeAutoPool(&autoPool); GfxWindowHandle = CreateDialog( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSGFX), NULL, MainWndProc ); PhSetEvent(&InitializedEvent); while (result = GetMessage(&message, NULL, 0, 0)) { if (result == -1) break; if (!IsDialogMessage(GfxWindowHandle, &message)) { TranslateMessage(&message); DispatchMessage(&message); } PhDrainAutoPool(&autoPool); } PhDeleteAutoPool(&autoPool); PhResetEvent(&InitializedEvent); NtClose(GfxThreadHandle); GfxWindowHandle = NULL; GfxPanelWindowHandle = NULL; GfxThreadHandle = NULL; return STATUS_SUCCESS; }
static NTSTATUS PhNetworkOutputDialogThreadStart( _In_ PVOID Parameter ) { BOOL result; MSG message; HWND windowHandle; PH_AUTO_POOL autoPool; PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)Parameter; PhInitializeAutoPool(&autoPool); windowHandle = CreateDialogParam( (HINSTANCE)PluginInstance->DllBase, MAKEINTRESOURCE(IDD_OUTPUT), PhMainWndHandle, NetworkOutputDlgProc, (LPARAM)Parameter ); ShowWindow(windowHandle, SW_SHOW); SetForegroundWindow(windowHandle); while (result = GetMessage(&message, NULL, 0, 0)) { if (result == -1) break; if (!IsDialogMessage(context->WindowHandle, &message)) { TranslateMessage(&message); DispatchMessage(&message); } PhDrainAutoPool(&autoPool); } PhDeleteAutoPool(&autoPool); DestroyWindow(windowHandle); return STATUS_SUCCESS; }
NTSTATUS PhNetworkPingDialogThreadStart( _In_ PVOID Parameter ) { BOOL result; MSG message; HWND windowHandle; PH_AUTO_POOL autoPool; PhInitializeAutoPool(&autoPool); windowHandle = CreateDialogParam( (HINSTANCE)PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PINGDIALOG), NULL, NetworkPingWndProc, (LPARAM)Parameter ); ShowWindow(windowHandle, SW_SHOW); SetForegroundWindow(windowHandle); while (result = GetMessage(&message, NULL, 0, 0)) { if (result == -1) break; if (!IsDialogMessage(windowHandle, &message)) { TranslateMessage(&message); DispatchMessage(&message); } PhDrainAutoPool(&autoPool); } PhDeleteAutoPool(&autoPool); return STATUS_SUCCESS; }
NTSTATUS PhpWorkQueueThreadStart( _In_ PVOID Parameter ) { PH_AUTO_POOL autoPool; PPH_WORK_QUEUE workQueue = (PPH_WORK_QUEUE)Parameter; PhInitializeAutoPool(&autoPool); while (TRUE) { NTSTATUS status; HANDLE semaphoreHandle; LARGE_INTEGER timeout; PPH_WORK_QUEUE_ITEM workQueueItem = NULL; // Check if we have more threads than the limit. if (workQueue->CurrentThreads > workQueue->MaximumThreads) { BOOLEAN terminate = FALSE; // Lock and re-check. PhAcquireQueuedLockExclusive(&workQueue->StateLock); // Check the minimum as well. if (workQueue->CurrentThreads > workQueue->MaximumThreads && workQueue->CurrentThreads > workQueue->MinimumThreads) { workQueue->CurrentThreads--; terminate = TRUE; } PhReleaseQueuedLockExclusive(&workQueue->StateLock); if (terminate) break; } semaphoreHandle = PhpGetSemaphoreWorkQueue(workQueue); if (!workQueue->Terminating) { // Wait for work. status = NtWaitForSingleObject( semaphoreHandle, FALSE, PhTimeoutFromMilliseconds(&timeout, workQueue->NoWorkTimeout) ); } else { status = STATUS_UNSUCCESSFUL; } if (status == STATUS_WAIT_0 && !workQueue->Terminating) { PLIST_ENTRY listEntry; // Dequeue the work item. PhAcquireQueuedLockExclusive(&workQueue->QueueLock); listEntry = RemoveHeadList(&workQueue->QueueListHead); if (IsListEmpty(&workQueue->QueueListHead)) PhPulseCondition(&workQueue->QueueEmptyCondition); PhReleaseQueuedLockExclusive(&workQueue->QueueLock); // Make sure we got work. if (listEntry != &workQueue->QueueListHead) { workQueueItem = CONTAINING_RECORD(listEntry, PH_WORK_QUEUE_ITEM, ListEntry); PhpExecuteWorkQueueItem(workQueueItem); _InterlockedDecrement(&workQueue->BusyCount); PhpDestroyWorkQueueItem(workQueueItem); } } else { BOOLEAN terminate = FALSE; // No work arrived before the timeout passed, or we are terminating, or some error // occurred. Terminate the thread. PhAcquireQueuedLockExclusive(&workQueue->StateLock); if (workQueue->Terminating || workQueue->CurrentThreads > workQueue->MinimumThreads) { workQueue->CurrentThreads--; terminate = TRUE; } PhReleaseQueuedLockExclusive(&workQueue->StateLock); if (terminate) break; } PhDrainAutoPool(&autoPool); } PhReleaseRundownProtection(&workQueue->RundownProtect); PhDeleteAutoPool(&autoPool); return STATUS_SUCCESS; }
static NTSTATUS ShowUpdateDialogThreadStart( __in PVOID Parameter ) { BOOL result; MSG message; PH_AUTO_POOL autoPool; PhInitializeAutoPool(&autoPool); UpdateDialogHandle = CreateDialog( (HINSTANCE)PluginInstance->DllBase, MAKEINTRESOURCE(IDD_UPDATE), PhMainWndHandle, UpdaterWndProc ); PhSetEvent(&InitializedEvent); while (result = GetMessage(&message, NULL, 0, 0)) { if (result == -1) break; if (!IsDialogMessage(UpdateDialogHandle, &message)) { TranslateMessage(&message); DispatchMessage(&message); } PhDrainAutoPool(&autoPool); } PhDeleteAutoPool(&autoPool); PhResetEvent(&InitializedEvent); // Ensure global objects are disposed and reset when window closes. if (SetupFilePath) { PhDereferenceObject(SetupFilePath); SetupFilePath = NULL; } if (UpdateCheckThreadHandle) { NtClose(UpdateCheckThreadHandle); UpdateCheckThreadHandle = NULL; } if (DownloadThreadHandle) { NtClose(DownloadThreadHandle); DownloadThreadHandle = NULL; } if (UpdaterDialogThreadHandle) { NtClose(UpdaterDialogThreadHandle); UpdaterDialogThreadHandle = NULL; } if (FontHandle) { DeleteObject(FontHandle); FontHandle = NULL; } FreeXmlData(); if (UpdateDialogHandle) { DestroyWindow(UpdateDialogHandle); UpdateDialogHandle = NULL; } return STATUS_SUCCESS; }
NTSTATUS PhSvcApiRequestThreadStart( _In_ PVOID Parameter ) { PH_AUTO_POOL autoPool; NTSTATUS status; PHSVC_THREAD_CONTEXT threadContext; HANDLE portHandle; PVOID portContext; SIZE_T messageSize; PPORT_MESSAGE receiveMessage; PPORT_MESSAGE replyMessage; CSHORT messageType; PPHSVC_CLIENT client; PPHSVC_API_PAYLOAD payload; PhInitializeAutoPool(&autoPool); threadContext.CurrentClient = NULL; threadContext.OldClient = NULL; TlsSetValue(PhSvcApiThreadContextTlsIndex, &threadContext); portHandle = PhSvcApiPortHandle; messageSize = PhIsExecutingInWow64() ? sizeof(PHSVC_API_MSG64) : sizeof(PHSVC_API_MSG); receiveMessage = PhAllocate(messageSize); replyMessage = NULL; while (TRUE) { status = NtReplyWaitReceivePort( portHandle, &portContext, replyMessage, receiveMessage ); portHandle = PhSvcApiPortHandle; replyMessage = NULL; if (!NT_SUCCESS(status)) { // Client probably died. continue; } messageType = receiveMessage->u2.s2.Type; if (messageType == LPC_CONNECTION_REQUEST) { PhSvcHandleConnectionRequest(receiveMessage); continue; } if (!portContext) continue; client = portContext; threadContext.CurrentClient = client; PhWaitForEvent(&client->ReadyEvent, NULL); if (messageType == LPC_REQUEST) { if (PhIsExecutingInWow64()) payload = &((PPHSVC_API_MSG64)receiveMessage)->p; else payload = &((PPHSVC_API_MSG)receiveMessage)->p; PhSvcDispatchApiCall(client, payload, &portHandle); replyMessage = receiveMessage; } else if (messageType == LPC_PORT_CLOSED) { PhDereferenceObject(client); if (_InterlockedDecrement(&PhSvcApiNumberOfClients) == 0) { NtSetEvent(PhSvcTimeoutStandbyEventHandle, NULL); } } assert(!threadContext.OldClient); PhDrainAutoPool(&autoPool); } PhDeleteAutoPool(&autoPool); }
INT WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR lpCmdLine, _In_ INT nCmdShow ) { LONG result; #ifdef DEBUG PHP_BASE_THREAD_DBG dbg; #endif CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); #ifndef DEBUG SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #endif PhInstanceHandle = (HINSTANCE)NtCurrentPeb()->ImageBaseAddress; if (!NT_SUCCESS(PhInitializePhLib())) return 1; if (!PhInitializeAppSystem()) return 1; PhInitializeCommonControls(); if (PhCurrentTokenQueryHandle) { PTOKEN_USER tokenUser; if (NT_SUCCESS(PhGetTokenUser(PhCurrentTokenQueryHandle, &tokenUser))) { PhCurrentUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL); PhFree(tokenUser); } } PhLocalSystemName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL); // There has been a report of the above call failing. if (!PhLocalSystemName) PhLocalSystemName = PhCreateString(L"NT AUTHORITY\\SYSTEM"); PhApplicationFileName = PhGetApplicationFileName(); PhApplicationDirectory = PhGetApplicationDirectory(); // Just in case if (!PhApplicationFileName) PhApplicationFileName = PhCreateString(L"ProcessHacker.exe"); if (!PhApplicationDirectory) PhApplicationDirectory = PhReferenceEmptyString(); PhpProcessStartupParameters(); PhSettingsInitialization(); PhpEnablePrivileges(); if (PhStartupParameters.RunAsServiceMode) { RtlExitUserProcess(PhRunAsServiceStart(PhStartupParameters.RunAsServiceMode)); } PhpInitializeSettings(); // Activate a previous instance if required. if (PhGetIntegerSetting(L"AllowOnlyOneInstance") && !PhStartupParameters.NewInstance && !PhStartupParameters.ShowOptions && !PhStartupParameters.CommandMode && !PhStartupParameters.PhSvc) { PhActivatePreviousInstance(); } if (PhGetIntegerSetting(L"EnableKph") && !PhStartupParameters.NoKph && !PhIsExecutingInWow64()) PhInitializeKph(); if (PhStartupParameters.CommandMode && PhStartupParameters.CommandType && PhStartupParameters.CommandAction) { NTSTATUS status; status = PhCommandModeStart(); if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) { PhShowStatus(NULL, L"Unable to execute the command", status, 0); } RtlExitUserProcess(status); } #ifdef DEBUG dbg.ClientId = NtCurrentTeb()->ClientId; dbg.StartAddress = wWinMain; dbg.Parameter = NULL; InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry); TlsSetValue(PhDbgThreadDbgTlsIndex, &dbg); #endif PhInitializeAutoPool(&BaseAutoPool); PhEmInitialization(); PhGuiSupportInitialization(); PhTreeNewInitialization(); PhGraphControlInitialization(); PhHexEditInitialization(); PhColorBoxInitialization(); PhSmallIconSize.X = GetSystemMetrics(SM_CXSMICON); PhSmallIconSize.Y = GetSystemMetrics(SM_CYSMICON); PhLargeIconSize.X = GetSystemMetrics(SM_CXICON); PhLargeIconSize.Y = GetSystemMetrics(SM_CYICON); if (PhStartupParameters.ShowOptions) { // Elevated options dialog for changing the value of Replace Task Manager with Process Hacker. PhShowOptionsDialog(PhStartupParameters.WindowHandle); RtlExitUserProcess(STATUS_SUCCESS); } #ifndef DEBUG if (PhIsExecutingInWow64() && !PhStartupParameters.PhSvc) { PhShowWarning( NULL, L"You are attempting to run the 32-bit version of Process Hacker on 64-bit Windows. " L"Most features will not work correctly.\n\n" L"Please run the 64-bit version of Process Hacker instead." ); } #endif PhPluginsEnabled = PhGetIntegerSetting(L"EnablePlugins") && !PhStartupParameters.NoPlugins; if (PhPluginsEnabled) { PhPluginsInitialization(); PhLoadPlugins(); } if (PhStartupParameters.PhSvc) { MSG message; // Turn the feedback cursor off. PostMessage(NULL, WM_NULL, 0, 0); GetMessage(&message, NULL, 0, 0); RtlExitUserProcess(PhSvcMain(NULL, NULL, NULL)); } // Create a mutant for the installer. { HANDLE mutantHandle; OBJECT_ATTRIBUTES oa; UNICODE_STRING mutantName; RtlInitUnicodeString(&mutantName, L"\\BaseNamedObjects\\ProcessHacker2Mutant"); InitializeObjectAttributes( &oa, &mutantName, 0, NULL, NULL ); NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); } // Set priority. { PROCESS_PRIORITY_CLASS priorityClass; priorityClass.Foreground = FALSE; priorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; if (PhStartupParameters.PriorityClass != 0) priorityClass.PriorityClass = (UCHAR)PhStartupParameters.PriorityClass; NtSetInformationProcess(NtCurrentProcess(), ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); } if (!PhMainWndInitialization(nCmdShow)) { PhShowError(NULL, L"Unable to initialize the main window."); return 1; } PhDrainAutoPool(&BaseAutoPool); result = PhMainMessageLoop(); RtlExitUserProcess(result); }
LONG PhMainMessageLoop( VOID ) { BOOL result; MSG message; HACCEL acceleratorTable; acceleratorTable = LoadAccelerators(PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND_ACCEL)); while (result = GetMessage(&message, NULL, 0, 0)) { BOOLEAN processed = FALSE; ULONG i; if (result == -1) return 1; if (FilterList) { for (i = 0; i < FilterList->Count; i++) { PPH_MESSAGE_LOOP_FILTER_ENTRY entry = FilterList->Items[i]; if (entry->Filter(&message, entry->Context)) { processed = TRUE; break; } } } if (!processed) { if ( message.hwnd == PhMainWndHandle || IsChild(PhMainWndHandle, message.hwnd) ) { if (TranslateAccelerator(PhMainWndHandle, acceleratorTable, &message)) processed = TRUE; } if (DialogList) { for (i = 0; i < DialogList->Count; i++) { if (IsDialogMessage((HWND)DialogList->Items[i], &message)) { processed = TRUE; break; } } } } if (!processed) { TranslateMessage(&message); DispatchMessage(&message); } PhDrainAutoPool(&BaseAutoPool); } return (LONG)message.wParam; }
NTSTATUS SaveDb( VOID ) { PH_AUTO_POOL autoPool; NTSTATUS status; HANDLE fileHandle; mxml_node_t *topNode; ULONG enumerationKey = 0; PDB_OBJECT *object; PhInitializeAutoPool(&autoPool); topNode = mxmlNewElement(MXML_NO_PARENT, "objects"); LockDb(); while (PhEnumHashtable(ObjectDb, (PVOID*)&object, &enumerationKey)) { CreateObjectElement( topNode, &UInt64ToBase10String((*object)->Tag)->sr, &(*object)->Name->sr, &UInt64ToBase10String((*object)->PriorityClass)->sr, &UInt64ToBase10String((*object)->IoPriorityPlusOne)->sr, &(*object)->Comment->sr, &UInt64ToBase10String((*object)->BackColor)->sr, &UInt64ToBase10String((*object)->Collapse)->sr, &UInt64ToBase10String((*object)->AffinityMask)->sr ); PhDrainAutoPool(&autoPool); } UnlockDb(); // Create the directory if it does not exist. { PPH_STRING fullPath; ULONG indexOfFileName; if (fullPath = PH_AUTO(PhGetFullPath(ObjectDbPath->Buffer, &indexOfFileName))) { if (indexOfFileName != -1) SHCreateDirectoryEx(NULL, PhaSubstring(fullPath, 0, indexOfFileName)->Buffer, NULL); } } PhDeleteAutoPool(&autoPool); status = PhCreateFileWin32( &fileHandle, ObjectDbPath->Buffer, FILE_GENERIC_WRITE, 0, FILE_SHARE_READ, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); if (!NT_SUCCESS(status)) { mxmlDelete(topNode); return status; } mxmlSaveFd(topNode, fileHandle, MXML_NO_CALLBACK); mxmlDelete(topNode); NtClose(fileHandle); return STATUS_SUCCESS; }
BOOLEAN PhModalPropertySheet( _Inout_ PROPSHEETHEADER *Header ) { // PropertySheet incorrectly discards WM_QUIT messages in certain cases, so we will use our own // message loop. An example of this is when GetMessage (called by PropertySheet's message loop) // dispatches a message directly from kernel-mode that causes the property sheet to close. // In that case PropertySheet will retrieve the WM_QUIT message but will ignore it because of // its buggy logic. // This is also a good opportunity to introduce an auto-pool. PH_AUTO_POOL autoPool; HWND oldFocus; HWND topLevelOwner; HWND hwnd; BOOL result; MSG message; PhInitializeAutoPool(&autoPool); oldFocus = GetFocus(); topLevelOwner = Header->hwndParent; while (topLevelOwner && (GetWindowLong(topLevelOwner, GWL_STYLE) & WS_CHILD)) topLevelOwner = GetParent(topLevelOwner); if (topLevelOwner && (topLevelOwner == GetDesktopWindow() || EnableWindow(topLevelOwner, FALSE))) topLevelOwner = NULL; Header->dwFlags |= PSH_MODELESS; hwnd = (HWND)PropertySheet(Header); if (!hwnd) { if (topLevelOwner) EnableWindow(topLevelOwner, TRUE); return FALSE; } while (result = GetMessage(&message, NULL, 0, 0)) { if (result == -1) break; if (!PropSheet_IsDialogMessage(hwnd, &message)) { TranslateMessage(&message); DispatchMessage(&message); } PhDrainAutoPool(&autoPool); // Destroy the window when necessary. if (!PropSheet_GetCurrentPageHwnd(hwnd)) break; } if (result == 0) PostQuitMessage((INT)message.wParam); if (Header->hwndParent && GetActiveWindow() == hwnd) SetActiveWindow(Header->hwndParent); if (topLevelOwner) EnableWindow(topLevelOwner, TRUE); if (oldFocus && IsWindow(oldFocus)) SetFocus(oldFocus); DestroyWindow(hwnd); PhDeleteAutoPool(&autoPool); return TRUE; }