Process Hacker
proctree.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * process tree list
4  *
5  * Copyright (C) 2010-2015 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /*
24  * The process tree list manages a list of tree nodes and handles callback
25  * events generated by the underlying treenew control. Retrieval of
26  * certain types of process information is also performed here, on the
27  * GUI thread (see PH_PROCESS_NODE.ValidMask). This is done for columns
28  * that require data not supplied by the process provider.
29  */
30 
31 #include <phapp.h>
32 #include <settings.h>
33 #include <extmgri.h>
34 #include <phplug.h>
35 #include <cpysave.h>
36 #include <emenu.h>
37 #include <verify.h>
38 
40  _In_ PPH_PROCESS_NODE ProcessNode
41  );
42 
44  VOID
45  );
46 
48  _Inout_ PPH_PROCESS_NODE ProcessNode
49  );
50 
52  _In_ LONG Result,
53  _In_ PVOID Node1,
54  _In_ PVOID Node2,
55  _In_ PH_SORT_ORDER SortOrder
56  );
57 
58 BOOLEAN NTAPI PhpProcessTreeNewCallback(
59  _In_ HWND hwnd,
60  _In_ PH_TREENEW_MESSAGE Message,
61  _In_opt_ PVOID Parameter1,
62  _In_opt_ PVOID Parameter2,
63  _In_opt_ PVOID Context
64  );
65 
66 static HWND ProcessTreeListHandle;
67 static ULONG ProcessTreeListSortColumn;
68 static PH_SORT_ORDER ProcessTreeListSortOrder;
69 static PH_CM_MANAGER ProcessTreeListCm;
70 
71 static PPH_HASH_ENTRY ProcessNodeHashSet[256] = PH_HASH_SET_INIT; // hashtable of all nodes
72 static PPH_LIST ProcessNodeList; // list of all nodes, used when sorting is enabled
73 static PPH_LIST ProcessNodeRootList; // list of root nodes
74 
76 static PPH_POINTER_LIST ProcessNodeStateList = NULL; // list of nodes which need to be processed
77 
78 static PH_TN_FILTER_SUPPORT FilterSupport;
79 static BOOLEAN NeedCyclesInformation = FALSE;
80 
81 static HDC GraphContext = NULL;
82 static ULONG GraphContextWidth = 0;
83 static ULONG GraphContextHeight = 0;
84 static HBITMAP GraphOldBitmap;
85 static HBITMAP GraphBitmap = NULL;
86 static PVOID GraphBits = NULL;
87 
89  VOID
90  )
91 {
92  ProcessNodeList = PhCreateList(40);
93  ProcessNodeRootList = PhCreateList(10);
94 }
95 
97  _In_ HWND hwnd
98  )
99 {
100  ProcessTreeListHandle = hwnd;
101  PhSetControlTheme(ProcessTreeListHandle, L"explorer");
103  SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);
104 
106 
108 
109  TreeNew_SetRedraw(hwnd, FALSE);
110 
111  // Default columns
112  PhAddTreeNewColumn(hwnd, PHPRTLC_NAME, TRUE, L"Name", 200, PH_ALIGN_LEFT, -2, 0);
113  PhAddTreeNewColumn(hwnd, PHPRTLC_PID, TRUE, L"PID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT);
114  PhAddTreeNewColumnEx(hwnd, PHPRTLC_CPU, TRUE, L"CPU", 45, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE);
115  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOTOTALRATE, TRUE, L"I/O Total Rate", 70, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE);
116  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEBYTES, TRUE, L"Private Bytes", 70, PH_ALIGN_RIGHT, 3, DT_RIGHT, TRUE);
117  PhAddTreeNewColumn(hwnd, PHPRTLC_USERNAME, TRUE, L"User Name", 140, PH_ALIGN_LEFT, 4, DT_PATH_ELLIPSIS);
118  PhAddTreeNewColumn(hwnd, PHPRTLC_DESCRIPTION, TRUE, L"Description", 180, PH_ALIGN_LEFT, 5, 0);
119 
120  // Customizable columns (1)
121  PhAddTreeNewColumn(hwnd, PHPRTLC_COMPANYNAME, FALSE, L"Company Name", 180, PH_ALIGN_LEFT, -1, 0);
122  PhAddTreeNewColumn(hwnd, PHPRTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0);
123  PhAddTreeNewColumn(hwnd, PHPRTLC_FILENAME, FALSE, L"File Name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS);
124  PhAddTreeNewColumn(hwnd, PHPRTLC_COMMANDLINE, FALSE, L"Command Line", 180, PH_ALIGN_LEFT, -1, 0);
125  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPRIVATEBYTES, FALSE, L"Peak Private Bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
126  PhAddTreeNewColumnEx(hwnd, PHPRTLC_WORKINGSET, FALSE, L"Working Set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
127  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKWORKINGSET, FALSE, L"Peak Working Set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
128  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEWS, FALSE, L"Private WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
129  PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREDWS, FALSE, L"Shared WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
130  PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREABLEWS, FALSE, L"Shareable WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
131  PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALSIZE, FALSE, L"Virtual Size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
132  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKVIRTUALSIZE, FALSE, L"Peak Virtual Size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
133  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTS, FALSE, L"Page Faults", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
134  PhAddTreeNewColumn(hwnd, PHPRTLC_SESSIONID, FALSE, L"Session ID", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT);
135  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIORITYCLASS, FALSE, L"Priority Class", 100, PH_ALIGN_LEFT, -1, 0, TRUE);
136  PhAddTreeNewColumnEx(hwnd, PHPRTLC_BASEPRIORITY, FALSE, L"Base Priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
137 
138  // Customizable columns (2)
139  PhAddTreeNewColumnEx(hwnd, PHPRTLC_THREADS, FALSE, L"Threads", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
140  PhAddTreeNewColumnEx(hwnd, PHPRTLC_HANDLES, FALSE, L"Handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
141  PhAddTreeNewColumnEx(hwnd, PHPRTLC_GDIHANDLES, FALSE, L"GDI Handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
142  PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERHANDLES, FALSE, L"USER Handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
143  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IORORATE, FALSE, L"I/O Read+Other Rate", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
144  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRATE, FALSE, L"I/O Write Rate", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
145  PhAddTreeNewColumn(hwnd, PHPRTLC_INTEGRITY, FALSE, L"Integrity", 100, PH_ALIGN_LEFT, -1, 0);
146  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOPRIORITY, FALSE, L"I/O Priority", 70, PH_ALIGN_LEFT, -1, 0, TRUE);
147  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEPRIORITY, FALSE, L"Page Priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
148  PhAddTreeNewColumnEx(hwnd, PHPRTLC_STARTTIME, FALSE, L"Start Time", 100, PH_ALIGN_LEFT, -1, 0, TRUE);
149  PhAddTreeNewColumnEx(hwnd, PHPRTLC_TOTALCPUTIME, FALSE, L"Total CPU Time", 90, PH_ALIGN_LEFT, -1, 0, TRUE);
150  PhAddTreeNewColumnEx(hwnd, PHPRTLC_KERNELCPUTIME, FALSE, L"Kernel CPU Time", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
151  PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERCPUTIME, FALSE, L"User CPU Time", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
152  PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFICATIONSTATUS, FALSE, L"Verification Status", 70, PH_ALIGN_LEFT, -1, 0);
153  PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFIEDSIGNER, FALSE, L"Verified Signer", 100, PH_ALIGN_LEFT, -1, 0);
154  PhAddTreeNewColumnEx(hwnd, PHPRTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, -1, 0, TRUE);
155  PhAddTreeNewColumn(hwnd, PHPRTLC_RELATIVESTARTTIME, FALSE, L"Relative Start Time", 180, PH_ALIGN_LEFT, -1, 0);
156  PhAddTreeNewColumn(hwnd, PHPRTLC_BITS, FALSE, L"Bits", 50, PH_ALIGN_LEFT, -1, 0);
157  PhAddTreeNewColumnEx(hwnd, PHPRTLC_ELEVATION, FALSE, L"Elevation", 60, PH_ALIGN_LEFT, -1, 0, TRUE);
158  PhAddTreeNewColumn(hwnd, PHPRTLC_WINDOWTITLE, FALSE, L"Window Title", 120, PH_ALIGN_LEFT, -1, 0);
159  PhAddTreeNewColumnEx(hwnd, PHPRTLC_WINDOWSTATUS, FALSE, L"Window Status", 60, PH_ALIGN_LEFT, -1, 0, TRUE);
160  PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLES, FALSE, L"Cycles", 110, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
161  PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLESDELTA, FALSE, L"Cycles Delta", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
165  PhAddTreeNewColumn(hwnd, PHPRTLC_DEPSTATUS, FALSE, L"DEP Status", 100, PH_ALIGN_LEFT, -1, 0);
166  PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALIZED, FALSE, L"Virtualized", 80, PH_ALIGN_LEFT, -1, 0, TRUE);
167  PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHES, FALSE, L"Context Switches", 100, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
168  PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHESDELTA, FALSE, L"Context Switches Delta", 80, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
169  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTSDELTA, FALSE, L"Page Faults Delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
170 
171  // I/O group columns
172  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADS, FALSE, L"I/O Reads", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
173  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITES, FALSE, L"I/O Writes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
174  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHER, FALSE, L"I/O Other", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
175  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADBYTES, FALSE, L"I/O Read Bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
176  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITEBYTES, FALSE, L"I/O Write Bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
177  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERBYTES, FALSE, L"I/O Other Bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
178  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADSDELTA, FALSE, L"I/O Reads Delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
179  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITESDELTA, FALSE, L"I/O Writes Delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
180  PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERDELTA, FALSE, L"I/O Other Delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
181 
182  // Customizable columns (3)
183  PhAddTreeNewColumn(hwnd, PHPRTLC_OSCONTEXT, FALSE, L"OS Context", 100, PH_ALIGN_LEFT, -1, 0);
184  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEDPOOL, FALSE, L"Paged Pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
185  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPAGEDPOOL, FALSE, L"Peak Paged Pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
186  PhAddTreeNewColumnEx(hwnd, PHPRTLC_NONPAGEDPOOL, FALSE, L"Non-Paged Pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
187  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKNONPAGEDPOOL, FALSE, L"Peak Non-Paged Pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
188  PhAddTreeNewColumnEx(hwnd, PHPRTLC_MINIMUMWORKINGSET, FALSE, L"Minimum Working Set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
189  PhAddTreeNewColumnEx(hwnd, PHPRTLC_MAXIMUMWORKINGSET, FALSE, L"Maximum Working Set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
190  PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEBYTESDELTA, FALSE, L"Private Bytes Delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE);
191  PhAddTreeNewColumn(hwnd, PHPRTLC_SUBSYSTEM, FALSE, L"Subsystem", 110, PH_ALIGN_LEFT, -1, 0);
192  PhAddTreeNewColumn(hwnd, PHPRTLC_PACKAGENAME, FALSE, L"Package Name", 160, PH_ALIGN_LEFT, -1, 0);
193  PhAddTreeNewColumn(hwnd, PHPRTLC_APPID, FALSE, L"App ID", 160, PH_ALIGN_LEFT, -1, 0);
194  PhAddTreeNewColumn(hwnd, PHPRTLC_DPIAWARENESS, FALSE, L"DPI Awareness", 110, PH_ALIGN_LEFT, -1, 0);
195  PhAddTreeNewColumnEx(hwnd, PHPRTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, -1, 0, TRUE);
196 
197  TreeNew_SetRedraw(hwnd, TRUE);
198 
199  TreeNew_SetTriState(hwnd, TRUE);
200  TreeNew_SetSort(hwnd, 0, NoSortOrder);
201 
203 
204  if (PhPluginsEnabled)
205  {
206  PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
207 
208  treeNewInfo.TreeNewHandle = hwnd;
209  treeNewInfo.CmData = &ProcessTreeListCm;
211  }
212 
213  PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, ProcessNodeList);
214 }
215 
217  VOID
218  )
219 {
220  PPH_STRING settings;
221  PPH_STRING sortSettings;
222 
223  settings = PhGetStringSetting(L"ProcessTreeListColumns");
224  sortSettings = PhGetStringSetting(L"ProcessTreeListSort");
225  PhCmLoadSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &settings->sr, &sortSettings->sr);
226  PhDereferenceObject(settings);
227  PhDereferenceObject(sortSettings);
228 
229  if (PhGetIntegerSetting(L"EnableInstantTooltips"))
230  {
231  SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0);
232  }
233 
235 }
236 
238  VOID
239  )
240 {
241  PPH_STRING settings;
242  PPH_STRING sortSettings;
243 
244  settings = PhCmSaveSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &sortSettings);
245  PhSetStringSetting2(L"ProcessTreeListColumns", &settings->sr);
246  PhSetStringSetting2(L"ProcessTreeListSort", &sortSettings->sr);
247  PhDereferenceObject(settings);
248  PhDereferenceObject(sortSettings);
249 }
250 
252  VOID
253  )
254 {
255  SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL,
256  PhGetIntegerSetting(L"EnableInstantTooltips") ? 0 : -1);
257 }
258 
260  VOID
261  )
262 {
263  return &FilterSupport;
264 }
265 
266 FORCEINLINE BOOLEAN PhCompareProcessNode(
267  _In_ PPH_PROCESS_NODE Value1,
268  _In_ PPH_PROCESS_NODE Value2
269  )
270 {
271  return Value1->ProcessId == Value2->ProcessId;
272 }
273 
274 FORCEINLINE ULONG PhHashProcessNode(
275  _In_ PPH_PROCESS_NODE Value
276  )
277 {
278  return (ULONG)Value->ProcessId / 4;
279 }
280 
281 FORCEINLINE BOOLEAN PhpValidateParentCreateTime(
282  _In_ PPH_PROCESS_NODE Child,
283  _In_ PPH_PROCESS_NODE Parent
284  )
285 {
286  return
287  PH_IS_FAKE_PROCESS_ID(Child->ProcessId) ||
288  Parent->ProcessItem->CreateTime.QuadPart <= Child->ProcessItem->CreateTime.QuadPart;
289 }
290 
292  _In_ PPH_PROCESS_ITEM ProcessItem,
293  _In_ ULONG RunId
294  )
295 {
296  PPH_PROCESS_NODE processNode;
297  PPH_PROCESS_NODE parentNode;
298  ULONG i;
299 
300  processNode = PhAllocate(PhEmGetObjectSize(EmProcessNodeType, sizeof(PH_PROCESS_NODE)));
301  memset(processNode, 0, sizeof(PH_PROCESS_NODE));
302  PhInitializeTreeNewNode(&processNode->Node);
303 
304  if (PhProcessTreeListStateHighlighting && RunId != 1)
305  {
307  &processNode->Node,
308  &processNode->ShState,
309  &ProcessNodeStateList,
310  NewItemState,
311  PhCsColorNew,
312  NULL
313  );
314  }
315 
316  processNode->ProcessId = ProcessItem->ProcessId;
317  processNode->ProcessItem = ProcessItem;
318  PhReferenceObject(ProcessItem);
319 
320  memset(processNode->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM);
321  processNode->Node.TextCache = processNode->TextCache;
322  processNode->Node.TextCacheSize = PHPRTLC_MAXIMUM;
323 
324  processNode->Children = PhCreateList(1);
325 
326  // Find this process' parent and add the process to it if we found it.
327  if (
328  (parentNode = PhFindProcessNode(ProcessItem->ParentProcessId)) &&
329  PhpValidateParentCreateTime(processNode, parentNode)
330  )
331  {
332  PhAddItemList(parentNode->Children, processNode);
333  processNode->Parent = parentNode;
334  }
335  else
336  {
337  // No parent, add to root list.
338  processNode->Parent = NULL;
339  PhAddItemList(ProcessNodeRootList, processNode);
340  }
341 
342  // Find this process' children and move them to this node.
343 
344  for (i = 0; i < ProcessNodeRootList->Count; i++)
345  {
346  PPH_PROCESS_NODE node = ProcessNodeRootList->Items[i];
347 
348  if (
349  node != processNode && // for cases where the parent PID = PID (e.g. System Idle Process)
350  node->ProcessItem->ParentProcessId == ProcessItem->ProcessId &&
351  PhpValidateParentCreateTime(node, processNode)
352  )
353  {
354  node->Parent = processNode;
355  PhAddItemList(processNode->Children, node);
356  }
357  }
358 
359  for (i = 0; i < processNode->Children->Count; i++)
360  {
362  ProcessNodeRootList,
363  PhFindItemList(ProcessNodeRootList, processNode->Children->Items[i])
364  );
365  }
366 
368  ProcessNodeHashSet,
369  PH_HASH_SET_SIZE(ProcessNodeHashSet),
370  &processNode->HashEntry,
371  PhHashProcessNode(processNode)
372  );
373  PhAddItemList(ProcessNodeList, processNode);
374 
376  {
377  static PH_STRINGREF servicesBaseName = PH_STRINGREF_INIT(L"\\services.exe");
378  static BOOLEAN servicesFound = FALSE;
379  static PPH_STRING servicesFileName = NULL;
380 
381  if (!servicesFound)
382  {
383  if (!servicesFileName)
384  {
385  PPH_STRING systemDirectory;
386 
387  systemDirectory = PhGetSystemDirectory();
388  servicesFileName = PhConcatStringRef2(&systemDirectory->sr, &servicesBaseName);
389  PhDereferenceObject(systemDirectory);
390  }
391 
392  // If this process is services.exe, collapse the node and free the string.
393  if (
394  ProcessItem->FileName &&
395  PhEqualString(ProcessItem->FileName, servicesFileName, TRUE)
396  )
397  {
398  processNode->Node.Expanded = FALSE;
399  PhDereferenceObject(servicesFileName);
400  servicesFileName = NULL;
401  servicesFound = TRUE;
402  }
403  }
404  }
405 
406  if (WindowsVersion >= WINDOWS_7 && PhEnableCycleCpuUsage && ProcessItem->ProcessId == INTERRUPTS_PROCESS_ID)
407  PhInitializeStringRef(&processNode->DescriptionText, L"Interrupts and DPCs");
408 
409  if (FilterSupport.FilterList)
410  processNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &processNode->Node);
411 
413 
414  TreeNew_NodesStructured(ProcessTreeListHandle);
415 
416  return processNode;
417 }
418 
420  _In_ HANDLE ProcessId
421  )
422 {
423  PH_PROCESS_NODE lookupNode;
424  PPH_HASH_ENTRY entry;
425  PPH_PROCESS_NODE node;
426 
427  lookupNode.ProcessId = ProcessId;
428  entry = PhFindEntryHashSet(
429  ProcessNodeHashSet,
430  PH_HASH_SET_SIZE(ProcessNodeHashSet),
431  PhHashProcessNode(&lookupNode)
432  );
433 
434  for (; entry; entry = entry->Next)
435  {
436  node = CONTAINING_RECORD(entry, PH_PROCESS_NODE, HashEntry);
437 
438  if (PhCompareProcessNode(&lookupNode, node))
439  return node;
440  }
441 
442  return NULL;
443 }
444 
446  _In_ PPH_PROCESS_NODE ProcessNode
447  )
448 {
449  // Remove from the hashtable here to avoid problems in case the key is re-used.
450  PhRemoveEntryHashSet(ProcessNodeHashSet, PH_HASH_SET_SIZE(ProcessNodeHashSet), &ProcessNode->HashEntry);
451 
453  {
455  &ProcessNode->Node,
456  &ProcessNode->ShState,
457  &ProcessNodeStateList,
460  ProcessTreeListHandle
461  );
462  }
463  else
464  {
465  PhpRemoveProcessNode(ProcessNode);
466  }
467 }
468 
470  _In_ PPH_PROCESS_NODE ProcessNode
471  )
472 {
473  ULONG index;
474  ULONG i;
475 
477 
478  if (ProcessNode->Parent)
479  {
480  // Remove the node from its parent.
481 
482  if ((index = PhFindItemList(ProcessNode->Parent->Children, ProcessNode)) != -1)
483  PhRemoveItemList(ProcessNode->Parent->Children, index);
484  }
485  else
486  {
487  // Remove the node from the root list.
488 
489  if ((index = PhFindItemList(ProcessNodeRootList, ProcessNode)) != -1)
490  PhRemoveItemList(ProcessNodeRootList, index);
491  }
492 
493  // Move the node's children to the root list.
494  for (i = 0; i < ProcessNode->Children->Count; i++)
495  {
496  PPH_PROCESS_NODE node = ProcessNode->Children->Items[i];
497 
498  node->Parent = NULL;
499  PhAddItemList(ProcessNodeRootList, node);
500  }
501 
502  // Remove from list and cleanup.
503 
504  if ((index = PhFindItemList(ProcessNodeList, ProcessNode)) != -1)
505  PhRemoveItemList(ProcessNodeList, index);
506 
507  PhDereferenceObject(ProcessNode->Children);
508 
509  if (ProcessNode->WindowText) PhDereferenceObject(ProcessNode->WindowText);
510  if (ProcessNode->AppIdText) PhDereferenceObject(ProcessNode->AppIdText);
511 
512  if (ProcessNode->TooltipText) PhDereferenceObject(ProcessNode->TooltipText);
513 
514  if (ProcessNode->IoTotalRateText) PhDereferenceObject(ProcessNode->IoTotalRateText);
515  if (ProcessNode->PrivateBytesText) PhDereferenceObject(ProcessNode->PrivateBytesText);
516  if (ProcessNode->PeakPrivateBytesText) PhDereferenceObject(ProcessNode->PeakPrivateBytesText);
517  if (ProcessNode->WorkingSetText) PhDereferenceObject(ProcessNode->WorkingSetText);
518  if (ProcessNode->PeakWorkingSetText) PhDereferenceObject(ProcessNode->PeakWorkingSetText);
519  if (ProcessNode->PrivateWsText) PhDereferenceObject(ProcessNode->PrivateWsText);
520  if (ProcessNode->SharedWsText) PhDereferenceObject(ProcessNode->SharedWsText);
521  if (ProcessNode->ShareableWsText) PhDereferenceObject(ProcessNode->ShareableWsText);
522  if (ProcessNode->VirtualSizeText) PhDereferenceObject(ProcessNode->VirtualSizeText);
523  if (ProcessNode->PeakVirtualSizeText) PhDereferenceObject(ProcessNode->PeakVirtualSizeText);
524  if (ProcessNode->PageFaultsText) PhDereferenceObject(ProcessNode->PageFaultsText);
525  if (ProcessNode->IoRoRateText) PhDereferenceObject(ProcessNode->IoRoRateText);
526  if (ProcessNode->IoWRateText) PhDereferenceObject(ProcessNode->IoWRateText);
527  if (ProcessNode->StartTimeText) PhDereferenceObject(ProcessNode->StartTimeText);
528  if (ProcessNode->RelativeStartTimeText) PhDereferenceObject(ProcessNode->RelativeStartTimeText);
529  if (ProcessNode->WindowTitleText) PhDereferenceObject(ProcessNode->WindowTitleText);
530  if (ProcessNode->CyclesText) PhDereferenceObject(ProcessNode->CyclesText);
531  if (ProcessNode->CyclesDeltaText) PhDereferenceObject(ProcessNode->CyclesDeltaText);
532  if (ProcessNode->ContextSwitchesText) PhDereferenceObject(ProcessNode->ContextSwitchesText);
533  if (ProcessNode->ContextSwitchesDeltaText) PhDereferenceObject(ProcessNode->ContextSwitchesDeltaText);
534  if (ProcessNode->PageFaultsDeltaText) PhDereferenceObject(ProcessNode->PageFaultsDeltaText);
535 
536  for (i = 0; i < PHPRTLC_IOGROUP_COUNT; i++)
537  if (ProcessNode->IoGroupText[i]) PhDereferenceObject(ProcessNode->IoGroupText[i]);
538 
539  if (ProcessNode->PagedPoolText) PhDereferenceObject(ProcessNode->PagedPoolText);
540  if (ProcessNode->PeakPagedPoolText) PhDereferenceObject(ProcessNode->PeakPagedPoolText);
541  if (ProcessNode->NonPagedPoolText) PhDereferenceObject(ProcessNode->NonPagedPoolText);
542  if (ProcessNode->PeakNonPagedPoolText) PhDereferenceObject(ProcessNode->PeakNonPagedPoolText);
543  if (ProcessNode->MinimumWorkingSetText) PhDereferenceObject(ProcessNode->MinimumWorkingSetText);
544  if (ProcessNode->MaximumWorkingSetText) PhDereferenceObject(ProcessNode->MaximumWorkingSetText);
545  if (ProcessNode->PrivateBytesDeltaText) PhDereferenceObject(ProcessNode->PrivateBytesDeltaText);
546 
547  PhDeleteGraphBuffers(&ProcessNode->CpuGraphBuffers);
548  PhDeleteGraphBuffers(&ProcessNode->PrivateGraphBuffers);
549  PhDeleteGraphBuffers(&ProcessNode->IoGraphBuffers);
550 
551  PhDereferenceObject(ProcessNode->ProcessItem);
552 
553  PhFree(ProcessNode);
554 
555  TreeNew_NodesStructured(ProcessTreeListHandle);
556 }
557 
559  _In_ PPH_PROCESS_NODE ProcessNode
560  )
561 {
562  memset(ProcessNode->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM);
563 
564  if (ProcessNode->TooltipText)
565  {
566  PhDereferenceObject(ProcessNode->TooltipText);
567  ProcessNode->TooltipText = NULL;
568  }
569 
571  TreeNew_InvalidateNode(ProcessTreeListHandle, &ProcessNode->Node);
572 }
573 
575  VOID
576  )
577 {
578  ULONG i;
579  PH_TREENEW_VIEW_PARTS viewParts;
580  BOOLEAN fullyInvalidated;
581  RECT rect;
582 
583  // Text invalidation, node updates
584 
585  for (i = 0; i < ProcessNodeList->Count; i++)
586  {
587  PPH_PROCESS_NODE node = ProcessNodeList->Items[i];
588 
589  // The name and PID never change, so we don't invalidate that.
590  memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2));
591  node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS; // Items that always remain valid
592 
593  // Invalidate graph buffers.
594  node->CpuGraphBuffers.Valid = FALSE;
596  node->IoGraphBuffers.Valid = FALSE;
597 
598  // Updates cycles if necessary.
599  if (NeedCyclesInformation)
601  }
602 
603  fullyInvalidated = FALSE;
604 
605  if (ProcessTreeListSortOrder != NoSortOrder)
606  {
607  // Force a rebuild to sort the items.
608  TreeNew_NodesStructured(ProcessTreeListHandle);
609  fullyInvalidated = TRUE;
610  }
611 
612  // State highlighting
613  PH_TICK_SH_STATE_TN(PH_PROCESS_NODE, ShState, ProcessNodeStateList, PhpRemoveProcessNode, PhCsHighlightingDuration, ProcessTreeListHandle, TRUE, &fullyInvalidated);
614 
615  if (!fullyInvalidated)
616  {
617  // The first column doesn't need to be invalidated because the process name never changes, and
618  // icon changes are handled by the modified event. This small optimization can save more than
619  // 10 million cycles per update (on my machine).
620  TreeNew_GetViewParts(ProcessTreeListHandle, &viewParts);
621  rect.left = viewParts.NormalLeft;
622  rect.top = viewParts.HeaderHeight;
623  rect.right = viewParts.ClientRect.right - viewParts.VScrollWidth;
624  rect.bottom = viewParts.ClientRect.bottom;
625  InvalidateRect(ProcessTreeListHandle, &rect, FALSE);
626  }
627 }
628 
629 static VOID PhpNeedGraphContext(
630  _In_ HDC hdc,
631  _In_ ULONG Width,
632  _In_ ULONG Height
633  )
634 {
635  BITMAPINFOHEADER header;
636 
637  // If we already have a graph context and it's the right size, then return immediately.
638  if (GraphContextWidth == Width && GraphContextHeight == Height)
639  return;
640 
641  if (GraphContext)
642  {
643  // The original bitmap must be selected back into the context, otherwise
644  // the bitmap can't be deleted.
645  SelectObject(GraphContext, GraphBitmap);
646  DeleteObject(GraphBitmap);
647  DeleteDC(GraphContext);
648 
649  GraphContext = NULL;
650  GraphBitmap = NULL;
651  GraphBits = NULL;
652  }
653 
654  GraphContext = CreateCompatibleDC(hdc);
655 
656  memset(&header, 0, sizeof(BITMAPINFOHEADER));
657  header.biSize = sizeof(BITMAPINFOHEADER);
658  header.biWidth = Width;
659  header.biHeight = Height;
660  header.biPlanes = 1;
661  header.biBitCount = 32;
662  GraphBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &GraphBits, NULL, 0);
663  GraphOldBitmap = SelectObject(GraphContext, GraphBitmap);
664 }
665 
666 static BOOLEAN PhpFormatInt32GroupDigits(
667  _In_ ULONG Value,
668  _Out_writes_bytes_(BufferLength) PWCHAR Buffer,
669  _In_ ULONG BufferLength,
670  _Out_opt_ PPH_STRINGREF String
671  )
672 {
673  PH_FORMAT format;
674  SIZE_T returnLength;
675 
676  PhInitFormatU(&format, Value);
677  format.Type |= FormatGroupDigits;
678 
679  if (PhFormatToBuffer(&format, 1, Buffer, BufferLength, &returnLength))
680  {
681  if (String)
682  {
683  String->Buffer = Buffer;
684  String->Length = returnLength - sizeof(WCHAR);
685  }
686 
687  return TRUE;
688  }
689  else
690  {
691  return FALSE;
692  }
693 }
694 
695 static FLOAT PhpCalculateInclusiveCpuUsage(
696  _In_ PPH_PROCESS_NODE ProcessNode
697  )
698 {
699  FLOAT cpuUsage;
700  ULONG i;
701 
702  cpuUsage = ProcessNode->ProcessItem->CpuUsage;
703 
704  for (i = 0; i < ProcessNode->Children->Count; i++)
705  {
706  cpuUsage += PhpCalculateInclusiveCpuUsage(ProcessNode->Children->Items[i]);
707  }
708 
709  return cpuUsage;
710 }
711 
712 static VOID PhpUpdateProcessNodeWsCounters(
713  _Inout_ PPH_PROCESS_NODE ProcessNode
714  )
715 {
716  if (!(ProcessNode->ValidMask & PHPN_WSCOUNTERS))
717  {
718  BOOLEAN success = FALSE;
719  HANDLE processHandle;
720 
722  &processHandle,
724  ProcessNode->ProcessItem->ProcessId
725  )))
726  {
728  processHandle,
729  &ProcessNode->WsCounters
730  )))
731  success = TRUE;
732 
733  NtClose(processHandle);
734  }
735 
736  if (!success)
737  memset(&ProcessNode->WsCounters, 0, sizeof(PH_PROCESS_WS_COUNTERS));
738 
739  ProcessNode->ValidMask |= PHPN_WSCOUNTERS;
740  }
741 }
742 
743 static VOID PhpUpdateProcessNodeGdiUserHandles(
744  _Inout_ PPH_PROCESS_NODE ProcessNode
745  )
746 {
747  if (!(ProcessNode->ValidMask & PHPN_GDIUSERHANDLES))
748  {
749  if (ProcessNode->ProcessItem->QueryHandle)
750  {
751  ProcessNode->GdiHandles = GetGuiResources(ProcessNode->ProcessItem->QueryHandle, GR_GDIOBJECTS);
752  ProcessNode->UserHandles = GetGuiResources(ProcessNode->ProcessItem->QueryHandle, GR_USEROBJECTS);
753  }
754  else
755  {
756  ProcessNode->GdiHandles = 0;
757  ProcessNode->UserHandles = 0;
758  }
759 
760  ProcessNode->ValidMask |= PHPN_GDIUSERHANDLES;
761  }
762 }
763 
764 static VOID PhpUpdateProcessNodeIoPagePriority(
765  _Inout_ PPH_PROCESS_NODE ProcessNode
766  )
767 {
768  if (!(ProcessNode->ValidMask & PHPN_IOPAGEPRIORITY))
769  {
770  if (ProcessNode->ProcessItem->QueryHandle)
771  {
772  if (!NT_SUCCESS(PhGetProcessIoPriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->IoPriority)))
773  ProcessNode->IoPriority = -1;
774  if (!NT_SUCCESS(PhGetProcessPagePriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->PagePriority)))
775  ProcessNode->PagePriority = -1;
776  }
777  else
778  {
779  ProcessNode->IoPriority = -1;
780  ProcessNode->PagePriority = -1;
781  }
782 
783  ProcessNode->ValidMask |= PHPN_IOPAGEPRIORITY;
784  }
785 }
786 
787 static VOID PhpUpdateProcessNodeWindow(
788  _Inout_ PPH_PROCESS_NODE ProcessNode
789  )
790 {
791  if (!(ProcessNode->ValidMask & PHPN_WINDOW))
792  {
793  ProcessNode->WindowHandle = PhGetProcessMainWindow(ProcessNode->ProcessId, ProcessNode->ProcessItem->QueryHandle);
794 
795  PhClearReference(&ProcessNode->WindowText);
796 
797  if (ProcessNode->WindowHandle)
798  {
799  PhGetWindowTextEx(ProcessNode->WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL, &ProcessNode->WindowText);
800  ProcessNode->WindowHung = !!IsHungAppWindow(ProcessNode->WindowHandle);
801  }
802 
803  ProcessNode->ValidMask |= PHPN_WINDOW;
804  }
805 }
806 
807 static VOID PhpUpdateProcessNodeDepStatus(
808  _Inout_ PPH_PROCESS_NODE ProcessNode
809  )
810 {
811  if (!(ProcessNode->ValidMask & PHPN_DEPSTATUS))
812  {
813  HANDLE processHandle;
814  ULONG depStatus;
815 
816  depStatus = 0;
817 
818 #ifdef _WIN64
819  if (ProcessNode->ProcessItem->IsWow64)
820 #else
821  if (TRUE)
822 #endif
823  {
825  &processHandle,
827  ProcessNode->ProcessItem->ProcessId
828  )))
829  {
830  PhGetProcessDepStatus(processHandle, &depStatus);
831  NtClose(processHandle);
832  }
833  }
834  else
835  {
836  if (ProcessNode->ProcessItem->QueryHandle)
838  }
839 
840  ProcessNode->DepStatus = depStatus;
841 
842  ProcessNode->ValidMask |= PHPN_DEPSTATUS;
843  }
844 }
845 
846 static VOID PhpUpdateProcessNodeToken(
847  _Inout_ PPH_PROCESS_NODE ProcessNode
848  )
849 {
850  if (!(ProcessNode->ValidMask & PHPN_TOKEN))
851  {
852  HANDLE tokenHandle;
853 
854  ProcessNode->VirtualizationAllowed = FALSE;
855  ProcessNode->VirtualizationEnabled = FALSE;
856 
857  if (WINDOWS_HAS_UAC && ProcessNode->ProcessItem->QueryHandle)
858  {
860  &tokenHandle,
861  TOKEN_QUERY,
862  ProcessNode->ProcessItem->QueryHandle
863  )))
864  {
865  if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &ProcessNode->VirtualizationAllowed)) &&
866  ProcessNode->VirtualizationAllowed)
867  {
868  if (!NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &ProcessNode->VirtualizationEnabled)))
869  {
870  ProcessNode->VirtualizationAllowed = FALSE; // display N/A on error
871  }
872  }
873 
874  NtClose(tokenHandle);
875  }
876  }
877 
878  ProcessNode->ValidMask |= PHPN_TOKEN;
879  }
880 }
881 
882 static VOID PhpUpdateProcessOsContext(
883  _Inout_ PPH_PROCESS_NODE ProcessNode
884  )
885 {
886  if (!(ProcessNode->ValidMask & PHPN_OSCONTEXT))
887  {
888  HANDLE processHandle;
889 
890  if (WindowsVersion >= WINDOWS_7)
891  {
892  if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId)))
893  {
894  if (NT_SUCCESS(PhGetProcessSwitchContext(processHandle, &ProcessNode->OsContextGuid)))
895  {
896  if (memcmp(&ProcessNode->OsContextGuid, &WINBLUE_CONTEXT_GUID, sizeof(GUID)) == 0)
897  ProcessNode->OsContextVersion = WINDOWS_8_1;
898  else if (memcmp(&ProcessNode->OsContextGuid, &WIN8_CONTEXT_GUID, sizeof(GUID)) == 0)
899  ProcessNode->OsContextVersion = WINDOWS_8;
900  else if (memcmp(&ProcessNode->OsContextGuid, &WIN7_CONTEXT_GUID, sizeof(GUID)) == 0)
901  ProcessNode->OsContextVersion = WINDOWS_7;
902  else if (memcmp(&ProcessNode->OsContextGuid, &VISTA_CONTEXT_GUID, sizeof(GUID)) == 0)
903  ProcessNode->OsContextVersion = WINDOWS_VISTA;
904  else if (memcmp(&ProcessNode->OsContextGuid, &XP_CONTEXT_GUID, sizeof(GUID)) == 0)
905  ProcessNode->OsContextVersion = WINDOWS_XP;
906  }
907 
908  NtClose(processHandle);
909  }
910  }
911 
912  ProcessNode->ValidMask |= PHPN_OSCONTEXT;
913  }
914 }
915 
916 static VOID PhpUpdateProcessNodeQuotaLimits(
917  _Inout_ PPH_PROCESS_NODE ProcessNode
918  )
919 {
920  if (!(ProcessNode->ValidMask & PHPN_QUOTALIMITS))
921  {
922  QUOTA_LIMITS quotaLimits;
923 
924  if (ProcessNode->ProcessItem->QueryHandle && NT_SUCCESS(NtQueryInformationProcess(
925  ProcessNode->ProcessItem->QueryHandle,
926  ProcessQuotaLimits,
927  &quotaLimits,
928  sizeof(QUOTA_LIMITS),
929  NULL
930  )))
931  {
932  ProcessNode->MinimumWorkingSetSize = quotaLimits.MinimumWorkingSetSize;
933  ProcessNode->MaximumWorkingSetSize = quotaLimits.MaximumWorkingSetSize;
934  }
935  else
936  {
937  ProcessNode->MinimumWorkingSetSize = 0;
938  ProcessNode->MaximumWorkingSetSize = 0;
939  }
940 
941  ProcessNode->ValidMask |= PHPN_QUOTALIMITS;
942  }
943 }
944 
945 static VOID PhpUpdateProcessNodeImage(
946  _Inout_ PPH_PROCESS_NODE ProcessNode
947  )
948 {
949  if (!(ProcessNode->ValidMask & PHPN_IMAGE))
950  {
951  HANDLE processHandle;
952  PROCESS_BASIC_INFORMATION basicInfo;
953  PVOID imageBaseAddress;
954  PH_REMOTE_MAPPED_IMAGE mappedImage;
955 
956  if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId)))
957  {
958  if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &basicInfo)))
959  {
961  processHandle,
962  PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ImageBaseAddress)),
963  &imageBaseAddress,
964  sizeof(PVOID),
965  NULL
966  )))
967  {
968  if (NT_SUCCESS(PhLoadRemoteMappedImage(processHandle, imageBaseAddress, &mappedImage)))
969  {
970  ProcessNode->ImageCharacteristics = mappedImage.NtHeaders->FileHeader.Characteristics;
971 
972  if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
973  {
974  ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->Subsystem;
975  ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics;
976  }
977  else if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
978  {
979  ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->Subsystem;
980  ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics;
981  }
982 
983  PhUnloadRemoteMappedImage(&mappedImage);
984  }
985  }
986  }
987 
988  NtClose(processHandle);
989  }
990 
991  ProcessNode->ValidMask |= PHPN_IMAGE;
992  }
993 }
994 
995 static VOID PhpUpdateProcessNodeAppId(
996  _Inout_ PPH_PROCESS_NODE ProcessNode
997  )
998 {
999  if (!(ProcessNode->ValidMask & PHPN_APPID))
1000  {
1001  HANDLE processHandle;
1002  ULONG windowFlags;
1003  PPH_STRING windowTitle;
1004 
1005  PhClearReference(&ProcessNode->AppIdText);
1006 
1007  if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId)))
1008  {
1009  if (WindowsVersion >= WINDOWS_7)
1010  {
1011  if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessNode->ProcessId)))
1012  goto Done;
1013  }
1014  else
1015  {
1016  goto Done;
1017  }
1018  }
1019 
1021  processHandle,
1022  &windowFlags,
1023  &windowTitle
1024  )))
1025  {
1026  if (windowFlags & STARTF_TITLEISAPPID)
1027  ProcessNode->AppIdText = windowTitle;
1028  else
1029  PhDereferenceObject(windowTitle);
1030  }
1031 
1032  NtClose(processHandle);
1033 
1034 Done:
1035  ProcessNode->ValidMask |= PHPN_APPID;
1036  }
1037 }
1038 
1039 static VOID PhpUpdateProcessNodeDpiAwareness(
1040  _Inout_ PPH_PROCESS_NODE ProcessNode
1041  )
1042 {
1043  static PH_INITONCE initOnce = PH_INITONCE_INIT;
1044  static BOOL (WINAPI *getProcessDpiAwarenessInternal)(
1045  _In_ HANDLE hprocess,
1046  _Out_ ULONG *value
1047  );
1048 
1049  if (PhBeginInitOnce(&initOnce))
1050  {
1051  getProcessDpiAwarenessInternal = PhGetModuleProcAddress(L"user32.dll", "GetProcessDpiAwarenessInternal");
1052  PhEndInitOnce(&initOnce);
1053  }
1054 
1055  if (!getProcessDpiAwarenessInternal)
1056  return;
1057 
1058  if (!(ProcessNode->ValidMask & PHPN_DPIAWARENESS))
1059  {
1060  if (ProcessNode->ProcessItem->QueryHandle)
1061  {
1062  ULONG dpiAwareness;
1063 
1064  if (getProcessDpiAwarenessInternal(ProcessNode->ProcessItem->QueryHandle, &dpiAwareness))
1065  ProcessNode->DpiAwareness = dpiAwareness + 1;
1066  }
1067 
1068  ProcessNode->ValidMask |= PHPN_DPIAWARENESS;
1069  }
1070 }
1071 
1073  VOID
1074  )
1075 {
1076  PH_TREENEW_COLUMN column;
1077 
1078  NeedCyclesInformation = FALSE;
1079 
1080  // Before Windows Vista, there is no cycle time measurement.
1081  // On Windows 7 and above, cycle time information is available directly from the process item.
1082  // We only need to query cycle time separately for Windows Vista.
1084  return;
1085 
1086  TreeNew_GetColumn(ProcessTreeListHandle, PHPRTLC_CYCLES, &column);
1087 
1088  if (column.Visible)
1089  {
1090  NeedCyclesInformation = TRUE;
1091  return;
1092  }
1093 
1094  TreeNew_GetColumn(ProcessTreeListHandle, PHPRTLC_CYCLESDELTA, &column);
1095 
1096  if (column.Visible)
1097  {
1098  NeedCyclesInformation = TRUE;
1099  return;
1100  }
1101 }
1102 
1104  _Inout_ PPH_PROCESS_NODE ProcessNode
1105  )
1106 {
1107  if (ProcessNode->ProcessId == SYSTEM_IDLE_PROCESS_ID)
1108  {
1109  PULARGE_INTEGER idleThreadCycleTimes;
1110  ULONG64 cycleTime;
1111  ULONG i;
1112 
1113  // System Idle Process requires special treatment.
1114 
1115  idleThreadCycleTimes = PhAllocate(
1116  sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors
1117  );
1118 
1119  if (NT_SUCCESS(NtQuerySystemInformation(
1121  idleThreadCycleTimes,
1122  sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors,
1123  NULL
1124  )))
1125  {
1126  cycleTime = 0;
1127 
1128  for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++)
1129  cycleTime += idleThreadCycleTimes[i].QuadPart;
1130 
1131  PhUpdateDelta(&ProcessNode->CyclesDelta, cycleTime);
1132  }
1133 
1134  PhFree(idleThreadCycleTimes);
1135  }
1136  else if (ProcessNode->ProcessItem->QueryHandle)
1137  {
1138  ULONG64 cycleTime;
1139 
1140  if (NT_SUCCESS(PhGetProcessCycleTime(ProcessNode->ProcessItem->QueryHandle, &cycleTime)))
1141  {
1142  PhUpdateDelta(&ProcessNode->CyclesDelta, cycleTime);
1143  }
1144  }
1145 
1146  if (ProcessNode->CyclesDelta.Value != 0)
1147  PhMoveReference(&ProcessNode->CyclesText, PhFormatUInt64(ProcessNode->CyclesDelta.Value, TRUE));
1148  else
1149  PhClearReference(&ProcessNode->CyclesText);
1150 
1151  if (ProcessNode->CyclesDelta.Delta != 0)
1152  PhMoveReference(&ProcessNode->CyclesDeltaText, PhFormatUInt64(ProcessNode->CyclesDelta.Delta, TRUE));
1153  else
1154  PhClearReference(&ProcessNode->CyclesDeltaText);
1155 }
1156 
1157 #define SORT_FUNCTION(Column) PhpProcessTreeNewCompare##Column
1158 
1159 #define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpProcessTreeNewCompare##Column( \
1160  _In_ const void *_elem1, \
1161  _In_ const void *_elem2 \
1162  ) \
1163 { \
1164  PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)_elem1; \
1165  PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)_elem2; \
1166  PPH_PROCESS_ITEM processItem1 = node1->ProcessItem; \
1167  PPH_PROCESS_ITEM processItem2 = node2->ProcessItem; \
1168  int sortResult = 0;
1169 
1170 #define END_SORT_FUNCTION \
1171  if (sortResult == 0) \
1172  sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId); \
1173  \
1174  return PhModifySort(sortResult, ProcessTreeListSortOrder); \
1175 }
1176 
1178  _In_ LONG Result,
1179  _In_ PVOID Node1,
1180  _In_ PVOID Node2,
1181  _In_ PH_SORT_ORDER SortOrder
1182  )
1183 {
1184  if (Result == 0)
1185  Result = intptrcmp((LONG_PTR)((PPH_PROCESS_NODE)Node1)->ProcessItem->ProcessId, (LONG_PTR)((PPH_PROCESS_NODE)Node2)->ProcessItem->ProcessId);
1186 
1187  return PhModifySort(Result, SortOrder);
1188 }
1189 
1191 {
1192  sortResult = PhCompareString(processItem1->ProcessName, processItem2->ProcessName, TRUE);
1193 }
1195 
1197 {
1198  // Use signed int so DPCs and Interrupts are placed above System Idle Process.
1199  sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId);
1200 }
1202 
1204 {
1205  sortResult = singlecmp(processItem1->CpuUsage, processItem2->CpuUsage);
1206 }
1208 
1210 {
1211  sortResult = uint64cmp(
1212  processItem1->IoReadDelta.Delta + processItem1->IoWriteDelta.Delta + processItem1->IoOtherDelta.Delta,
1213  processItem2->IoReadDelta.Delta + processItem2->IoWriteDelta.Delta + processItem2->IoOtherDelta.Delta
1214  );
1215 }
1217 
1218 BEGIN_SORT_FUNCTION(PrivateBytes)
1219 {
1220  sortResult = uintptrcmp(processItem1->VmCounters.PagefileUsage, processItem2->VmCounters.PagefileUsage);
1221 }
1223 
1225 {
1226  sortResult = PhCompareStringWithNull(processItem1->UserName, processItem2->UserName, TRUE);
1227 }
1229 
1231 {
1232  PH_STRINGREF sr1;
1233  PH_STRINGREF sr2;
1234 
1235  sr1 = processItem1->VersionInfo.FileDescription ? processItem1->VersionInfo.FileDescription->sr : node1->DescriptionText;
1236  sr2 = processItem2->VersionInfo.FileDescription ? processItem2->VersionInfo.FileDescription->sr : node2->DescriptionText;
1237 
1238  sortResult = PhCompareStringRef(&sr1, &sr2, TRUE);
1239 }
1241 
1243 {
1244  sortResult = PhCompareStringWithNull(
1245  processItem1->VersionInfo.CompanyName,
1246  processItem2->VersionInfo.CompanyName,
1247  TRUE
1248  );
1249 }
1251 
1253 {
1254  sortResult = PhCompareStringWithNull(
1255  processItem1->VersionInfo.FileVersion,
1256  processItem2->VersionInfo.FileVersion,
1257  TRUE
1258  );
1259 }
1261 
1263 {
1264  sortResult = PhCompareStringWithNull(
1265  processItem1->FileName,
1266  processItem2->FileName,
1267  TRUE
1268  );
1269 }
1271 
1273 {
1274  sortResult = PhCompareStringWithNull(
1275  processItem1->CommandLine,
1276  processItem2->CommandLine,
1277  TRUE
1278  );
1279 }
1281 
1282 BEGIN_SORT_FUNCTION(PeakPrivateBytes)
1283 {
1284  sortResult = uintptrcmp(processItem1->VmCounters.PeakPagefileUsage, processItem2->VmCounters.PeakPagefileUsage);
1285 }
1287 
1289 {
1290  sortResult = uintptrcmp(processItem1->VmCounters.WorkingSetSize, processItem2->VmCounters.WorkingSetSize);
1291 }
1293 
1294 BEGIN_SORT_FUNCTION(PeakWorkingSet)
1295 {
1296  sortResult = uintptrcmp(processItem1->VmCounters.PeakWorkingSetSize, processItem2->VmCounters.PeakWorkingSetSize);
1297 }
1299 
1301 {
1302  PhpUpdateProcessNodeWsCounters(node1);
1303  PhpUpdateProcessNodeWsCounters(node2);
1304  sortResult = uintptrcmp(node1->WsCounters.NumberOfPrivatePages, node2->WsCounters.NumberOfPrivatePages);
1305 }
1307 
1308 BEGIN_SORT_FUNCTION(PrivateWsWin7)
1309 {
1310  sortResult = uintptrcmp(processItem1->WorkingSetPrivateSize, processItem2->WorkingSetPrivateSize);
1311 }
1313 
1315 {
1316  PhpUpdateProcessNodeWsCounters(node1);
1317  PhpUpdateProcessNodeWsCounters(node2);
1318  sortResult = uintptrcmp(node1->WsCounters.NumberOfSharedPages, node2->WsCounters.NumberOfSharedPages);
1319 }
1321 
1323 {
1324  PhpUpdateProcessNodeWsCounters(node1);
1325  PhpUpdateProcessNodeWsCounters(node2);
1326  sortResult = uintptrcmp(node1->WsCounters.NumberOfShareablePages, node2->WsCounters.NumberOfShareablePages);
1327 }
1329 
1331 {
1332  sortResult = uintptrcmp(processItem1->VmCounters.VirtualSize, processItem2->VmCounters.VirtualSize);
1333 }
1335 
1336 BEGIN_SORT_FUNCTION(PeakVirtualSize)
1337 {
1338  sortResult = uintptrcmp(processItem1->VmCounters.PeakVirtualSize, processItem2->VmCounters.PeakVirtualSize);
1339 }
1341 
1343 {
1344  sortResult = uintcmp(processItem1->VmCounters.PageFaultCount, processItem2->VmCounters.PageFaultCount);
1345 }
1347 
1349 {
1350  sortResult = uintcmp(processItem1->SessionId, processItem2->SessionId);
1351 }
1353 
1354 BEGIN_SORT_FUNCTION(BasePriority)
1355 {
1356  sortResult = intcmp(processItem1->BasePriority, processItem2->BasePriority);
1357 }
1359 
1361 {
1362  sortResult = uintcmp(processItem1->NumberOfThreads, processItem2->NumberOfThreads);
1363 }
1365 
1367 {
1368  sortResult = uintcmp(processItem1->NumberOfHandles, processItem2->NumberOfHandles);
1369 }
1371 
1373 {
1374  sortResult = uintcmp(node1->GdiHandles, node2->GdiHandles);
1375 }
1377 
1379 {
1380  sortResult = uintcmp(node1->UserHandles, node2->UserHandles);
1381 }
1383 
1385 {
1386  sortResult = uint64cmp(
1387  processItem1->IoReadDelta.Delta + processItem1->IoOtherDelta.Delta,
1388  processItem2->IoReadDelta.Delta + processItem2->IoOtherDelta.Delta
1389  );
1390 }
1392 
1394 {
1395  sortResult = uint64cmp(
1396  processItem1->IoWriteDelta.Delta,
1397  processItem2->IoWriteDelta.Delta
1398  );
1399 }
1401 
1403 {
1404  sortResult = uintcmp(processItem1->IntegrityLevel, processItem2->IntegrityLevel);
1405 }
1407 
1409 {
1410  sortResult = uintcmp(node1->IoPriority, node2->IoPriority);
1411 }
1413 
1414 BEGIN_SORT_FUNCTION(PagePriority)
1415 {
1416  sortResult = uintcmp(node1->PagePriority, node2->PagePriority);
1417 }
1419 
1421 {
1422  sortResult = int64cmp(processItem1->CreateTime.QuadPart, processItem2->CreateTime.QuadPart);
1423 }
1425 
1426 BEGIN_SORT_FUNCTION(TotalCpuTime)
1427 {
1428  sortResult = uint64cmp(
1429  processItem1->KernelTime.QuadPart + processItem1->UserTime.QuadPart,
1430  processItem2->KernelTime.QuadPart + processItem2->UserTime.QuadPart
1431  );
1432 }
1434 
1435 BEGIN_SORT_FUNCTION(KernelCpuTime)
1436 {
1437  sortResult = uint64cmp(
1438  processItem1->KernelTime.QuadPart,
1439  processItem2->KernelTime.QuadPart
1440  );
1441 }
1443 
1445 {
1446  sortResult = uint64cmp(
1447  processItem1->UserTime.QuadPart,
1448  processItem2->UserTime.QuadPart
1449  );
1450 }
1452 
1453 BEGIN_SORT_FUNCTION(VerificationStatus)
1454 {
1455  sortResult = intcmp(processItem1->VerifyResult, processItem2->VerifyResult);
1456 }
1458 
1459 BEGIN_SORT_FUNCTION(VerifiedSigner)
1460 {
1461  sortResult = PhCompareStringWithNull(
1462  processItem1->VerifySignerName,
1463  processItem2->VerifySignerName,
1464  TRUE
1465  );
1466 }
1468 
1470 {
1471  PhpUpdateProcessNodeImage(node1);
1472  PhpUpdateProcessNodeImage(node2);
1473  sortResult = intcmp(
1474  node1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE,
1475  node2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
1476  );
1477 }
1479 
1480 BEGIN_SORT_FUNCTION(RelativeStartTime)
1481 {
1482  sortResult = -int64cmp(processItem1->CreateTime.QuadPart, processItem2->CreateTime.QuadPart);
1483 }
1485 
1487 {
1488  sortResult = intcmp(processItem1->IsWow64Valid, processItem2->IsWow64Valid);
1489 
1490  if (sortResult == 0)
1491  sortResult = intcmp(processItem1->IsWow64, processItem2->IsWow64);
1492 }
1494 
1496 {
1497  ULONG key1;
1498  ULONG key2;
1499 
1500  switch (processItem1->ElevationType)
1501  {
1502  case TokenElevationTypeFull:
1503  key1 = 2;
1504  break;
1505  case TokenElevationTypeLimited:
1506  key1 = 1;
1507  break;
1508  default:
1509  key1 = 0;
1510  break;
1511  }
1512 
1513  switch (processItem2->ElevationType)
1514  {
1515  case TokenElevationTypeFull:
1516  key2 = 2;
1517  break;
1518  case TokenElevationTypeLimited:
1519  key2 = 1;
1520  break;
1521  default:
1522  key2 = 0;
1523  break;
1524  }
1525 
1526  sortResult = intcmp(key1, key2);
1527 }
1529 
1531 {
1532  PhpUpdateProcessNodeWindow(node1);
1533  PhpUpdateProcessNodeWindow(node2);
1534  sortResult = PhCompareStringWithNull(node1->WindowText, node2->WindowText, TRUE);
1535 }
1537 
1538 BEGIN_SORT_FUNCTION(WindowStatus)
1539 {
1540  PhpUpdateProcessNodeWindow(node1);
1541  PhpUpdateProcessNodeWindow(node2);
1542  sortResult = intcmp(node1->WindowHung, node2->WindowHung);
1543 
1544  // Make sure all processes with windows get grouped together.
1545  if (sortResult == 0)
1546  sortResult = intcmp(!!node1->WindowHandle, !!node2->WindowHandle);
1547 }
1549 
1551 {
1552  sortResult = uint64cmp(node1->CyclesDelta.Value, node2->CyclesDelta.Value);
1553 }
1555 
1557 {
1558  sortResult = uint64cmp(processItem1->CycleTimeDelta.Value, processItem2->CycleTimeDelta.Value);
1559 }
1561 
1563 {
1564  sortResult = uint64cmp(node1->CyclesDelta.Delta, node2->CyclesDelta.Delta);
1565 }
1567 
1568 BEGIN_SORT_FUNCTION(CyclesDeltaWin7)
1569 {
1570  sortResult = uint64cmp(processItem1->CycleTimeDelta.Delta, processItem2->CycleTimeDelta.Delta);
1571 }
1573 
1575 {
1576  PhpUpdateProcessNodeDepStatus(node1);
1577  PhpUpdateProcessNodeDepStatus(node2);
1578  sortResult = uintcmp(node1->DepStatus, node2->DepStatus);
1579 }
1581 
1583 {
1584  PhpUpdateProcessNodeToken(node1);
1585  PhpUpdateProcessNodeToken(node2);
1586  sortResult = intcmp(node1->VirtualizationEnabled, node2->VirtualizationEnabled);
1587 }
1589 
1590 BEGIN_SORT_FUNCTION(ContextSwitches)
1591 {
1592  sortResult = uintcmp(processItem1->ContextSwitchesDelta.Value, processItem2->ContextSwitchesDelta.Value);
1593 }
1595 
1596 BEGIN_SORT_FUNCTION(ContextSwitchesDelta)
1597 {
1598  sortResult = intcmp((LONG)processItem1->ContextSwitchesDelta.Delta, (LONG)processItem2->ContextSwitchesDelta.Delta);
1599 }
1601 
1602 BEGIN_SORT_FUNCTION(PageFaultsDelta)
1603 {
1604  sortResult = uintcmp(processItem1->PageFaultsDelta.Delta, processItem2->PageFaultsDelta.Delta);
1605 }
1607 
1609 {
1610  sortResult = uint64cmp(processItem1->IoReadCountDelta.Value, processItem2->IoReadCountDelta.Value);
1611 }
1613 
1615 {
1616  sortResult = uint64cmp(processItem1->IoWriteCountDelta.Value, processItem2->IoWriteCountDelta.Value);
1617 }
1619 
1621 {
1622  sortResult = uint64cmp(processItem1->IoOtherCountDelta.Value, processItem2->IoOtherCountDelta.Value);
1623 }
1625 
1627 {
1628  sortResult = uint64cmp(processItem1->IoReadDelta.Value, processItem2->IoReadDelta.Value);
1629 }
1631 
1632 BEGIN_SORT_FUNCTION(IoWriteBytes)
1633 {
1634  sortResult = uint64cmp(processItem1->IoWriteDelta.Value, processItem2->IoWriteDelta.Value);
1635 }
1637 
1638 BEGIN_SORT_FUNCTION(IoOtherBytes)
1639 {
1640  sortResult = uint64cmp(processItem1->IoOtherDelta.Value, processItem2->IoOtherDelta.Value);
1641 }
1643 
1644 BEGIN_SORT_FUNCTION(IoReadsDelta)
1645 {
1646  sortResult = uint64cmp(processItem1->IoReadCountDelta.Delta, processItem2->IoReadCountDelta.Delta);
1647 }
1649 
1650 BEGIN_SORT_FUNCTION(IoWritesDelta)
1651 {
1652  sortResult = uint64cmp(processItem1->IoWriteCountDelta.Delta, processItem2->IoWriteCountDelta.Delta);
1653 }
1655 
1656 BEGIN_SORT_FUNCTION(IoOtherDelta)
1657 {
1658  sortResult = uint64cmp(processItem1->IoOtherCountDelta.Delta, processItem2->IoOtherCountDelta.Delta);
1659 }
1661 
1663 {
1664  PhpUpdateProcessOsContext(node1);
1665  PhpUpdateProcessOsContext(node2);
1666  sortResult = uintcmp(node1->OsContextVersion, node2->OsContextVersion);
1667 }
1669 
1671 {
1672  sortResult = uintptrcmp(processItem1->VmCounters.QuotaPagedPoolUsage, processItem2->VmCounters.QuotaPagedPoolUsage);
1673 }
1675 
1676 BEGIN_SORT_FUNCTION(PeakPagedPool)
1677 {
1678  sortResult = uintptrcmp(processItem1->VmCounters.QuotaPeakPagedPoolUsage, processItem2->VmCounters.QuotaPeakPagedPoolUsage);
1679 }
1681 
1682 BEGIN_SORT_FUNCTION(NonPagedPool)
1683 {
1684  sortResult = uintptrcmp(processItem1->VmCounters.QuotaNonPagedPoolUsage, processItem2->VmCounters.QuotaNonPagedPoolUsage);
1685 }
1687 
1688 BEGIN_SORT_FUNCTION(PeakNonPagedPool)
1689 {
1690  sortResult = uintptrcmp(processItem1->VmCounters.QuotaPeakNonPagedPoolUsage, processItem2->VmCounters.QuotaPeakNonPagedPoolUsage);
1691 }
1693 
1694 BEGIN_SORT_FUNCTION(MinimumWorkingSet)
1695 {
1696  PhpUpdateProcessNodeQuotaLimits(node1);
1697  PhpUpdateProcessNodeQuotaLimits(node2);
1698  sortResult = uintptrcmp(node1->MinimumWorkingSetSize, node2->MinimumWorkingSetSize);
1699 }
1701 
1702 BEGIN_SORT_FUNCTION(MaximumWorkingSet)
1703 {
1704  PhpUpdateProcessNodeQuotaLimits(node1);
1705  PhpUpdateProcessNodeQuotaLimits(node2);
1706  sortResult = uintptrcmp(node1->MaximumWorkingSetSize, node2->MaximumWorkingSetSize);
1707 }
1709 
1710 BEGIN_SORT_FUNCTION(PrivateBytesDelta)
1711 {
1712  sortResult = intptrcmp(processItem1->PrivateBytesDelta.Delta, processItem2->PrivateBytesDelta.Delta);
1713 }
1715 
1717 {
1718  PhpUpdateProcessNodeImage(node1);
1719  PhpUpdateProcessNodeImage(node2);
1720  sortResult = intcmp(node1->ImageSubsystem, node2->ImageSubsystem);
1721 }
1723 
1725 {
1726  sortResult = PhCompareStringWithNull(processItem1->PackageFullName, processItem2->PackageFullName, TRUE);
1727 }
1729 
1731 {
1732  PhpUpdateProcessNodeAppId(node1);
1733  PhpUpdateProcessNodeAppId(node2);
1734  sortResult = PhCompareStringWithNull(node1->AppIdText, node2->AppIdText, TRUE);
1735 }
1737 
1738 BEGIN_SORT_FUNCTION(DpiAwareness)
1739 {
1740  PhpUpdateProcessNodeDpiAwareness(node1);
1741  PhpUpdateProcessNodeDpiAwareness(node2);
1742  sortResult = uintcmp(node1->DpiAwareness, node2->DpiAwareness);
1743 }
1745 
1747 {
1748  PhpUpdateProcessNodeImage(node1);
1749  PhpUpdateProcessNodeImage(node2);
1750  sortResult = intcmp(
1751  node1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF,
1752  node2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF
1753  );
1754 }
1756 
1758  _In_ HWND hwnd,
1759  _In_ PH_TREENEW_MESSAGE Message,
1760  _In_opt_ PVOID Parameter1,
1761  _In_opt_ PVOID Parameter2,
1762  _In_opt_ PVOID Context
1763  )
1764 {
1765  PPH_PROCESS_NODE node;
1766 
1767  if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &ProcessTreeListCm))
1768  return TRUE;
1769 
1770  switch (Message)
1771  {
1772  case TreeNewGetChildren:
1773  {
1774  PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;
1775 
1776  node = (PPH_PROCESS_NODE)getChildren->Node;
1777 
1778  if (ProcessTreeListSortOrder == NoSortOrder)
1779  {
1780  if (!node)
1781  {
1782  getChildren->Children = (PPH_TREENEW_NODE *)ProcessNodeRootList->Items;
1783  getChildren->NumberOfChildren = ProcessNodeRootList->Count;
1784  }
1785  else
1786  {
1787  getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;
1788  getChildren->NumberOfChildren = node->Children->Count;
1789  }
1790  }
1791  else
1792  {
1793  if (!node)
1794  {
1795  static PVOID sortFunctions[] =
1796  {
1797  SORT_FUNCTION(Name),
1798  SORT_FUNCTION(Pid),
1799  SORT_FUNCTION(Cpu),
1800  SORT_FUNCTION(IoTotalRate),
1801  SORT_FUNCTION(PrivateBytes),
1802  SORT_FUNCTION(UserName),
1803  SORT_FUNCTION(Description),
1804  SORT_FUNCTION(CompanyName),
1805  SORT_FUNCTION(Version),
1806  SORT_FUNCTION(FileName),
1807  SORT_FUNCTION(CommandLine),
1808  SORT_FUNCTION(PeakPrivateBytes),
1809  SORT_FUNCTION(WorkingSet),
1810  SORT_FUNCTION(PeakWorkingSet),
1811  SORT_FUNCTION(PrivateWs),
1812  SORT_FUNCTION(SharedWs),
1813  SORT_FUNCTION(ShareableWs),
1814  SORT_FUNCTION(VirtualSize),
1815  SORT_FUNCTION(PeakVirtualSize),
1816  SORT_FUNCTION(PageFaults),
1817  SORT_FUNCTION(SessionId),
1818  SORT_FUNCTION(BasePriority), // Priority Class
1819  SORT_FUNCTION(BasePriority),
1820  SORT_FUNCTION(Threads),
1821  SORT_FUNCTION(Handles),
1822  SORT_FUNCTION(GdiHandles),
1823  SORT_FUNCTION(UserHandles),
1824  SORT_FUNCTION(IoRoRate),
1825  SORT_FUNCTION(IoWRate),
1826  SORT_FUNCTION(Integrity),
1827  SORT_FUNCTION(IoPriority),
1828  SORT_FUNCTION(PagePriority),
1829  SORT_FUNCTION(StartTime),
1830  SORT_FUNCTION(TotalCpuTime),
1831  SORT_FUNCTION(KernelCpuTime),
1832  SORT_FUNCTION(UserCpuTime),
1833  SORT_FUNCTION(VerificationStatus),
1834  SORT_FUNCTION(VerifiedSigner),
1835  SORT_FUNCTION(Aslr),
1836  SORT_FUNCTION(RelativeStartTime),
1837  SORT_FUNCTION(Bits),
1838  SORT_FUNCTION(Elevation),
1839  SORT_FUNCTION(WindowTitle),
1840  SORT_FUNCTION(WindowStatus),
1841  SORT_FUNCTION(Cycles),
1842  SORT_FUNCTION(CyclesDelta),
1843  SORT_FUNCTION(Cpu), // CPU History
1844  SORT_FUNCTION(PrivateBytes), // Private Bytes History
1845  SORT_FUNCTION(IoTotalRate), // I/O History
1846  SORT_FUNCTION(DepStatus),
1847  SORT_FUNCTION(Virtualized),
1848  SORT_FUNCTION(ContextSwitches),
1849  SORT_FUNCTION(ContextSwitchesDelta),
1850  SORT_FUNCTION(PageFaultsDelta),
1851  SORT_FUNCTION(IoReads),
1852  SORT_FUNCTION(IoWrites),
1853  SORT_FUNCTION(IoOther),
1854  SORT_FUNCTION(IoReadBytes),
1855  SORT_FUNCTION(IoWriteBytes),
1856  SORT_FUNCTION(IoOtherBytes),
1857  SORT_FUNCTION(IoReadsDelta),
1858  SORT_FUNCTION(IoWritesDelta),
1859  SORT_FUNCTION(IoOtherDelta),
1860  SORT_FUNCTION(OsContext),
1861  SORT_FUNCTION(PagedPool),
1862  SORT_FUNCTION(PeakPagedPool),
1863  SORT_FUNCTION(NonPagedPool),
1864  SORT_FUNCTION(PeakNonPagedPool),
1865  SORT_FUNCTION(MinimumWorkingSet),
1866  SORT_FUNCTION(MaximumWorkingSet),
1867  SORT_FUNCTION(PrivateBytesDelta),
1868  SORT_FUNCTION(Subsystem),
1869  SORT_FUNCTION(PackageName),
1870  SORT_FUNCTION(AppId),
1871  SORT_FUNCTION(DpiAwareness),
1872  SORT_FUNCTION(CfGuard)
1873  };
1874  static PH_INITONCE initOnce = PH_INITONCE_INIT;
1875  int (__cdecl *sortFunction)(const void *, const void *);
1876 
1877  if (PhBeginInitOnce(&initOnce))
1878  {
1879  if (WindowsVersion >= WINDOWS_7)
1880  {
1881  sortFunctions[PHPRTLC_PRIVATEWS] = SORT_FUNCTION(PrivateWsWin7);
1882  sortFunctions[PHPRTLC_CYCLES] = SORT_FUNCTION(CyclesWin7);
1883  sortFunctions[PHPRTLC_CYCLESDELTA] = SORT_FUNCTION(CyclesDeltaWin7);
1884  }
1885 
1886  PhEndInitOnce(&initOnce);
1887  }
1888 
1889  if (!PhCmForwardSort(
1890  (PPH_TREENEW_NODE *)ProcessNodeList->Items,
1891  ProcessNodeList->Count,
1892  ProcessTreeListSortColumn,
1893  ProcessTreeListSortOrder,
1894  &ProcessTreeListCm
1895  ))
1896  {
1897  if (ProcessTreeListSortColumn < PHPRTLC_MAXIMUM)
1898  sortFunction = sortFunctions[ProcessTreeListSortColumn];
1899  else
1900  sortFunction = NULL;
1901 
1902  if (sortFunction)
1903  {
1904  qsort(ProcessNodeList->Items, ProcessNodeList->Count, sizeof(PVOID), sortFunction);
1905  }
1906  }
1907 
1908  getChildren->Children = (PPH_TREENEW_NODE *)ProcessNodeList->Items;
1909  getChildren->NumberOfChildren = ProcessNodeList->Count;
1910  }
1911  }
1912  }
1913  return TRUE;
1914  case TreeNewIsLeaf:
1915  {
1916  PPH_TREENEW_IS_LEAF isLeaf = Parameter1;
1917 
1918  node = (PPH_PROCESS_NODE)isLeaf->Node;
1919 
1920  if (ProcessTreeListSortOrder == NoSortOrder)
1921  isLeaf->IsLeaf = node->Children->Count == 0;
1922  else
1923  isLeaf->IsLeaf = TRUE;
1924  }
1925  return TRUE;
1926  case TreeNewGetCellText:
1927  {
1928  PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;
1929  PPH_PROCESS_ITEM processItem;
1930 
1931  node = (PPH_PROCESS_NODE)getCellText->Node;
1932  processItem = node->ProcessItem;
1933 
1934  switch (getCellText->Id)
1935  {
1936  case PHPRTLC_NAME:
1937  getCellText->Text = processItem->ProcessName->sr;
1938  break;
1939  case PHPRTLC_PID:
1940  PhInitializeStringRefLongHint(&getCellText->Text, processItem->ProcessIdString);
1941  break;
1942  case PHPRTLC_CPU:
1943  {
1944  FLOAT cpuUsage;
1945 
1946  if (!PhCsPropagateCpuUsage || node->Node.Expanded || ProcessTreeListSortOrder != NoSortOrder)
1947  {
1948  cpuUsage = processItem->CpuUsage * 100;
1949  }
1950  else
1951  {
1952  cpuUsage = PhpCalculateInclusiveCpuUsage(node) * 100;
1953  }
1954 
1955  if (cpuUsage >= 0.01)
1956  {
1957  PH_FORMAT format;
1958  SIZE_T returnLength;
1959 
1960  PhInitFormatF(&format, cpuUsage, 2);
1961 
1962  if (PhFormatToBuffer(&format, 1, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength))
1963  {
1964  getCellText->Text.Buffer = node->CpuUsageText;
1965  getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator
1966  }
1967  }
1968  else if (cpuUsage != 0 && PhCsShowCpuBelow001)
1969  {
1970  PH_FORMAT format[2];
1971  SIZE_T returnLength;
1972 
1973  PhInitFormatS(&format[0], L"< ");
1974  PhInitFormatF(&format[1], 0.01, 2);
1975 
1976  if (PhFormatToBuffer(format, 2, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength))
1977  {
1978  getCellText->Text.Buffer = node->CpuUsageText;
1979  getCellText->Text.Length = returnLength - sizeof(WCHAR);
1980  }
1981  }
1982  }
1983  break;
1984  case PHPRTLC_IOTOTALRATE:
1985  {
1986  ULONG64 number;
1987 
1988  if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) // delta is wrong on first run of process provider
1989  {
1990  number = processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta;
1991  number *= 1000;
1992  number /= PhCsUpdateInterval;
1993  }
1994  else
1995  {
1996  number = 0;
1997  }
1998 
1999  if (number != 0)
2000  {
2001  PH_FORMAT format[2];
2002 
2003  PhInitFormatSize(&format[0], number);
2004  PhInitFormatS(&format[1], L"/s");
2005  PhMoveReference(&node->IoTotalRateText, PhFormat(format, 2, 0));
2006  getCellText->Text = node->IoTotalRateText->sr;
2007  }
2008  }
2009  break;
2010  case PHPRTLC_PRIVATEBYTES:
2011  PhMoveReference(&node->PrivateBytesText, PhFormatSize(processItem->VmCounters.PagefileUsage, -1));
2012  getCellText->Text = node->PrivateBytesText->sr;
2013  break;
2014  case PHPRTLC_USERNAME:
2015  getCellText->Text = PhGetStringRef(processItem->UserName);
2016  break;
2017  case PHPRTLC_DESCRIPTION:
2018  if (processItem->VersionInfo.FileDescription)
2019  getCellText->Text = processItem->VersionInfo.FileDescription->sr;
2020  else
2021  getCellText->Text = node->DescriptionText;
2022  break;
2023  case PHPRTLC_COMPANYNAME:
2024  getCellText->Text = PhGetStringRef(processItem->VersionInfo.CompanyName);
2025  break;
2026  case PHPRTLC_VERSION:
2027  getCellText->Text = PhGetStringRef(processItem->VersionInfo.FileVersion);
2028  break;
2029  case PHPRTLC_FILENAME:
2030  getCellText->Text = PhGetStringRef(processItem->FileName);
2031  break;
2032  case PHPRTLC_COMMANDLINE:
2033  getCellText->Text = PhGetStringRef(processItem->CommandLine);
2034  break;
2036  PhMoveReference(&node->PeakPrivateBytesText, PhFormatSize(processItem->VmCounters.PeakPagefileUsage, -1));
2037  getCellText->Text = node->PeakPrivateBytesText->sr;
2038  break;
2039  case PHPRTLC_WORKINGSET:
2040  PhMoveReference(&node->WorkingSetText, PhFormatSize(processItem->VmCounters.WorkingSetSize, -1));
2041  getCellText->Text = node->WorkingSetText->sr;
2042  break;
2044  PhMoveReference(&node->PeakWorkingSetText, PhFormatSize(processItem->VmCounters.PeakWorkingSetSize, -1));
2045  getCellText->Text = node->PeakWorkingSetText->sr;
2046  break;
2047  case PHPRTLC_PRIVATEWS:
2048  if (WindowsVersion >= WINDOWS_7)
2049  {
2051  }
2052  else
2053  {
2054  PhpUpdateProcessNodeWsCounters(node);
2056  }
2057  getCellText->Text = node->PrivateWsText->sr;
2058  break;
2059  case PHPRTLC_SHAREDWS:
2060  PhpUpdateProcessNodeWsCounters(node);
2062  getCellText->Text = node->SharedWsText->sr;
2063  break;
2064  case PHPRTLC_SHAREABLEWS:
2065  PhpUpdateProcessNodeWsCounters(node);
2066  PhMoveReference(&node->ShareableWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfShareablePages * PAGE_SIZE, -1));
2067  getCellText->Text = node->ShareableWsText->sr;
2068  break;
2069  case PHPRTLC_VIRTUALSIZE:
2070  PhMoveReference(&node->VirtualSizeText, PhFormatSize(processItem->VmCounters.VirtualSize, -1));
2071  getCellText->Text = node->VirtualSizeText->sr;
2072  break;
2074  PhMoveReference(&node->PeakVirtualSizeText, PhFormatSize(processItem->VmCounters.PeakVirtualSize, -1));
2075  getCellText->Text = node->PeakVirtualSizeText->sr;
2076  break;
2077  case PHPRTLC_PAGEFAULTS:
2078  PhMoveReference(&node->PageFaultsText, PhFormatUInt64(processItem->VmCounters.PageFaultCount, TRUE));
2079  getCellText->Text = node->PageFaultsText->sr;
2080  break;
2081  case PHPRTLC_SESSIONID:
2082  PhInitializeStringRefLongHint(&getCellText->Text, processItem->SessionIdString);
2083  break;
2084  case PHPRTLC_PRIORITYCLASS:
2086  break;
2087  case PHPRTLC_BASEPRIORITY:
2088  PhPrintInt32(node->BasePriorityText, processItem->BasePriority);
2089  PhInitializeStringRefLongHint(&getCellText->Text, node->BasePriorityText);
2090  break;
2091  case PHPRTLC_THREADS:
2092  PhpFormatInt32GroupDigits(processItem->NumberOfThreads, node->ThreadsText, sizeof(node->ThreadsText), &getCellText->Text);
2093  break;
2094  case PHPRTLC_HANDLES:
2095  PhpFormatInt32GroupDigits(processItem->NumberOfHandles, node->HandlesText, sizeof(node->HandlesText), &getCellText->Text);
2096  break;
2097  case PHPRTLC_GDIHANDLES:
2098  PhpUpdateProcessNodeGdiUserHandles(node);
2099  PhpFormatInt32GroupDigits(node->GdiHandles, node->GdiHandlesText, sizeof(node->GdiHandlesText), &getCellText->Text);
2100  break;
2101  case PHPRTLC_USERHANDLES:
2102  PhpUpdateProcessNodeGdiUserHandles(node);
2103  PhpFormatInt32GroupDigits(node->UserHandles, node->UserHandlesText, sizeof(node->UserHandlesText), &getCellText->Text);
2104  break;
2105  case PHPRTLC_IORORATE:
2106  {
2107  ULONG64 number;
2108 
2109  if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value)
2110  {
2111  number = processItem->IoReadDelta.Delta + processItem->IoOtherDelta.Delta;
2112  number *= 1000;
2113  number /= PhCsUpdateInterval;
2114  }
2115  else
2116  {
2117  number = 0;
2118  }
2119 
2120  if (number != 0)
2121  {
2122  PH_FORMAT format[2];
2123 
2124  PhInitFormatSize(&format[0], number);
2125  PhInitFormatS(&format[1], L"/s");
2126  PhMoveReference(&node->IoRoRateText, PhFormat(format, 2, 0));
2127  getCellText->Text = node->IoRoRateText->sr;
2128  }
2129  }
2130  break;
2131  case PHPRTLC_IOWRATE:
2132  {
2133  ULONG64 number;
2134 
2135  if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value)
2136  {
2137  number = processItem->IoWriteDelta.Delta;
2138  number *= 1000;
2139  number /= PhCsUpdateInterval;
2140  }
2141  else
2142  {
2143  number = 0;
2144  }
2145 
2146  if (number != 0)
2147  {
2148  PH_FORMAT format[2];
2149 
2150  PhInitFormatSize(&format[0], number);
2151  PhInitFormatS(&format[1], L"/s");
2152  PhMoveReference(&node->IoWRateText, PhFormat(format, 2, 0));
2153  getCellText->Text = node->IoWRateText->sr;
2154  }
2155  }
2156  break;
2157  case PHPRTLC_INTEGRITY:
2158  if (processItem->IntegrityString)
2159  PhInitializeStringRefLongHint(&getCellText->Text, processItem->IntegrityString);
2160  break;
2161  case PHPRTLC_IOPRIORITY:
2162  PhpUpdateProcessNodeIoPagePriority(node);
2163 
2164  if (node->IoPriority != -1)
2165  {
2166  if (node->IoPriority < MaxIoPriorityTypes)
2168  }
2169 
2170  break;
2171  case PHPRTLC_PAGEPRIORITY:
2172  PhpUpdateProcessNodeIoPagePriority(node);
2173 
2174  if (node->PagePriority != -1)
2175  {
2177  PhInitializeStringRefLongHint(&getCellText->Text, node->PagePriorityText);
2178  }
2179 
2180  break;
2181  case PHPRTLC_STARTTIME:
2182  {
2183  SYSTEMTIME systemTime;
2184 
2185  if (processItem->CreateTime.QuadPart != 0)
2186  {
2187  PhLargeIntegerToLocalSystemTime(&systemTime, &processItem->CreateTime);
2188  PhMoveReference(&node->StartTimeText, PhFormatDateTime(&systemTime));
2189  getCellText->Text = node->StartTimeText->sr;
2190  }
2191  }
2192  break;
2193  case PHPRTLC_TOTALCPUTIME:
2195  processItem->KernelTime.QuadPart + processItem->UserTime.QuadPart,
2197  PhInitializeStringRefLongHint(&getCellText->Text, node->TotalCpuTimeText);
2198  break;
2199  case PHPRTLC_KERNELCPUTIME:
2200  PhPrintTimeSpan(node->KernelCpuTimeText, processItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM);
2202  break;
2203  case PHPRTLC_USERCPUTIME:
2204  PhPrintTimeSpan(node->UserCpuTimeText, processItem->UserTime.QuadPart, PH_TIMESPAN_HMSM);
2205  PhInitializeStringRefLongHint(&getCellText->Text, node->UserCpuTimeText);
2206  break;
2208  if (processItem->VerifyResult == VrTrusted)
2209  PhInitializeStringRef(&getCellText->Text, L"Trusted");
2210  break;
2212  getCellText->Text = PhGetStringRef(processItem->VerifySignerName);
2213  break;
2214  case PHPRTLC_ASLR:
2215  PhpUpdateProcessNodeImage(node);
2216 
2218  {
2219  if (node->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)
2220  PhInitializeStringRef(&getCellText->Text, L"ASLR");
2221  }
2222  else
2223  {
2224  PhInitializeStringRef(&getCellText->Text, L"N/A");
2225  }
2226  break;
2228  {
2229  if (processItem->CreateTime.QuadPart != 0)
2230  {
2231  LARGE_INTEGER currentTime;
2232  PPH_STRING startTimeString;
2233 
2234  PhQuerySystemTime(&currentTime);
2235  startTimeString = PhFormatTimeSpanRelative(currentTime.QuadPart - processItem->CreateTime.QuadPart);
2236  PhMoveReference(&node->RelativeStartTimeText, PhConcatStrings2(startTimeString->Buffer, L" ago"));
2237  PhDereferenceObject(startTimeString);
2238  getCellText->Text = node->RelativeStartTimeText->sr;
2239  }
2240  }
2241  break;
2242  case PHPRTLC_BITS:
2243 #ifdef _WIN64
2244  if (processItem->IsWow64Valid)
2245  PhInitializeStringRef(&getCellText->Text, processItem->IsWow64 ? L"32" : L"64");
2246 #else
2247  PhInitializeStringRef(&getCellText->Text, L"32");
2248 #endif
2249  break;
2250  case PHPRTLC_ELEVATION:
2251  {
2252  PWSTR type;
2253 
2254  if (WINDOWS_HAS_UAC)
2255  {
2256  switch (processItem->ElevationType)
2257  {
2258  case TokenElevationTypeDefault:
2259  type = L"N/A";
2260  break;
2261  case TokenElevationTypeLimited:
2262  type = L"Limited";
2263  break;
2264  case TokenElevationTypeFull:
2265  type = L"Full";
2266  break;
2267  default:
2268  type = L"N/A";
2269  break;
2270  }
2271  }
2272  else
2273  {
2274  type = L"";
2275  }
2276 
2277  PhInitializeStringRefLongHint(&getCellText->Text, type);
2278  }
2279  break;
2280  case PHPRTLC_WINDOWTITLE:
2281  PhpUpdateProcessNodeWindow(node);
2283  getCellText->Text = PhGetStringRef(node->WindowTitleText);
2284  break;
2285  case PHPRTLC_WINDOWSTATUS:
2286  PhpUpdateProcessNodeWindow(node);
2287 
2288  if (node->WindowHandle)
2289  PhInitializeStringRef(&getCellText->Text, node->WindowHung ? L"Not responding" : L"Running");
2290 
2291  break;
2292  case PHPRTLC_CYCLES:
2293  if (WindowsVersion >= WINDOWS_7)
2294  {
2295  if (processItem->CycleTimeDelta.Value != 0)
2296  {
2298  getCellText->Text = node->CyclesText->sr;
2299  }
2300  }
2301  else
2302  {
2303  getCellText->Text = PhGetStringRef(node->CyclesText);
2304  }
2305  break;
2306  case PHPRTLC_CYCLESDELTA:
2307  if (WindowsVersion >= WINDOWS_7)
2308  {
2309  if (processItem->CycleTimeDelta.Delta != 0)
2310  {
2312  getCellText->Text = node->CyclesDeltaText->sr;
2313  }
2314  }
2315  else
2316  {
2317  getCellText->Text = PhGetStringRef(node->CyclesDeltaText);
2318  }
2319  break;
2320  case PHPRTLC_DEPSTATUS:
2321  PhpUpdateProcessNodeDepStatus(node);
2322 
2323  if (node->DepStatus & PH_PROCESS_DEP_ENABLED)
2324  {
2325  if (node->DepStatus & PH_PROCESS_DEP_PERMANENT)
2326  PhInitializeStringRef(&getCellText->Text, L"DEP (Permanent)");
2327  else
2328  PhInitializeStringRef(&getCellText->Text, L"DEP");
2329  }
2330 
2331  break;
2332  case PHPRTLC_VIRTUALIZED:
2333  PhpUpdateProcessNodeToken(node);
2334 
2335  if (node->VirtualizationEnabled)
2336  PhInitializeStringRef(&getCellText->Text, L"Virtualized");
2337 
2338  break;
2340  if (processItem->ContextSwitchesDelta.Value != 0)
2341  {
2343  getCellText->Text = node->ContextSwitchesText->sr;
2344  }
2345  break;
2347  if ((LONG)processItem->ContextSwitchesDelta.Delta > 0) // the delta may be negative if a thread exits - just don't show anything
2348  {
2350  getCellText->Text = node->ContextSwitchesDeltaText->sr;
2351  }
2352  break;
2354  if (processItem->PageFaultsDelta.Delta != 0)
2355  {
2357  getCellText->Text = node->PageFaultsDeltaText->sr;
2358  }
2359  break;
2360  case PHPRTLC_IOREADS:
2361  if (processItem->IoReadCountDelta.Value != 0)
2362  {
2364  getCellText->Text = node->IoGroupText[0]->sr;
2365  }
2366  break;
2367  case PHPRTLC_IOWRITES:
2368  if (processItem->IoWriteCountDelta.Value != 0)
2369  {
2371  getCellText->Text = node->IoGroupText[1]->sr;
2372  }
2373  break;
2374  case PHPRTLC_IOOTHER:
2375  if (processItem->IoOtherCountDelta.Value != 0)
2376  {
2378  getCellText->Text = node->IoGroupText[2]->sr;
2379  }
2380  break;
2381  case PHPRTLC_IOREADBYTES:
2382  if (processItem->IoReadDelta.Value != 0)
2383  {
2384  PhMoveReference(&node->IoGroupText[3], PhFormatSize(processItem->IoReadDelta.Value, -1));
2385  getCellText->Text = node->IoGroupText[3]->sr;
2386  }
2387  break;
2388  case PHPRTLC_IOWRITEBYTES:
2389  if (processItem->IoWriteDelta.Value != 0)
2390  {
2391  PhMoveReference(&node->IoGroupText[4], PhFormatSize(processItem->IoWriteDelta.Value, -1));
2392  getCellText->Text = node->IoGroupText[4]->sr;
2393  }
2394  break;
2395  case PHPRTLC_IOOTHERBYTES:
2396  if (processItem->IoOtherDelta.Value != 0)
2397  {
2398  PhMoveReference(&node->IoGroupText[5], PhFormatSize(processItem->IoOtherDelta.Value, -1));
2399  getCellText->Text = node->IoGroupText[5]->sr;
2400  }
2401  break;
2402  case PHPRTLC_IOREADSDELTA:
2403  if (processItem->IoReadCountDelta.Delta != 0)
2404  {
2406  getCellText->Text = node->IoGroupText[6]->sr;
2407  }
2408  break;
2409  case PHPRTLC_IOWRITESDELTA:
2410  if (processItem->IoWriteCountDelta.Delta != 0)
2411  {
2413  getCellText->Text = node->IoGroupText[7]->sr;
2414  }
2415  break;
2416  case PHPRTLC_IOOTHERDELTA:
2417  if (processItem->IoOtherCountDelta.Delta != 0)
2418  {
2420  getCellText->Text = node->IoGroupText[8]->sr;
2421  }
2422  break;
2423  case PHPRTLC_OSCONTEXT:
2424  PhpUpdateProcessOsContext(node);
2425 
2426  if (WindowsVersion >= WINDOWS_7)
2427  {
2428  switch (node->OsContextVersion)
2429  {
2430  case WINDOWS_8_1:
2431  PhInitializeStringRef(&getCellText->Text, L"Windows 8.1");
2432  break;
2433  case WINDOWS_8:
2434  PhInitializeStringRef(&getCellText->Text, L"Windows 8");
2435  break;
2436  case WINDOWS_7:
2437  PhInitializeStringRef(&getCellText->Text, L"Windows 7");
2438  break;
2439  case WINDOWS_VISTA:
2440  PhInitializeStringRef(&getCellText->Text, L"Windows Vista");
2441  break;
2442  case WINDOWS_XP:
2443  PhInitializeStringRef(&getCellText->Text, L"Windows XP");
2444  break;
2445  }
2446  }
2447  else
2448  {
2449  PhInitializeStringRef(&getCellText->Text, L"N/A");
2450  }
2451  break;
2452  case PHPRTLC_PAGEDPOOL:
2453  PhMoveReference(&node->PagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPagedPoolUsage, -1));
2454  getCellText->Text = node->PagedPoolText->sr;
2455  break;
2456  case PHPRTLC_PEAKPAGEDPOOL:
2457  PhMoveReference(&node->PeakPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakPagedPoolUsage, -1));
2458  getCellText->Text = node->PeakPagedPoolText->sr;
2459  break;
2460  case PHPRTLC_NONPAGEDPOOL:
2461  PhMoveReference(&node->NonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaNonPagedPoolUsage, -1));
2462  getCellText->Text = node->NonPagedPoolText->sr;
2463  break;
2465  PhMoveReference(&node->PeakNonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakNonPagedPoolUsage, -1));
2466  getCellText->Text = node->PeakNonPagedPoolText->sr;
2467  break;
2469  PhpUpdateProcessNodeQuotaLimits(node);
2471  getCellText->Text = node->MinimumWorkingSetText->sr;
2472  break;
2474  PhpUpdateProcessNodeQuotaLimits(node);
2476  getCellText->Text = node->MaximumWorkingSetText->sr;
2477  break;
2479  {
2480  LONG_PTR delta;
2481 
2482  delta = processItem->PrivateBytesDelta.Delta;
2483 
2484  if (delta != 0)
2485  {
2486  PH_FORMAT format[2];
2487 
2488  if (delta > 0)
2489  {
2490  PhInitFormatC(&format[0], '+');
2491  }
2492  else
2493  {
2494  PhInitFormatC(&format[0], '-');
2495  delta = -delta;
2496  }
2497 
2498  format[1].Type = SizeFormatType | FormatUseRadix;
2499  format[1].Radix = (UCHAR)PhMaxSizeUnit;
2500  format[1].u.Size = delta;
2501 
2502  PhMoveReference(&node->PrivateBytesDeltaText, PhFormat(format, 2, 0));
2503  getCellText->Text = node->PrivateBytesDeltaText->sr;
2504  }
2505  }
2506  break;
2507  case PHPRTLC_SUBSYSTEM:
2508  PhpUpdateProcessNodeImage(node);
2509 
2510  switch (node->ImageSubsystem)
2511  {
2512  case 0:
2513  break;
2514  case IMAGE_SUBSYSTEM_NATIVE:
2515  PhInitializeStringRef(&getCellText->Text, L"Native");
2516  break;
2517  case IMAGE_SUBSYSTEM_WINDOWS_GUI:
2518  PhInitializeStringRef(&getCellText->Text, L"Windows");
2519  break;
2520  case IMAGE_SUBSYSTEM_WINDOWS_CUI:
2521  PhInitializeStringRef(&getCellText->Text, L"Windows Console");
2522  break;
2523  case IMAGE_SUBSYSTEM_OS2_CUI:
2524  PhInitializeStringRef(&getCellText->Text, L"OS/2");
2525  break;
2526  case IMAGE_SUBSYSTEM_POSIX_CUI:
2527  PhInitializeStringRef(&getCellText->Text, L"POSIX");
2528  break;
2529  default:
2530  PhInitializeStringRef(&getCellText->Text, L"Unknown");
2531  break;
2532  }
2533  break;
2534  case PHPRTLC_PACKAGENAME:
2535  getCellText->Text = PhGetStringRef(processItem->PackageFullName);
2536  break;
2537  case PHPRTLC_APPID:
2538  PhpUpdateProcessNodeAppId(node);
2539  getCellText->Text = PhGetStringRef(node->AppIdText);
2540  break;
2541  case PHPRTLC_DPIAWARENESS:
2542  PhpUpdateProcessNodeDpiAwareness(node);
2543 
2544  switch (node->DpiAwareness)
2545  {
2546  case 0:
2547  break;
2548  case 1:
2549  PhInitializeStringRef(&getCellText->Text, L"Unaware");
2550  break;
2551  case 2:
2552  PhInitializeStringRef(&getCellText->Text, L"System Aware");
2553  break;
2554  case 3:
2555  PhInitializeStringRef(&getCellText->Text, L"Per-Monitor Aware");
2556  break;
2557  }
2558  break;
2559  case PHPRTLC_CFGUARD:
2560  PhpUpdateProcessNodeImage(node);
2561 
2562  if (WindowsVersion >= WINDOWS_8_1)
2563  {
2564  if (node->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF)
2565  PhInitializeStringRef(&getCellText->Text, L"CF Guard");
2566  }
2567  else
2568  {
2569  PhInitializeStringRef(&getCellText->Text, L"N/A");
2570  }
2571  break;
2572  default:
2573  return FALSE;
2574  }
2575 
2576  getCellText->Flags = TN_CACHE;
2577  }
2578  return TRUE;
2579  case TreeNewGetNodeColor:
2580  {
2581  PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;
2582  PPH_PROCESS_ITEM processItem;
2583 
2584  node = (PPH_PROCESS_NODE)getNodeColor->Node;
2585  processItem = node->ProcessItem;
2586 
2587  if (PhPluginsEnabled)
2588  {
2589  PH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor;
2590 
2591  getHighlightingColor.Parameter = processItem;
2592  getHighlightingColor.BackColor = RGB(0xff, 0xff, 0xff);
2593  getHighlightingColor.Handled = FALSE;
2594  getHighlightingColor.Cache = FALSE;
2595 
2597 
2598  if (getHighlightingColor.Handled)
2599  {
2600  getNodeColor->BackColor = getHighlightingColor.BackColor;
2601  getNodeColor->Flags = TN_AUTO_FORECOLOR;
2602 
2603  if (getHighlightingColor.Cache)
2604  getNodeColor->Flags |= TN_CACHE;
2605 
2606  return TRUE;
2607  }
2608  }
2609 
2610  if (!processItem)
2611  ; // Dummy
2612  else if (PhCsUseColorDebuggedProcesses && processItem->IsBeingDebugged)
2613  getNodeColor->BackColor = PhCsColorDebuggedProcesses;
2614  else if (PhCsUseColorSuspended && processItem->IsSuspended)
2615  getNodeColor->BackColor = PhCsColorSuspended;
2616  else if (PhCsUseColorElevatedProcesses && processItem->IsElevated)
2617  getNodeColor->BackColor = PhCsColorElevatedProcesses;
2618  else if (PhCsUseColorPosixProcesses && processItem->IsPosix)
2619  getNodeColor->BackColor = PhCsColorPosixProcesses;
2620  else if (PhCsUseColorJobProcesses && processItem->IsInSignificantJob)
2621  getNodeColor->BackColor = PhCsColorJobProcesses;
2622  else if (PhCsUseColorImmersiveProcesses && processItem->IsImmersive)
2623  getNodeColor->BackColor = PhCsColorImmersiveProcesses;
2624  else if (PhCsUseColorDotNet && processItem->IsDotNet)
2625  getNodeColor->BackColor = PhCsColorDotNet;
2626  else if (PhCsUseColorPacked && processItem->IsPacked)
2627  getNodeColor->BackColor = PhCsColorPacked;
2628  else if (PhCsUseColorWow64Processes && processItem->IsWow64)
2629  getNodeColor->BackColor = PhCsColorWow64Processes;
2630  else if (PhCsUseColorServiceProcesses && processItem->ServiceList && processItem->ServiceList->Count != 0)
2631  getNodeColor->BackColor = PhCsColorServiceProcesses;
2632  else if (
2634  processItem->UserName &&
2636  )
2637  getNodeColor->BackColor = PhCsColorSystemProcesses;
2638  else if (
2640  processItem->UserName &&
2643  )
2644  getNodeColor->BackColor = PhCsColorOwnProcesses;
2645 
2646  getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR;
2647  }
2648  return TRUE;
2649  case TreeNewGetNodeIcon:
2650  {
2651  PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1;
2652 
2653  node = (PPH_PROCESS_NODE)getNodeIcon->Node;
2654 
2655  if (node->ProcessItem->SmallIcon)
2656  {
2657  getNodeIcon->Icon = node->ProcessItem->SmallIcon;
2658  }
2659  else
2660  {
2661  PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL);
2662  }
2663 
2664  getNodeIcon->Flags = TN_CACHE;
2665  }
2666  return TRUE;
2667  case TreeNewGetCellTooltip:
2668  {
2669  PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1;
2670  ULONG tickCount;
2671 
2672  node = (PPH_PROCESS_NODE)getCellTooltip->Node;
2673 
2674  if (getCellTooltip->Column->Id != 0)
2675  return FALSE;
2676 
2677  tickCount = GetTickCount();
2678 
2679  if ((LONG)(node->TooltipTextValidToTickCount - tickCount) < 0)
2680  PhClearReference(&node->TooltipText);
2681  if (!node->TooltipText)
2683 
2684  if (!PhIsNullOrEmptyString(node->TooltipText))
2685  {
2686  getCellTooltip->Text = node->TooltipText->sr;
2687  getCellTooltip->Unfolding = FALSE;
2688  getCellTooltip->MaximumWidth = -1;
2689  }
2690  else
2691  {
2692  return FALSE;
2693  }
2694  }
2695  return TRUE;
2696  case TreeNewCustomDraw:
2697  {
2698  PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;
2699  PPH_PROCESS_ITEM processItem;
2700  RECT rect;
2701  PH_GRAPH_DRAW_INFO drawInfo;
2702 
2703  node = (PPH_PROCESS_NODE)customDraw->Node;
2704  processItem = node->ProcessItem;
2705  rect = customDraw->CellRect;
2706 
2707  if (rect.right - rect.left <= 1)
2708  break; // nothing to draw
2709 
2710  // Generic graph pre-processing
2711  switch (customDraw->Column->Id)
2712  {
2713  case PHPRTLC_CPUHISTORY:
2715  case PHPRTLC_IOHISTORY:
2716  memset(&drawInfo, 0, sizeof(PH_GRAPH_DRAW_INFO));
2717  drawInfo.Width = rect.right - rect.left - 1; // leave a small gap
2718  drawInfo.Height = rect.bottom - rect.top - 1; // leave a small gap
2719  drawInfo.Step = 2;
2720  drawInfo.BackColor = RGB(0x00, 0x00, 0x00);
2721  break;
2722  }
2723 
2724  // Specific graph processing
2725  switch (customDraw->Column->Id)
2726  {
2727  case PHPRTLC_CPUHISTORY:
2728  {
2729  drawInfo.Flags = PH_GRAPH_USE_LINE_2;
2730  drawInfo.LineColor1 = PhCsColorCpuKernel;
2731  drawInfo.LineColor2 = PhCsColorCpuUser;
2734 
2736  &node->CpuGraphBuffers,
2737  &drawInfo,
2738  processItem->CpuKernelHistory.Count
2739  );
2740 
2741  if (!node->CpuGraphBuffers.Valid)
2742  {
2743  PhCopyCircularBuffer_FLOAT(&processItem->CpuKernelHistory,
2744  node->CpuGraphBuffers.Data1, drawInfo.LineDataCount);
2745  PhCopyCircularBuffer_FLOAT(&processItem->CpuUserHistory,
2746  node->CpuGraphBuffers.Data2, drawInfo.LineDataCount);
2747  node->CpuGraphBuffers.Valid = TRUE;
2748  }
2749  }
2750  break;
2752  {
2753  drawInfo.Flags = 0;
2754  drawInfo.LineColor1 = PhCsColorPrivate;
2756 
2758  &node->PrivateGraphBuffers,
2759  &drawInfo,
2760  processItem->PrivateBytesHistory.Count
2761  );
2762 
2763  if (!node->PrivateGraphBuffers.Valid)
2764  {
2765  ULONG i;
2766  FLOAT total;
2767  FLOAT max;
2768 
2769  for (i = 0; i < drawInfo.LineDataCount; i++)
2770  {
2771  node->PrivateGraphBuffers.Data1[i] =
2772  (FLOAT)PhGetItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, i);
2773  }
2774 
2775  // This makes it easier for the user to see what processes are hogging memory.
2776  // Scaling is still *not* consistent across all graphs.
2777  total = (FLOAT)PhPerfInformation.CommittedPages * PAGE_SIZE / 4; // divide by 4 to make the scaling a bit better
2778  max = (FLOAT)processItem->VmCounters.PeakPagefileUsage;
2779 
2780  if (max < total)
2781  max = total;
2782 
2783  if (max != 0)
2784  {
2785  // Scale the data.
2787  node->PrivateGraphBuffers.Data1,
2788  max,
2789  drawInfo.LineDataCount
2790  );
2791  }
2792 
2793  node->PrivateGraphBuffers.Valid = TRUE;
2794  }
2795  }
2796  break;
2797  case PHPRTLC_IOHISTORY:
2798  {
2799  drawInfo.Flags = PH_GRAPH_USE_LINE_2;
2800  drawInfo.LineColor1 = PhCsColorIoReadOther;
2801  drawInfo.LineColor2 = PhCsColorIoWrite;
2804 
2806  &node->IoGraphBuffers,
2807  &drawInfo,
2808  processItem->IoReadHistory.Count
2809  );
2810 
2811  if (!node->IoGraphBuffers.Valid)
2812  {
2813  ULONG i;
2814  FLOAT total;
2815  FLOAT max = 0;
2816 
2817  for (i = 0; i < drawInfo.LineDataCount; i++)
2818  {
2819  FLOAT data1;
2820  FLOAT data2;
2821 
2822  node->IoGraphBuffers.Data1[i] = data1 =
2823  (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoReadHistory, i) +
2824  (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, i);
2825  node->IoGraphBuffers.Data2[i] = data2 =
2826  (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, i);
2827 
2828  if (max < data1 + data2)
2829  max = data1 + data2;
2830  }
2831 
2832  // Make the scaling a bit more consistent across the processes.
2833  // It does *not* scale all graphs using the same maximum.
2835 
2836  if (max < total)
2837  max = total;
2838 
2839  if (max != 0)
2840  {
2841  // Scale the data.
2842 
2844  node->IoGraphBuffers.Data1,
2845  max,
2846  drawInfo.LineDataCount
2847  );
2849  node->IoGraphBuffers.Data2,
2850  max,
2851  drawInfo.LineDataCount
2852  );
2853  }
2854 
2855  node->IoGraphBuffers.Valid = TRUE;
2856  }
2857  }
2858  break;
2859  }
2860 
2861  // Draw the graph.
2862  switch (customDraw->Column->Id)
2863  {
2864  case PHPRTLC_CPUHISTORY:
2866  case PHPRTLC_IOHISTORY:
2867  PhpNeedGraphContext(customDraw->Dc, drawInfo.Width, drawInfo.Height);
2868 
2869  if (GraphBits)
2870  {
2871  PhDrawGraphDirect(GraphContext, GraphBits, &drawInfo);
2872  BitBlt(
2873  customDraw->Dc,
2874  rect.left,
2875  rect.top + 1, // + 1 for small gap
2876  drawInfo.Width,
2877  drawInfo.Height,
2878  GraphContext,
2879  0,
2880  0,
2881  SRCCOPY
2882  );
2883  }
2884 
2885  break;
2886  }
2887  }
2888  return TRUE;
2889  case TreeNewColumnResized:
2890  {
2891  PPH_TREENEW_COLUMN column = Parameter1;
2892  ULONG i;
2893 
2894  if (column->Id == PHPRTLC_CPUHISTORY || column->Id == PHPRTLC_IOHISTORY || column->Id == PHPRTLC_PRIVATEBYTESHISTORY)
2895  {
2896  for (i = 0; i < ProcessNodeList->Count; i++)
2897  {
2898  node = ProcessNodeList->Items[i];
2899 
2900  if (column->Id == PHPRTLC_CPUHISTORY)
2901  node->CpuGraphBuffers.Valid = FALSE;
2902  if (column->Id == PHPRTLC_IOHISTORY)
2903  node->IoGraphBuffers.Valid = FALSE;
2904  if (column->Id == PHPRTLC_PRIVATEBYTESHISTORY)
2906  }
2907  }
2908  }
2909  return TRUE;
2910  case TreeNewSortChanged:
2911  {
2912  TreeNew_GetSort(hwnd, &ProcessTreeListSortColumn, &ProcessTreeListSortOrder);
2913  // Force a rebuild to sort the items.
2915  }
2916  return TRUE;
2917  case TreeNewKeyDown:
2918  {
2919  PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;
2920 
2921  switch (keyEvent->VirtualKey)
2922  {
2923  case 'C':
2924  if (GetKeyState(VK_CONTROL) < 0)
2925  SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_COPY, 0);
2926  break;
2927  case 'A':
2928  if (GetKeyState(VK_CONTROL) < 0)
2929  TreeNew_SelectRange(ProcessTreeListHandle, 0, -1);
2930  break;
2931  case VK_DELETE:
2932  if (GetKeyState(VK_SHIFT) >= 0)
2933  SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_TERMINATE, 0);
2934  else
2935  SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_TERMINATETREE, 0);
2936  break;
2937  case VK_RETURN:
2938  if (GetKeyState(VK_CONTROL) >= 0)
2939  SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_PROPERTIES, 0);
2940  else
2941  SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_OPENFILELOCATION, 0);
2942  break;
2943  }
2944  }
2945  return TRUE;
2947  {
2949 
2950  data.TreeNewHandle = hwnd;
2951  data.MouseEvent = Parameter1;
2952  data.DefaultSortColumn = 0;
2955 
2959 
2962 
2964  }
2965  return TRUE;
2967  {
2968  SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_PROPERTIES, 0);
2969  }
2970  return TRUE;
2971  case TreeNewContextMenu:
2972  {
2973  PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;
2974 
2975  PhShowProcessContextMenu(contextMenu);
2976  }
2977  return TRUE;
2978  case TreeNewNodeExpanding:
2979  {
2980  node = Parameter1;
2981 
2983  PhUpdateProcessNode(node);
2984  }
2985  return TRUE;
2986  }
2987 
2988  return FALSE;
2989 }
2990 
2992  VOID
2993  )
2994 {
2995  PPH_PROCESS_ITEM processItem = NULL;
2996  ULONG i;
2997 
2998  for (i = 0; i < ProcessNodeList->Count; i++)
2999  {
3000  PPH_PROCESS_NODE node = ProcessNodeList->Items[i];
3001 
3002  if (node->Node.Selected)
3003  {
3004  processItem = node->ProcessItem;
3005  break;
3006  }
3007  }
3008 
3009  return processItem;
3010 }
3011 
3013  _Out_ PPH_PROCESS_ITEM **Processes,
3014  _Out_ PULONG NumberOfProcesses
3015  )
3016 {
3017  PPH_LIST list;
3018  ULONG i;
3019 
3020  list = PhCreateList(2);
3021 
3022  for (i = 0; i < ProcessNodeList->Count; i++)
3023  {
3024  PPH_PROCESS_NODE node = ProcessNodeList->Items[i];
3025 
3026  if (node->Node.Selected)
3027  {
3028  PhAddItemList(list, node->ProcessItem);
3029  }
3030  }
3031 
3032  *Processes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);
3033  *NumberOfProcesses = list->Count;
3034 
3035  PhDereferenceObject(list);
3036 }
3037 
3039  VOID
3040  )
3041 {
3042  TreeNew_DeselectRange(ProcessTreeListHandle, 0, -1);
3043 }
3044 
3046  _In_ BOOLEAN Expand
3047  )
3048 {
3049  ULONG i;
3050  BOOLEAN needsRestructure = FALSE;
3051 
3052  for (i = 0; i < ProcessNodeList->Count; i++)
3053  {
3054  PPH_PROCESS_NODE node = ProcessNodeList->Items[i];
3055 
3056  if (node->Children->Count != 0 && node->Node.Expanded != Expand)
3057  {
3058  node->Node.Expanded = Expand;
3059  needsRestructure = TRUE;
3060  }
3061  }
3062 
3063  if (needsRestructure)
3064  TreeNew_NodesStructured(ProcessTreeListHandle);
3065 }
3066 
3068  VOID
3069  )
3070 {
3071  ULONG i;
3072 
3073  for (i = 0; i < ProcessNodeList->Count; i++)
3074  {
3075  PPH_PROCESS_NODE node = ProcessNodeList->Items[i];
3076 
3077  memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM);
3079  node->ValidMask = 0;
3080 
3081  // Invalidate graph buffers.
3082  node->CpuGraphBuffers.Valid = FALSE;
3084  node->IoGraphBuffers.Valid = FALSE;
3085  }
3086 
3087  InvalidateRect(ProcessTreeListHandle, NULL, FALSE);
3088 }
3089 
3091  _In_ PPH_PROCESS_NODE ProcessNode
3092  )
3093 {
3094  PhSelectAndEnsureVisibleProcessNodes(&ProcessNode, 1);
3095 }
3096 
3098  _In_ PPH_PROCESS_NODE *ProcessNodes,
3099  _In_ ULONG NumberOfProcessNodes
3100  )
3101 {
3102  ULONG i;
3103  PPH_PROCESS_NODE leader = NULL;
3104  PPH_PROCESS_NODE node;
3105  BOOLEAN needsRestructure = FALSE;
3106 
3108 
3109  for (i = 0; i < NumberOfProcessNodes; i++)
3110  {
3111  if (ProcessNodes[i]->Node.Visible)
3112  {
3113  leader = ProcessNodes[i];
3114  break;
3115  }
3116  }
3117 
3118  if (!leader)
3119  return;
3120 
3121  // Expand recursively upwards, and select the nodes.
3122 
3123  for (i = 0; i < NumberOfProcessNodes; i++)
3124  {
3125  if (!ProcessNodes[i]->Node.Visible)
3126  continue;
3127 
3128  node = ProcessNodes[i]->Parent;
3129 
3130  while (node)
3131  {
3132  if (!node->Node.Expanded)
3133  needsRestructure = TRUE;
3134 
3135  node->Node.Expanded = TRUE;
3136  node = node->Parent;
3137  }
3138 
3139  ProcessNodes[i]->Node.Selected = TRUE;
3140  }
3141 
3142  if (needsRestructure)
3143  TreeNew_NodesStructured(ProcessTreeListHandle);
3144 
3145  TreeNew_SetFocusNode(ProcessTreeListHandle, &leader->Node);
3146  TreeNew_SetMarkNode(ProcessTreeListHandle, &leader->Node);
3147  TreeNew_EnsureVisible(ProcessTreeListHandle, &leader->Node);
3148  TreeNew_InvalidateNode(ProcessTreeListHandle, &leader->Node);
3149 }
3150 
3152  _In_ HWND TreeListHandle,
3153  _In_ PPH_PROCESS_NODE Node,
3154  _In_ ULONG Level,
3155  _In_ PPH_STRING **Table,
3156  _Inout_ PULONG Index,
3157  _In_ PULONG DisplayToId,
3158  _In_ ULONG Columns
3159  )
3160 {
3161  ULONG i;
3162 
3163  for (i = 0; i < Columns; i++)
3164  {
3165  PH_TREENEW_GET_CELL_TEXT getCellText;
3166  PPH_STRING text;
3167 
3168  getCellText.Node = &Node->Node;
3169  getCellText.Id = DisplayToId[i];
3170  PhInitializeEmptyStringRef(&getCellText.Text);
3171  TreeNew_GetCellText(TreeListHandle, &getCellText);
3172 
3173  if (i != 0)
3174  {
3175  text = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length);
3176  }
3177  else
3178  {
3179  // If this is the first column in the row, add some indentation.
3180  text = PhaCreateStringEx(
3181  NULL,
3182  getCellText.Text.Length + Level * 2 * sizeof(WCHAR)
3183  );
3184  wmemset(text->Buffer, ' ', Level * 2);
3185  memcpy(&text->Buffer[Level * 2], getCellText.Text.Buffer, getCellText.Text.Length);
3186  }
3187 
3188  Table[*Index][i] = text;
3189  }
3190 
3191  (*Index)++;
3192 
3193  // Process the children.
3194  for (i = 0; i < Node->Children->Count; i++)
3195  {
3197  TreeListHandle,
3198  Node->Children->Items[i],
3199  Level + 1,
3200  Table,
3201  Index,
3202  DisplayToId,
3203  Columns
3204  );
3205  }
3206 }
3207 
3209  _In_ HWND TreeListHandle,
3210  _In_ ULONG NumberOfNodes,
3211  _In_ PPH_LIST RootNodes,
3212  _In_ ULONG Mode
3213  )
3214 {
3215  PH_AUTO_POOL autoPool;
3216  PPH_LIST lines;
3217  // The number of rows in the table (including +1 for the column headers).
3218  ULONG rows;
3219  // The number of columns.
3220  ULONG columns;
3221  // A column display index to ID map.
3222  PULONG displayToId;
3223  // A column display index to text map.
3224  PWSTR *displayToText;
3225  // The actual string table.
3226  PPH_STRING **table;
3227  ULONG i;
3228  ULONG j;
3229 
3230  // Use a local auto-pool to make memory mangement a bit less painful.
3231  PhInitializeAutoPool(&autoPool);
3232 
3233  rows = NumberOfNodes + 1;
3234 
3235  // Create the display index to ID map.
3236  PhMapDisplayIndexTreeNew(TreeListHandle, &displayToId, &displayToText, &columns);
3237 
3238  PhaCreateTextTable(&table, rows, columns);
3239 
3240  // Populate the first row with the column headers.
3241  for (i = 0; i < columns; i++)
3242  {
3243  table[0][i] = PhaCreateString(displayToText[i]);
3244  }
3245 
3246  // Go through the nodes in the process tree and populate each cell of the table.
3247 
3248  j = 1; // index starts at one because the first row contains the column headers.
3249 
3250  for (i = 0; i < RootNodes->Count; i++)
3251  {
3253  TreeListHandle,
3254  RootNodes->Items[i],
3255  0,
3256  table,
3257  &j,
3258  displayToId,
3259  columns
3260  );
3261  }
3262 
3263  PhFree(displayToId);
3264  PhFree(displayToText);
3265 
3266  lines = PhaFormatTextTable(table, rows, columns, Mode);
3267 
3268  PhDeleteAutoPool(&autoPool);
3269 
3270  return lines;
3271 }
3272 
3274  VOID
3275  )
3276 {
3277  PPH_STRING text;
3278 
3279  text = PhGetTreeNewText(ProcessTreeListHandle, 0);
3280  PhSetClipboardString(ProcessTreeListHandle, &text->sr);
3281  PhDereferenceObject(text);
3282 }
3283 
3285  _Inout_ PPH_FILE_STREAM FileStream,
3286  _In_ ULONG Mode
3287  )
3288 {
3289  PPH_LIST lines;
3290  ULONG i;
3291 
3292  lines = PhGetProcessTreeListLines(
3293  ProcessTreeListHandle,
3294  ProcessNodeList->Count,
3295  ProcessNodeRootList,
3296  Mode
3297  );
3298 
3299  for (i = 0; i < lines->Count; i++)
3300  {
3301  PPH_STRING line;
3302 
3303  line = lines->Items[i];
3304  PhWriteStringAsUtf8FileStream(FileStream, &line->sr);
3305  PhDereferenceObject(line);
3306  PhWriteStringAsUtf8FileStream2(FileStream, L"\r\n");
3307  }
3308 
3309  PhDereferenceObject(lines);
3310 }
3311 
3313  VOID
3314  )
3315 {
3316  PPH_LIST newList;
3317 
3318  newList = PhCreateList(ProcessNodeList->Count);
3319  PhInsertItemsList(newList, 0, ProcessNodeList->Items, ProcessNodeList->Count);
3320 
3321  return newList;
3322 }