2025-05-13 19:45:22 +03:00

1717 lines
51 KiB
C

/*
* Process Hacker User Notes -
* main program
*
* Copyright (C) 2011-2016 wj32
* Copyright (C) 2016 dmex
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "usernotes.h"
#include <toolstatusintf.h>
#include <commdlg.h>
VOID SearchChangedHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
static PPH_PLUGIN PluginInstance;
static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginMenuHookCallbackRegistration;
static PH_CALLBACK_REGISTRATION TreeNewMessageCallbackRegistration;
static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION GetProcessHighlightingColorCallbackRegistration;
static PH_CALLBACK_REGISTRATION ServiceTreeNewInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION MiListSectionMenuInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ProcessModifiedCallbackRegistration;
static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
static PH_CALLBACK_REGISTRATION SearchChangedRegistration;
static PTOOLSTATUS_INTERFACE ToolStatusInterface = NULL;
HWND ProcessTreeNewHandle;
LIST_ENTRY ProcessListHead = { &ProcessListHead, &ProcessListHead };
PH_QUEUED_LOCK ProcessListLock = PH_QUEUED_LOCK_INIT;
HWND ServiceTreeNewHandle;
LIST_ENTRY ServiceListHead = { &ServiceListHead, &ServiceListHead };
PH_QUEUED_LOCK ServiceListLock = PH_QUEUED_LOCK_INIT;
static COLORREF ProcessCustomColors[16] = { 0 };
BOOLEAN MatchDbObjectIntent(
_In_ PDB_OBJECT Object,
_In_ ULONG Intent
)
{
return (!(Intent & INTENT_PROCESS_COMMENT) || Object->Comment->Length != 0) &&
(!(Intent & INTENT_PROCESS_PRIORITY_CLASS) || Object->PriorityClass != 0) &&
(!(Intent & INTENT_PROCESS_IO_PRIORITY) || Object->IoPriorityPlusOne != 0) &&
(!(Intent & INTENT_PROCESS_HIGHLIGHT) || Object->BackColor != ULONG_MAX) &&
(!(Intent & INTENT_PROCESS_COLLAPSE) || Object->Collapse);
}
PDB_OBJECT FindDbObjectForProcess(
_In_ PPH_PROCESS_ITEM ProcessItem,
_In_ ULONG Intent
)
{
PDB_OBJECT object;
if (
ProcessItem->CommandLine &&
(object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) &&
MatchDbObjectIntent(object, Intent)
)
{
return object;
}
if (
(object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) &&
MatchDbObjectIntent(object, Intent)
)
{
return object;
}
return NULL;
}
VOID DeleteDbObjectForProcessIfUnused(
_In_ PDB_OBJECT Object
)
{
if (
Object->Comment->Length == 0 &&
Object->PriorityClass == 0 &&
Object->IoPriorityPlusOne == 0 &&
Object->BackColor == ULONG_MAX &&
!Object->Collapse
)
{
DeleteDbObject(Object);
}
}
VOID LoadCustomColors(
VOID
)
{
PPH_STRING settingsString;
PH_STRINGREF remaining;
PH_STRINGREF part;
settingsString = PhaGetStringSetting(SETTING_NAME_CUSTOM_COLOR_LIST);
remaining = settingsString->sr;
if (remaining.Length == 0)
return;
for (ULONG i = 0; i < ARRAYSIZE(ProcessCustomColors); i++)
{
ULONG64 integer = 0;
if (remaining.Length == 0)
break;
PhSplitStringRefAtChar(&remaining, ',', &part, &remaining);
if (PhStringToInteger64(&part, 10, &integer))
{
ProcessCustomColors[i] = (COLORREF)integer;
}
}
}
PPH_STRING SaveCustomColors(
VOID
)
{
PH_STRING_BUILDER stringBuilder;
PhInitializeStringBuilder(&stringBuilder, 100);
for (ULONG i = 0; i < ARRAYSIZE(ProcessCustomColors); i++)
{
PhAppendFormatStringBuilder(
&stringBuilder,
L"%lu,",
ProcessCustomColors[i]
);
}
if (stringBuilder.String->Length != 0)
PhRemoveEndStringBuilder(&stringBuilder, 1);
return PhFinalStringBuilderString(&stringBuilder);
}
IO_PRIORITY_HINT GetProcessIoPriority(
_In_ HANDLE ProcessId
)
{
HANDLE processHandle;
IO_PRIORITY_HINT ioPriority = -1;
if (NT_SUCCESS(PhOpenProcess(
&processHandle,
ProcessQueryAccess,
ProcessId
)))
{
if (!NT_SUCCESS(PhGetProcessIoPriority(
processHandle,
&ioPriority
)))
{
ioPriority = -1;
}
NtClose(processHandle);
}
return ioPriority;
}
ULONG GetPriorityClassFromId(
_In_ ULONG Id
)
{
switch (Id)
{
case PHAPP_ID_PRIORITY_REALTIME:
return PROCESS_PRIORITY_CLASS_REALTIME;
case PHAPP_ID_PRIORITY_HIGH:
return PROCESS_PRIORITY_CLASS_HIGH;
case PHAPP_ID_PRIORITY_ABOVENORMAL:
return PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
case PHAPP_ID_PRIORITY_NORMAL:
return PROCESS_PRIORITY_CLASS_NORMAL;
case PHAPP_ID_PRIORITY_BELOWNORMAL:
return PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
case PHAPP_ID_PRIORITY_IDLE:
return PROCESS_PRIORITY_CLASS_IDLE;
}
return 0;
}
ULONG GetIoPriorityFromId(
_In_ ULONG Id
)
{
switch (Id)
{
case PHAPP_ID_IOPRIORITY_VERYLOW:
return 0;
case PHAPP_ID_IOPRIORITY_LOW:
return 1;
case PHAPP_ID_IOPRIORITY_NORMAL:
return 2;
case PHAPP_ID_IOPRIORITY_HIGH:
return 3;
}
return -1;
}
VOID NTAPI LoadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN toolStatusPlugin;
PPH_STRING path;
if (toolStatusPlugin = PhFindPlugin(TOOLSTATUS_PLUGIN_NAME))
{
ToolStatusInterface = PhGetPluginInformation(toolStatusPlugin)->Interface;
if (ToolStatusInterface->Version < TOOLSTATUS_INTERFACE_VERSION)
ToolStatusInterface = NULL;
}
path = PhaGetStringSetting(SETTING_NAME_DATABASE_PATH);
path = PH_AUTO(PhExpandEnvironmentStrings(&path->sr));
LoadCustomColors();
if (RtlDetermineDosPathNameType_U(path->Buffer) == RtlPathTypeRelative)
{
PPH_STRING directory;
directory = PH_AUTO(PhGetApplicationDirectory());
path = PH_AUTO(PhConcatStringRef2(&directory->sr, &path->sr));
}
SetDbPath(path);
LoadDb();
}
VOID NTAPI UnloadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
SaveDb();
}
VOID NTAPI ShowOptionsCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
DialogBox(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_OPTIONS),
(HWND)Parameter,
OptionsDlgProc
);
}
VOID NTAPI MenuItemCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_ITEM menuItem = Parameter;
PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();
PDB_OBJECT object;
if (!processItem)
return;
switch (menuItem->Id)
{
case PROCESS_PRIORITY_SAVE_ID:
{
LockDb();
if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->PriorityClass != 0)
{
object->PriorityClass = 0;
DeleteDbObjectForProcessIfUnused(object);
}
else
{
object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL);
object->PriorityClass = processItem->PriorityClass;
}
UnlockDb();
SaveDb();
}
break;
case PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID:
{
if (processItem->CommandLine)
{
LockDb();
if ((object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->PriorityClass != 0)
{
object->PriorityClass = 0;
DeleteDbObjectForProcessIfUnused(object);
}
else
{
object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL);
object->PriorityClass = processItem->PriorityClass;
}
UnlockDb();
SaveDb();
}
}
break;
case PROCESS_IO_PRIORITY_SAVE_ID:
{
LockDb();
if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->IoPriorityPlusOne != 0)
{
object->IoPriorityPlusOne = 0;
DeleteDbObjectForProcessIfUnused(object);
}
else
{
object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL);
object->IoPriorityPlusOne = GetProcessIoPriority(processItem->ProcessId) + 1;
}
UnlockDb();
SaveDb();
}
break;
case PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID:
{
if (processItem->CommandLine)
{
LockDb();
if ((object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->IoPriorityPlusOne != 0)
{
object->IoPriorityPlusOne = 0;
DeleteDbObjectForProcessIfUnused(object);
}
else
{
object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL);
object->IoPriorityPlusOne = GetProcessIoPriority(processItem->ProcessId) + 1;
}
UnlockDb();
SaveDb();
}
}
break;
case PROCESS_HIGHLIGHT_ID:
{
BOOLEAN highlightPresent = (BOOLEAN)menuItem->Context;
if (!highlightPresent)
{
CHOOSECOLOR chooseColor = { sizeof(CHOOSECOLOR) };
chooseColor.hwndOwner = PhMainWndHandle;
chooseColor.lpCustColors = ProcessCustomColors;
chooseColor.lpfnHook = ColorDlgHookProc;
chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_SOLIDCOLOR | CC_ENABLEHOOK;
if (ChooseColor(&chooseColor))
{
PhSetStringSetting2(SETTING_NAME_CUSTOM_COLOR_LIST, &PH_AUTO_T(PH_STRING, SaveCustomColors())->sr);
LockDb();
object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL);
object->BackColor = chooseColor.rgbResult;
UnlockDb();
SaveDb();
}
}
else
{
LockDb();
if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->BackColor != ULONG_MAX)
{
object->BackColor = ULONG_MAX;
DeleteDbObjectForProcessIfUnused(object);
}
UnlockDb();
SaveDb();
}
PhInvalidateAllProcessNodes();
}
break;
case PROCESS_COLLAPSE_ID:
{
LockDb();
if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->Collapse)
{
object->Collapse = FALSE;
DeleteDbObjectForProcessIfUnused(object);
}
else
{
object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL);
object->Collapse = TRUE;
}
UnlockDb();
SaveDb();
}
break;
}
}
VOID NTAPI MenuHookCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_HOOK_INFORMATION menuHookInfo = Parameter;
ULONG id = menuHookInfo->SelectedItem->Id;
switch (id)
{
case PHAPP_ID_PRIORITY_REALTIME:
case PHAPP_ID_PRIORITY_HIGH:
case PHAPP_ID_PRIORITY_ABOVENORMAL:
case PHAPP_ID_PRIORITY_NORMAL:
case PHAPP_ID_PRIORITY_BELOWNORMAL:
case PHAPP_ID_PRIORITY_IDLE:
{
BOOLEAN changed = FALSE;
PPH_PROCESS_ITEM *processes;
ULONG numberOfProcesses;
ULONG i;
PhGetSelectedProcessItems(&processes, &numberOfProcesses);
LockDb();
for (i = 0; i < numberOfProcesses; i++)
{
PDB_OBJECT object;
if (object = FindDbObjectForProcess(processes[i], INTENT_PROCESS_PRIORITY_CLASS))
{
ULONG newPriorityClass = GetPriorityClassFromId(id);
if (object->PriorityClass != newPriorityClass)
{
object->PriorityClass = newPriorityClass;
changed = TRUE;
}
}
}
UnlockDb();
PhFree(processes);
if (changed)
SaveDb();
}
break;
case PHAPP_ID_IOPRIORITY_VERYLOW:
case PHAPP_ID_IOPRIORITY_LOW:
case PHAPP_ID_IOPRIORITY_NORMAL:
case PHAPP_ID_IOPRIORITY_HIGH:
{
BOOLEAN changed = FALSE;
PPH_PROCESS_ITEM *processes;
ULONG numberOfProcesses;
ULONG i;
PhGetSelectedProcessItems(&processes, &numberOfProcesses);
LockDb();
for (i = 0; i < numberOfProcesses; i++)
{
PDB_OBJECT object;
if (object = FindDbObjectForProcess(processes[i], INTENT_PROCESS_IO_PRIORITY))
{
ULONG newIoPriorityPlusOne = GetIoPriorityFromId(id) + 1;
if (object->IoPriorityPlusOne != newIoPriorityPlusOne)
{
object->IoPriorityPlusOne = newIoPriorityPlusOne;
changed = TRUE;
}
}
}
UnlockDb();
PhFree(processes);
if (changed)
SaveDb();
}
break;
}
}
VOID InvalidateProcessComments(
VOID
)
{
PLIST_ENTRY listEntry;
PhAcquireQueuedLockExclusive(&ProcessListLock);
listEntry = ProcessListHead.Flink;
while (listEntry != &ProcessListHead)
{
PPROCESS_EXTENSION extension;
extension = CONTAINING_RECORD(listEntry, PROCESS_EXTENSION, ListEntry);
extension->Valid = FALSE;
listEntry = listEntry->Flink;
}
PhReleaseQueuedLockExclusive(&ProcessListLock);
}
VOID UpdateProcessComment(
_In_ PPH_PROCESS_NODE Node,
_In_ PPROCESS_EXTENSION Extension
)
{
if (!Extension->Valid)
{
PDB_OBJECT object;
LockDb();
if (object = FindDbObjectForProcess(Node->ProcessItem, INTENT_PROCESS_COMMENT))
{
PhSwapReference(&Extension->Comment, object->Comment);
}
else
{
PhClearReference(&Extension->Comment);
}
UnlockDb();
Extension->Valid = TRUE;
}
}
VOID InvalidateServiceComments(
VOID
)
{
PLIST_ENTRY listEntry;
PhAcquireQueuedLockExclusive(&ServiceListLock);
listEntry = ServiceListHead.Flink;
while (listEntry != &ServiceListHead)
{
PSERVICE_EXTENSION extension;
extension = CONTAINING_RECORD(listEntry, SERVICE_EXTENSION, ListEntry);
extension->Valid = FALSE;
listEntry = listEntry->Flink;
}
PhReleaseQueuedLockExclusive(&ServiceListLock);
}
VOID UpdateServiceComment(
_In_ PPH_SERVICE_NODE Node,
_In_ PSERVICE_EXTENSION Extension
)
{
if (!Extension->Valid)
{
PDB_OBJECT object;
LockDb();
if (object = FindDbObject(SERVICE_TAG, &Node->ServiceItem->Name->sr))
{
PhSwapReference(&Extension->Comment, object->Comment);
}
else
{
PhClearReference(&Extension->Comment);
}
UnlockDb();
Extension->Valid = TRUE;
}
}
VOID TreeNewMessageCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_TREENEW_MESSAGE message = Parameter;
switch (message->Message)
{
case TreeNewGetCellText:
{
PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1;
if (message->TreeNewHandle == ProcessTreeNewHandle)
{
PPH_PROCESS_NODE node;
node = (PPH_PROCESS_NODE)getCellText->Node;
switch (message->SubId)
{
case COMMENT_COLUMN_ID:
{
PPROCESS_EXTENSION extension;
extension = PhPluginGetObjectExtension(PluginInstance, node->ProcessItem, EmProcessItemType);
UpdateProcessComment(node, extension);
getCellText->Text = PhGetStringRef(extension->Comment);
}
break;
}
}
else if (message->TreeNewHandle == ServiceTreeNewHandle)
{
PPH_SERVICE_NODE node;
node = (PPH_SERVICE_NODE)getCellText->Node;
switch (message->SubId)
{
case COMMENT_COLUMN_ID:
{
PSERVICE_EXTENSION extension;
extension = PhPluginGetObjectExtension(PluginInstance, node->ServiceItem, EmServiceItemType);
UpdateServiceComment(node, extension);
getCellText->Text = PhGetStringRef(extension->Comment);
}
break;
}
}
}
break;
}
}
VOID MainWindowShowingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
if (ToolStatusInterface)
{
PhRegisterCallback(ToolStatusInterface->SearchChangedEvent, SearchChangedHandler, NULL, &SearchChangedRegistration);
}
}
VOID ProcessPropertiesInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter;
PhAddProcessPropPage(
propContext->PropContext,
PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCCOMMENT), ProcessCommentPageDlgProc, NULL)
);
}
VOID AddSavePriorityMenuItemsAndHook(
_In_ PPH_PLUGIN_MENU_INFORMATION MenuInfo,
_In_ PPH_PROCESS_ITEM ProcessItem,
_In_ BOOLEAN UseSelectionForHook
)
{
PPH_EMENU_ITEM priorityMenuItem;
PPH_EMENU_ITEM ioPriorityMenuItem;
PPH_EMENU_ITEM saveMenuItem;
PPH_EMENU_ITEM saveForCommandLineMenuItem;
PDB_OBJECT object;
// Priority
if (priorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"Priority", 0))
{
PhInsertEMenuItem(priorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1);
PhInsertEMenuItem(priorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1);
PhInsertEMenuItem(priorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1);
if (!ProcessItem->CommandLine)
saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED;
LockDb();
if ((object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) && object->PriorityClass != 0)
saveMenuItem->Flags |= PH_EMENU_CHECKED;
if (ProcessItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) && object->PriorityClass != 0)
saveForCommandLineMenuItem->Flags |= PH_EMENU_CHECKED;
UnlockDb();
}
// I/O Priority
if (ioPriorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"I/O Priority", 0))
{
PhInsertEMenuItem(ioPriorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1);
PhInsertEMenuItem(ioPriorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1);
PhInsertEMenuItem(ioPriorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1);
if (!ProcessItem->CommandLine)
saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED;
LockDb();
if ((object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) && object->IoPriorityPlusOne != 0)
saveMenuItem->Flags |= PH_EMENU_CHECKED;
if (ProcessItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) && object->IoPriorityPlusOne != 0)
saveForCommandLineMenuItem->Flags |= PH_EMENU_CHECKED;
UnlockDb();
}
PhPluginAddMenuHook(MenuInfo, PluginInstance, UseSelectionForHook ? NULL : ProcessItem->ProcessId);
}
VOID ProcessMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
PPH_PROCESS_ITEM processItem;
PPH_EMENU_ITEM miscMenuItem;
BOOLEAN highlightPresent = FALSE;
PPH_EMENU_ITEM collapseMenuItem;
PPH_EMENU_ITEM highlightMenuItem;
PDB_OBJECT object;
if (menuInfo->u.Process.NumberOfProcesses != 1)
return;
processItem = menuInfo->u.Process.Processes[0];
if (PH_IS_FAKE_PROCESS_ID(processItem->ProcessId) || processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID || processItem->ProcessId == SYSTEM_PROCESS_ID)
return;
AddSavePriorityMenuItemsAndHook(menuInfo, processItem, TRUE);
if (!(miscMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Miscellaneous", 0)))
return;
LockDb();
if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->BackColor != ULONG_MAX)
highlightPresent = TRUE;
UnlockDb();
PhInsertEMenuItem(miscMenuItem, collapseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_COLLAPSE_ID, L"Collapse by default", NULL), 0);
PhInsertEMenuItem(miscMenuItem, highlightMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_HIGHLIGHT_ID, L"Highlight", UlongToPtr(highlightPresent)), 1);
PhInsertEMenuItem(miscMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), 2);
LockDb();
if ((object = FindDbObject(FILE_TAG, &menuInfo->u.Process.Processes[0]->ProcessName->sr)) && object->Collapse)
collapseMenuItem->Flags |= PH_EMENU_CHECKED;
if (highlightPresent)
highlightMenuItem->Flags |= PH_EMENU_CHECKED;
UnlockDb();
}
static LONG NTAPI ProcessCommentSortFunction(
_In_ PVOID Node1,
_In_ PVOID Node2,
_In_ ULONG SubId,
_In_ PVOID Context
)
{
PPH_PROCESS_NODE node1 = Node1;
PPH_PROCESS_NODE node2 = Node2;
PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ProcessItem, EmProcessItemType);
PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ProcessItem, EmProcessItemType);
UpdateProcessComment(node1, extension1);
UpdateProcessComment(node2, extension2);
return PhCompareStringWithNull(extension1->Comment, extension2->Comment, TRUE);
}
VOID ProcessTreeNewInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_TREENEW_INFORMATION info = Parameter;
PH_TREENEW_COLUMN column;
ProcessTreeNewHandle = info->TreeNewHandle;
memset(&column, 0, sizeof(PH_TREENEW_COLUMN));
column.Text = L"Comment";
column.Width = 120;
column.Alignment = PH_ALIGN_LEFT;
PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COMMENT_COLUMN_ID, NULL, ProcessCommentSortFunction);
}
VOID GetProcessHighlightingColorCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter;
PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)getHighlightingColor->Parameter;
PDB_OBJECT object;
if (getHighlightingColor->Handled)
return;
LockDb();
if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->BackColor != ULONG_MAX)
{
getHighlightingColor->BackColor = object->BackColor;
getHighlightingColor->Cache = TRUE;
getHighlightingColor->Handled = TRUE;
}
UnlockDb();
}
VOID ServicePropertiesInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter;
PROPSHEETPAGE propSheetPage;
if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages)
{
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
propSheetPage.dwFlags = PSP_USETITLE;
propSheetPage.hInstance = PluginInstance->DllBase;
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVCOMMENT);
propSheetPage.pszTitle = L"Comment";
propSheetPage.pfnDlgProc = ServiceCommentPageDlgProc;
propSheetPage.lParam = (LPARAM)objectProperties->Parameter;
objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage);
}
}
LONG NTAPI ServiceCommentSortFunction(
_In_ PVOID Node1,
_In_ PVOID Node2,
_In_ ULONG SubId,
_In_ PVOID Context
)
{
PPH_SERVICE_NODE node1 = Node1;
PPH_SERVICE_NODE node2 = Node2;
PSERVICE_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ServiceItem, EmServiceItemType);
PSERVICE_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ServiceItem, EmServiceItemType);
UpdateServiceComment(node1, extension1);
UpdateServiceComment(node2, extension2);
return PhCompareStringWithNull(extension1->Comment, extension2->Comment, TRUE);
}
VOID ServiceTreeNewInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_TREENEW_INFORMATION info = Parameter;
PH_TREENEW_COLUMN column;
ServiceTreeNewHandle = info->TreeNewHandle;
memset(&column, 0, sizeof(PH_TREENEW_COLUMN));
column.Text = L"Comment";
column.Width = 120;
column.Alignment = PH_ALIGN_LEFT;
PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COMMENT_COLUMN_ID, NULL, ServiceCommentSortFunction);
}
VOID MiListSectionMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
PPH_PROCESS_ITEM processItem = menuInfo->u.MiListSection.ProcessGroup->Representative;
if (PH_IS_FAKE_PROCESS_ID(processItem->ProcessId) || processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID || processItem->ProcessId == SYSTEM_PROCESS_ID)
return;
AddSavePriorityMenuItemsAndHook(menuInfo, processItem, FALSE);
}
VOID ProcessModifiedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PROCESS_ITEM processItem = Parameter;
PPROCESS_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, processItem, EmProcessItemType);
extension->Valid = FALSE;
}
VOID ProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PLIST_ENTRY listEntry;
if (GetNumberOfDbObjects() == 0)
return;
PhAcquireQueuedLockExclusive(&ProcessListLock);
LockDb();
listEntry = ProcessListHead.Flink;
while (listEntry != &ProcessListHead)
{
PPROCESS_EXTENSION extension;
PPH_PROCESS_ITEM processItem;
PDB_OBJECT object;
extension = CONTAINING_RECORD(listEntry, PROCESS_EXTENSION, ListEntry);
processItem = extension->ProcessItem;
if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_PRIORITY_CLASS))
{
if (processItem->PriorityClass != object->PriorityClass)
{
HANDLE processHandle;
PROCESS_PRIORITY_CLASS priorityClass;
if (NT_SUCCESS(PhOpenProcess(
&processHandle,
PROCESS_SET_INFORMATION,
processItem->ProcessId
)))
{
priorityClass.Foreground = FALSE;
priorityClass.PriorityClass = (UCHAR)object->PriorityClass;
NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS));
NtClose(processHandle);
}
}
}
if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_IO_PRIORITY))
{
if (object->IoPriorityPlusOne != 0)
{
HANDLE processHandle;
if (NT_SUCCESS(PhOpenProcess(
&processHandle,
PROCESS_SET_INFORMATION,
processItem->ProcessId
)))
{
PhSetProcessIoPriority(processHandle, object->IoPriorityPlusOne - 1);
NtClose(processHandle);
}
}
}
listEntry = listEntry->Flink;
}
UnlockDb();
PhReleaseQueuedLockExclusive(&ProcessListLock);
}
VOID SearchChangedHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_STRING searchText = Parameter;
if (PhIsNullOrEmptyString(searchText))
{
// ToolStatus expanded all nodes for searching, but the search text just became empty. We
// should re-collapse processes.
PPH_LIST nodes = PH_AUTO(PhDuplicateProcessNodeList());
ULONG i;
BOOLEAN changed = FALSE;
LockDb();
for (i = 0; i < nodes->Count; i++)
{
PPH_PROCESS_NODE node = nodes->Items[i];
PDB_OBJECT object;
if ((object = FindDbObjectForProcess(node->ProcessItem, INTENT_PROCESS_COLLAPSE)) && object->Collapse)
{
node->Node.Expanded = FALSE;
changed = TRUE;
}
}
UnlockDb();
if (changed)
TreeNew_NodesStructured(ProcessTreeNewHandle);
}
}
VOID ProcessItemCreateCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
PPH_PROCESS_ITEM processItem = Object;
PPROCESS_EXTENSION extension = Extension;
memset(extension, 0, sizeof(PROCESS_EXTENSION));
extension->ProcessItem = processItem;
PhAcquireQueuedLockExclusive(&ProcessListLock);
InsertTailList(&ProcessListHead, &extension->ListEntry);
PhReleaseQueuedLockExclusive(&ProcessListLock);
}
VOID ProcessItemDeleteCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
PPH_PROCESS_ITEM processItem = Object;
PPROCESS_EXTENSION extension = Extension;
PhClearReference(&extension->Comment);
PhAcquireQueuedLockExclusive(&ProcessListLock);
RemoveEntryList(&extension->ListEntry);
PhReleaseQueuedLockExclusive(&ProcessListLock);
}
VOID ProcessNodeCreateCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
PPH_PROCESS_NODE processNode = Object;
PDB_OBJECT object;
LockDb();
if ((object = FindDbObjectForProcess(processNode->ProcessItem, INTENT_PROCESS_COLLAPSE)) && object->Collapse)
processNode->Node.Expanded = FALSE;
UnlockDb();
}
VOID ServiceItemCreateCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
PPH_SERVICE_ITEM processItem = Object;
PSERVICE_EXTENSION extension = Extension;
memset(extension, 0, sizeof(SERVICE_EXTENSION));
PhAcquireQueuedLockExclusive(&ServiceListLock);
InsertTailList(&ServiceListHead, &extension->ListEntry);
PhReleaseQueuedLockExclusive(&ServiceListLock);
}
VOID ServiceItemDeleteCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
PPH_SERVICE_ITEM processItem = Object;
PSERVICE_EXTENSION extension = Extension;
PhClearReference(&extension->Comment);
PhAcquireQueuedLockExclusive(&ServiceListLock);
RemoveEntryList(&extension->ListEntry);
PhReleaseQueuedLockExclusive(&ServiceListLock);
}
LOGICAL DllMain(
_In_ HINSTANCE Instance,
_In_ ULONG Reason,
_Reserved_ PVOID Reserved
)
{
if (Reason == DLL_PROCESS_ATTACH)
{
PPH_PLUGIN_INFORMATION info;
PH_SETTING_CREATE settings[] =
{
{ StringSettingType, SETTING_NAME_DATABASE_PATH, L"%APPDATA%\\Process Hacker 2\\usernotesdb.xml" },
{ StringSettingType, SETTING_NAME_CUSTOM_COLOR_LIST, L"" }
};
PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info);
if (!PluginInstance)
return FALSE;
info->DisplayName = L"User Notes";
info->Author = L"dmex, wj32";
info->Description = L"Allows the user to add comments for processes and services. Also allows the user to save process priority. Also allows the user to highlight individual processes.";
info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1120";
info->HasOptions = TRUE;
InitializeDb();
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackLoad),
LoadCallback,
NULL,
&PluginLoadCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackUnload),
UnloadCallback,
NULL,
&PluginUnloadCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions),
ShowOptionsCallback,
NULL,
&PluginShowOptionsCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem),
MenuItemCallback,
NULL,
&PluginMenuItemCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackMenuHook),
MenuHookCallback,
NULL,
&PluginMenuHookCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage),
TreeNewMessageCallback,
NULL,
&TreeNewMessageCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackMainWindowShowing),
MainWindowShowingCallback,
NULL,
&MainWindowShowingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing),
ProcessPropertiesInitializingCallback,
NULL,
&ProcessPropertiesInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing),
ServicePropertiesInitializingCallback,
NULL,
&ServicePropertiesInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing),
ProcessMenuInitializingCallback,
NULL,
&ProcessMenuInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing),
ProcessTreeNewInitializingCallback,
NULL,
&ProcessTreeNewInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor),
GetProcessHighlightingColorCallback,
NULL,
&GetProcessHighlightingColorCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing),
ServiceTreeNewInitializingCallback,
NULL,
&ServiceTreeNewInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackMiListSectionMenuInitializing),
MiListSectionMenuInitializingCallback,
NULL,
&MiListSectionMenuInitializingCallbackRegistration
);
PhRegisterCallback(&PhProcessModifiedEvent,
ProcessModifiedCallback,
NULL,
&ProcessModifiedCallbackRegistration
);
PhRegisterCallback(
&PhProcessesUpdatedEvent,
ProcessesUpdatedCallback,
NULL,
&ProcessesUpdatedCallbackRegistration
);
PhPluginSetObjectExtension(
PluginInstance,
EmProcessItemType,
sizeof(PROCESS_EXTENSION),
ProcessItemCreateCallback,
ProcessItemDeleteCallback
);
PhPluginSetObjectExtension(
PluginInstance,
EmProcessNodeType,
sizeof(PROCESS_EXTENSION),
ProcessNodeCreateCallback,
NULL
);
PhPluginSetObjectExtension(
PluginInstance,
EmServiceItemType,
sizeof(SERVICE_EXTENSION),
ServiceItemCreateCallback,
ServiceItemDeleteCallback
);
PhAddSettings(settings, ARRAYSIZE(settings));
}
return TRUE;
}
INT_PTR CALLBACK OptionsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
SetDlgItemText(hwndDlg, IDC_DATABASE, PhaGetStringSetting(SETTING_NAME_DATABASE_PATH)->Buffer);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDOK:
{
PhSetStringSetting2(SETTING_NAME_DATABASE_PATH,
&PhaGetDlgItemText(hwndDlg, IDC_DATABASE)->sr);
EndDialog(hwndDlg, IDOK);
}
break;
case IDC_BROWSE:
{
static PH_FILETYPE_FILTER filters[] =
{
{ L"XML files (*.xml)", L"*.xml" },
{ L"All files (*.*)", L"*.*" }
};
PVOID fileDialog;
PPH_STRING fileName;
fileDialog = PhCreateOpenFileDialog();
PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_DATABASE)));
PhSetFileDialogFileName(fileDialog, fileName->Buffer);
if (PhShowFileDialog(hwndDlg, fileDialog))
{
fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));
SetDlgItemText(hwndDlg, IDC_DATABASE, fileName->Buffer);
}
PhFreeFileDialog(fileDialog);
}
break;
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK ProcessCommentPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
LPPROPSHEETPAGE propSheetPage;
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
PPH_PROCESS_ITEM processItem;
PPROCESS_COMMENT_PAGE_CONTEXT context;
if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))
{
context = propPageContext->Context;
}
else
{
return FALSE;
}
switch (uMsg)
{
case WM_INITDIALOG:
{
PDB_OBJECT object;
PPH_STRING comment;
context = PhAllocate(sizeof(PROCESS_COMMENT_PAGE_CONTEXT));
context->CommentHandle = GetDlgItem(hwndDlg, IDC_COMMENT);
context->RevertHandle = GetDlgItem(hwndDlg, IDC_REVERT);
context->MatchCommandlineHandle = GetDlgItem(hwndDlg, IDC_MATCHCOMMANDLINE);
propPageContext->Context = context;
// Load the comment.
Edit_LimitText(context->CommentHandle, UNICODE_STRING_MAX_CHARS);
LockDb();
if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_COMMENT))
{
PhSetReference(&comment, object->Comment);
if (processItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->Comment->Length != 0)
{
Button_SetCheck(context->MatchCommandlineHandle, BST_CHECKED);
}
}
else
{
comment = PhReferenceEmptyString();
}
UnlockDb();
Edit_SetText(context->CommentHandle, comment->Buffer);
context->OriginalComment = comment;
if (!processItem->CommandLine)
EnableWindow(context->MatchCommandlineHandle, FALSE);
}
break;
case WM_DESTROY:
{
PDB_OBJECT object;
PPH_STRING comment;
BOOLEAN matchCommandLine;
BOOLEAN done = FALSE;
comment = PH_AUTO(PhGetWindowText(context->CommentHandle));
matchCommandLine = Button_GetCheck(context->MatchCommandlineHandle) == BST_CHECKED;
if (!processItem->CommandLine)
matchCommandLine = FALSE;
LockDb();
if (processItem->CommandLine && !matchCommandLine)
{
PDB_OBJECT objectForProcessName;
PPH_STRING message = NULL;
object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr);
objectForProcessName = FindDbObject(FILE_TAG, &processItem->ProcessName->sr);
if (object && objectForProcessName && object->Comment->Length != 0 && objectForProcessName->Comment->Length != 0 &&
!PhEqualString(comment, objectForProcessName->Comment, FALSE))
{
message = PhaFormatString(
L"Do you want to replace the comment for %s which is currently\n \"%s\"\n"
L"with\n \"%s\"?",
processItem->ProcessName->Buffer,
objectForProcessName->Comment->Buffer,
comment->Buffer
);
}
if (object)
{
PhMoveReference(&object->Comment, PhReferenceEmptyString());
DeleteDbObjectForProcessIfUnused(object);
}
if (message)
{
// Prevent deadlocks.
UnlockDb();
if (MessageBox(hwndDlg, message->Buffer, L"Comment", MB_ICONQUESTION | MB_YESNO) == IDNO)
{
done = TRUE;
}
LockDb();
}
}
if (!done)
{
if (comment->Length != 0)
{
if (matchCommandLine)
CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, comment);
else
CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, comment);
}
else
{
if (
(!matchCommandLine && (object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr))) ||
(matchCommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)))
)
{
PhMoveReference(&object->Comment, PhReferenceEmptyString());
DeleteDbObjectForProcessIfUnused(object);
}
}
}
UnlockDb();
PhDereferenceObject(context->OriginalComment);
PhFree(context);
PhPropPageDlgProcDestroy(hwndDlg);
SaveDb();
InvalidateProcessComments();
}
break;
case WM_SHOWWINDOW:
{
PPH_LAYOUT_ITEM dialogItem;
if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))
{
PhAddPropPageLayoutItem(hwndDlg, context->CommentHandle, dialogItem, PH_ANCHOR_ALL);
PhAddPropPageLayoutItem(hwndDlg, context->RevertHandle, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);
PhAddPropPageLayoutItem(hwndDlg, context->MatchCommandlineHandle, dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
PhEndPropPageLayout(hwndDlg, propPageContext);
}
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_COMMENT:
{
if (HIWORD(wParam) == EN_CHANGE)
EnableWindow(context->RevertHandle, TRUE);
}
break;
case IDC_REVERT:
{
Edit_SetText(context->CommentHandle, context->OriginalComment->Buffer);
SendMessage(context->CommentHandle, EM_SETSEL, 0, -1);
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->CommentHandle, TRUE);
EnableWindow(context->RevertHandle, FALSE);
}
break;
}
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case PSN_QUERYINITIALFOCUS:
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)context->MatchCommandlineHandle);
}
return TRUE;
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK ServiceCommentPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_COMMENT_PAGE_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_COMMENT_PAGE_CONTEXT));
memset(context, 0, sizeof(SERVICE_COMMENT_PAGE_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_COMMENT_PAGE_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam;
PDB_OBJECT object;
PPH_STRING comment;
context->ServiceItem = serviceItem;
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_COMMENT), NULL, PH_ANCHOR_ALL);
// Load the comment.
SendMessage(GetDlgItem(hwndDlg, IDC_COMMENT), EM_SETLIMITTEXT, UNICODE_STRING_MAX_CHARS, 0);
LockDb();
if (object = FindDbObject(SERVICE_TAG, &serviceItem->Name->sr))
comment = object->Comment;
else
comment = PH_AUTO(PhReferenceEmptyString());
UnlockDb();
SetDlgItemText(hwndDlg, IDC_COMMENT, comment->Buffer);
EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&context->LayoutManager);
PhFree(context);
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&context->LayoutManager);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_COMMENT:
{
if (HIWORD(wParam) == EN_CHANGE)
EnableWindow(GetDlgItem(hwndDlg, IDC_REVERT), TRUE);
}
break;
}
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case PSN_KILLACTIVE:
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE);
}
return TRUE;
case PSN_APPLY:
{
PDB_OBJECT object;
PPH_STRING comment;
comment = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_COMMENT)));
LockDb();
if (comment->Length != 0)
{
CreateDbObject(SERVICE_TAG, &context->ServiceItem->Name->sr, comment);
}
else
{
if (object = FindDbObject(SERVICE_TAG, &context->ServiceItem->Name->sr))
DeleteDbObject(object);
}
UnlockDb();
SaveDb();
InvalidateServiceComments();
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
}
return TRUE;
}
}
break;
}
return FALSE;
}
UINT_PTR CALLBACK ColorDlgHookProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
PhCenterWindow(hwndDlg, PhMainWndHandle);
EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
}
break;
}
return FALSE;
}