Process Hacker
memlist.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * memory region list
4  *
5  * Copyright (C) 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 #include <phapp.h>
24 #include <settings.h>
25 #include <extmgri.h>
26 #include <phplug.h>
27 #include <emenu.h>
28 
30  _Inout_ PPH_MEMORY_LIST_CONTEXT Context
31  );
32 
34  _In_ PPH_MEMORY_NODE MemoryNode
35  );
36 
38  _In_ LONG Result,
39  _In_ PVOID Node1,
40  _In_ PVOID Node2,
41  _In_ PH_SORT_ORDER SortOrder
42  );
43 
44 BOOLEAN NTAPI PhpMemoryTreeNewCallback(
45  _In_ HWND hwnd,
46  _In_ PH_TREENEW_MESSAGE Message,
47  _In_opt_ PVOID Parameter1,
48  _In_opt_ PVOID Parameter2,
49  _In_opt_ PVOID Context
50  );
51 
53  _In_ HWND ParentWindowHandle,
54  _In_ HWND TreeNewHandle,
55  _Out_ PPH_MEMORY_LIST_CONTEXT Context
56  )
57 {
58  HWND hwnd;
59 
60  memset(Context, 0, sizeof(PH_MEMORY_LIST_CONTEXT));
61 
62  Context->AllocationBaseNodeList = PhCreateList(100);
63  Context->RegionNodeList = PhCreateList(400);
64 
65  Context->ParentWindowHandle = ParentWindowHandle;
66  Context->TreeNewHandle = TreeNewHandle;
67  hwnd = TreeNewHandle;
68  PhSetControlTheme(hwnd, L"explorer");
69 
71 
72  TreeNew_SetRedraw(hwnd, FALSE);
73 
74  // Default columns
75  PhAddTreeNewColumn(hwnd, PHMMTLC_BASEADDRESS, TRUE, L"Base Address", 120, PH_ALIGN_LEFT, -2, 0);
76  PhAddTreeNewColumn(hwnd, PHMMTLC_TYPE, TRUE, L"Type", 90, PH_ALIGN_LEFT, 0, 0);
77  PhAddTreeNewColumnEx(hwnd, PHMMTLC_SIZE, TRUE, L"Size", 80, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE);
78  PhAddTreeNewColumn(hwnd, PHMMTLC_PROTECTION, TRUE, L"Protection", 60, PH_ALIGN_LEFT, 2, 0);
79  PhAddTreeNewColumn(hwnd, PHMMTLC_USE, TRUE, L"Use", 200, PH_ALIGN_LEFT, 3, 0);
80  PhAddTreeNewColumnEx(hwnd, PHMMTLC_TOTALWS, TRUE, L"Total WS", 80, PH_ALIGN_RIGHT, 4, DT_RIGHT, TRUE);
81  PhAddTreeNewColumnEx(hwnd, PHMMTLC_PRIVATEWS, TRUE, L"Private WS", 80, PH_ALIGN_RIGHT, 5, DT_RIGHT, TRUE);
82  PhAddTreeNewColumnEx(hwnd, PHMMTLC_SHAREABLEWS, TRUE, L"Shareable WS", 80, PH_ALIGN_RIGHT, 6, DT_RIGHT, TRUE);
83  PhAddTreeNewColumnEx(hwnd, PHMMTLC_SHAREDWS, TRUE, L"Shared WS", 80, PH_ALIGN_RIGHT, 7, DT_RIGHT, TRUE);
84  PhAddTreeNewColumnEx(hwnd, PHMMTLC_LOCKEDWS, TRUE, L"Locked WS", 80, PH_ALIGN_RIGHT, 8, DT_RIGHT, TRUE);
85 
86  PhAddTreeNewColumnEx(hwnd, PHMMTLC_COMMITTED, FALSE, L"Committed", 80, PH_ALIGN_RIGHT, 9, DT_RIGHT, TRUE);
87  PhAddTreeNewColumnEx(hwnd, PHMMTLC_PRIVATE, FALSE, L"Private", 80, PH_ALIGN_RIGHT, 10, DT_RIGHT, TRUE);
88 
89  TreeNew_SetRedraw(hwnd, TRUE);
90 
92  TreeNew_SetSort(hwnd, 0, NoSortOrder);
93 
95 }
96 
98  _Inout_ PPH_MEMORY_LIST_CONTEXT Context
99  )
100 {
101  ULONG i;
102 
103  for (i = 0; i < Context->AllocationBaseNodeList->Count; i++)
104  PhpDestroyMemoryNode(Context->AllocationBaseNodeList->Items[i]);
105  for (i = 0; i < Context->RegionNodeList->Count; i++)
106  PhpDestroyMemoryNode(Context->RegionNodeList->Items[i]);
107 
108  PhClearList(Context->AllocationBaseNodeList);
109  PhClearList(Context->RegionNodeList);
110 }
111 
113  _In_ PPH_MEMORY_LIST_CONTEXT Context
114  )
115 {
116  PhCmDeleteManager(&Context->Cm);
117 
118  PhpClearMemoryList(Context);
119  PhDereferenceObject(Context->AllocationBaseNodeList);
120  PhDereferenceObject(Context->RegionNodeList);
121 }
122 
124  _Inout_ PPH_MEMORY_LIST_CONTEXT Context
125  )
126 {
127  PPH_STRING settings;
128  PPH_STRING sortSettings;
129 
130  settings = PhGetStringSetting(L"MemoryTreeListColumns");
131  sortSettings = PhGetStringSetting(L"MemoryTreeListSort");
132  PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr);
133  PhDereferenceObject(settings);
134  PhDereferenceObject(sortSettings);
135 }
136 
138  _Inout_ PPH_MEMORY_LIST_CONTEXT Context
139  )
140 {
141  PPH_STRING settings;
142  PPH_STRING sortSettings;
143 
144  settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings);
145  PhSetStringSetting2(L"MemoryTreeListColumns", &settings->sr);
146  PhSetStringSetting2(L"MemoryTreeListSort", &sortSettings->sr);
147  PhDereferenceObject(settings);
148  PhDereferenceObject(sortSettings);
149 }
150 
152  _Inout_ PPH_MEMORY_LIST_CONTEXT Context,
153  _In_ BOOLEAN HideFreeRegions
154  )
155 {
156  ULONG i;
157  ULONG k;
158  BOOLEAN modified;
159 
160  if (Context->HideFreeRegions != HideFreeRegions)
161  {
162  PPH_LIST lists[2];
163 
164  Context->HideFreeRegions = HideFreeRegions;
165  modified = FALSE;
166  lists[0] = Context->AllocationBaseNodeList;
167  lists[1] = Context->RegionNodeList;
168 
169  for (k = 0; k < 2; k++)
170  {
171  for (i = 0; i < lists[k]->Count; i++)
172  {
173  PPH_MEMORY_NODE node = lists[k]->Items[i];
174  BOOLEAN visible;
175 
176  visible = TRUE;
177 
178  if (HideFreeRegions && (node->MemoryItem->State & MEM_FREE))
179  visible = FALSE;
180 
181  if (node->Node.Visible != visible)
182  {
183  node->Node.Visible = visible;
184  modified = TRUE;
185 
186  if (!visible)
187  node->Node.Selected = FALSE;
188  }
189  }
190  }
191 
192  if (modified)
193  {
194  TreeNew_NodesStructured(Context->TreeNewHandle);
195  }
196  }
197 }
198 
200  _In_ PPH_MEMORY_NODE MemoryNode
201  )
202 {
204 
205  PhClearReference(&MemoryNode->SizeText);
206  PhClearReference(&MemoryNode->UseText);
207  PhClearReference(&MemoryNode->TotalWsText);
208  PhClearReference(&MemoryNode->PrivateWsText);
209  PhClearReference(&MemoryNode->ShareableWsText);
210  PhClearReference(&MemoryNode->SharedWsText);
211  PhClearReference(&MemoryNode->LockedWsText);
212  PhClearReference(&MemoryNode->CommittedText);
213  PhClearReference(&MemoryNode->PrivateText);
214 
215  PhClearReference(&MemoryNode->Children);
216  PhDereferenceObject(MemoryNode->MemoryItem);
217 
218  PhFree(MemoryNode);
219 }
220 
222  _Inout_ PPH_MEMORY_LIST_CONTEXT Context,
223  _In_ PVOID AllocationBase
224  )
225 {
226  PPH_MEMORY_NODE memoryNode;
227  PPH_MEMORY_ITEM memoryItem;
228 
229  memoryNode = PhAllocate(PhEmGetObjectSize(EmMemoryNodeType, sizeof(PH_MEMORY_NODE)));
230  memset(memoryNode, 0, sizeof(PH_MEMORY_NODE));
231  PhInitializeTreeNewNode(&memoryNode->Node);
232  memoryNode->Node.Expanded = FALSE;
233 
234  memoryNode->IsAllocationBase = TRUE;
235  memoryItem = PhCreateMemoryItem();
236  memoryNode->MemoryItem = memoryItem;
237 
238  memoryItem->BaseAddress = AllocationBase;
239  memoryItem->AllocationBase = AllocationBase;
240 
241  memoryNode->Children = PhCreateList(1);
242 
243  memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM);
244  memoryNode->Node.TextCache = memoryNode->TextCache;
245  memoryNode->Node.TextCacheSize = PHMMTLC_MAXIMUM;
246 
247  PhAddItemList(Context->AllocationBaseNodeList, memoryNode);
248 
250 
251  return memoryNode;
252 }
253 
255  _Inout_ PPH_MEMORY_LIST_CONTEXT Context,
256  _In_ PPH_MEMORY_ITEM MemoryItem
257  )
258 {
259  PPH_MEMORY_NODE memoryNode;
260 
261  memoryNode = PhAllocate(PhEmGetObjectSize(EmMemoryNodeType, sizeof(PH_MEMORY_NODE)));
262  memset(memoryNode, 0, sizeof(PH_MEMORY_NODE));
263  PhInitializeTreeNewNode(&memoryNode->Node);
264 
265  memoryNode->IsAllocationBase = FALSE;
266  memoryNode->MemoryItem = MemoryItem;
267  PhReferenceObject(MemoryItem);
268 
269  memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM);
270  memoryNode->Node.TextCache = memoryNode->TextCache;
271  memoryNode->Node.TextCacheSize = PHMMTLC_MAXIMUM;
272 
273  PhAddItemList(Context->RegionNodeList, memoryNode);
274 
276 
277  return memoryNode;
278 }
279 
281  _In_ PPH_MEMORY_ITEM Source,
282  _Inout_ PPH_MEMORY_ITEM Destination
283  )
284 {
285  if (Destination->RegionType == CustomRegion)
286  PhClearReference(&Destination->u.Custom.Text);
287  else if (Destination->RegionType == MappedFileRegion)
288  PhClearReference(&Destination->u.MappedFile.FileName);
289 
290  Destination->RegionType = Source->RegionType;
291  Destination->u = Source->u;
292 
293  if (Destination->RegionType == CustomRegion)
294  PhReferenceObject(Destination->u.Custom.Text);
295  else if (Destination->RegionType == MappedFileRegion)
296  PhReferenceObject(Destination->u.MappedFile.FileName);
297 }
298 
300  _Inout_ PPH_MEMORY_LIST_CONTEXT Context,
301  _In_opt_ PPH_MEMORY_ITEM_LIST List
302  )
303 {
304  PLIST_ENTRY listEntry;
305  PPH_MEMORY_NODE allocationBaseNode = NULL;
306 
307  PhpClearMemoryList(Context);
308 
309  if (!List)
310  {
311  TreeNew_NodesStructured(Context->TreeNewHandle);
312  return;
313  }
314 
315  for (listEntry = List->ListHead.Flink; listEntry != &List->ListHead; listEntry = listEntry->Flink)
316  {
317  PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry);
318  PPH_MEMORY_NODE memoryNode;
319 
320  if (memoryItem->AllocationBaseItem == memoryItem)
321  allocationBaseNode = PhpAddAllocationBaseNode(Context, memoryItem->AllocationBase);
322 
323  memoryNode = PhpAddRegionNode(Context, memoryItem);
324 
325  if (Context->HideFreeRegions && (memoryItem->State & MEM_FREE))
326  memoryNode->Node.Visible = FALSE;
327 
328  if (allocationBaseNode && memoryItem->AllocationBase == allocationBaseNode->MemoryItem->BaseAddress)
329  {
330  if (!(memoryItem->State & MEM_FREE))
331  {
332  memoryNode->Parent = allocationBaseNode;
333  PhAddItemList(allocationBaseNode->Children, memoryNode);
334  }
335 
336  // Aggregate various statistics.
337  allocationBaseNode->MemoryItem->RegionSize += memoryItem->RegionSize;
338  allocationBaseNode->MemoryItem->CommittedSize += memoryItem->CommittedSize;
339  allocationBaseNode->MemoryItem->PrivateSize += memoryItem->PrivateSize;
340  allocationBaseNode->MemoryItem->TotalWorkingSetPages += memoryItem->TotalWorkingSetPages;
341  allocationBaseNode->MemoryItem->PrivateWorkingSetPages += memoryItem->PrivateWorkingSetPages;
342  allocationBaseNode->MemoryItem->SharedWorkingSetPages += memoryItem->SharedWorkingSetPages;
343  allocationBaseNode->MemoryItem->ShareableWorkingSetPages += memoryItem->ShareableWorkingSetPages;
344  allocationBaseNode->MemoryItem->LockedWorkingSetPages += memoryItem->LockedWorkingSetPages;
345 
346  if (memoryItem->AllocationBaseItem == memoryItem)
347  {
348  if (memoryItem->State & MEM_FREE)
349  allocationBaseNode->MemoryItem->State = MEM_FREE;
350 
351  allocationBaseNode->MemoryItem->Protect = memoryItem->AllocationProtect;
352  PhGetMemoryProtectionString(allocationBaseNode->MemoryItem->Protect, allocationBaseNode->ProtectionText);
353  allocationBaseNode->MemoryItem->Type = memoryItem->Type;
354 
355  if (memoryItem->RegionType != CustomRegion || memoryItem->u.Custom.PropertyOfAllocationBase)
356  PhpCopyMemoryRegionTypeInfo(memoryItem, allocationBaseNode->MemoryItem);
357 
358  if (Context->HideFreeRegions && (allocationBaseNode->MemoryItem->State & MEM_FREE))
359  allocationBaseNode->Node.Visible = FALSE;
360  }
361  else
362  {
363  if (memoryItem->RegionType == UnknownRegion)
364  PhpCopyMemoryRegionTypeInfo(allocationBaseNode->MemoryItem, memoryItem);
365  }
366  }
367 
368  PhGetMemoryProtectionString(memoryItem->Protect, memoryNode->ProtectionText);
369  }
370 
371  TreeNew_NodesStructured(Context->TreeNewHandle);
372 }
373 
375  _In_ PPH_MEMORY_LIST_CONTEXT Context,
376  _In_ PPH_MEMORY_NODE MemoryNode
377  )
378 {
379  PhGetMemoryProtectionString(MemoryNode->MemoryItem->Protect, MemoryNode->ProtectionText);
380  memset(MemoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM);
381  TreeNew_InvalidateNode(Context->TreeNewHandle, &MemoryNode->Node);
382 }
383 
385  _In_ PPH_MEMORY_ITEM MemoryItem
386  )
387 {
388  PH_MEMORY_REGION_TYPE type = MemoryItem->RegionType;
389 
390  switch (type)
391  {
392  case UnknownRegion:
393  return PhReferenceEmptyString();
394  case CustomRegion:
395  PhReferenceObject(MemoryItem->u.Custom.Text);
396  return MemoryItem->u.Custom.Text;
397  case UnusableRegion:
398  return PhReferenceEmptyString();
399  case MappedFileRegion:
400  PhReferenceObject(MemoryItem->u.MappedFile.FileName);
401  return MemoryItem->u.MappedFile.FileName;
403  return PhCreateString(L"USER_SHARED_DATA");
404  case PebRegion:
405  case Peb32Region:
406  return PhFormatString(L"PEB%s", type == Peb32Region ? L" 32-bit" : L"");
407  case TebRegion:
408  case Teb32Region:
409  return PhFormatString(L"TEB%s (thread %u)",
410  type == Teb32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.Teb.ThreadId);
411  case StackRegion:
412  case Stack32Region:
413  return PhFormatString(L"Stack%s (thread %u)",
414  type == Stack32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.Stack.ThreadId);
415  case HeapRegion:
416  case Heap32Region:
417  return PhFormatString(L"Heap%s (ID %u)",
418  type == Heap32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.Heap.Index + 1);
419  case HeapSegmentRegion:
420  case HeapSegment32Region:
421  return PhFormatString(L"Heap Segment%s (ID %u)",
422  type == HeapSegment32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.HeapSegment.HeapItem->u.Heap.Index + 1);
423  default:
424  return PhReferenceEmptyString();
425  }
426 }
427 
429  _Inout_ PPH_MEMORY_NODE MemoryNode
430  )
431 {
432  if (!MemoryNode->UseText)
433  MemoryNode->UseText = PhpGetMemoryRegionUseText(MemoryNode->MemoryItem);
434 }
435 
437  _In_ ULONG64 Size
438  )
439 {
440  if (Size != 0)
441  return PhFormatSize(Size, 1);
442  else
443  return NULL;
444 }
445 
446 #define SORT_FUNCTION(Column) PhpMemoryTreeNewCompare##Column
447 
448 #define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpMemoryTreeNewCompare##Column( \
449  _In_ void *_context, \
450  _In_ const void *_elem1, \
451  _In_ const void *_elem2 \
452  ) \
453 { \
454  PPH_MEMORY_NODE node1 = *(PPH_MEMORY_NODE *)_elem1; \
455  PPH_MEMORY_NODE node2 = *(PPH_MEMORY_NODE *)_elem2; \
456  PPH_MEMORY_ITEM memoryItem1 = node1->MemoryItem; \
457  PPH_MEMORY_ITEM memoryItem2 = node2->MemoryItem; \
458  int sortResult = 0;
459 
460 #define END_SORT_FUNCTION \
461  if (sortResult == 0) \
462  sortResult = uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress); \
463  \
464  return PhModifySort(sortResult, ((PPH_MEMORY_LIST_CONTEXT)_context)->TreeNewSortOrder); \
465 }
466 
468  _In_ LONG Result,
469  _In_ PVOID Node1,
470  _In_ PVOID Node2,
471  _In_ PH_SORT_ORDER SortOrder
472  )
473 {
474  if (Result == 0)
475  Result = uintptrcmp((ULONG_PTR)((PPH_MEMORY_NODE)Node1)->MemoryItem->BaseAddress, (ULONG_PTR)((PPH_MEMORY_NODE)Node2)->MemoryItem->BaseAddress);
476 
477  return PhModifySort(Result, SortOrder);
478 }
479 
481 {
482  sortResult = uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress);
483 }
485 
487 {
488  sortResult = uintcmp(memoryItem1->Type | memoryItem1->State, memoryItem2->Type | memoryItem2->State);
489 
490  if (sortResult == 0)
491  sortResult = intcmp(memoryItem1->RegionType, memoryItem2->RegionType);
492 }
494 
496 {
497  sortResult = uintptrcmp(memoryItem1->RegionSize, memoryItem2->RegionSize);
498 }
500 
502 {
503  sortResult = PhCompareStringZ(node1->ProtectionText, node2->ProtectionText, FALSE);
504 }
506 
508 {
511  sortResult = PhCompareStringWithNull(node1->UseText, node2->UseText, TRUE);
512 }
514 
516 {
517  sortResult = uintptrcmp(memoryItem1->TotalWorkingSetPages, memoryItem2->TotalWorkingSetPages);
518 }
520 
522 {
523  sortResult = uintptrcmp(memoryItem1->PrivateWorkingSetPages, memoryItem2->PrivateWorkingSetPages);
524 }
526 
528 {
529  sortResult = uintptrcmp(memoryItem1->ShareableWorkingSetPages, memoryItem2->ShareableWorkingSetPages);
530 }
532 
534 {
535  sortResult = uintptrcmp(memoryItem1->SharedWorkingSetPages, memoryItem2->SharedWorkingSetPages);
536 }
538 
540 {
541  sortResult = uintptrcmp(memoryItem1->LockedWorkingSetPages, memoryItem2->LockedWorkingSetPages);
542 }
544 
546 {
547  sortResult = uintptrcmp(memoryItem1->CommittedSize, memoryItem2->CommittedSize);
548 }
550 
552 {
553  sortResult = uintptrcmp(memoryItem1->PrivateSize, memoryItem2->PrivateSize);
554 }
556 
558  _In_ HWND hwnd,
559  _In_ PH_TREENEW_MESSAGE Message,
560  _In_opt_ PVOID Parameter1,
561  _In_opt_ PVOID Parameter2,
562  _In_opt_ PVOID Context
563  )
564 {
565  PPH_MEMORY_LIST_CONTEXT context;
566  PPH_MEMORY_NODE node;
567 
568  context = Context;
569 
570  if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm))
571  return TRUE;
572 
573  switch (Message)
574  {
575  case TreeNewGetChildren:
576  {
577  PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;
578 
579  node = (PPH_MEMORY_NODE)getChildren->Node;
580 
581  if (context->TreeNewSortOrder == NoSortOrder)
582  {
583  if (!node)
584  {
585  getChildren->Children = (PPH_TREENEW_NODE *)context->AllocationBaseNodeList->Items;
586  getChildren->NumberOfChildren = context->AllocationBaseNodeList->Count;
587  }
588  else
589  {
590  getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;
591  getChildren->NumberOfChildren = node->Children->Count;
592  }
593  }
594  else
595  {
596  if (!node)
597  {
598  static PVOID sortFunctions[] =
599  {
600  SORT_FUNCTION(BaseAddress),
601  SORT_FUNCTION(Type),
603  SORT_FUNCTION(Protection),
604  SORT_FUNCTION(Use),
605  SORT_FUNCTION(TotalWs),
606  SORT_FUNCTION(PrivateWs),
607  SORT_FUNCTION(ShareableWs),
608  SORT_FUNCTION(SharedWs),
609  SORT_FUNCTION(LockedWs),
610  SORT_FUNCTION(Committed),
611  SORT_FUNCTION(Private)
612  };
613  int (__cdecl *sortFunction)(void *, const void *, const void *);
614 
615  if (!PhCmForwardSort(
617  context->RegionNodeList->Count,
618  context->TreeNewSortColumn,
619  context->TreeNewSortOrder,
620  &context->Cm
621  ))
622  {
623  if (context->TreeNewSortColumn < PHMMTLC_MAXIMUM)
624  sortFunction = sortFunctions[context->TreeNewSortColumn];
625  else
626  sortFunction = NULL;
627  }
628  else
629  {
630  sortFunction = NULL;
631  }
632 
633  if (sortFunction)
634  {
635  qsort_s(context->RegionNodeList->Items, context->RegionNodeList->Count, sizeof(PVOID), sortFunction, context);
636  }
637 
638  getChildren->Children = (PPH_TREENEW_NODE *)context->RegionNodeList->Items;
639  getChildren->NumberOfChildren = context->RegionNodeList->Count;
640  }
641  }
642  }
643  return TRUE;
644  case TreeNewIsLeaf:
645  {
646  PPH_TREENEW_IS_LEAF isLeaf = Parameter1;
647 
648  node = (PPH_MEMORY_NODE)isLeaf->Node;
649 
650  if (context->TreeNewSortOrder == NoSortOrder)
651  isLeaf->IsLeaf = !node->Children || node->Children->Count == 0;
652  else
653  isLeaf->IsLeaf = TRUE;
654  }
655  return TRUE;
656  case TreeNewGetCellText:
657  {
658  PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;
659  PPH_MEMORY_ITEM memoryItem;
660 
661  node = (PPH_MEMORY_NODE)getCellText->Node;
662  memoryItem = node->MemoryItem;
663 
664  switch (getCellText->Id)
665  {
666  case PHMMTLC_BASEADDRESS:
667  PhPrintPointer(node->BaseAddressText, memoryItem->BaseAddress);
668  PhInitializeStringRefLongHint(&getCellText->Text, node->BaseAddressText);
669  break;
670  case PHMMTLC_TYPE:
671  if (memoryItem->State & MEM_FREE)
672  {
673  if (memoryItem->RegionType == UnusableRegion)
674  PhInitializeStringRef(&getCellText->Text, L"Free (Unusable)");
675  else
676  PhInitializeStringRef(&getCellText->Text, L"Free");
677  }
678  else if (node->IsAllocationBase)
679  {
680  PhInitializeStringRefLongHint(&getCellText->Text, PhGetMemoryTypeString(memoryItem->Type));
681  }
682  else
683  {
684  PH_FORMAT format[3];
685  SIZE_T returnLength;
686 
687  PhInitFormatS(&format[0], PhGetMemoryTypeString(memoryItem->Type));
688  PhInitFormatS(&format[1], L": ");
689  PhInitFormatS(&format[2], PhGetMemoryStateString(memoryItem->State));
690 
691  if (PhFormatToBuffer(format, 3, node->TypeText, sizeof(node->TypeText), &returnLength))
692  {
693  getCellText->Text.Buffer = node->TypeText;
694  getCellText->Text.Length = returnLength - sizeof(WCHAR);
695  }
696  }
697  break;
698  case PHMMTLC_SIZE:
699  PhMoveReference(&node->SizeText, PhFormatSize(memoryItem->RegionSize, 1));
700  getCellText->Text = PhGetStringRef(node->SizeText);
701  break;
702  case PHMMTLC_PROTECTION:
703  PhInitializeStringRefLongHint(&getCellText->Text, node->ProtectionText);
704  break;
705  case PHMMTLC_USE:
707  getCellText->Text = PhGetStringRef(node->UseText);
708  break;
709  case PHMMTLC_TOTALWS:
711  getCellText->Text = PhGetStringRef(node->TotalWsText);
712  break;
713  case PHMMTLC_PRIVATEWS:
714  PhMoveReference(&node->PrivateWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->PrivateWorkingSetPages * PAGE_SIZE));
715  getCellText->Text = PhGetStringRef(node->PrivateWsText);
716  break;
717  case PHMMTLC_SHAREABLEWS:
718  PhMoveReference(&node->ShareableWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->ShareableWorkingSetPages * PAGE_SIZE));
719  getCellText->Text = PhGetStringRef(node->ShareableWsText);
720  break;
721  case PHMMTLC_SHAREDWS:
722  PhMoveReference(&node->SharedWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->SharedWorkingSetPages * PAGE_SIZE));
723  getCellText->Text = PhGetStringRef(node->SharedWsText);
724  break;
725  case PHMMTLC_LOCKEDWS:
726  PhMoveReference(&node->LockedWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->LockedWorkingSetPages * PAGE_SIZE));
727  getCellText->Text = PhGetStringRef(node->LockedWsText);
728  break;
729  case PHMMTLC_COMMITTED:
731  getCellText->Text = PhGetStringRef(node->CommittedText);
732  break;
733  case PHMMTLC_PRIVATE:
735  getCellText->Text = PhGetStringRef(node->PrivateText);
736  break;
737  default:
738  return FALSE;
739  }
740 
741  getCellText->Flags = TN_CACHE;
742  }
743  return TRUE;
744  case TreeNewGetNodeColor:
745  {
746  /*PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1;
747  PPH_MEMORY_ITEM memoryItem;
748 
749  node = (PPH_MEMORY_NODE)getNodeColor->Node;
750  memoryItem = node->MemoryItem;*/
751 
752  // TODO
753 
754  //getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR;
755  }
756  return TRUE;
757  case TreeNewSortChanged:
758  {
759  TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder);
760  // Force a rebuild to sort the items.
762  }
763  return TRUE;
764  case TreeNewKeyDown:
765  {
766  PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;
767 
768  switch (keyEvent->VirtualKey)
769  {
770  case 'C':
771  if (GetKeyState(VK_CONTROL) < 0)
772  SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_COPY, 0);
773  break;
774  case 'A':
775  if (GetKeyState(VK_CONTROL) < 0)
776  TreeNew_SelectRange(context->TreeNewHandle, 0, -1);
777  break;
778  case VK_RETURN:
779  SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_READWRITEMEMORY, 0);
780  break;
781  case VK_F5:
782  SendMessage(context->ParentWindowHandle, WM_COMMAND, IDC_REFRESH, 0);
783  break;
784  }
785  }
786  return TRUE;
788  {
790 
791  data.TreeNewHandle = hwnd;
792  data.MouseEvent = Parameter1;
793  data.DefaultSortColumn = 0;
796 
801  }
802  return TRUE;
804  {
805  PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1;
806 
807  node = (PPH_MEMORY_NODE)mouseEvent->Node;
808 
809  if (node && node->IsAllocationBase)
810  TreeNew_SetNodeExpanded(hwnd, node, !node->Node.Expanded);
811  else
812  SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_READWRITEMEMORY, 0);
813  }
814  return TRUE;
815  case TreeNewContextMenu:
816  {
817  PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;
818 
819  SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu);
820  }
821  return TRUE;
823  {
824  PULONG code = Parameter2;
825 
826  if (PtrToUlong(Parameter1) == VK_RETURN)
827  {
828  *code = DLGC_WANTMESSAGE;
829  return TRUE;
830  }
831  }
832  return FALSE;
833  }
834 
835  return FALSE;
836 }
837 
839  _In_ PPH_MEMORY_LIST_CONTEXT Context
840  )
841 {
842  ULONG i;
843 
844  if (Context->TreeNewSortOrder == NoSortOrder)
845  {
846  for (i = 0; i < Context->AllocationBaseNodeList->Count; i++)
847  {
848  PPH_MEMORY_NODE node = Context->AllocationBaseNodeList->Items[i];
849 
850  if (node->Node.Selected)
851  return node;
852  }
853  }
854 
855  for (i = 0; i < Context->RegionNodeList->Count; i++)
856  {
857  PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i];
858 
859  if (node->Node.Selected)
860  return node;
861  }
862 
863  return NULL;
864 }
865 
867  _In_ PPH_MEMORY_LIST_CONTEXT Context,
868  _Out_ PPH_MEMORY_NODE **MemoryNodes,
869  _Out_ PULONG NumberOfMemoryNodes
870  )
871 {
872  PPH_LIST list;
873  ULONG i;
874 
875  list = PhCreateList(2);
876 
877  if (Context->TreeNewSortOrder == NoSortOrder)
878  {
879  for (i = 0; i < Context->AllocationBaseNodeList->Count; i++)
880  {
881  PPH_MEMORY_NODE node = Context->AllocationBaseNodeList->Items[i];
882 
883  if (node->Node.Selected)
884  PhAddItemList(list, node);
885  }
886  }
887 
888  for (i = 0; i < Context->RegionNodeList->Count; i++)
889  {
890  PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i];
891 
892  if (node->Node.Selected)
893  PhAddItemList(list, node);
894  }
895 
896  *MemoryNodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);
897  *NumberOfMemoryNodes = list->Count;
898 
899  PhDereferenceObject(list);
900 }
901 
903  _In_ PPH_MEMORY_LIST_CONTEXT Context
904  )
905 {
906  TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1);
907 }