/* * Process Hacker Extended Notifications - * main program * * Copyright (C) 2010-2011 wj32 * * This file is part of Process Hacker. * * Process Hacker is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Process Hacker is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Process Hacker. If not, see . */ #include #include #include #include "extnoti.h" #include "resource.h" #include "gntp-send/growl.h" VOID NTAPI LoadCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ); VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ); VOID NTAPI NotifyEventCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ); VOID RegisterGrowl( _In_ BOOLEAN Force ); VOID NotifyGrowl( _In_ PPH_PLUGIN_NOTIFY_EVENT NotifyEvent ); NTSTATUS NTAPI RegisterGrowlCallback( _In_ PVOID Parameter ); INT_PTR CALLBACK ProcessesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ); INT_PTR CALLBACK ServicesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ); INT_PTR CALLBACK LoggingDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ); INT_PTR CALLBACK GrowlDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ); PPH_PLUGIN PluginInstance; PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; PH_CALLBACK_REGISTRATION NotifyEventCallbackRegistration; PPH_LIST ProcessFilterList; PPH_LIST ServiceFilterList; PSTR GrowlNotifications[] = { "Process Created", "Process Terminated", "Service Created", "Service Deleted", "Service Started", "Service Stopped" }; LOGICAL DllMain( _In_ HINSTANCE Instance, _In_ ULONG Reason, _Reserved_ PVOID Reserved ) { switch (Reason) { case DLL_PROCESS_ATTACH: { PPH_PLUGIN_INFORMATION info; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); if (!PluginInstance) return FALSE; info->DisplayName = L"Extended Notifications"; info->Author = L"wj32"; info->Description = L"Filters notifications."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1112"; info->HasOptions = TRUE; PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackLoad), LoadCallback, NULL, &PluginLoadCallbackRegistration ); PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration ); PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackNotifyEvent), NotifyEventCallback, NULL, &NotifyEventCallbackRegistration ); { static PH_SETTING_CREATE settings[] = { { IntegerSettingType, SETTING_NAME_ENABLE_GROWL, L"0" }, { StringSettingType, SETTING_NAME_LOG_FILENAME, L"" }, { StringSettingType, SETTING_NAME_PROCESS_LIST, L"\\i*" }, { StringSettingType, SETTING_NAME_SERVICE_LIST, L"\\i*" } }; PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); } ProcessFilterList = PhCreateList(10); ServiceFilterList = PhCreateList(10); } break; } return TRUE; } VOID FreeFilterEntry( _In_ PFILTER_ENTRY Entry ) { PhDereferenceObject(Entry->Filter); PhFree(Entry); } VOID ClearFilterList( _Inout_ PPH_LIST FilterList ) { ULONG i; for (i = 0; i < FilterList->Count; i++) FreeFilterEntry(FilterList->Items[i]); PhClearList(FilterList); } VOID CopyFilterList( _Inout_ PPH_LIST Destination, _In_ PPH_LIST Source ) { ULONG i; for (i = 0; i < Source->Count; i++) { PFILTER_ENTRY entry = Source->Items[i]; PFILTER_ENTRY newEntry; newEntry = PhAllocate(sizeof(FILTER_ENTRY)); newEntry->Type = entry->Type; newEntry->Filter = entry->Filter; PhReferenceObject(newEntry->Filter); PhAddItemList(Destination, newEntry); } } VOID LoadFilterList( _Inout_ PPH_LIST FilterList, _In_ PPH_STRING String ) { PH_STRING_BUILDER stringBuilder; SIZE_T length; SIZE_T i; PFILTER_ENTRY entry; length = String->Length / 2; PhInitializeStringBuilder(&stringBuilder, 20); entry = NULL; for (i = 0; i < length; i++) { if (String->Buffer[i] == '\\') { if (i != length - 1) { i++; switch (String->Buffer[i]) { case 'i': case 'e': if (entry) { entry->Filter = PhFinalStringBuilderString(&stringBuilder); PhAddItemList(FilterList, entry); PhInitializeStringBuilder(&stringBuilder, 20); } entry = PhAllocate(sizeof(FILTER_ENTRY)); entry->Type = String->Buffer[i] == 'i' ? FilterInclude : FilterExclude; break; default: PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]); break; } } else { // Trailing backslash. Just ignore it. break; } } else { PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]); } } if (entry) { entry->Filter = PhFinalStringBuilderString(&stringBuilder); PhAddItemList(FilterList, entry); } else { PhDeleteStringBuilder(&stringBuilder); } } PPH_STRING SaveFilterList( _Inout_ PPH_LIST FilterList ) { PH_STRING_BUILDER stringBuilder; SIZE_T i; SIZE_T j; WCHAR temp[2]; PhInitializeStringBuilder(&stringBuilder, 100); temp[0] = '\\'; for (i = 0; i < FilterList->Count; i++) { PFILTER_ENTRY entry = FilterList->Items[i]; SIZE_T length; // Write the entry type. temp[1] = entry->Type == FilterInclude ? 'i' : 'e'; PhAppendStringBuilderEx(&stringBuilder, temp, 4); // Write the filter string. length = entry->Filter->Length / 2; for (j = 0; j < length; j++) { if (entry->Filter->Buffer[j] == '\\') // escape backslashes { temp[1] = entry->Filter->Buffer[j]; PhAppendStringBuilderEx(&stringBuilder, temp, 4); } else { PhAppendCharStringBuilder(&stringBuilder, entry->Filter->Buffer[j]); } } } return PhFinalStringBuilderString(&stringBuilder); } VOID NTAPI LoadCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { LoadFilterList(ProcessFilterList, PhaGetStringSetting(SETTING_NAME_PROCESS_LIST)); LoadFilterList(ServiceFilterList, PhaGetStringSetting(SETTING_NAME_SERVICE_LIST)); FileLogInitialization(); if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) { PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), RegisterGrowlCallback, NULL); } } VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; PROPSHEETPAGE propSheetPage; HPROPSHEETPAGE pages[4]; propSheetHeader.dwFlags = PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_PROPTITLE; propSheetHeader.hwndParent = (HWND)Parameter; propSheetHeader.pszCaption = L"Extended Notifications"; propSheetHeader.nPages = 0; propSheetHeader.nStartPage = 0; propSheetHeader.phpage = pages; // Processes memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.hInstance = PluginInstance->DllBase; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PROCESSES); propSheetPage.pfnDlgProc = ProcessesDlgProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); // Services memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.hInstance = PluginInstance->DllBase; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SERVICES); propSheetPage.pfnDlgProc = ServicesDlgProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); // Logging memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.hInstance = PluginInstance->DllBase; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_LOGGING); propSheetPage.pfnDlgProc = LoggingDlgProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); // Growl memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.hInstance = PluginInstance->DllBase; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_GROWL); propSheetPage.pfnDlgProc = GrowlDlgProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); PhModalPropertySheet(&propSheetHeader); } BOOLEAN MatchFilterList( _In_ PPH_LIST FilterList, _In_ PPH_STRING String, _Out_ FILTER_TYPE *FilterType ) { ULONG i; BOOLEAN isFileName; isFileName = PhFindCharInString(String, 0, '\\') != -1; for (i = 0; i < FilterList->Count; i++) { PFILTER_ENTRY entry = FilterList->Items[i]; if (isFileName && PhFindCharInString(entry->Filter, 0, '\\') == -1) continue; // ignore filters without backslashes if we're matching a file name if (entry->Filter->Length == 2 && entry->Filter->Buffer[0] == '*') // shortcut { *FilterType = entry->Type; return TRUE; } if (PhMatchWildcards(entry->Filter->Buffer, String->Buffer, TRUE)) { *FilterType = entry->Type; return TRUE; } } return FALSE; } VOID NTAPI NotifyEventCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_PLUGIN_NOTIFY_EVENT notifyEvent = Parameter; PPH_PROCESS_ITEM processItem; PPH_SERVICE_ITEM serviceItem; FILTER_TYPE filterType; BOOLEAN found = FALSE; filterType = FilterExclude; switch (notifyEvent->Type) { case PH_NOTIFY_PROCESS_CREATE: case PH_NOTIFY_PROCESS_DELETE: processItem = notifyEvent->Parameter; if (processItem->FileName) found = MatchFilterList(ProcessFilterList, processItem->FileName, &filterType); if (!found) MatchFilterList(ProcessFilterList, processItem->ProcessName, &filterType); break; case PH_NOTIFY_SERVICE_CREATE: case PH_NOTIFY_SERVICE_DELETE: case PH_NOTIFY_SERVICE_START: case PH_NOTIFY_SERVICE_STOP: serviceItem = notifyEvent->Parameter; MatchFilterList(ServiceFilterList, serviceItem->Name, &filterType); break; } if (filterType == FilterExclude) notifyEvent->Handled = TRUE; // pretend we handled the notification to prevent it from displaying if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) NotifyGrowl(notifyEvent); } VOID RegisterGrowl( _In_ BOOLEAN Force ) { static BOOLEAN registered = FALSE; if (!Force && registered) return; growl_tcp_register("127.0.0.1", "Process Hacker", GrowlNotifications, sizeof(GrowlNotifications) / sizeof(PSTR), NULL, NULL); registered = TRUE; } VOID NotifyGrowl( _In_ PPH_PLUGIN_NOTIFY_EVENT NotifyEvent ) { PSTR notification; PPH_STRING title; PPH_BYTES titleUtf8; PPH_STRING message; PPH_BYTES messageUtf8; PPH_PROCESS_ITEM processItem; PPH_SERVICE_ITEM serviceItem; PPH_PROCESS_ITEM parentProcessItem; if (NotifyEvent->Handled) return; switch (NotifyEvent->Type) { case PH_NOTIFY_PROCESS_CREATE: processItem = NotifyEvent->Parameter; notification = GrowlNotifications[0]; title = processItem->ProcessName; parentProcessItem = PhReferenceProcessItemForParent( processItem->ParentProcessId, processItem->ProcessId, &processItem->CreateTime ); message = PhaFormatString( L"The process %s (%lu) was started by %s.", processItem->ProcessName->Buffer, HandleToUlong(processItem->ProcessId), parentProcessItem ? parentProcessItem->ProcessName->Buffer : L"an unknown process" ); if (parentProcessItem) PhDereferenceObject(parentProcessItem); break; case PH_NOTIFY_PROCESS_DELETE: processItem = NotifyEvent->Parameter; notification = GrowlNotifications[1]; title = processItem->ProcessName; message = PhaFormatString(L"The process %s (%lu) was terminated.", processItem->ProcessName->Buffer, HandleToUlong(processItem->ProcessId) ); break; case PH_NOTIFY_SERVICE_CREATE: serviceItem = NotifyEvent->Parameter; notification = GrowlNotifications[2]; title = serviceItem->DisplayName; message = PhaFormatString(L"The service %s (%s) has been created.", serviceItem->Name->Buffer, serviceItem->DisplayName->Buffer ); break; case PH_NOTIFY_SERVICE_DELETE: serviceItem = NotifyEvent->Parameter; notification = GrowlNotifications[3]; title = serviceItem->DisplayName; message = PhaFormatString(L"The service %s (%s) has been deleted.", serviceItem->Name->Buffer, serviceItem->DisplayName->Buffer ); break; case PH_NOTIFY_SERVICE_START: serviceItem = NotifyEvent->Parameter; notification = GrowlNotifications[4]; title = serviceItem->DisplayName; message = PhaFormatString(L"The service %s (%s) has been started.", serviceItem->Name->Buffer, serviceItem->DisplayName->Buffer ); break; case PH_NOTIFY_SERVICE_STOP: serviceItem = NotifyEvent->Parameter; notification = GrowlNotifications[5]; title = serviceItem->DisplayName; message = PhaFormatString(L"The service %s (%s) has been stopped.", serviceItem->Name->Buffer, serviceItem->DisplayName->Buffer ); break; default: return; } titleUtf8 = PH_AUTO(PhConvertUtf16ToUtf8Ex(title->Buffer, title->Length)); messageUtf8 = PH_AUTO(PhConvertUtf16ToUtf8Ex(message->Buffer, message->Length)); RegisterGrowl(TRUE); if (growl_tcp_notify("127.0.0.1", "Process Hacker", notification, titleUtf8->Buffer, messageUtf8->Buffer, NULL, NULL, NULL) == 0) NotifyEvent->Handled = TRUE; } NTSTATUS NTAPI RegisterGrowlCallback( _In_ PVOID Parameter ) { RegisterGrowl(FALSE); return STATUS_SUCCESS; } PPH_STRING FormatFilterEntry( _In_ PFILTER_ENTRY Entry ) { return PhConcatStrings2(Entry->Type == FilterInclude ? L"[Include] " : L"[Exclude] ", Entry->Filter->Buffer); } VOID AddEntriesToListBox( _In_ HWND ListBox, _In_ PPH_LIST FilterList ) { ULONG i; for (i = 0; i < FilterList->Count; i++) { PFILTER_ENTRY entry = FilterList->Items[i]; ListBox_AddString(ListBox, PH_AUTO_T(PH_STRING, FormatFilterEntry(entry))->Buffer); } } PPH_LIST EditingProcessFilterList; PPH_LIST EditingServiceFilterList; LRESULT CALLBACK TextBoxSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, _In_ UINT_PTR uIdSubclass, _In_ ULONG_PTR dwRefData ) { switch (uMsg) { case WM_NCDESTROY: RemoveWindowSubclass(hWnd, TextBoxSubclassProc, uIdSubclass); break; case WM_GETDLGCODE: { if (wParam == VK_RETURN) return DLGC_WANTALLKEYS; } break; case WM_CHAR: { if (wParam == VK_RETURN) { SendMessage(GetParent(hWnd), WM_COMMAND, IDC_TEXT_RETURN, 0); return 0; } } break; } return DefSubclassProc(hWnd, uMsg, wParam, lParam); } VOID FixControlStates( _In_ HWND hwndDlg, _In_ HWND ListBox ) { ULONG i; ULONG count; i = ListBox_GetCurSel(ListBox); count = ListBox_GetCount(ListBox); EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), i != LB_ERR); EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), i != LB_ERR && i != 0); EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), i != LB_ERR && i != count - 1); } INT_PTR HandleCommonMessages( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, _In_ HWND ListBox, _In_ PPH_LIST FilterList ) { switch (uMsg) { case WM_INITDIALOG: { SetWindowSubclass(GetDlgItem(hwndDlg, IDC_TEXT), TextBoxSubclassProc, 0, 0); Button_SetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE), BST_CHECKED); FixControlStates(hwndDlg, ListBox); } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_LIST: { if (HIWORD(wParam) == LBN_SELCHANGE) { ULONG i; i = ListBox_GetCurSel(ListBox); if (i != LB_ERR) { PFILTER_ENTRY entry; entry = FilterList->Items[i]; SetDlgItemText(hwndDlg, IDC_TEXT, entry->Filter->Buffer); Button_SetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE), entry->Type == FilterInclude ? BST_CHECKED : BST_UNCHECKED); Button_SetCheck(GetDlgItem(hwndDlg, IDC_EXCLUDE), entry->Type == FilterExclude ? BST_CHECKED : BST_UNCHECKED); } FixControlStates(hwndDlg, ListBox); } } break; case IDC_ADD: case IDC_TEXT_RETURN: { ULONG i; PPH_STRING string; PFILTER_ENTRY entry = NULL; FILTER_TYPE type; PPH_STRING entryString; string = PhGetWindowText(GetDlgItem(hwndDlg, IDC_TEXT)); if (string->Length == 0) { PhDereferenceObject(string); return FALSE; } for (i = 0; i < FilterList->Count; i++) { entry = FilterList->Items[i]; if (PhEqualString(entry->Filter, string, TRUE)) break; } type = Button_GetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE)) == BST_CHECKED ? FilterInclude : FilterExclude; if (i == FilterList->Count) { // No existing entry, so add a new one. entry = PhAllocate(sizeof(FILTER_ENTRY)); entry->Type = type; entry->Filter = string; PhInsertItemList(FilterList, 0, entry); entryString = FormatFilterEntry(entry); ListBox_InsertString(ListBox, 0, entryString->Buffer); PhDereferenceObject(entryString); ListBox_SetCurSel(ListBox, 0); } else { entry->Type = type; PhDereferenceObject(entry->Filter); entry->Filter = string; ListBox_DeleteString(ListBox, i); entryString = FormatFilterEntry(entry); ListBox_InsertString(ListBox, i, entryString->Buffer); PhDereferenceObject(entryString); ListBox_SetCurSel(ListBox, i); } SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_TEXT), TRUE); Edit_SetSel(GetDlgItem(hwndDlg, IDC_TEXT), 0, -1); FixControlStates(hwndDlg, ListBox); } break; case IDC_REMOVE: { ULONG i; PFILTER_ENTRY entry; i = ListBox_GetCurSel(ListBox); if (i != LB_ERR) { entry = FilterList->Items[i]; FreeFilterEntry(entry); PhRemoveItemList(FilterList, i); ListBox_DeleteString(ListBox, i); if (i >= FilterList->Count) i = FilterList->Count - 1; ListBox_SetCurSel(ListBox, i); FixControlStates(hwndDlg, ListBox); } } break; case IDC_MOVEUP: { ULONG i; PFILTER_ENTRY entry; PPH_STRING entryString; i = ListBox_GetCurSel(ListBox); if (i != LB_ERR && i != 0) { entry = FilterList->Items[i]; PhRemoveItemList(FilterList, i); PhInsertItemList(FilterList, i - 1, entry); ListBox_DeleteString(ListBox, i); entryString = FormatFilterEntry(entry); ListBox_InsertString(ListBox, i - 1, entryString->Buffer); PhDereferenceObject(entryString); i--; ListBox_SetCurSel(ListBox, i); FixControlStates(hwndDlg, ListBox); } } break; case IDC_MOVEDOWN: { ULONG i; PFILTER_ENTRY entry; PPH_STRING entryString; i = ListBox_GetCurSel(ListBox); if (i != LB_ERR && i != FilterList->Count - 1) { entry = FilterList->Items[i]; PhRemoveItemList(FilterList, i); PhInsertItemList(FilterList, i + 1, entry); ListBox_DeleteString(ListBox, i); entryString = FormatFilterEntry(entry); ListBox_InsertString(ListBox, i + 1, entryString->Buffer); PhDereferenceObject(entryString); i++; ListBox_SetCurSel(ListBox, i); FixControlStates(hwndDlg, ListBox); } } break; } } break; } return FALSE; } INT_PTR CALLBACK ProcessesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { INT_PTR result; if (result = HandleCommonMessages(hwndDlg, uMsg, wParam, lParam, GetDlgItem(hwndDlg, IDC_LIST), EditingProcessFilterList)) return result; switch (uMsg) { case WM_INITDIALOG: { EditingProcessFilterList = PhCreateList(ProcessFilterList->Count + 10); CopyFilterList(EditingProcessFilterList, ProcessFilterList); AddEntriesToListBox(GetDlgItem(hwndDlg, IDC_LIST), EditingProcessFilterList); } break; case WM_DESTROY: { ClearFilterList(EditingProcessFilterList); PhDereferenceObject(EditingProcessFilterList); EditingProcessFilterList = NULL; } break; case WM_COMMAND: { switch (LOWORD(wParam)) { NOTHING; } } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case PSN_APPLY: { PPH_STRING string; ClearFilterList(ProcessFilterList); CopyFilterList(ProcessFilterList, EditingProcessFilterList); string = SaveFilterList(ProcessFilterList); PhSetStringSetting2(SETTING_NAME_PROCESS_LIST, &string->sr); PhDereferenceObject(string); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); } return TRUE; } } break; } return FALSE; } INT_PTR CALLBACK ServicesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { if (HandleCommonMessages(hwndDlg, uMsg, wParam, lParam, GetDlgItem(hwndDlg, IDC_LIST), EditingServiceFilterList)) return FALSE; switch (uMsg) { case WM_INITDIALOG: { EditingServiceFilterList = PhCreateList(ServiceFilterList->Count + 10); CopyFilterList(EditingServiceFilterList, ServiceFilterList); AddEntriesToListBox(GetDlgItem(hwndDlg, IDC_LIST), EditingServiceFilterList); } break; case WM_DESTROY: { ClearFilterList(EditingServiceFilterList); PhDereferenceObject(EditingServiceFilterList); EditingServiceFilterList = NULL; } break; case WM_COMMAND: { switch (LOWORD(wParam)) { NOTHING; } } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case PSN_APPLY: { PPH_STRING string; ClearFilterList(ServiceFilterList); CopyFilterList(ServiceFilterList, EditingServiceFilterList); string = SaveFilterList(ServiceFilterList); PhSetStringSetting2(SETTING_NAME_SERVICE_LIST, &string->sr); PhDereferenceObject(string); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); } return TRUE; } } break; } return FALSE; } INT_PTR CALLBACK LoggingDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { SetDlgItemText(hwndDlg, IDC_LOGFILENAME, ((PPH_STRING)PH_AUTO(PhGetStringSetting(SETTING_NAME_LOG_FILENAME)))->Buffer); } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_BROWSE: { static PH_FILETYPE_FILTER filters[] = { { L"Log files (*.txt;*.log)", L"*.txt;*.log" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; PPH_STRING fileName; fileDialog = PhCreateSaveFileDialog(); PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_LOGFILENAME))); PhSetFileDialogFileName(fileDialog, fileName->Buffer); if (PhShowFileDialog(hwndDlg, fileDialog)) { fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); SetDlgItemText(hwndDlg, IDC_LOGFILENAME, fileName->Buffer); } PhFreeFileDialog(fileDialog); } break; } } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case PSN_APPLY: { PhSetStringSetting2(SETTING_NAME_LOG_FILENAME, &PhaGetDlgItemText(hwndDlg, IDC_LOGFILENAME)->sr); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); } return TRUE; } } break; } return FALSE; } INT_PTR CALLBACK GrowlDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { SetDlgItemText(hwndDlg, IDC_LICENSE, PH_AUTO_T(PH_STRING, PhConvertUtf8ToUtf16(gntp_send_license_text))->Buffer); Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL), PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL) ? BST_CHECKED : BST_UNCHECKED); } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case PSN_QUERYINITIALFOCUS: { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_ENABLEGROWL)); } return TRUE; case PSN_APPLY: { PhSetIntegerSetting(SETTING_NAME_ENABLE_GROWL, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL)) == BST_CHECKED); if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) RegisterGrowl(FALSE); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); } return TRUE; } } break; } return FALSE; }