VOID PhpRefreshProcessMemoryList( _In_ HWND hwndDlg, _In_ PPH_PROCESS_PROPPAGECONTEXT PropPageContext ) { PPH_MEMORY_CONTEXT memoryContext = PropPageContext->Context; if (memoryContext->MemoryItemListValid) { PhDeleteMemoryItemList(&memoryContext->MemoryItemList); memoryContext->MemoryItemListValid = FALSE; } memoryContext->LastRunStatus = PhQueryMemoryItemList( memoryContext->ProcessId, PH_QUERY_MEMORY_REGION_TYPE | PH_QUERY_MEMORY_WS_COUNTERS, &memoryContext->MemoryItemList ); if (NT_SUCCESS(memoryContext->LastRunStatus)) { if (PhPluginsEnabled) { PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL control; control.Type = PluginMemoryItemListInitialized; control.u.Initialized.List = &memoryContext->MemoryItemList; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryItemListControl), &control); } memoryContext->MemoryItemListValid = TRUE; TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &EmptyMemoryText, 0); PhReplaceMemoryList(&memoryContext->ListContext, &memoryContext->MemoryItemList); } else { PPH_STRING message; message = PhGetStatusMessage(memoryContext->LastRunStatus, 0); PhMoveReference(&memoryContext->ErrorMessage, PhFormatString(L"Unable to query memory information:\n%s", PhGetStringOrDefault(message, L"Unknown error."))); PhClearReference(&message); TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &memoryContext->ErrorMessage->sr, 0); PhReplaceMemoryList(&memoryContext->ListContext, NULL); } }
INT_PTR CALLBACK DotNetAsmPageDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { LPPROPSHEETPAGE propSheetPage; PPH_PROCESS_PROPPAGECONTEXT propPageContext; PPH_PROCESS_ITEM processItem; PASMPAGE_CONTEXT context; if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { context = propPageContext->Context; } else { return FALSE; } switch (uMsg) { case WM_INITDIALOG: { PPH_STRING settings; HWND tnHandle; context = PhAllocate(sizeof(ASMPAGE_CONTEXT)); memset(context, 0, sizeof(ASMPAGE_CONTEXT)); propPageContext->Context = context; context->WindowHandle = hwndDlg; context->ProcessItem = processItem; context->ClrVersions = 0; PhGetProcessIsDotNetEx(processItem->ProcessId, NULL, 0, NULL, &context->ClrVersions); tnHandle = GetDlgItem(hwndDlg, IDC_LIST); context->TnHandle = tnHandle; TreeNew_SetCallback(tnHandle, DotNetAsmTreeNewCallback, context); TreeNew_SetExtendedFlags(tnHandle, TN_FLAG_ITEM_DRAG_SELECT, TN_FLAG_ITEM_DRAG_SELECT); PhSetControlTheme(tnHandle, L"explorer"); SendMessage(TreeNew_GetTooltips(tnHandle), TTM_SETMAXTIPWIDTH, 0, MAXSHORT); PhAddTreeNewColumn(tnHandle, DNATNC_STRUCTURE, TRUE, L"Structure", 240, PH_ALIGN_LEFT, -2, 0); PhAddTreeNewColumn(tnHandle, DNATNC_ID, TRUE, L"ID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); PhAddTreeNewColumn(tnHandle, DNATNC_FLAGS, TRUE, L"Flags", 120, PH_ALIGN_LEFT, 1, 0); PhAddTreeNewColumn(tnHandle, DNATNC_PATH, TRUE, L"Path", 600, PH_ALIGN_LEFT, 2, 0); // don't use path ellipsis - the user already has the base file name PhAddTreeNewColumn(tnHandle, DNATNC_NATIVEPATH, TRUE, L"Native image path", 600, PH_ALIGN_LEFT, 3, 0); settings = PhGetStringSetting(SETTING_NAME_ASM_TREE_LIST_COLUMNS); PhCmLoadSettings(tnHandle, &settings->sr); PhDereferenceObject(settings); PhSwapReference(&context->TnErrorMessage, PhCreateString(L"Loading .NET assemblies...")); TreeNew_SetEmptyText(tnHandle, &context->TnErrorMessage->sr, 0); if ( !IsProcessSuspended(processItem->ProcessId) || PhShowMessage(hwndDlg, MB_ICONWARNING | MB_YESNO, L".NET assembly enumeration may not work properly because the process is currently suspended. Do you want to continue?") == IDYES ) { CreateDotNetTraceQueryThread( hwndDlg, context->ClrVersions, processItem->ProcessId ); } else { PhSwapReference(&context->TnErrorMessage, PhCreateString(L"Unable to start the event tracing session because the process is suspended.") ); TreeNew_SetEmptyText(tnHandle, &context->TnErrorMessage->sr, 0); InvalidateRect(tnHandle, NULL, FALSE); } } break; case WM_DESTROY: { PPH_STRING settings; ULONG i; settings = PhCmSaveSettings(context->TnHandle); PhSetStringSetting2(SETTING_NAME_ASM_TREE_LIST_COLUMNS, &settings->sr); PhDereferenceObject(settings); if (context->NodeList) { for (i = 0; i < context->NodeList->Count; i++) DestroyNode(context->NodeList->Items[i]); PhDereferenceObject(context->NodeList); } if (context->NodeRootList) PhDereferenceObject(context->NodeRootList); PhClearReference(&context->TnErrorMessage); PhFree(context); PhPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { PPH_LAYOUT_ITEM dialogItem; if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) { PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PhEndPropPageLayout(hwndDlg, propPageContext); } } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case ID_COPY: { PPH_STRING text; text = PhGetTreeNewText(context->TnHandle, 0); PhSetClipboardString(context->TnHandle, &text->sr); PhDereferenceObject(text); } break; } } break; case UPDATE_MSG: { ULONG result = (ULONG)wParam; PASMPAGE_QUERY_CONTEXT queryContext = (PASMPAGE_QUERY_CONTEXT)lParam; if (result == 0) { PhSwapReference(&context->NodeList, queryContext->NodeList); PhSwapReference(&context->NodeRootList, queryContext->NodeRootList); DestroyDotNetTraceQuery(queryContext); TreeNew_NodesStructured(context->TnHandle); } else { PhSwapReference(&context->TnErrorMessage, PhConcatStrings2(L"Unable to start the event tracing session: ", PhGetStringOrDefault(PhGetWin32Message(result), L"Unknown error")) ); TreeNew_SetEmptyText(context->TnHandle, &context->TnErrorMessage->sr, 0); InvalidateRect(context->TnHandle, NULL, FALSE); } } break; } return FALSE; }
INT_PTR CALLBACK PhpProcessMemoryDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { LPPROPSHEETPAGE propSheetPage; PPH_PROCESS_PROPPAGECONTEXT propPageContext; PPH_PROCESS_ITEM processItem; PPH_MEMORY_CONTEXT memoryContext; HWND tnHandle; if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { memoryContext = (PPH_MEMORY_CONTEXT)propPageContext->Context; if (memoryContext) tnHandle = memoryContext->ListContext.TreeNewHandle; } else { return FALSE; } switch (uMsg) { case WM_INITDIALOG: { memoryContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmMemoryContextType, sizeof(PH_MEMORY_CONTEXT))); memset(memoryContext, 0, sizeof(PH_MEMORY_CONTEXT)); memoryContext->ProcessId = processItem->ProcessId; // Initialize the list. tnHandle = GetDlgItem(hwndDlg, IDC_LIST); BringWindowToTop(tnHandle); PhInitializeMemoryList(hwndDlg, tnHandle, &memoryContext->ListContext); TreeNew_SetEmptyText(tnHandle, &PhpLoadingText, 0); memoryContext->LastRunStatus = -1; memoryContext->ErrorMessage = NULL; PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectCreate); if (PhPluginsEnabled) { PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; treeNewInfo.TreeNewHandle = tnHandle; treeNewInfo.CmData = &memoryContext->ListContext.Cm; treeNewInfo.SystemContext = memoryContext; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryTreeNewInitializing), &treeNewInfo); } PhLoadSettingsMemoryList(&memoryContext->ListContext); PhSetOptionsMemoryList(&memoryContext->ListContext, TRUE); Button_SetCheck(GetDlgItem(hwndDlg, IDC_HIDEFREEREGIONS), memoryContext->ListContext.HideFreeRegions ? BST_CHECKED : BST_UNCHECKED); PhpRefreshProcessMemoryList(hwndDlg, propPageContext); } break; case WM_DESTROY: { PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectDelete); if (PhPluginsEnabled) { PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; treeNewInfo.TreeNewHandle = tnHandle; treeNewInfo.CmData = &memoryContext->ListContext.Cm; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryTreeNewUninitializing), &treeNewInfo); } PhSaveSettingsMemoryList(&memoryContext->ListContext); PhDeleteMemoryList(&memoryContext->ListContext); if (memoryContext->MemoryItemListValid) PhDeleteMemoryItemList(&memoryContext->MemoryItemList); PhClearReference(&memoryContext->ErrorMessage); PhFree(memoryContext); PhpPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { if (!propPageContext->LayoutInitialized) { PPH_LAYOUT_ITEM dialogItem; dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STRINGS), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_REFRESH), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, memoryContext->ListContext.TreeNewHandle, dialogItem, PH_ANCHOR_ALL); PhDoPropPageLayout(hwndDlg); propPageContext->LayoutInitialized = TRUE; } } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case ID_SHOWCONTEXTMENU: { PhShowMemoryContextMenu(hwndDlg, processItem, memoryContext, (PPH_TREENEW_CONTEXT_MENU)lParam); } break; case ID_MEMORY_READWRITEMEMORY: { PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext); if (memoryNode && !memoryNode->IsAllocationBase) { if (memoryNode->MemoryItem->State & MEM_COMMIT) { PPH_SHOWMEMORYEDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOWMEMORYEDITOR)); memset(showMemoryEditor, 0, sizeof(PH_SHOWMEMORYEDITOR)); showMemoryEditor->ProcessId = processItem->ProcessId; showMemoryEditor->BaseAddress = memoryNode->MemoryItem->BaseAddress; showMemoryEditor->RegionSize = memoryNode->MemoryItem->RegionSize; showMemoryEditor->SelectOffset = -1; showMemoryEditor->SelectLength = 0; ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); } else { PhShowError(hwndDlg, L"Unable to edit the memory region because it is not committed."); } } } break; case ID_MEMORY_SAVE: { NTSTATUS status; HANDLE processHandle; PPH_MEMORY_NODE *memoryNodes; ULONG numberOfMemoryNodes; if (!NT_SUCCESS(status = PhOpenProcess( &processHandle, PROCESS_VM_READ, processItem->ProcessId ))) { PhShowStatus(hwndDlg, L"Unable to open the process", status, 0); break; } PhGetSelectedMemoryNodes(&memoryContext->ListContext, &memoryNodes, &numberOfMemoryNodes); if (numberOfMemoryNodes != 0) { static PH_FILETYPE_FILTER filters[] = { { L"Binary files (*.bin)", L"*.bin" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; fileDialog = PhCreateSaveFileDialog(); PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); PhSetFileDialogFileName(fileDialog, PhaConcatStrings2(processItem->ProcessName->Buffer, L".bin")->Buffer); if (PhShowFileDialog(hwndDlg, fileDialog)) { PPH_STRING fileName; PPH_FILE_STREAM fileStream; PVOID buffer; ULONG i; ULONG_PTR offset; fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); if (NT_SUCCESS(status = PhCreateFileStream( &fileStream, fileName->Buffer, FILE_GENERIC_WRITE, FILE_SHARE_READ, FILE_OVERWRITE_IF, 0 ))) { buffer = PhAllocatePage(PAGE_SIZE, NULL); // Go through each selected memory item and append the region contents // to the file. for (i = 0; i < numberOfMemoryNodes; i++) { PPH_MEMORY_NODE memoryNode = memoryNodes[i]; PPH_MEMORY_ITEM memoryItem = memoryNode->MemoryItem; if (!memoryNode->IsAllocationBase && !(memoryItem->State & MEM_COMMIT)) continue; for (offset = 0; offset < memoryItem->RegionSize; offset += PAGE_SIZE) { if (NT_SUCCESS(NtReadVirtualMemory( processHandle, PTR_ADD_OFFSET(memoryItem->BaseAddress, offset), buffer, PAGE_SIZE, NULL ))) { PhWriteFileStream(fileStream, buffer, PAGE_SIZE); } } } PhFreePage(buffer); PhDereferenceObject(fileStream); } if (!NT_SUCCESS(status)) PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); } PhFreeFileDialog(fileDialog); } PhFree(memoryNodes); NtClose(processHandle); } break; case ID_MEMORY_CHANGEPROTECTION: { PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext); if (memoryNode) { PhReferenceObject(memoryNode->MemoryItem); PhShowMemoryProtectDialog(hwndDlg, processItem, memoryNode->MemoryItem); PhUpdateMemoryNode(&memoryContext->ListContext, memoryNode); PhDereferenceObject(memoryNode->MemoryItem); } } break; case ID_MEMORY_FREE: { PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext); if (memoryNode) { PhReferenceObject(memoryNode->MemoryItem); PhUiFreeMemory(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem, TRUE); PhDereferenceObject(memoryNode->MemoryItem); // TODO: somehow update the list } } break; case ID_MEMORY_DECOMMIT: { PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext); if (memoryNode) { PhReferenceObject(memoryNode->MemoryItem); PhUiFreeMemory(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem, FALSE); PhDereferenceObject(memoryNode->MemoryItem); } } break; case ID_MEMORY_READWRITEADDRESS: { PPH_STRING selectedChoice = NULL; if (!memoryContext->MemoryItemListValid) break; while (PhaChoiceDialog( hwndDlg, L"Read/Write Address", L"Enter an address:", NULL, 0, NULL, PH_CHOICE_DIALOG_USER_CHOICE, &selectedChoice, NULL, L"MemoryReadWriteAddressChoices" )) { ULONG64 address64; PVOID address; if (selectedChoice->Length == 0) continue; if (PhStringToInteger64(&selectedChoice->sr, 0, &address64)) { PPH_MEMORY_ITEM memoryItem; address = (PVOID)address64; memoryItem = PhLookupMemoryItemList(&memoryContext->MemoryItemList, address); if (memoryItem) { PPH_SHOWMEMORYEDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOWMEMORYEDITOR)); memset(showMemoryEditor, 0, sizeof(PH_SHOWMEMORYEDITOR)); showMemoryEditor->ProcessId = processItem->ProcessId; showMemoryEditor->BaseAddress = memoryItem->BaseAddress; showMemoryEditor->RegionSize = memoryItem->RegionSize; showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)address - (ULONG_PTR)memoryItem->BaseAddress); showMemoryEditor->SelectLength = 0; ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); break; } else { PhShowError(hwndDlg, L"Unable to find the memory region for the selected address."); } } } } break; case ID_MEMORY_COPY: { PPH_STRING text; text = PhGetTreeNewText(tnHandle, 0); PhSetClipboardString(tnHandle, &text->sr); PhDereferenceObject(text); } break; case IDC_HIDEFREEREGIONS: { BOOLEAN hide; hide = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HIDEFREEREGIONS)) == BST_CHECKED; PhSetOptionsMemoryList(&memoryContext->ListContext, hide); } break; case IDC_STRINGS: PhShowMemoryStringDialog(hwndDlg, processItem); break; case IDC_REFRESH: PhpRefreshProcessMemoryList(hwndDlg, propPageContext); break; } } break; } return FALSE; }
INT_PTR CALLBACK PhpProcessThreadsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { LPPROPSHEETPAGE propSheetPage; PPH_PROCESS_PROPPAGECONTEXT propPageContext; PPH_PROCESS_ITEM processItem; PPH_THREADS_CONTEXT threadsContext; HWND tnHandle; if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { threadsContext = (PPH_THREADS_CONTEXT)propPageContext->Context; if (threadsContext) tnHandle = threadsContext->ListContext.TreeNewHandle; } else { return FALSE; } switch (uMsg) { case WM_INITDIALOG: { threadsContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmThreadsContextType, sizeof(PH_THREADS_CONTEXT))); // The thread provider has a special registration mechanism. threadsContext->Provider = PhCreateThreadProvider( processItem->ProcessId ); PhRegisterCallback( &threadsContext->Provider->ThreadAddedEvent, ThreadAddedHandler, threadsContext, &threadsContext->AddedEventRegistration ); PhRegisterCallback( &threadsContext->Provider->ThreadModifiedEvent, ThreadModifiedHandler, threadsContext, &threadsContext->ModifiedEventRegistration ); PhRegisterCallback( &threadsContext->Provider->ThreadRemovedEvent, ThreadRemovedHandler, threadsContext, &threadsContext->RemovedEventRegistration ); PhRegisterCallback( &threadsContext->Provider->UpdatedEvent, ThreadsUpdatedHandler, threadsContext, &threadsContext->UpdatedEventRegistration ); PhRegisterCallback( &threadsContext->Provider->LoadingStateChangedEvent, ThreadsLoadingStateChangedHandler, threadsContext, &threadsContext->LoadingStateChangedEventRegistration ); threadsContext->WindowHandle = hwndDlg; // Initialize the list. tnHandle = GetDlgItem(hwndDlg, IDC_LIST); BringWindowToTop(tnHandle); PhInitializeThreadList(hwndDlg, tnHandle, &threadsContext->ListContext); TreeNew_SetEmptyText(tnHandle, &EmptyThreadsText, 0); PhInitializeProviderEventQueue(&threadsContext->EventQueue, 100); // Use Cycles instead of Context Switches on Vista and above, but only when we can // open the process, since cycle time information requires sufficient access to the // threads. if (WINDOWS_HAS_CYCLE_TIME) { HANDLE processHandle; PROCESS_EXTENDED_BASIC_INFORMATION extendedBasicInfo; // We make a distinction between PROCESS_QUERY_INFORMATION and PROCESS_QUERY_LIMITED_INFORMATION since // the latter can be used when opening audiodg.exe even though we can't access its threads using // THREAD_QUERY_LIMITED_INFORMATION. if (processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID) { threadsContext->ListContext.UseCycleTime = TRUE; } else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, processItem->ProcessId))) { threadsContext->ListContext.UseCycleTime = TRUE; NtClose(processHandle); } else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, processItem->ProcessId))) { threadsContext->ListContext.UseCycleTime = TRUE; // We can't use cycle time for protected processes (without KProcessHacker). if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &extendedBasicInfo)) && extendedBasicInfo.IsProtectedProcess) { threadsContext->ListContext.UseCycleTime = FALSE; } NtClose(processHandle); } } if (processItem->ServiceList && processItem->ServiceList->Count != 0 && WINDOWS_HAS_SERVICE_TAGS) threadsContext->ListContext.HasServices = TRUE; PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectCreate); if (PhPluginsEnabled) { PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; treeNewInfo.TreeNewHandle = tnHandle; treeNewInfo.CmData = &threadsContext->ListContext.Cm; treeNewInfo.SystemContext = threadsContext; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadTreeNewInitializing), &treeNewInfo); } PhLoadSettingsThreadList(&threadsContext->ListContext); PhThreadProviderInitialUpdate(threadsContext->Provider); PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration); SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER))); } break; case WM_DESTROY: { PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectDelete); PhUnregisterCallback( &threadsContext->Provider->ThreadAddedEvent, &threadsContext->AddedEventRegistration ); PhUnregisterCallback( &threadsContext->Provider->ThreadModifiedEvent, &threadsContext->ModifiedEventRegistration ); PhUnregisterCallback( &threadsContext->Provider->ThreadRemovedEvent, &threadsContext->RemovedEventRegistration ); PhUnregisterCallback( &threadsContext->Provider->UpdatedEvent, &threadsContext->UpdatedEventRegistration ); PhUnregisterCallback( &threadsContext->Provider->LoadingStateChangedEvent, &threadsContext->LoadingStateChangedEventRegistration ); PhUnregisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration); PhSetTerminatingThreadProvider(threadsContext->Provider); PhDereferenceObject(threadsContext->Provider); PhDeleteProviderEventQueue(&threadsContext->EventQueue); if (PhPluginsEnabled) { PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; treeNewInfo.TreeNewHandle = tnHandle; treeNewInfo.CmData = &threadsContext->ListContext.Cm; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadTreeNewUninitializing), &treeNewInfo); } PhSaveSettingsThreadList(&threadsContext->ListContext); PhDeleteThreadList(&threadsContext->ListContext); PhFree(threadsContext); PhpPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { if (!propPageContext->LayoutInitialized) { PPH_LAYOUT_ITEM dialogItem; dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); #define ADD_BL_ITEM(Id) \ PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, Id), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM) // Thread details area { ULONG id; for (id = IDC_STATICBL1; id <= IDC_STATICBL11; id++) ADD_BL_ITEM(id); // Not in sequence ADD_BL_ITEM(IDC_STATICBL12); } PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTMODULE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); ADD_BL_ITEM(IDC_STARTED); ADD_BL_ITEM(IDC_KERNELTIME); ADD_BL_ITEM(IDC_USERTIME); ADD_BL_ITEM(IDC_CONTEXTSWITCHES); ADD_BL_ITEM(IDC_CYCLES); ADD_BL_ITEM(IDC_STATE); ADD_BL_ITEM(IDC_PRIORITY); ADD_BL_ITEM(IDC_BASEPRIORITY); ADD_BL_ITEM(IDC_IOPRIORITY); ADD_BL_ITEM(IDC_PAGEPRIORITY); ADD_BL_ITEM(IDC_IDEALPROCESSOR); PhDoPropPageLayout(hwndDlg); propPageContext->LayoutInitialized = TRUE; } } break; case WM_COMMAND: { INT id = LOWORD(wParam); switch (id) { case ID_SHOWCONTEXTMENU: { PhShowThreadContextMenu(hwndDlg, processItem, threadsContext, (PPH_TREENEW_CONTEXT_MENU)lParam); } break; case ID_THREAD_INSPECT: { PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); if (threadItem) { PhReferenceObject(threadsContext->Provider); PhShowThreadStackDialog( hwndDlg, threadsContext->Provider->ProcessId, threadItem->ThreadId, threadsContext->Provider ); PhDereferenceObject(threadsContext->Provider); } } break; case ID_THREAD_TERMINATE: { PPH_THREAD_ITEM *threads; ULONG numberOfThreads; PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads); PhReferenceObjects(threads, numberOfThreads); if (PhUiTerminateThreads(hwndDlg, threads, numberOfThreads)) PhDeselectAllThreadNodes(&threadsContext->ListContext); PhDereferenceObjects(threads, numberOfThreads); PhFree(threads); } break; case ID_THREAD_SUSPEND: { PPH_THREAD_ITEM *threads; ULONG numberOfThreads; PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads); PhReferenceObjects(threads, numberOfThreads); PhUiSuspendThreads(hwndDlg, threads, numberOfThreads); PhDereferenceObjects(threads, numberOfThreads); PhFree(threads); } break; case ID_THREAD_RESUME: { PPH_THREAD_ITEM *threads; ULONG numberOfThreads; PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads); PhReferenceObjects(threads, numberOfThreads); PhUiResumeThreads(hwndDlg, threads, numberOfThreads); PhDereferenceObjects(threads, numberOfThreads); PhFree(threads); } break; case ID_THREAD_AFFINITY: { PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); if (threadItem) { PhReferenceObject(threadItem); PhShowProcessAffinityDialog(hwndDlg, NULL, threadItem); PhDereferenceObject(threadItem); } } break; case ID_THREAD_PERMISSIONS: { PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); PH_STD_OBJECT_SECURITY stdObjectSecurity; PPH_ACCESS_ENTRY accessEntries; ULONG numberOfAccessEntries; if (threadItem) { stdObjectSecurity.OpenObject = PhpThreadPermissionsOpenThread; stdObjectSecurity.ObjectType = L"Thread"; stdObjectSecurity.Context = threadItem->ThreadId; if (PhGetAccessEntries(L"Thread", &accessEntries, &numberOfAccessEntries)) { PhEditSecurity( hwndDlg, PhaFormatString(L"Thread %u", HandleToUlong(threadItem->ThreadId))->Buffer, PhStdGetObjectSecurity, PhStdSetObjectSecurity, &stdObjectSecurity, accessEntries, numberOfAccessEntries ); PhFree(accessEntries); } } } break; case ID_THREAD_TOKEN: { NTSTATUS status; PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); HANDLE threadHandle; if (threadItem) { if (NT_SUCCESS(status = PhOpenThread( &threadHandle, ThreadQueryAccess, threadItem->ThreadId ))) { PhShowTokenProperties( hwndDlg, PhpOpenThreadTokenObject, (PVOID)threadHandle, NULL ); NtClose(threadHandle); } else { PhShowStatus(hwndDlg, L"Unable to open the thread", status, 0); } } } break; case ID_ANALYZE_WAIT: { PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); if (threadItem) { PhReferenceObject(threadsContext->Provider->SymbolProvider); PhUiAnalyzeWaitThread( hwndDlg, processItem->ProcessId, threadItem->ThreadId, threadsContext->Provider->SymbolProvider ); PhDereferenceObject(threadsContext->Provider->SymbolProvider); } } break; case ID_PRIORITY_TIMECRITICAL: case ID_PRIORITY_HIGHEST: case ID_PRIORITY_ABOVENORMAL: case ID_PRIORITY_NORMAL: case ID_PRIORITY_BELOWNORMAL: case ID_PRIORITY_LOWEST: case ID_PRIORITY_IDLE: { PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); if (threadItem) { ULONG threadPriorityWin32; switch (id) { case ID_PRIORITY_TIMECRITICAL: threadPriorityWin32 = THREAD_PRIORITY_TIME_CRITICAL; break; case ID_PRIORITY_HIGHEST: threadPriorityWin32 = THREAD_PRIORITY_HIGHEST; break; case ID_PRIORITY_ABOVENORMAL: threadPriorityWin32 = THREAD_PRIORITY_ABOVE_NORMAL; break; case ID_PRIORITY_NORMAL: threadPriorityWin32 = THREAD_PRIORITY_NORMAL; break; case ID_PRIORITY_BELOWNORMAL: threadPriorityWin32 = THREAD_PRIORITY_BELOW_NORMAL; break; case ID_PRIORITY_LOWEST: threadPriorityWin32 = THREAD_PRIORITY_LOWEST; break; case ID_PRIORITY_IDLE: threadPriorityWin32 = THREAD_PRIORITY_IDLE; break; } PhReferenceObject(threadItem); PhUiSetPriorityThread(hwndDlg, threadItem, threadPriorityWin32); PhDereferenceObject(threadItem); } } break; case ID_IOPRIORITY_VERYLOW: case ID_IOPRIORITY_LOW: case ID_IOPRIORITY_NORMAL: case ID_IOPRIORITY_HIGH: { PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); if (threadItem) { IO_PRIORITY_HINT ioPriority; switch (id) { case ID_IOPRIORITY_VERYLOW: ioPriority = IoPriorityVeryLow; break; case ID_IOPRIORITY_LOW: ioPriority = IoPriorityLow; break; case ID_IOPRIORITY_NORMAL: ioPriority = IoPriorityNormal; break; case ID_IOPRIORITY_HIGH: ioPriority = IoPriorityHigh; break; } PhReferenceObject(threadItem); PhUiSetIoPriorityThread(hwndDlg, threadItem, ioPriority); PhDereferenceObject(threadItem); } } break; case ID_PAGEPRIORITY_VERYLOW: case ID_PAGEPRIORITY_LOW: case ID_PAGEPRIORITY_MEDIUM: case ID_PAGEPRIORITY_BELOWNORMAL: case ID_PAGEPRIORITY_NORMAL: { PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); if (threadItem) { ULONG pagePriority; switch (id) { case ID_PAGEPRIORITY_VERYLOW: pagePriority = MEMORY_PRIORITY_VERY_LOW; break; case ID_PAGEPRIORITY_LOW: pagePriority = MEMORY_PRIORITY_LOW; break; case ID_PAGEPRIORITY_MEDIUM: pagePriority = MEMORY_PRIORITY_MEDIUM; break; case ID_PAGEPRIORITY_BELOWNORMAL: pagePriority = MEMORY_PRIORITY_BELOW_NORMAL; break; case ID_PAGEPRIORITY_NORMAL: pagePriority = MEMORY_PRIORITY_NORMAL; break; } PhReferenceObject(threadItem); PhUiSetPagePriorityThread(hwndDlg, threadItem, pagePriority); PhDereferenceObject(threadItem); } } break; case ID_THREAD_COPY: { PPH_STRING text; text = PhGetTreeNewText(tnHandle, 0); PhSetClipboardString(tnHandle, &text->sr); PhDereferenceObject(text); } break; case IDC_OPENSTARTMODULE: { PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); if (threadItem && threadItem->StartAddressFileName) { PhShellExploreFile(hwndDlg, threadItem->StartAddressFileName->Buffer); } } break; } } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case PSN_SETACTIVE: break; case PSN_KILLACTIVE: // Can't disable, it screws up the deltas. break; } } break; case WM_PH_THREADS_UPDATED: { ULONG upToRunId = (ULONG)wParam; BOOLEAN firstRun = !!lParam; PPH_PROVIDER_EVENT events; ULONG count; ULONG i; events = PhFlushProviderEventQueue(&threadsContext->EventQueue, upToRunId, &count); if (events) { TreeNew_SetRedraw(tnHandle, FALSE); for (i = 0; i < count; i++) { PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]); PPH_THREAD_ITEM threadItem = PH_PROVIDER_EVENT_OBJECT(events[i]); switch (type) { case ProviderAddedEvent: PhAddThreadNode(&threadsContext->ListContext, threadItem, firstRun); PhDereferenceObject(threadItem); break; case ProviderModifiedEvent: PhUpdateThreadNode(&threadsContext->ListContext, PhFindThreadNode(&threadsContext->ListContext, threadItem->ThreadId)); break; case ProviderRemovedEvent: PhRemoveThreadNode(&threadsContext->ListContext, PhFindThreadNode(&threadsContext->ListContext, threadItem->ThreadId)); break; } } PhFree(events); } PhTickThreadNodes(&threadsContext->ListContext); if (count != 0) TreeNew_SetRedraw(tnHandle, TRUE); if (propPageContext->PropContext->SelectThreadId) { PPH_THREAD_NODE threadNode; if (threadNode = PhFindThreadNode(&threadsContext->ListContext, propPageContext->PropContext->SelectThreadId)) { if (threadNode->Node.Visible) { TreeNew_SetFocusNode(tnHandle, &threadNode->Node); TreeNew_SetMarkNode(tnHandle, &threadNode->Node); TreeNew_SelectRange(tnHandle, threadNode->Node.Index, threadNode->Node.Index); TreeNew_EnsureVisible(tnHandle, &threadNode->Node); } } propPageContext->PropContext->SelectThreadId = NULL; } PhpUpdateThreadDetails(hwndDlg, threadsContext, FALSE); } break; case WM_PH_THREAD_SELECTION_CHANGED: { PhpUpdateThreadDetails(hwndDlg, threadsContext, TRUE); } break; } return FALSE; }