Process Hacker
main.c
Go to the documentation of this file.
1 /*
2  * Process Hacker Extended Notifications -
3  * main program
4  *
5  * Copyright (C) 2010-2011 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 <phdk.h>
24 #include <windowsx.h>
25 #include "extnoti.h"
26 #include "resource.h"
27 #include "gntp-send/growl.h"
28 
29 VOID NTAPI LoadCallback(
30  _In_opt_ PVOID Parameter,
31  _In_opt_ PVOID Context
32  );
33 
35  _In_opt_ PVOID Parameter,
36  _In_opt_ PVOID Context
37  );
38 
40  _In_opt_ PVOID Parameter,
41  _In_opt_ PVOID Context
42  );
43 
45  _In_ BOOLEAN Force
46  );
47 
49  _In_ PPH_PLUGIN_NOTIFY_EVENT NotifyEvent
50  );
51 
52 NTSTATUS NTAPI RegisterGrowlCallback(
53  _In_ PVOID Parameter
54  );
55 
56 INT_PTR CALLBACK ProcessesDlgProc(
57  _In_ HWND hwndDlg,
58  _In_ UINT uMsg,
59  _In_ WPARAM wParam,
60  _In_ LPARAM lParam
61  );
62 
63 INT_PTR CALLBACK ServicesDlgProc(
64  _In_ HWND hwndDlg,
65  _In_ UINT uMsg,
66  _In_ WPARAM wParam,
67  _In_ LPARAM lParam
68  );
69 
70 INT_PTR CALLBACK LoggingDlgProc(
71  _In_ HWND hwndDlg,
72  _In_ UINT uMsg,
73  _In_ WPARAM wParam,
74  _In_ LPARAM lParam
75  );
76 
77 INT_PTR CALLBACK GrowlDlgProc(
78  _In_ HWND hwndDlg,
79  _In_ UINT uMsg,
80  _In_ WPARAM wParam,
81  _In_ LPARAM lParam
82  );
83 
88 
91 
93 {
94  "Process Created",
95  "Process Terminated",
96  "Service Created",
97  "Service Deleted",
98  "Service Started",
99  "Service Stopped"
100 };
101 
103  _In_ HINSTANCE Instance,
104  _In_ ULONG Reason,
105  _Reserved_ PVOID Reserved
106  )
107 {
108  switch (Reason)
109  {
110  case DLL_PROCESS_ATTACH:
111  {
113 
114  PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info);
115 
116  if (!PluginInstance)
117  return FALSE;
118 
119  info->DisplayName = L"Extended Notifications";
120  info->Author = L"wj32";
121  info->Description = L"Filters notifications.";
122  info->Url = L"http://processhacker.sf.net/forums/viewtopic.php?t=1112";
123  info->HasOptions = TRUE;
124 
126  PhGetPluginCallback(PluginInstance, PluginCallbackLoad),
127  LoadCallback,
128  NULL,
129  &PluginLoadCallbackRegistration
130  );
134  NULL,
135  &PluginShowOptionsCallbackRegistration
136  );
137 
141  NULL,
142  &NotifyEventCallbackRegistration
143  );
144 
145  {
146  static PH_SETTING_CREATE settings[] =
147  {
152  };
153 
154  PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE));
155  }
156 
157  ProcessFilterList = PhCreateList(10);
158  ServiceFilterList = PhCreateList(10);
159  }
160  break;
161  }
162 
163  return TRUE;
164 }
165 
167  _In_ PFILTER_ENTRY Entry
168  )
169 {
170  PhDereferenceObject(Entry->Filter);
171  PhFree(Entry);
172 }
173 
175  _Inout_ PPH_LIST FilterList
176  )
177 {
178  ULONG i;
179 
180  for (i = 0; i < FilterList->Count; i++)
181  FreeFilterEntry(FilterList->Items[i]);
182 
183  PhClearList(FilterList);
184 }
185 
187  _Inout_ PPH_LIST Destination,
188  _In_ PPH_LIST Source
189  )
190 {
191  ULONG i;
192 
193  for (i = 0; i < Source->Count; i++)
194  {
195  PFILTER_ENTRY entry = Source->Items[i];
196  PFILTER_ENTRY newEntry;
197 
198  newEntry = PhAllocate(sizeof(FILTER_ENTRY));
199  newEntry->Type = entry->Type;
200  newEntry->Filter = entry->Filter;
201  PhReferenceObject(newEntry->Filter);
202 
203  PhAddItemList(Destination, newEntry);
204  }
205 }
206 
208  _Inout_ PPH_LIST FilterList,
209  _In_ PPH_STRING String
210  )
211 {
212  PH_STRING_BUILDER stringBuilder;
213  SIZE_T length;
214  SIZE_T i;
215  PFILTER_ENTRY entry;
216 
217  length = String->Length / 2;
218  PhInitializeStringBuilder(&stringBuilder, 20);
219 
220  entry = NULL;
221 
222  for (i = 0; i < length; i++)
223  {
224  if (String->Buffer[i] == '\\')
225  {
226  if (i != length - 1)
227  {
228  i++;
229 
230  switch (String->Buffer[i])
231  {
232  case 'i':
233  case 'e':
234  if (entry)
235  {
236  entry->Filter = PhFinalStringBuilderString(&stringBuilder);
237  PhAddItemList(FilterList, entry);
238  PhInitializeStringBuilder(&stringBuilder, 20);
239  }
240 
241  entry = PhAllocate(sizeof(FILTER_ENTRY));
242  entry->Type = String->Buffer[i] == 'i' ? FilterInclude : FilterExclude;
243 
244  break;
245 
246  default:
247  PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);
248  break;
249  }
250  }
251  else
252  {
253  // Trailing backslash. Just ignore it.
254  break;
255  }
256  }
257  else
258  {
259  PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);
260  }
261  }
262 
263  if (entry)
264  {
265  entry->Filter = PhFinalStringBuilderString(&stringBuilder);
266  PhAddItemList(FilterList, entry);
267  }
268  else
269  {
270  PhDeleteStringBuilder(&stringBuilder);
271  }
272 }
273 
275  _Inout_ PPH_LIST FilterList
276  )
277 {
278  PH_STRING_BUILDER stringBuilder;
279  SIZE_T i;
280  SIZE_T j;
281  WCHAR temp[2];
282 
283  PhInitializeStringBuilder(&stringBuilder, 100);
284 
285  temp[0] = '\\';
286 
287  for (i = 0; i < FilterList->Count; i++)
288  {
289  PFILTER_ENTRY entry = FilterList->Items[i];
290  SIZE_T length;
291 
292  // Write the entry type.
293 
294  temp[1] = entry->Type == FilterInclude ? 'i' : 'e';
295 
296  PhAppendStringBuilderEx(&stringBuilder, temp, 4);
297 
298  // Write the filter string.
299 
300  length = entry->Filter->Length / 2;
301 
302  for (j = 0; j < length; j++)
303  {
304  if (entry->Filter->Buffer[j] == '\\') // escape backslashes
305  {
306  temp[1] = entry->Filter->Buffer[j];
307  PhAppendStringBuilderEx(&stringBuilder, temp, 4);
308  }
309  else
310  {
311  PhAppendCharStringBuilder(&stringBuilder, entry->Filter->Buffer[j]);
312  }
313  }
314  }
315 
316  return PhFinalStringBuilderString(&stringBuilder);
317 }
318 
319 VOID NTAPI LoadCallback(
320  _In_opt_ PVOID Parameter,
321  _In_opt_ PVOID Context
322  )
323 {
324  PPH_STRING string;
325 
327  LoadFilterList(ProcessFilterList, string);
328  PhDereferenceObject(string);
329 
331  LoadFilterList(ServiceFilterList, string);
332  PhDereferenceObject(string);
333 
335 
337  {
339  }
340 }
341 
343  _In_opt_ PVOID Parameter,
344  _In_opt_ PVOID Context
345  )
346 {
347  PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };
348  PROPSHEETPAGE propSheetPage;
349  HPROPSHEETPAGE pages[4];
350 
351  propSheetHeader.dwFlags =
352  PSH_NOAPPLYNOW |
353  PSH_NOCONTEXTHELP |
354  PSH_PROPTITLE;
355  propSheetHeader.hwndParent = (HWND)Parameter;
356  propSheetHeader.pszCaption = L"Extended Notifications";
357  propSheetHeader.nPages = 0;
358  propSheetHeader.nStartPage = 0;
359  propSheetHeader.phpage = pages;
360 
361  // Processes
362  memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
363  propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
364  propSheetPage.hInstance = PluginInstance->DllBase;
365  propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PROCESSES);
366  propSheetPage.pfnDlgProc = ProcessesDlgProc;
367  pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);
368 
369  // Services
370  memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
371  propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
372  propSheetPage.hInstance = PluginInstance->DllBase;
373  propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SERVICES);
374  propSheetPage.pfnDlgProc = ServicesDlgProc;
375  pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);
376 
377  // Logging
378  memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
379  propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
380  propSheetPage.hInstance = PluginInstance->DllBase;
381  propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_LOGGING);
382  propSheetPage.pfnDlgProc = LoggingDlgProc;
383  pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);
384 
385  // Growl
386  memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
387  propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
388  propSheetPage.hInstance = PluginInstance->DllBase;
389  propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_GROWL);
390  propSheetPage.pfnDlgProc = GrowlDlgProc;
391  pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage);
392 
393  PropertySheet(&propSheetHeader);
394 }
395 
397  _In_ PPH_LIST FilterList,
398  _In_ PPH_STRING String,
399  _Out_ FILTER_TYPE *FilterType
400  )
401 {
402  ULONG i;
403  BOOLEAN isFileName;
404 
405  isFileName = PhFindCharInString(String, 0, '\\') != -1;
406 
407  for (i = 0; i < FilterList->Count; i++)
408  {
409  PFILTER_ENTRY entry = FilterList->Items[i];
410 
411  if (isFileName && PhFindCharInString(entry->Filter, 0, '\\') == -1)
412  continue; // ignore filters without backslashes if we're matching a file name
413 
414  if (entry->Filter->Length == 2 && entry->Filter->Buffer[0] == '*') // shortcut
415  {
416  *FilterType = entry->Type;
417  return TRUE;
418  }
419 
420  if (PhMatchWildcards(entry->Filter->Buffer, String->Buffer, TRUE))
421  {
422  *FilterType = entry->Type;
423  return TRUE;
424  }
425  }
426 
427  return FALSE;
428 }
429 
431  _In_opt_ PVOID Parameter,
432  _In_opt_ PVOID Context
433  )
434 {
435  PPH_PLUGIN_NOTIFY_EVENT notifyEvent = Parameter;
436  PPH_PROCESS_ITEM processItem;
437  PPH_SERVICE_ITEM serviceItem;
438  FILTER_TYPE filterType;
439  BOOLEAN found = FALSE;
440 
441  filterType = FilterExclude;
442 
443  switch (notifyEvent->Type)
444  {
447  processItem = notifyEvent->Parameter;
448 
449  if (processItem->FileName)
450  found = MatchFilterList(ProcessFilterList, processItem->FileName, &filterType);
451 
452  if (!found)
453  MatchFilterList(ProcessFilterList, processItem->ProcessName, &filterType);
454 
455  break;
456 
461  serviceItem = notifyEvent->Parameter;
462 
463  MatchFilterList(ServiceFilterList, serviceItem->Name, &filterType);
464 
465  break;
466  }
467 
468  if (filterType == FilterExclude)
469  notifyEvent->Handled = TRUE; // pretend we handled the notification to prevent it from displaying
470 
472  NotifyGrowl(notifyEvent);
473 }
474 
476  _In_ BOOLEAN Force
477  )
478 {
479  static BOOLEAN registered = FALSE;
480 
481  if (!Force && registered)
482  return;
483 
484  growl_tcp_register("127.0.0.1", "Process Hacker", GrowlNotifications, sizeof(GrowlNotifications) / sizeof(PSTR), NULL, NULL);
485 
486  registered = TRUE;
487 }
488 
490  _In_ PPH_PLUGIN_NOTIFY_EVENT NotifyEvent
491  )
492 {
493  PSTR notification;
494  PPH_STRING title;
495  PPH_BYTES titleUtf8;
496  PPH_STRING message;
497  PPH_BYTES messageUtf8;
498  PPH_PROCESS_ITEM processItem;
499  PPH_SERVICE_ITEM serviceItem;
500  PPH_PROCESS_ITEM parentProcessItem;
501 
502  if (NotifyEvent->Handled)
503  return;
504 
505  switch (NotifyEvent->Type)
506  {
508  processItem = NotifyEvent->Parameter;
509  notification = GrowlNotifications[0];
510  title = processItem->ProcessName;
511  PhReferenceObject(title);
512 
513  parentProcessItem = PhReferenceProcessItemForParent(
514  processItem->ParentProcessId,
515  processItem->ProcessId,
516  &processItem->CreateTime
517  );
518 
519  message = PhFormatString(
520  L"The process %s (%lu) was started by %s.",
521  processItem->ProcessName->Buffer,
522  HandleToUlong(processItem->ProcessId),
523  parentProcessItem ? parentProcessItem->ProcessName->Buffer : L"an unknown process"
524  );
525 
526  if (parentProcessItem)
527  PhDereferenceObject(parentProcessItem);
528 
529  break;
531  processItem = NotifyEvent->Parameter;
532  notification = GrowlNotifications[1];
533  title = processItem->ProcessName;
534  PhReferenceObject(title);
535 
536  message = PhFormatString(L"The process %s (%lu) was terminated.",
537  processItem->ProcessName->Buffer,
538  HandleToUlong(processItem->ProcessId)
539  );
540 
541  break;
543  serviceItem = NotifyEvent->Parameter;
544  notification = GrowlNotifications[2];
545  title = serviceItem->DisplayName;
546  PhReferenceObject(title);
547 
548  message = PhFormatString(L"The service %s (%s) has been created.",
549  serviceItem->Name->Buffer,
550  serviceItem->DisplayName->Buffer
551  );
552 
553  break;
555  serviceItem = NotifyEvent->Parameter;
556  notification = GrowlNotifications[3];
557  title = serviceItem->DisplayName;
558  PhReferenceObject(title);
559 
560  message = PhFormatString(L"The service %s (%s) has been deleted.",
561  serviceItem->Name->Buffer,
562  serviceItem->DisplayName->Buffer
563  );
564 
565  break;
567  serviceItem = NotifyEvent->Parameter;
568  notification = GrowlNotifications[4];
569  title = serviceItem->DisplayName;
570  PhReferenceObject(title);
571 
572  message = PhFormatString(L"The service %s (%s) has been started.",
573  serviceItem->Name->Buffer,
574  serviceItem->DisplayName->Buffer
575  );
576 
577  break;
579  serviceItem = NotifyEvent->Parameter;
580  notification = GrowlNotifications[5];
581  title = serviceItem->DisplayName;
582  PhReferenceObject(title);
583 
584  message = PhFormatString(L"The service %s (%s) has been stopped.",
585  serviceItem->Name->Buffer,
586  serviceItem->DisplayName->Buffer
587  );
588 
589  break;
590  default:
591  return;
592  }
593 
594  titleUtf8 = PhConvertUtf16ToUtf8Ex(title->Buffer, title->Length);
595  messageUtf8 = PhConvertUtf16ToUtf8Ex(message->Buffer, message->Length);
596 
598 
599  if (growl_tcp_notify("127.0.0.1", "Process Hacker", notification, titleUtf8->Buffer, messageUtf8->Buffer, NULL, NULL, NULL) == 0)
600  NotifyEvent->Handled = TRUE;
601 
602  PhDereferenceObject(messageUtf8);
603  PhDereferenceObject(titleUtf8);
604  PhDereferenceObject(message);
605  PhDereferenceObject(title);
606 }
607 
608 NTSTATUS NTAPI RegisterGrowlCallback(
609  _In_ PVOID Parameter
610  )
611 {
613 
614  return STATUS_SUCCESS;
615 }
616 
618  _In_ PFILTER_ENTRY Entry
619  )
620 {
621  return PhConcatStrings2(Entry->Type == FilterInclude ? L"[Include] " : L"[Exclude] ", Entry->Filter->Buffer);
622 }
623 
625  _In_ HWND ListBox,
626  _In_ PPH_LIST FilterList
627  )
628 {
629  ULONG i;
630 
631  for (i = 0; i < FilterList->Count; i++)
632  {
633  PFILTER_ENTRY entry = FilterList->Items[i];
634  PPH_STRING string;
635 
636  string = FormatFilterEntry(entry);
637  ListBox_AddString(ListBox, string->Buffer);
638  PhDereferenceObject(string);
639  }
640 }
641 
644 
645 static LRESULT CALLBACK TextBoxSubclassProc(
646  _In_ HWND hWnd,
647  _In_ UINT uMsg,
648  _In_ WPARAM wParam,
649  _In_ LPARAM lParam,
650  _In_ UINT_PTR uIdSubclass,
651  _In_ ULONG_PTR dwRefData
652  )
653 {
654  switch (uMsg)
655  {
656  case WM_NCDESTROY:
657  RemoveWindowSubclass(hWnd, TextBoxSubclassProc, uIdSubclass);
658  break;
659  case WM_GETDLGCODE:
660  {
661  if (wParam == VK_RETURN)
662  return DLGC_WANTALLKEYS;
663  }
664  break;
665  case WM_CHAR:
666  {
667  if (wParam == VK_RETURN)
668  {
669  SendMessage(GetParent(hWnd), WM_COMMAND, IDC_TEXT_RETURN, 0);
670  return 0;
671  }
672  }
673  break;
674  }
675 
676  return DefSubclassProc(hWnd, uMsg, wParam, lParam);
677 }
678 
680  _In_ HWND hwndDlg,
681  _In_ HWND ListBox
682  )
683 {
684  ULONG i;
685  ULONG count;
686 
687  i = ListBox_GetCurSel(ListBox);
688  count = ListBox_GetCount(ListBox);
689 
690  EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), i != LB_ERR);
691  EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), i != LB_ERR && i != 0);
692  EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), i != LB_ERR && i != count - 1);
693 }
694 
696  _In_ HWND hwndDlg,
697  _In_ UINT uMsg,
698  _In_ WPARAM wParam,
699  _In_ LPARAM lParam,
700  _In_ HWND ListBox,
701  _In_ PPH_LIST FilterList
702  )
703 {
704  switch (uMsg)
705  {
706  case WM_INITDIALOG:
707  {
708  SetWindowSubclass(GetDlgItem(hwndDlg, IDC_TEXT), TextBoxSubclassProc, 0, 0);
709 
710  Button_SetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE), BST_CHECKED);
711 
712  FixControlStates(hwndDlg, ListBox);
713  }
714  break;
715  case WM_COMMAND:
716  {
717  switch (LOWORD(wParam))
718  {
719  case IDC_LIST:
720  {
721  if (HIWORD(wParam) == LBN_SELCHANGE)
722  {
723  ULONG i;
724 
725  i = ListBox_GetCurSel(ListBox);
726 
727  if (i != LB_ERR)
728  {
729  PFILTER_ENTRY entry;
730 
731  entry = FilterList->Items[i];
732  SetDlgItemText(hwndDlg, IDC_TEXT, entry->Filter->Buffer);
733  Button_SetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE),
734  entry->Type == FilterInclude ? BST_CHECKED : BST_UNCHECKED);
735  Button_SetCheck(GetDlgItem(hwndDlg, IDC_EXCLUDE),
736  entry->Type == FilterExclude ? BST_CHECKED : BST_UNCHECKED);
737  }
738 
739  FixControlStates(hwndDlg, ListBox);
740  }
741  }
742  break;
743  case IDC_ADD:
744  case IDC_TEXT_RETURN:
745  {
746  ULONG i;
747  PPH_STRING string;
748  PFILTER_ENTRY entry = NULL;
749  FILTER_TYPE type;
750  PPH_STRING entryString;
751 
752  string = PhGetWindowText(GetDlgItem(hwndDlg, IDC_TEXT));
753 
754  if (string->Length == 0)
755  {
756  PhDereferenceObject(string);
757  return FALSE;
758  }
759 
760  for (i = 0; i < FilterList->Count; i++)
761  {
762  entry = FilterList->Items[i];
763 
764  if (PhEqualString(entry->Filter, string, TRUE))
765  break;
766  }
767 
768  type = Button_GetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE)) == BST_CHECKED ? FilterInclude : FilterExclude;
769 
770  if (i == FilterList->Count)
771  {
772  // No existing entry, so add a new one.
773 
774  entry = PhAllocate(sizeof(FILTER_ENTRY));
775  entry->Type = type;
776  entry->Filter = string;
777  PhInsertItemList(FilterList, 0, entry);
778 
779  entryString = FormatFilterEntry(entry);
780  ListBox_InsertString(ListBox, 0, entryString->Buffer);
781  PhDereferenceObject(entryString);
782 
783  ListBox_SetCurSel(ListBox, 0);
784  }
785  else
786  {
787  entry->Type = type;
788  PhDereferenceObject(entry->Filter);
789  entry->Filter = string;
790 
791  ListBox_DeleteString(ListBox, i);
792  entryString = FormatFilterEntry(entry);
793  ListBox_InsertString(ListBox, i, entryString->Buffer);
794  PhDereferenceObject(entryString);
795 
796  ListBox_SetCurSel(ListBox, i);
797  }
798 
799  SetFocus(GetDlgItem(hwndDlg, IDC_TEXT));
800  Edit_SetSel(GetDlgItem(hwndDlg, IDC_TEXT), 0, -1);
801 
802  FixControlStates(hwndDlg, ListBox);
803  }
804  break;
805  case IDC_REMOVE:
806  {
807  ULONG i;
808  PFILTER_ENTRY entry;
809 
810  i = ListBox_GetCurSel(ListBox);
811 
812  if (i != LB_ERR)
813  {
814  entry = FilterList->Items[i];
815  FreeFilterEntry(entry);
816  PhRemoveItemList(FilterList, i);
817  ListBox_DeleteString(ListBox, i);
818 
819  if (i >= FilterList->Count)
820  i = FilterList->Count - 1;
821 
822  ListBox_SetCurSel(ListBox, i);
823 
824  FixControlStates(hwndDlg, ListBox);
825  }
826  }
827  break;
828  case IDC_MOVEUP:
829  {
830  ULONG i;
831  PFILTER_ENTRY entry;
832  PPH_STRING entryString;
833 
834  i = ListBox_GetCurSel(ListBox);
835 
836  if (i != LB_ERR && i != 0)
837  {
838  entry = FilterList->Items[i];
839 
840  PhRemoveItemList(FilterList, i);
841  PhInsertItemList(FilterList, i - 1, entry);
842 
843  ListBox_DeleteString(ListBox, i);
844  entryString = FormatFilterEntry(entry);
845  ListBox_InsertString(ListBox, i - 1, entryString->Buffer);
846  PhDereferenceObject(entryString);
847 
848  i--;
849  ListBox_SetCurSel(ListBox, i);
850 
851  FixControlStates(hwndDlg, ListBox);
852  }
853  }
854  break;
855  case IDC_MOVEDOWN:
856  {
857  ULONG i;
858  PFILTER_ENTRY entry;
859  PPH_STRING entryString;
860 
861  i = ListBox_GetCurSel(ListBox);
862 
863  if (i != LB_ERR && i != FilterList->Count - 1)
864  {
865  entry = FilterList->Items[i];
866 
867  PhRemoveItemList(FilterList, i);
868  PhInsertItemList(FilterList, i + 1, entry);
869 
870  ListBox_DeleteString(ListBox, i);
871  entryString = FormatFilterEntry(entry);
872  ListBox_InsertString(ListBox, i + 1, entryString->Buffer);
873  PhDereferenceObject(entryString);
874 
875  i++;
876  ListBox_SetCurSel(ListBox, i);
877 
878  FixControlStates(hwndDlg, ListBox);
879  }
880  }
881  break;
882  }
883  }
884  break;
885  }
886 
887  return FALSE;
888 }
889 
890 INT_PTR CALLBACK ProcessesDlgProc(
891  _In_ HWND hwndDlg,
892  _In_ UINT uMsg,
893  _In_ WPARAM wParam,
894  _In_ LPARAM lParam
895  )
896 {
897  INT_PTR result;
898 
899  if (result = HandleCommonMessages(hwndDlg, uMsg, wParam, lParam,
900  GetDlgItem(hwndDlg, IDC_LIST), EditingProcessFilterList))
901  return result;
902 
903  switch (uMsg)
904  {
905  case WM_INITDIALOG:
906  {
907  EditingProcessFilterList = PhCreateList(ProcessFilterList->Count + 10);
908  CopyFilterList(EditingProcessFilterList, ProcessFilterList);
909 
910  AddEntriesToListBox(GetDlgItem(hwndDlg, IDC_LIST), EditingProcessFilterList);
911  }
912  break;
913  case WM_DESTROY:
914  {
915  ClearFilterList(EditingProcessFilterList);
916  PhDereferenceObject(EditingProcessFilterList);
917  EditingProcessFilterList = NULL;
918  }
919  break;
920  case WM_COMMAND:
921  {
922  switch (LOWORD(wParam))
923  {
924  // Nothing
925  }
926  }
927  break;
928  case WM_NOTIFY:
929  {
930  LPNMHDR header = (LPNMHDR)lParam;
931 
932  switch (header->code)
933  {
934  case PSN_APPLY:
935  {
936  PPH_STRING string;
937 
938  ClearFilterList(ProcessFilterList);
939  CopyFilterList(ProcessFilterList, EditingProcessFilterList);
940 
941  string = SaveFilterList(ProcessFilterList);
943  PhDereferenceObject(string);
944 
945  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
946  }
947  return TRUE;
948  }
949  }
950  break;
951  }
952 
953  return FALSE;
954 }
955 
956 INT_PTR CALLBACK ServicesDlgProc(
957  _In_ HWND hwndDlg,
958  _In_ UINT uMsg,
959  _In_ WPARAM wParam,
960  _In_ LPARAM lParam
961  )
962 {
963  if (HandleCommonMessages(hwndDlg, uMsg, wParam, lParam,
964  GetDlgItem(hwndDlg, IDC_LIST), EditingServiceFilterList))
965  return FALSE;
966 
967  switch (uMsg)
968  {
969  case WM_INITDIALOG:
970  {
971  EditingServiceFilterList = PhCreateList(ServiceFilterList->Count + 10);
972  CopyFilterList(EditingServiceFilterList, ServiceFilterList);
973 
974  AddEntriesToListBox(GetDlgItem(hwndDlg, IDC_LIST), EditingServiceFilterList);
975  }
976  break;
977  case WM_DESTROY:
978  {
979  ClearFilterList(EditingServiceFilterList);
980  PhDereferenceObject(EditingServiceFilterList);
981  EditingServiceFilterList = NULL;
982  }
983  break;
984  case WM_COMMAND:
985  {
986  switch (LOWORD(wParam))
987  {
988  // Nothing
989  }
990  }
991  break;
992  case WM_NOTIFY:
993  {
994  LPNMHDR header = (LPNMHDR)lParam;
995 
996  switch (header->code)
997  {
998  case PSN_APPLY:
999  {
1000  PPH_STRING string;
1001 
1002  ClearFilterList(ServiceFilterList);
1003  CopyFilterList(ServiceFilterList, EditingServiceFilterList);
1004 
1005  string = SaveFilterList(ServiceFilterList);
1007  PhDereferenceObject(string);
1008 
1009  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
1010  }
1011  return TRUE;
1012  }
1013  }
1014  break;
1015  }
1016 
1017  return FALSE;
1018 }
1019 
1020 INT_PTR CALLBACK LoggingDlgProc(
1021  _In_ HWND hwndDlg,
1022  _In_ UINT uMsg,
1023  _In_ WPARAM wParam,
1024  _In_ LPARAM lParam
1025  )
1026 {
1027  switch (uMsg)
1028  {
1029  case WM_INITDIALOG:
1030  {
1032  }
1033  break;
1034  case WM_COMMAND:
1035  {
1036  switch (LOWORD(wParam))
1037  {
1038  case IDC_BROWSE:
1039  {
1040  static PH_FILETYPE_FILTER filters[] =
1041  {
1042  { L"Log files (*.txt;*.log)", L"*.txt;*.log" },
1043  { L"All files (*.*)", L"*.*" }
1044  };
1045  PVOID fileDialog;
1046  PPH_STRING fileName;
1047 
1048  fileDialog = PhCreateSaveFileDialog();
1049  PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
1050 
1051  fileName = PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_LOGFILENAME));
1052  PhSetFileDialogFileName(fileDialog, fileName->Buffer);
1053  PhDereferenceObject(fileName);
1054 
1055  if (PhShowFileDialog(hwndDlg, fileDialog))
1056  {
1057  fileName = PhGetFileDialogFileName(fileDialog);
1058  SetDlgItemText(hwndDlg, IDC_LOGFILENAME, fileName->Buffer);
1059  PhDereferenceObject(fileName);
1060  }
1061 
1062  PhFreeFileDialog(fileDialog);
1063  }
1064  break;
1065  }
1066  }
1067  break;
1068  case WM_NOTIFY:
1069  {
1070  LPNMHDR header = (LPNMHDR)lParam;
1071 
1072  switch (header->code)
1073  {
1074  case PSN_APPLY:
1075  {
1077 
1078  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
1079  }
1080  return TRUE;
1081  }
1082  }
1083  break;
1084  }
1085 
1086  return FALSE;
1087 }
1088 
1089 INT_PTR CALLBACK GrowlDlgProc(
1090  _In_ HWND hwndDlg,
1091  _In_ UINT uMsg,
1092  _In_ WPARAM wParam,
1093  _In_ LPARAM lParam
1094  )
1095 {
1096  switch (uMsg)
1097  {
1098  case WM_INITDIALOG:
1099  {
1100  PPH_STRING licenseText;
1101 
1103  SetDlgItemText(hwndDlg, IDC_LICENSE, licenseText->Buffer);
1104  PhDereferenceObject(licenseText);
1105 
1106  Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL), PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL) ? BST_CHECKED : BST_UNCHECKED);
1107  }
1108  break;
1109  case WM_NOTIFY:
1110  {
1111  LPNMHDR header = (LPNMHDR)lParam;
1112 
1113  switch (header->code)
1114  {
1115  case PSN_QUERYINITIALFOCUS:
1116  {
1117  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_ENABLEGROWL));
1118  }
1119  return TRUE;
1120  case PSN_APPLY:
1121  {
1122  PhSetIntegerSetting(SETTING_NAME_ENABLE_GROWL, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL)) == BST_CHECKED);
1123 
1126 
1127  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
1128  }
1129  return TRUE;
1130  }
1131  }
1132  break;
1133  }
1134 
1135  return FALSE;
1136 }