Process Hacker
plugin.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * plugin support
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 #include <phapp.h>
24 #include <settings.h>
25 #include <emenu.h>
26 #include <phplug.h>
27 #include <extmgri.h>
28 #include <notifico.h>
29 #include <phsvccl.h>
30 
31 typedef struct _PHP_PLUGIN_LOAD_ERROR
32 {
33  PPH_STRING FileName;
34  PPH_STRING ErrorMessage;
36 
37 typedef struct _PHP_PLUGIN_MENU_HOOK
38 {
39  PPH_PLUGIN Plugin;
40  PVOID Context;
42 
44  _In_ PPH_AVL_LINKS Links1,
46  );
47 
48 BOOLEAN PhLoadPlugin(
49  _In_ PPH_STRING FileName
50  );
51 
53  _In_ PH_PLUGIN_CALLBACK Callback,
54  _In_ BOOLEAN StartupParameters
55  );
56 
58 
59 static PH_CALLBACK GeneralCallbacks[GeneralCallbackMaximum];
60 static PPH_STRING PluginsDirectory;
61 static PPH_LIST LoadErrors;
62 static ULONG NextPluginId = IDPLUGINS + 1;
63 
65  VOID
66  )
67 {
68  ULONG i;
69 
70  for (i = 0; i < GeneralCallbackMaximum; i++)
71  PhInitializeCallback(&GeneralCallbacks[i]);
72 
74  {
75  PH_STRINGREF extendedTools = PH_STRINGREF_INIT(L"ExtendedTools.dll");
76 
77  // HACK and violation of abstraction.
78  // Always disable ExtendedTools on XP to avoid the annoying error message.
79  PhSetPluginDisabled(&extendedTools, TRUE);
80  }
81 }
82 
84  _In_ PPH_AVL_LINKS Links1,
86  )
87 {
88  PPH_PLUGIN plugin1 = CONTAINING_RECORD(Links1, PH_PLUGIN, Links);
89  PPH_PLUGIN plugin2 = CONTAINING_RECORD(Links2, PH_PLUGIN, Links);
90 
91  return PhCompareStringRef(&plugin1->Name, &plugin2->Name, FALSE);
92 }
93 
95  _In_ PPH_STRING List,
96  _In_ PPH_STRINGREF BaseName,
97  _Out_opt_ PULONG FoundIndex
98  )
99 {
100  PH_STRINGREF namePart;
101  PH_STRINGREF remainingPart;
102 
103  remainingPart = List->sr;
104 
105  while (remainingPart.Length != 0)
106  {
107  PhSplitStringRefAtChar(&remainingPart, '|', &namePart, &remainingPart);
108 
109  if (PhEqualStringRef(&namePart, BaseName, TRUE))
110  {
111  if (FoundIndex)
112  *FoundIndex = (ULONG)(namePart.Buffer - List->Buffer);
113 
114  return TRUE;
115  }
116  }
117 
118  return FALSE;
119 }
120 
122  _In_ PPH_STRINGREF BaseName
123  )
124 {
125  BOOLEAN found;
126  PPH_STRING disabled;
127 
128  disabled = PhGetStringSetting(L"DisabledPlugins");
129  found = PhpLocateDisabledPlugin(disabled, BaseName, NULL);
130  PhDereferenceObject(disabled);
131 
132  return found;
133 }
134 
136  _In_ PPH_STRINGREF BaseName,
137  _In_ BOOLEAN Disable
138  )
139 {
140  BOOLEAN found;
141  PPH_STRING disabled;
142  ULONG foundIndex;
143  PPH_STRING newDisabled;
144 
145  disabled = PhGetStringSetting(L"DisabledPlugins");
146 
147  found = PhpLocateDisabledPlugin(disabled, BaseName, &foundIndex);
148 
149  if (Disable && !found)
150  {
151  // We need to add the plugin to the disabled list.
152 
153  if (disabled->Length != 0)
154  {
155  // We have other disabled plugins. Append a pipe character followed by the plugin name.
156  newDisabled = PhCreateStringEx(NULL, disabled->Length + sizeof(WCHAR) + BaseName->Length);
157  memcpy(newDisabled->Buffer, disabled->Buffer, disabled->Length);
158  newDisabled->Buffer[disabled->Length / 2] = '|';
159  memcpy(&newDisabled->Buffer[disabled->Length / 2 + 1], BaseName->Buffer, BaseName->Length);
160  PhSetStringSetting2(L"DisabledPlugins", &newDisabled->sr);
161  PhDereferenceObject(newDisabled);
162  }
163  else
164  {
165  // This is the first disabled plugin.
166  PhSetStringSetting2(L"DisabledPlugins", BaseName);
167  }
168  }
169  else if (!Disable && found)
170  {
171  ULONG removeCount;
172 
173  // We need to remove the plugin from the disabled list.
174 
175  removeCount = (ULONG)BaseName->Length / 2;
176 
177  if (foundIndex + (ULONG)BaseName->Length / 2 < (ULONG)disabled->Length / 2)
178  {
179  // Remove the following pipe character as well.
180  removeCount++;
181  }
182  else if (foundIndex != 0)
183  {
184  // Remove the preceding pipe character as well.
185  foundIndex--;
186  removeCount++;
187  }
188 
189  newDisabled = PhCreateStringEx(NULL, disabled->Length - removeCount * sizeof(WCHAR));
190  memcpy(newDisabled->Buffer, disabled->Buffer, foundIndex * sizeof(WCHAR));
191  memcpy(&newDisabled->Buffer[foundIndex], &disabled->Buffer[foundIndex + removeCount],
192  disabled->Length - removeCount * sizeof(WCHAR) - foundIndex * sizeof(WCHAR));
193  PhSetStringSetting2(L"DisabledPlugins", &newDisabled->sr);
194  PhDereferenceObject(newDisabled);
195  }
196 
197  PhDereferenceObject(disabled);
198 }
199 
200 static BOOLEAN EnumPluginsDirectoryCallback(
201  _In_ PFILE_DIRECTORY_INFORMATION Information,
202  _In_opt_ PVOID Context
203  )
204 {
205  PH_STRINGREF baseName;
206  PPH_STRING fileName;
207 
208  baseName.Buffer = Information->FileName;
209  baseName.Length = Information->FileNameLength;
210 
211  if (PhEndsWithStringRef2(&baseName, L".dll", TRUE))
212  {
213  if (!PhIsPluginDisabled(&baseName))
214  {
215  fileName = PhCreateStringEx(NULL, PluginsDirectory->Length + Information->FileNameLength);
216  memcpy(fileName->Buffer, PluginsDirectory->Buffer, PluginsDirectory->Length);
217  memcpy(&fileName->Buffer[PluginsDirectory->Length / 2], Information->FileName, Information->FileNameLength);
218 
219  PhLoadPlugin(fileName);
220 
221  PhDereferenceObject(fileName);
222  }
223  }
224 
225  return TRUE;
226 }
227 
232  VOID
233  )
234 {
235  HANDLE pluginsDirectoryHandle;
236  PPH_STRING pluginsDirectory;
237 
238  pluginsDirectory = PhGetStringSetting(L"PluginsDirectory");
239 
240  if (RtlDetermineDosPathNameType_U(pluginsDirectory->Buffer) == RtlPathTypeRelative)
241  {
242  // Not absolute. Make sure it is.
243  PluginsDirectory = PhConcatStrings(4, PhApplicationDirectory->Buffer, L"\\", pluginsDirectory->Buffer, L"\\");
244  PhDereferenceObject(pluginsDirectory);
245  }
246  else
247  {
248  PluginsDirectory = pluginsDirectory;
249  }
250 
252  &pluginsDirectoryHandle,
253  PluginsDirectory->Buffer,
254  FILE_GENERIC_READ,
255  0,
256  FILE_SHARE_READ,
257  FILE_OPEN,
259  )))
260  {
261  UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*.dll");
262 
263  PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, EnumPluginsDirectoryCallback, NULL);
264  NtClose(pluginsDirectoryHandle);
265  }
266 
267  // Handle load errors.
268  // In certain startup modes we want to ignore all plugin load errors.
269  if (LoadErrors && LoadErrors->Count != 0 && !PhStartupParameters.PhSvc)
270  {
272  ULONG i;
273  PPHP_PLUGIN_LOAD_ERROR loadError;
274  PPH_STRING baseName;
275 
276  PhInitializeStringBuilder(&sb, 100);
277  PhAppendStringBuilder2(&sb, L"Unable to load the following plugin(s):\n\n");
278 
279  for (i = 0; i < LoadErrors->Count; i++)
280  {
281  loadError = LoadErrors->Items[i];
282  baseName = PhGetBaseName(loadError->FileName);
283  PhAppendFormatStringBuilder(&sb, L"%s: %s\n",
284  baseName->Buffer, PhGetStringOrDefault(loadError->ErrorMessage, L"An unknown error occurred."));
285  PhDereferenceObject(baseName);
286  }
287 
288  PhAppendStringBuilder2(&sb, L"\nDo you want to disable the above plugin(s)?");
289 
290  if (PhShowMessage(
291  NULL,
292  MB_ICONERROR | MB_YESNO,
293  sb.String->Buffer
294  ) == IDYES)
295  {
296  ULONG i;
297 
298  for (i = 0; i < LoadErrors->Count; i++)
299  {
300  loadError = LoadErrors->Items[i];
301  baseName = PhGetBaseName(loadError->FileName);
302  PhSetPluginDisabled(&baseName->sr, TRUE);
303  PhDereferenceObject(baseName);
304  }
305  }
306 
308  }
309 
310  // When we loaded settings before, we didn't know about plugin settings, so they
311  // went into the ignored settings list. Now that they've had a chance to add
312  // settings, we should scan the ignored settings list and move the settings to
313  // the right places.
314  if (PhSettingsFileName)
316 
318 }
319 
324  VOID
325  )
326 {
328 }
329 
335 BOOLEAN PhLoadPlugin(
336  _In_ PPH_STRING FileName
337  )
338 {
339  BOOLEAN success;
340  PPH_STRING fileName;
341  PPH_STRING errorMessage;
342 
343  fileName = PhGetFullPath(FileName->Buffer, NULL);
344 
345  if (!fileName)
346  PhSetReference(&fileName, FileName);
347 
348  success = TRUE;
349 
350  if (!LoadLibrary(fileName->Buffer))
351  {
352  success = FALSE;
353  errorMessage = PhGetWin32Message(GetLastError());
354  }
355 
356  if (!success)
357  {
358  PPHP_PLUGIN_LOAD_ERROR loadError;
359 
360  loadError = PhAllocate(sizeof(PHP_PLUGIN_LOAD_ERROR));
361  PhSetReference(&loadError->FileName, fileName);
362  PhSetReference(&loadError->ErrorMessage, errorMessage);
363 
364  if (!LoadErrors)
365  LoadErrors = PhCreateList(2);
366 
367  PhAddItemList(LoadErrors, loadError);
368 
369  if (errorMessage)
370  PhDereferenceObject(errorMessage);
371  }
372 
373  PhDereferenceObject(fileName);
374 
375  return success;
376 }
377 
379  _In_ PH_PLUGIN_CALLBACK Callback,
380  _In_ BOOLEAN StartupParameters
381  )
382 {
383  PPH_AVL_LINKS links;
384 
385  links = PhMinimumElementAvlTree(&PhPluginsByName);
386 
387  while (links)
388  {
389  PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links);
390  PPH_LIST parameters = NULL;
391 
392  // Find relevant startup parameters for this plugin.
393  if (StartupParameters && PhStartupParameters.PluginParameters)
394  {
395  ULONG i;
396 
397  for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++)
398  {
400  PH_STRINGREF pluginName;
401  PH_STRINGREF parameter;
402 
403  if (PhSplitStringRefAtChar(&string->sr, ':', &pluginName, &parameter) &&
404  PhEqualStringRef(&pluginName, &plugin->Name, FALSE) &&
405  parameter.Length != 0)
406  {
407  if (!parameters)
408  parameters = PhCreateList(3);
409 
410  PhAddItemList(parameters, PhCreateString2(&parameter));
411  }
412  }
413  }
414 
415  PhInvokeCallback(PhGetPluginCallback(plugin, Callback), parameters);
416 
417  if (parameters)
418  {
419  ULONG i;
420 
421  for (i = 0; i < parameters->Count; i++)
422  PhDereferenceObject(parameters->Items[i]);
423 
424  PhDereferenceObject(parameters);
425  }
426 
427  links = PhSuccessorElementAvlTree(links);
428  }
429 }
430 
432  _In_ PPH_STRINGREF Name
433  )
434 {
435  SIZE_T i;
436  PWSTR buffer;
437  SIZE_T count;
438 
439  buffer = Name->Buffer;
440  count = Name->Length / sizeof(WCHAR);
441 
442  for (i = 0; i < count; i++)
443  {
444  if (!iswalnum(buffer[i]) && buffer[i] != ' ' && buffer[i] != '.' && buffer[i] != '_')
445  {
446  return FALSE;
447  }
448  }
449 
450  return TRUE;
451 }
452 
470  _In_ PWSTR Name,
471  _In_ PVOID DllBase,
472  _Out_opt_ PPH_PLUGIN_INFORMATION *Information
473  )
474 {
475  PPH_PLUGIN plugin;
476  PH_STRINGREF pluginName;
477  PPH_AVL_LINKS existingLinks;
478  ULONG i;
479  PPH_STRING fileName;
480 
481  PhInitializeStringRefLongHint(&pluginName, Name);
482 
483  if (!PhpValidatePluginName(&pluginName))
484  return NULL;
485 
486  fileName = PhGetDllFileName(DllBase, NULL);
487 
488  if (!fileName)
489  return NULL;
490 
491  plugin = PhAllocate(sizeof(PH_PLUGIN));
492  memset(plugin, 0, sizeof(PH_PLUGIN));
493 
494  plugin->Name = pluginName;
495  plugin->DllBase = DllBase;
496 
497  plugin->FileName = fileName;
498 
499  existingLinks = PhAddElementAvlTree(&PhPluginsByName, &plugin->Links);
500 
501  if (existingLinks)
502  {
503  // Another plugin has already been registered with the same name.
504  PhFree(plugin);
505  return NULL;
506  }
507 
508  for (i = 0; i < PluginCallbackMaximum; i++)
509  PhInitializeCallback(&plugin->Callbacks[i]);
510 
511  PhEmInitializeAppContext(&plugin->AppContext, &pluginName);
512 
513  if (Information)
514  *Information = &plugin->Information;
515 
516  return plugin;
517 }
518 
527  _In_ PWSTR Name
528  )
529 {
530  PH_STRINGREF name;
531 
532  PhInitializeStringRefLongHint(&name, Name);
533 
534  return PhFindPlugin2(&name);
535 }
536 
545  _In_ PPH_STRINGREF Name
546  )
547 {
548  PPH_AVL_LINKS links;
549  PH_PLUGIN lookupPlugin;
550 
551  lookupPlugin.Name = *Name;
552  links = PhFindElementAvlTree(&PhPluginsByName, &lookupPlugin.Links);
553 
554  if (links)
555  return CONTAINING_RECORD(links, PH_PLUGIN, Links);
556  else
557  return NULL;
558 }
559 
568  _In_ PPH_PLUGIN Plugin
569  )
570 {
571  return &Plugin->Information;
572 }
573 
584  _In_ PPH_PLUGIN Plugin,
585  _In_ PH_PLUGIN_CALLBACK Callback
586  )
587 {
588  if (Callback >= PluginCallbackMaximum)
589  PhRaiseStatus(STATUS_INVALID_PARAMETER_2);
590 
591  return &Plugin->Callbacks[Callback];
592 }
593 
603  _In_ PH_GENERAL_CALLBACK Callback
604  )
605 {
606  if (Callback >= GeneralCallbackMaximum)
607  PhRaiseStatus(STATUS_INVALID_PARAMETER_2);
608 
609  return &GeneralCallbacks[Callback];
610 }
611 
623  _In_ ULONG Count
624  )
625 {
626  ULONG nextPluginId;
627 
628  nextPluginId = NextPluginId;
629  NextPluginId += Count;
630 
631  return nextPluginId;
632 }
633 
657  _In_ PPH_PLUGIN Plugin,
658  _In_ ULONG_PTR Location,
659  _In_opt_ PWSTR InsertAfter,
660  _In_ ULONG Id,
661  _In_ PWSTR Text,
662  _In_opt_ PVOID Context
663  )
664 {
665  PH_ADDMENUITEM addMenuItem;
666 
667  addMenuItem.Plugin = Plugin;
668  addMenuItem.InsertAfter = InsertAfter;
669  addMenuItem.Text = Text;
670  addMenuItem.Context = Context;
671 
672  if (Location < 0x1000)
673  {
674  addMenuItem.Location = (ULONG)Location;
675  }
676  else
677  {
678  return 0;
679  }
680 
681  addMenuItem.Flags = Id & PH_MENU_ITEM_VALID_FLAGS;
682  Id &= ~PH_MENU_ITEM_VALID_FLAGS;
683  addMenuItem.Id = Id;
684 
685  return ProcessHacker_AddMenuItem(PhMainWndHandle, &addMenuItem);
686 }
687 
692  _Out_ PPH_PLUGIN_SYSTEM_STATISTICS Statistics
693  )
694 {
695  Statistics->Performance = &PhPerfInformation;
696 
697  Statistics->NumberOfProcesses = PhTotalProcesses;
698  Statistics->NumberOfThreads = PhTotalThreads;
699  Statistics->NumberOfHandles = PhTotalHandles;
700 
701  Statistics->CpuKernelUsage = PhCpuKernelUsage;
702  Statistics->CpuUserUsage = PhCpuUserUsage;
703 
704  Statistics->IoReadDelta = PhIoReadDelta;
705  Statistics->IoWriteDelta = PhIoWriteDelta;
706  Statistics->IoOtherDelta = PhIoOtherDelta;
707 
708  Statistics->CommitPages = PhGetItemCircularBuffer_ULONG(&PhCommitHistory, 0);
709  Statistics->PhysicalPages = PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, 0);
710 
711  Statistics->MaxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0));
712  Statistics->MaxIoProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0));
713 
714  Statistics->CpuKernelHistory = &PhCpuKernelHistory;
715  Statistics->CpuUserHistory = &PhCpuUserHistory;
716  Statistics->CpusKernelHistory = &PhCpusKernelHistory;
717  Statistics->CpusUserHistory = &PhCpusUserHistory;
718  Statistics->IoReadHistory = &PhIoReadHistory;
719  Statistics->IoWriteHistory = &PhIoWriteHistory;
720  Statistics->IoOtherHistory = &PhIoOtherHistory;
721  Statistics->CommitHistory = &PhCommitHistory;
722  Statistics->PhysicalHistory = &PhPhysicalHistory;
723  Statistics->MaxCpuHistory = &PhMaxCpuHistory;
724  Statistics->MaxIoHistory = &PhMaxIoHistory;
725 #ifdef PH_RECORD_MAX_USAGE
726  Statistics->MaxCpuUsageHistory = &PhMaxCpuUsageHistory;
727  Statistics->MaxIoReadOtherHistory = &PhMaxIoReadOtherHistory;
728  Statistics->MaxIoWriteHistory = &PhMaxIoWriteHistory;
729 #else
730  Statistics->MaxCpuUsageHistory = NULL;
731  Statistics->MaxIoReadOtherHistory = NULL;
732  Statistics->MaxIoWriteHistory = NULL;
733 #endif
734 }
735 
736 static VOID NTAPI PhpPluginEMenuItemDeleteFunction(
737  _In_ PPH_EMENU_ITEM Item
738  )
739 {
740  PPH_PLUGIN_MENU_ITEM pluginMenuItem;
741 
742  pluginMenuItem = Item->Context;
743 
744  if (pluginMenuItem->DeleteFunction)
745  pluginMenuItem->DeleteFunction(pluginMenuItem);
746 
747  PhFree(pluginMenuItem);
748 }
749 
768  _In_ PPH_PLUGIN Plugin,
769  _In_ ULONG Flags,
770  _In_ ULONG Id,
771  _In_ PWSTR Text,
772  _In_opt_ PVOID Context
773  )
774 {
775  PPH_EMENU_ITEM item;
776  PPH_PLUGIN_MENU_ITEM pluginMenuItem;
777 
778  item = PhCreateEMenuItem(Flags, ID_PLUGIN_MENU_ITEM, Text, NULL, NULL);
779 
780  pluginMenuItem = PhAllocate(sizeof(PH_PLUGIN_MENU_ITEM));
781  memset(pluginMenuItem, 0, sizeof(PH_PLUGIN_MENU_ITEM));
782  pluginMenuItem->Plugin = Plugin;
783  pluginMenuItem->Id = Id;
784  pluginMenuItem->Context = Context;
785 
786  item->Context = pluginMenuItem;
787  item->DeleteFunction = PhpPluginEMenuItemDeleteFunction;
788 
789  return item;
790 }
791 
803  _Inout_ PPH_PLUGIN_MENU_INFORMATION MenuInfo,
804  _In_ PPH_PLUGIN Plugin,
805  _In_opt_ PVOID Context
806  )
807 {
809 
810  if (MenuInfo->Flags & PH_PLUGIN_MENU_DISALLOW_HOOKS)
811  return FALSE;
812 
813  if (!MenuInfo->PluginHookList)
814  MenuInfo->PluginHookList = PhAutoDereferenceObject(PhCreateList(2));
815 
817  hook->Plugin = Plugin;
818  hook->Context = Context;
819  PhAddItemList(MenuInfo->PluginHookList, hook);
820 
821  return TRUE;
822 }
823 
835  _Out_ PPH_PLUGIN_MENU_INFORMATION MenuInfo,
836  _In_opt_ PPH_EMENU Menu,
837  _In_ HWND OwnerWindow,
838  _In_ ULONG Flags
839  )
840 {
841  memset(MenuInfo, 0, sizeof(PH_PLUGIN_MENU_INFORMATION));
842  MenuInfo->Menu = Menu;
843  MenuInfo->OwnerWindow = OwnerWindow;
844  MenuInfo->Flags = Flags;
845 }
846 
856  _In_ PPH_PLUGIN_MENU_INFORMATION MenuInfo,
857  _In_ PPH_EMENU_ITEM Item
858  )
859 {
860  PPH_PLUGIN_MENU_ITEM pluginMenuItem;
861  ULONG i;
863  PH_PLUGIN_MENU_HOOK_INFORMATION menuHookInfo;
864 
865  if (MenuInfo->PluginHookList)
866  {
867  for (i = 0; i < MenuInfo->PluginHookList->Count; i++)
868  {
869  hook = MenuInfo->PluginHookList->Items[i];
870  menuHookInfo.MenuInfo = MenuInfo;
871  menuHookInfo.SelectedItem = Item;
872  menuHookInfo.Context = hook->Context;
873  menuHookInfo.Handled = FALSE;
874  PhInvokeCallback(PhGetPluginCallback(hook->Plugin, PluginCallbackMenuHook), &menuHookInfo);
875 
876  if (menuHookInfo.Handled)
877  return TRUE;
878  }
879  }
880 
881  if (Item->Id != ID_PLUGIN_MENU_ITEM)
882  return FALSE;
883 
884  pluginMenuItem = Item->Context;
885 
886  pluginMenuItem->OwnerWindow = MenuInfo->OwnerWindow;
887 
888  PhInvokeCallback(PhGetPluginCallback(pluginMenuItem->Plugin, PluginCallbackMenuItem), pluginMenuItem);
889 
890  return TRUE;
891 }
892 
906  _In_ PPH_PLUGIN Plugin,
907  _In_ PVOID CmData,
908  _In_ PPH_TREENEW_COLUMN Column,
909  _In_ ULONG SubId,
910  _In_opt_ PVOID Context,
911  _In_opt_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction
912  )
913 {
914  return !!PhCmCreateColumn(
915  CmData,
916  Column,
917  Plugin,
918  SubId,
919  Context,
920  SortFunction
921  );
922 }
923 
934  _In_ PPH_PLUGIN Plugin,
935  _In_ PH_EM_OBJECT_TYPE ObjectType,
936  _In_ ULONG ExtensionSize,
937  _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback,
938  _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback
939  )
940 {
942  &Plugin->AppContext,
943  ObjectType,
944  ExtensionSize,
945  CreateCallback,
946  DeleteCallback
947  );
948 }
949 
958  _In_ PPH_PLUGIN Plugin,
959  _In_ PVOID Object,
960  _In_ PH_EM_OBJECT_TYPE ObjectType
961  )
962 {
963  return PhEmGetObjectExtension(
964  &Plugin->AppContext,
965  ObjectType,
966  Object
967  );
968 }
969 
984  _In_ PPH_PLUGIN Plugin,
985  _In_ ULONG SubId,
986  _In_opt_ PVOID Context,
987  _In_ PWSTR Text,
988  _In_ ULONG Flags,
989  _In_ struct _PH_NF_ICON_REGISTRATION_DATA *RegistrationData
990  )
991 {
992  return PhNfRegisterIcon(
993  Plugin,
994  SubId,
995  Context,
996  Text,
997  Flags,
998  RegistrationData->UpdateCallback,
999  RegistrationData->MessageCallback
1000  );
1001 }
1002 
1011  _In_ PPH_PLUGIN Plugin,
1012  _In_ PVOID CmData
1013  )
1014 {
1015  PhCmSetNotifyPlugin(CmData, Plugin);
1016 }
1017 
1019  _Out_ PPH_PLUGIN_PHSVC_CLIENT Client
1020  )
1021 {
1023  return FALSE;
1024 
1025  Client->ServerProcessId = PhSvcClServerProcessId;
1026  Client->FreeHeap = PhSvcpFreeHeap;
1027  Client->CreateString = PhSvcpCreateString;
1028 
1029  return TRUE;
1030 }
1031 
1033  _In_ PPH_PLUGIN Plugin,
1034  _In_ ULONG SubId,
1035  _In_reads_bytes_opt_(InLength) PVOID InBuffer,
1036  _In_ ULONG InLength,
1037  _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer,
1038  _In_ ULONG OutLength
1039  )
1040 {
1041  NTSTATUS status;
1042  PPH_STRING apiId;
1043  PH_FORMAT format[4];
1044 
1045  PhInitFormatC(&format[0], '+');
1046  PhInitFormatSR(&format[1], Plugin->Name);
1047  PhInitFormatC(&format[2], '+');
1048  PhInitFormatU(&format[3], SubId);
1049  apiId = PhFormat(format, 4, 50);
1050 
1051  status = PhSvcCallPlugin(&apiId->sr, InBuffer, InLength, OutBuffer, OutLength);
1052  PhDereferenceObject(apiId);
1053 
1054  return status;
1055 }