Skip to content

Commit db520d3

Browse files
committed
Add search support to process threads tab
1 parent c57b049 commit db520d3

File tree

5 files changed

+176
-7
lines changed

5 files changed

+176
-7
lines changed

ProcessHacker/ProcessHacker.rc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,9 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM
517517
CAPTION "Threads"
518518
FONT 8, "MS Shell Dlg", 400, 0, 0x1
519519
BEGIN
520-
CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,2,256,256,WS_EX_CLIENTEDGE
520+
CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE
521+
EDITTEXT IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL
522+
PUSHBUTTON "Options",IDC_FILTEROPTIONS,2,2,50,14
521523
END
522524

523525
IDD_PROCHANDLES DIALOGEX 0, 0, 260, 260

ProcessHacker/include/procprpp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,10 @@ typedef struct _PH_THREADS_CONTEXT
164164
PH_CALLBACK_REGISTRATION LoadingStateChangedEventRegistration;
165165

166166
HWND WindowHandle;
167+
HWND SearchboxHandle;
167168
// end_phapppub
168-
169+
PPH_STRING SearchboxText;
170+
PPH_TN_FILTER_ENTRY FilterEntry;
169171
union
170172
{
171173
PH_THREAD_LIST_CONTEXT ListContext;

ProcessHacker/include/thrdlist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ typedef struct _PH_THREAD_LIST_CONTEXT
8585

8686
BOOLEAN EnableStateHighlighting;
8787
PPH_POINTER_LIST NodeStateList;
88+
PH_TN_FILTER_SUPPORT TreeFilterSupport;
8889
} PH_THREAD_LIST_CONTEXT, *PPH_THREAD_LIST_CONTEXT;
8990

9091
VOID PhInitializeThreadList(

ProcessHacker/prpgthrd.c

Lines changed: 167 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,136 @@ static NTSTATUS NTAPI PhpOpenThreadTokenObject(
315315
);
316316
}
317317

318+
static BOOLEAN PhpWordMatchThreadStringRef(
319+
_In_ PPH_STRING SearchText,
320+
_In_ PPH_STRINGREF Text
321+
)
322+
{
323+
PH_STRINGREF part;
324+
PH_STRINGREF remainingPart;
325+
326+
remainingPart = SearchText->sr;
327+
328+
while (remainingPart.Length)
329+
{
330+
PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart);
331+
332+
if (part.Length)
333+
{
334+
if (PhFindStringInStringRef(Text, &part, TRUE) != -1)
335+
return TRUE;
336+
}
337+
}
338+
339+
return FALSE;
340+
}
341+
342+
static BOOLEAN PhpWordMatchThreadStringZ(
343+
_In_ PPH_STRING SearchText,
344+
_In_ PWSTR Text
345+
)
346+
{
347+
PH_STRINGREF text;
348+
349+
PhInitializeStringRef(&text, Text);
350+
351+
return PhpWordMatchThreadStringRef(SearchText, &text);
352+
}
353+
354+
BOOLEAN PhpThreadTreeFilterCallback(
355+
_In_ PPH_TREENEW_NODE Node,
356+
_In_opt_ PPH_THREADS_CONTEXT Context
357+
)
358+
{
359+
PPH_THREAD_NODE threadNode = (PPH_THREAD_NODE)Node;
360+
PPH_THREAD_ITEM threadItem = threadNode->ThreadItem;
361+
362+
if (PhIsNullOrEmptyString(Context->SearchboxText))
363+
return TRUE;
364+
365+
// thread properties
366+
367+
if (threadNode->ThreadIdText[0])
368+
{
369+
if (PhpWordMatchThreadStringZ(Context->SearchboxText, threadNode->ThreadIdText))
370+
return TRUE;
371+
}
372+
373+
if (threadNode->PriorityText[0])
374+
{
375+
if (PhpWordMatchThreadStringZ(Context->SearchboxText, threadNode->PriorityText))
376+
return TRUE;
377+
}
378+
379+
if (threadNode->BasePriorityText[0])
380+
{
381+
if (PhpWordMatchThreadStringZ(Context->SearchboxText, threadNode->BasePriorityText))
382+
return TRUE;
383+
}
384+
385+
if (threadNode->IdealProcessorText[0])
386+
{
387+
if (PhpWordMatchThreadStringZ(Context->SearchboxText, threadNode->IdealProcessorText))
388+
return TRUE;
389+
}
390+
391+
if (threadNode->ThreadIdHexText[0])
392+
{
393+
if (PhpWordMatchThreadStringZ(Context->SearchboxText, threadNode->ThreadIdHexText))
394+
return TRUE;
395+
}
396+
397+
if (!PhIsNullOrEmptyString(threadNode->StartAddressText))
398+
{
399+
if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->StartAddressText->sr))
400+
return TRUE;
401+
}
402+
403+
if (!PhIsNullOrEmptyString(threadNode->PrioritySymbolicText))
404+
{
405+
if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->PrioritySymbolicText->sr))
406+
return TRUE;
407+
}
408+
409+
if (!PhIsNullOrEmptyString(threadNode->CreatedText))
410+
{
411+
if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->CreatedText->sr))
412+
return TRUE;
413+
}
414+
415+
if (!PhIsNullOrEmptyString(threadNode->NameText))
416+
{
417+
if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->NameText->sr))
418+
return TRUE;
419+
}
420+
421+
if (!PhIsNullOrEmptyString(threadNode->StateText))
422+
{
423+
if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->StateText->sr))
424+
return TRUE;
425+
}
426+
427+
if (!PhIsNullOrEmptyString(threadNode->ThreadItem->ServiceName))
428+
{
429+
if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->ThreadItem->ServiceName->sr))
430+
return TRUE;
431+
}
432+
433+
if (!PhIsNullOrEmptyString(threadNode->ThreadItem->StartAddressString))
434+
{
435+
if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->ThreadItem->StartAddressString->sr))
436+
return TRUE;
437+
}
438+
439+
if (!PhIsNullOrEmptyString(threadNode->ThreadItem->StartAddressFileName))
440+
{
441+
if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->ThreadItem->StartAddressFileName->sr))
442+
return TRUE;
443+
}
444+
445+
return FALSE;
446+
}
447+
318448
VOID PhShowThreadContextMenu(
319449
_In_ HWND hwndDlg,
320450
_In_ PPH_PROCESS_ITEM ProcessItem,
@@ -445,21 +575,27 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc(
445575
&threadsContext->LoadingStateChangedEventRegistration
446576
);
447577
threadsContext->WindowHandle = hwndDlg;
578+
threadsContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_SEARCH);
579+
580+
PhCreateSearchControl(hwndDlg, threadsContext->SearchboxHandle, L"Search Threads (Ctrl+K)");
448581

449582
// Initialize the list.
450583
tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
451584
PhInitializeThreadList(hwndDlg, tnHandle, &threadsContext->ListContext);
452585
TreeNew_SetEmptyText(tnHandle, &EmptyThreadsText, 0);
453586
PhInitializeProviderEventQueue(&threadsContext->EventQueue, 100);
587+
threadsContext->SearchboxText = PhReferenceEmptyString();
588+
threadsContext->FilterEntry = PhAddTreeNewFilter(&threadsContext->ListContext.TreeFilterSupport, PhpThreadTreeFilterCallback, threadsContext);
589+
454590
// Use Cycles instead of Context Switches on Vista and above, but only when we can
455591
// open the process, since cycle time information requires sufficient access to the
456-
// threads.
592+
// threads. (wj32)
457593
{
458594
HANDLE processHandle;
459595

460596
// We make a distinction between PROCESS_QUERY_INFORMATION and PROCESS_QUERY_LIMITED_INFORMATION since
461597
// the latter can be used when opening audiodg.exe even though we can't access its threads using
462-
// THREAD_QUERY_LIMITED_INFORMATION.
598+
// THREAD_QUERY_LIMITED_INFORMATION. (wj32)
463599

464600
if (processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID)
465601
{
@@ -474,7 +610,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc(
474610
{
475611
threadsContext->ListContext.UseCycleTime = TRUE;
476612

477-
// We can't use cycle time for protected processes (without KProcessHacker).
613+
// We can't use cycle time for protected processes (without KProcessHacker). (wj32)
478614
if (processItem->IsProtectedProcess)
479615
{
480616
threadsContext->ListContext.UseCycleTime = FALSE;
@@ -509,6 +645,9 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc(
509645
break;
510646
case WM_DESTROY:
511647
{
648+
PhRemoveTreeNewFilter(&threadsContext->ListContext.TreeFilterSupport, threadsContext->FilterEntry);
649+
if (threadsContext->SearchboxText) PhDereferenceObject(threadsContext->SearchboxText);
650+
512651
PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectDelete);
513652

514653
PhUnregisterCallback(
@@ -557,13 +696,36 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc(
557696

558697
if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))
559698
{
560-
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL);
699+
PhAddPropPageLayoutItem(hwndDlg, threadsContext->SearchboxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
700+
PhAddPropPageLayoutItem(hwndDlg, tnHandle, dialogItem, PH_ANCHOR_ALL);
561701
PhEndPropPageLayout(hwndDlg, propPageContext);
562702
}
563703
}
564704
break;
565705
case WM_COMMAND:
566706
{
707+
switch (GET_WM_COMMAND_CMD(wParam, lParam))
708+
{
709+
case EN_CHANGE:
710+
{
711+
PPH_STRING newSearchboxText;
712+
713+
if (GET_WM_COMMAND_HWND(wParam, lParam) != threadsContext->SearchboxHandle)
714+
break;
715+
716+
newSearchboxText = PH_AUTO(PhGetWindowText(threadsContext->SearchboxHandle));
717+
718+
if (!PhEqualString(threadsContext->SearchboxText, newSearchboxText, FALSE))
719+
{
720+
// Cache the current search text for our callback.
721+
PhSwapReference(&threadsContext->SearchboxText, newSearchboxText);
722+
723+
PhApplyTreeNewFilters(&threadsContext->ListContext.TreeFilterSupport);
724+
}
725+
}
726+
break;
727+
}
728+
567729
switch (GET_WM_COMMAND_ID(wParam, lParam))
568730
{
569731
case ID_SHOWCONTEXTMENU:
@@ -915,7 +1077,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc(
9151077
// Can't disable, it screws up the deltas.
9161078
break;
9171079
case PSN_QUERYINITIALFOCUS:
918-
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_LIST));
1080+
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)tnHandle);
9191081
return TRUE;
9201082
}
9211083
}

ProcessHacker/thrdlist.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ VOID PhInitializeThreadList(
120120
//TreeNew_SetSort(TreeNewHandle, PHTHTLC_CYCLESDELTA, DescendingSortOrder);
121121

122122
PhCmInitializeManager(&Context->Cm, TreeNewHandle, PH_THREAD_TREELIST_COLUMN_MAXIMUM, PhpThreadTreeNewPostSortFunction);
123+
124+
PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList);
123125
}
124126

125127
VOID PhDeleteThreadList(

0 commit comments

Comments
 (0)