Process Hacker
netlist.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * network list
4  *
5  * Copyright (C) 2011-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 <cpysave.h>
28 #include <emenu.h>
29 
31  _In_ PVOID Entry1,
32  _In_ PVOID Entry2
33  );
34 
36  _In_ PVOID Entry
37  );
38 
40  _In_ PPH_NETWORK_NODE NetworkNode
41  );
42 
44  _In_ LONG Result,
45  _In_ PVOID Node1,
46  _In_ PVOID Node2,
47  _In_ PH_SORT_ORDER SortOrder
48  );
49 
50 BOOLEAN NTAPI PhpNetworkTreeNewCallback(
51  _In_ HWND hwnd,
52  _In_ PH_TREENEW_MESSAGE Message,
53  _In_opt_ PVOID Parameter1,
54  _In_opt_ PVOID Parameter2,
55  _In_opt_ PVOID Context
56  );
57 
59  _In_ PPH_NETWORK_ITEM NetworkItem
60  );
61 
63  _In_ PPH_NETWORK_NODE NetworkNode
64  );
65 
66 static HWND NetworkTreeListHandle;
67 static ULONG NetworkTreeListSortColumn;
68 static PH_SORT_ORDER NetworkTreeListSortOrder;
69 static PH_CM_MANAGER NetworkTreeListCm;
70 
71 static PPH_HASHTABLE NetworkNodeHashtable; // hashtable of all nodes
72 static PPH_LIST NetworkNodeList; // list of all nodes
73 static LONG NextUniqueId = 1;
74 
76 static PPH_POINTER_LIST NetworkNodeStateList = NULL; // list of nodes which need to be processed
77 
78 static PH_TN_FILTER_SUPPORT FilterSupport;
79 
81  VOID
82  )
83 {
84  NetworkNodeHashtable = PhCreateHashtable(
85  sizeof(PPH_NETWORK_NODE),
88  100
89  );
90  NetworkNodeList = PhCreateList(100);
91 }
92 
94  _In_ PVOID Entry1,
95  _In_ PVOID Entry2
96  )
97 {
98  PPH_NETWORK_NODE networkNode1 = *(PPH_NETWORK_NODE *)Entry1;
99  PPH_NETWORK_NODE networkNode2 = *(PPH_NETWORK_NODE *)Entry2;
100 
101  return networkNode1->NetworkItem == networkNode2->NetworkItem;
102 }
103 
105  _In_ PVOID Entry
106  )
107 {
108  return PhHashIntPtr((ULONG_PTR)(*(PPH_NETWORK_NODE *)Entry)->NetworkItem);
109 }
110 
112  _In_ HWND hwnd
113  )
114 {
115  NetworkTreeListHandle = hwnd;
116  PhSetControlTheme(NetworkTreeListHandle, L"explorer");
117  SendMessage(TreeNew_GetTooltips(NetworkTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT);
118 
120 
121  TreeNew_SetRedraw(hwnd, FALSE);
122 
123  // Default columns
124  PhAddTreeNewColumn(hwnd, PHNETLC_PROCESS, TRUE, L"Name", 100, PH_ALIGN_LEFT, 0, 0);
125  PhAddTreeNewColumn(hwnd, PHNETLC_LOCALADDRESS, TRUE, L"Local Address", 120, PH_ALIGN_LEFT, 1, 0);
126  PhAddTreeNewColumn(hwnd, PHNETLC_LOCALPORT, TRUE, L"Local Port", 50, PH_ALIGN_RIGHT, 2, DT_RIGHT);
127  PhAddTreeNewColumn(hwnd, PHNETLC_REMOTEADDRESS, TRUE, L"Remote Address", 120, PH_ALIGN_LEFT, 3, 0);
128  PhAddTreeNewColumn(hwnd, PHNETLC_REMOTEPORT, TRUE, L"Remote Port", 50, PH_ALIGN_RIGHT, 4, DT_RIGHT);
129  PhAddTreeNewColumn(hwnd, PHNETLC_PROTOCOL, TRUE, L"Protocol", 45, PH_ALIGN_LEFT, 5, 0);
130  PhAddTreeNewColumn(hwnd, PHNETLC_STATE, TRUE, L"State", 70, PH_ALIGN_LEFT, 6, 0);
132  PhAddTreeNewColumnEx(hwnd, PHNETLC_TIMESTAMP, FALSE, L"Time Stamp", 100, PH_ALIGN_LEFT, -1, 0, TRUE);
133 
134  TreeNew_SetRedraw(hwnd, TRUE);
135 
137 
139 
140  if (PhPluginsEnabled)
141  {
142  PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
143 
144  treeNewInfo.TreeNewHandle = hwnd;
145  treeNewInfo.CmData = &NetworkTreeListCm;
147  }
148 
149  PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, NetworkNodeList);
150 }
151 
153  VOID
154  )
155 {
156  PPH_STRING settings;
157  PPH_STRING sortSettings;
158 
159  settings = PhGetStringSetting(L"NetworkTreeListColumns");
160  sortSettings = PhGetStringSetting(L"NetworkTreeListSort");
161  PhCmLoadSettingsEx(NetworkTreeListHandle, &NetworkTreeListCm, 0, &settings->sr, &sortSettings->sr);
162  PhDereferenceObject(settings);
163  PhDereferenceObject(sortSettings);
164 }
165 
167  VOID
168  )
169 {
170  PPH_STRING settings;
171  PPH_STRING sortSettings;
172 
173  settings = PhCmSaveSettingsEx(NetworkTreeListHandle, &NetworkTreeListCm, 0, &sortSettings);
174  PhSetStringSetting2(L"NetworkTreeListColumns", &settings->sr);
175  PhSetStringSetting2(L"NetworkTreeListSort", &sortSettings->sr);
176  PhDereferenceObject(settings);
177  PhDereferenceObject(sortSettings);
178 }
179 
181  VOID
182  )
183 {
184  return &FilterSupport;
185 }
186 
188  _In_ PPH_NETWORK_ITEM NetworkItem,
189  _In_ ULONG RunId
190  )
191 {
192  PPH_NETWORK_NODE networkNode;
193 
194  networkNode = PhAllocate(PhEmGetObjectSize(EmNetworkNodeType, sizeof(PH_NETWORK_NODE)));
195  memset(networkNode, 0, sizeof(PH_NETWORK_NODE));
196  PhInitializeTreeNewNode(&networkNode->Node);
197 
198  if (PhNetworkTreeListStateHighlighting && RunId != 1)
199  {
201  &networkNode->Node,
202  &networkNode->ShState,
203  &NetworkNodeStateList,
204  NewItemState,
205  PhCsColorNew,
206  NULL
207  );
208  }
209 
210  networkNode->NetworkItem = NetworkItem;
211  PhReferenceObject(NetworkItem);
212  networkNode->UniqueId = NextUniqueId++; // used to stabilize sorting
213 
214  memset(networkNode->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM);
215  networkNode->Node.TextCache = networkNode->TextCache;
216  networkNode->Node.TextCacheSize = PHNETLC_MAXIMUM;
217 
218  networkNode->ProcessNameText = PhpGetNetworkItemProcessName(NetworkItem);
220 
221  PhAddEntryHashtable(NetworkNodeHashtable, &networkNode);
222  PhAddItemList(NetworkNodeList, networkNode);
223 
224  if (FilterSupport.NodeList)
225  networkNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &networkNode->Node);
226 
228 
229  TreeNew_NodesStructured(NetworkTreeListHandle);
230 
231  return networkNode;
232 }
233 
235  _In_ PPH_NETWORK_ITEM NetworkItem
236  )
237 {
238  PH_NETWORK_NODE lookupNetworkNode;
239  PPH_NETWORK_NODE lookupNetworkNodePtr = &lookupNetworkNode;
240  PPH_NETWORK_NODE *networkNode;
241 
242  lookupNetworkNode.NetworkItem = NetworkItem;
243 
244  networkNode = (PPH_NETWORK_NODE *)PhFindEntryHashtable(
245  NetworkNodeHashtable,
246  &lookupNetworkNodePtr
247  );
248 
249  if (networkNode)
250  return *networkNode;
251  else
252  return NULL;
253 }
254 
256  _In_ PPH_NETWORK_NODE NetworkNode
257  )
258 {
259  // Remove from the hashtable here to avoid problems in case the key is re-used.
260  PhRemoveEntryHashtable(NetworkNodeHashtable, &NetworkNode);
261 
263  {
265  &NetworkNode->Node,
266  &NetworkNode->ShState,
267  &NetworkNodeStateList,
270  NetworkTreeListHandle
271  );
272  }
273  else
274  {
275  PhpRemoveNetworkNode(NetworkNode);
276  }
277 }
278 
280  _In_ PPH_NETWORK_NODE NetworkNode
281  )
282 {
283  ULONG index;
284 
286 
287  // Remove from list and cleanup.
288 
289  if ((index = PhFindItemList(NetworkNodeList, NetworkNode)) != -1)
290  PhRemoveItemList(NetworkNodeList, index);
291 
292  if (NetworkNode->ProcessNameText) PhDereferenceObject(NetworkNode->ProcessNameText);
293  if (NetworkNode->TimeStampText) PhDereferenceObject(NetworkNode->TimeStampText);
294  if (NetworkNode->TooltipText) PhDereferenceObject(NetworkNode->TooltipText);
295 
296  PhDereferenceObject(NetworkNode->NetworkItem);
297 
298  PhFree(NetworkNode);
299 
300  TreeNew_NodesStructured(NetworkTreeListHandle);
301 }
302 
304  _In_ PPH_NETWORK_NODE NetworkNode
305  )
306 {
307  memset(NetworkNode->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM);
309  PhClearReference(&NetworkNode->TooltipText);
310 
311  PhInvalidateTreeNewNode(&NetworkNode->Node, TN_CACHE_ICON);
312  TreeNew_NodesStructured(NetworkTreeListHandle);
313 }
314 
316  VOID
317  )
318 {
319  if (NetworkTreeListSortOrder != NoSortOrder && NetworkTreeListSortColumn >= PHNETLC_MAXIMUM)
320  {
321  // Sorting is on, but it's not one of our columns. Force a rebuild. (If it was one of our
322  // columns, the restructure would have been handled in PhUpdateNetworkNode.)
323  TreeNew_NodesStructured(NetworkTreeListHandle);
324  }
325 
326  PH_TICK_SH_STATE_TN(PH_NETWORK_NODE, ShState, NetworkNodeStateList, PhpRemoveNetworkNode, PhCsHighlightingDuration, NetworkTreeListHandle, TRUE, NULL);
327 }
328 
329 #define SORT_FUNCTION(Column) PhpNetworkTreeNewCompare##Column
330 
331 #define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpNetworkTreeNewCompare##Column( \
332  _In_ const void *_elem1, \
333  _In_ const void *_elem2 \
334  ) \
335 { \
336  PPH_NETWORK_NODE node1 = *(PPH_NETWORK_NODE *)_elem1; \
337  PPH_NETWORK_NODE node2 = *(PPH_NETWORK_NODE *)_elem2; \
338  PPH_NETWORK_ITEM networkItem1 = node1->NetworkItem; \
339  PPH_NETWORK_ITEM networkItem2 = node2->NetworkItem; \
340  int sortResult = 0;
341 
342 #define END_SORT_FUNCTION \
343  if (sortResult == 0) \
344  sortResult = intcmp(node1->UniqueId, node2->UniqueId); \
345  \
346  return PhModifySort(sortResult, NetworkTreeListSortOrder); \
347 }
348 
350  _In_ LONG Result,
351  _In_ PVOID Node1,
352  _In_ PVOID Node2,
353  _In_ PH_SORT_ORDER SortOrder
354  )
355 {
356  if (Result == 0)
357  Result = intcmp(((PPH_NETWORK_NODE)Node1)->UniqueId, ((PPH_NETWORK_NODE)Node2)->UniqueId);
358 
359  return PhModifySort(Result, SortOrder);
360 }
361 
363 {
364  sortResult = PhCompareString(node1->ProcessNameText, node2->ProcessNameText, TRUE);
365 }
367 
368 BEGIN_SORT_FUNCTION(LocalAddress)
369 {
370  sortResult = PhCompareStringRef(&node1->LocalAddressText, &node2->LocalAddressText, TRUE);
371 }
373 
375 {
376  sortResult = uintcmp(networkItem1->LocalEndpoint.Port, networkItem2->LocalEndpoint.Port);
377 }
379 
380 BEGIN_SORT_FUNCTION(RemoteAddress)
381 {
382  sortResult = PhCompareStringRef(&node1->RemoteAddressText, &node2->RemoteAddressText, TRUE);
383 }
385 
387 {
388  sortResult = uintcmp(networkItem1->RemoteEndpoint.Port, networkItem2->RemoteEndpoint.Port);
389 }
391 
393 {
394  sortResult = uintcmp(networkItem1->ProtocolType, networkItem2->ProtocolType);
395 }
397 
399 {
400  sortResult = uintcmp(networkItem1->State, networkItem2->State);
401 }
403 
405 {
406  sortResult = PhCompareStringWithNull(networkItem1->OwnerName, networkItem2->OwnerName, TRUE);
407 }
409 
411 {
412  sortResult = uint64cmp(networkItem1->CreateTime.QuadPart, networkItem2->CreateTime.QuadPart);
413 }
415 
417  _In_ HWND hwnd,
418  _In_ PH_TREENEW_MESSAGE Message,
419  _In_opt_ PVOID Parameter1,
420  _In_opt_ PVOID Parameter2,
421  _In_opt_ PVOID Context
422  )
423 {
424  PPH_NETWORK_NODE node;
425 
426  if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &NetworkTreeListCm))
427  return TRUE;
428 
429  switch (Message)
430  {
431  case TreeNewGetChildren:
432  {
433  PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;
434 
435  if (!getChildren->Node)
436  {
437  static PVOID sortFunctions[] =
438  {
439  SORT_FUNCTION(Process),
440  SORT_FUNCTION(LocalAddress),
441  SORT_FUNCTION(LocalPort),
442  SORT_FUNCTION(RemoteAddress),
443  SORT_FUNCTION(RemotePort),
444  SORT_FUNCTION(Protocol),
445  SORT_FUNCTION(State),
446  SORT_FUNCTION(Owner),
447  SORT_FUNCTION(TimeStamp)
448  };
449  int (__cdecl *sortFunction)(const void *, const void *);
450 
451  if (!PhCmForwardSort(
452  (PPH_TREENEW_NODE *)NetworkNodeList->Items,
453  NetworkNodeList->Count,
454  NetworkTreeListSortColumn,
455  NetworkTreeListSortOrder,
456  &NetworkTreeListCm
457  ))
458  {
459  if (NetworkTreeListSortColumn < PHNETLC_MAXIMUM)
460  sortFunction = sortFunctions[NetworkTreeListSortColumn];
461  else
462  sortFunction = NULL;
463 
464  if (sortFunction)
465  {
466  qsort(NetworkNodeList->Items, NetworkNodeList->Count, sizeof(PVOID), sortFunction);
467  }
468  }
469 
470  getChildren->Children = (PPH_TREENEW_NODE *)NetworkNodeList->Items;
471  getChildren->NumberOfChildren = NetworkNodeList->Count;
472  }
473  }
474  return TRUE;
475  case TreeNewIsLeaf:
476  {
477  PPH_TREENEW_IS_LEAF isLeaf = Parameter1;
478 
479  isLeaf->IsLeaf = TRUE;
480  }
481  return TRUE;
482  case TreeNewGetCellText:
483  {
484  PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;
485  PPH_NETWORK_ITEM networkItem;
486 
487  node = (PPH_NETWORK_NODE)getCellText->Node;
488  networkItem = node->NetworkItem;
489 
490  switch (getCellText->Id)
491  {
492  case PHNETLC_PROCESS:
493  getCellText->Text = node->ProcessNameText->sr;
494  break;
496  getCellText->Text = node->LocalAddressText;
497  break;
498  case PHNETLC_LOCALPORT:
499  PhInitializeStringRefLongHint(&getCellText->Text, networkItem->LocalPortString);
500  break;
502  getCellText->Text = node->RemoteAddressText;
503  break;
504  case PHNETLC_REMOTEPORT:
505  PhInitializeStringRefLongHint(&getCellText->Text, networkItem->RemotePortString);
506  break;
507  case PHNETLC_PROTOCOL:
509  break;
510  case PHNETLC_STATE:
511  if (networkItem->ProtocolType & PH_TCP_PROTOCOL_TYPE)
512  PhInitializeStringRefLongHint(&getCellText->Text, PhGetTcpStateName(networkItem->State));
513  else
514  PhInitializeEmptyStringRef(&getCellText->Text);
515  break;
516  case PHNETLC_OWNER:
518  getCellText->Text = PhGetStringRef(networkItem->OwnerName);
519  else
520  PhInitializeStringRef(&getCellText->Text, L"N/A"); // make sure the user knows this column doesn't work on XP
521  break;
522  case PHNETLC_TIMESTAMP:
523  {
524  SYSTEMTIME systemTime;
525 
526  if (networkItem->CreateTime.QuadPart != 0)
527  {
528  PhLargeIntegerToLocalSystemTime(&systemTime, &networkItem->CreateTime);
529  PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime));
530  getCellText->Text = node->TimeStampText->sr;
531  }
532  else
533  {
534  PhInitializeEmptyStringRef(&getCellText->Text);
535  }
536  }
537  break;
538  default:
539  return FALSE;
540  }
541 
542  getCellText->Flags = TN_CACHE;
543  }
544  return TRUE;
545  case TreeNewGetNodeIcon:
546  {
547  PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1;
548 
549  node = (PPH_NETWORK_NODE)getNodeIcon->Node;
550 
551  if (node->NetworkItem->ProcessIconValid)
552  {
553  // TODO: Check if the icon handle is actually valid, since the process item
554  // might get destroyed while the network node is still valid.
555  getNodeIcon->Icon = node->NetworkItem->ProcessIcon;
556  }
557  else
558  {
559  PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL);
560  }
561 
562  getNodeIcon->Flags = TN_CACHE;
563  }
564  return TRUE;
566  {
567  PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1;
568  PPH_PROCESS_ITEM processItem;
569 
570  node = (PPH_NETWORK_NODE)getCellTooltip->Node;
571 
572  if (getCellTooltip->Column->Id != 0)
573  return FALSE;
574 
575  if (!node->TooltipText)
576  {
577  if (processItem = PhReferenceProcessItem(node->NetworkItem->ProcessId))
578  {
579  node->TooltipText = PhGetProcessTooltipText(processItem, NULL);
580  PhDereferenceObject(processItem);
581  }
582  }
583 
585  {
586  getCellTooltip->Text = node->TooltipText->sr;
587  getCellTooltip->Unfolding = FALSE;
588  getCellTooltip->MaximumWidth = -1;
589  }
590  else
591  {
592  return FALSE;
593  }
594  }
595  return TRUE;
596  case TreeNewSortChanged:
597  {
598  TreeNew_GetSort(hwnd, &NetworkTreeListSortColumn, &NetworkTreeListSortOrder);
599  // Force a rebuild to sort the items.
601  }
602  return TRUE;
603  case TreeNewKeyDown:
604  {
605  PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;
606 
607  switch (keyEvent->VirtualKey)
608  {
609  case 'C':
610  if (GetKeyState(VK_CONTROL) < 0)
611  SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_COPY, 0);
612  break;
613  case 'A':
614  if (GetKeyState(VK_CONTROL) < 0)
615  TreeNew_SelectRange(NetworkTreeListHandle, 0, -1);
616  break;
617  case VK_RETURN:
618  SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_GOTOPROCESS, 0);
619  break;
620  }
621  }
622  return TRUE;
624  {
626 
627  data.TreeNewHandle = hwnd;
628  data.MouseEvent = Parameter1;
629  data.DefaultSortColumn = 0;
632 
637  }
638  return TRUE;
640  {
641  SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_GOTOPROCESS, 0);
642  }
643  return TRUE;
644  case TreeNewContextMenu:
645  {
646  PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1;
647 
648  PhShowNetworkContextMenu(contextMenu);
649  }
650  return TRUE;
651  }
652 
653  return FALSE;
654 }
655 
657  _In_ PPH_NETWORK_ITEM NetworkItem
658  )
659 {
660  PH_FORMAT format[4];
661 
662  if (!NetworkItem->ProcessId)
663  return PhCreateString(L"Waiting Connections");
664 
665  PhInitFormatS(&format[1], L" (");
666  PhInitFormatU(&format[2], (ULONG)NetworkItem->ProcessId);
667  PhInitFormatC(&format[3], ')');
668 
669  if (NetworkItem->ProcessName)
670  PhInitFormatSR(&format[0], NetworkItem->ProcessName->sr);
671  else
672  PhInitFormatS(&format[0], L"Unknown Process");
673 
674  return PhFormat(format, 4, 96);
675 }
676 
678  _In_ PPH_NETWORK_NODE NetworkNode
679  )
680 {
681  if (NetworkNode->NetworkItem->LocalHostString)
682  NetworkNode->LocalAddressText = NetworkNode->NetworkItem->LocalHostString->sr;
683  else
684  PhInitializeStringRefLongHint(&NetworkNode->LocalAddressText, NetworkNode->NetworkItem->LocalAddressString);
685 
686  if (NetworkNode->NetworkItem->RemoteHostString)
687  NetworkNode->RemoteAddressText = NetworkNode->NetworkItem->RemoteHostString->sr;
688  else
689  PhInitializeStringRefLongHint(&NetworkNode->RemoteAddressText, NetworkNode->NetworkItem->RemoteAddressString);
690 }
691 
693  VOID
694  )
695 {
696  PPH_NETWORK_ITEM networkItem = NULL;
697  ULONG i;
698 
699  for (i = 0; i < NetworkNodeList->Count; i++)
700  {
701  PPH_NETWORK_NODE node = NetworkNodeList->Items[i];
702 
703  if (node->Node.Selected)
704  {
705  networkItem = node->NetworkItem;
706  break;
707  }
708  }
709 
710  return networkItem;
711 }
712 
714  _Out_ PPH_NETWORK_ITEM **NetworkItems,
715  _Out_ PULONG NumberOfNetworkItems
716  )
717 {
718  PPH_LIST list;
719  ULONG i;
720 
721  list = PhCreateList(2);
722 
723  for (i = 0; i < NetworkNodeList->Count; i++)
724  {
725  PPH_NETWORK_NODE node = NetworkNodeList->Items[i];
726 
727  if (node->Node.Selected)
728  {
729  PhAddItemList(list, node->NetworkItem);
730  }
731  }
732 
733  *NetworkItems = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);
734  *NumberOfNetworkItems = list->Count;
735 
736  PhDereferenceObject(list);
737 }
738 
740  VOID
741  )
742 {
743  TreeNew_DeselectRange(NetworkTreeListHandle, 0, -1);
744 }
745 
747  _In_ PPH_NETWORK_NODE NetworkNode
748  )
749 {
751 
752  if (!NetworkNode->Node.Visible)
753  return;
754 
755  TreeNew_SetFocusNode(NetworkTreeListHandle, &NetworkNode->Node);
756  TreeNew_SetMarkNode(NetworkTreeListHandle, &NetworkNode->Node);
757  TreeNew_SelectRange(NetworkTreeListHandle, NetworkNode->Node.Index, NetworkNode->Node.Index);
758  TreeNew_EnsureVisible(NetworkTreeListHandle, &NetworkNode->Node);
759 }
760 
762  VOID
763  )
764 {
765  PPH_STRING text;
766 
767  text = PhGetTreeNewText(NetworkTreeListHandle, 0);
768  PhSetClipboardString(NetworkTreeListHandle, &text->sr);
769  PhDereferenceObject(text);
770 }
771 
773  _Inout_ PPH_FILE_STREAM FileStream,
774  _In_ ULONG Mode
775  )
776 {
777  PPH_LIST lines;
778  ULONG i;
779 
780  lines = PhGetGenericTreeNewLines(NetworkTreeListHandle, Mode);
781 
782  for (i = 0; i < lines->Count; i++)
783  {
784  PPH_STRING line;
785 
786  line = lines->Items[i];
787  PhWriteStringAsUtf8FileStream(FileStream, &line->sr);
788  PhDereferenceObject(line);
789  PhWriteStringAsUtf8FileStream2(FileStream, L"\r\n");
790  }
791 
792  PhDereferenceObject(lines);
793 }