Files
mirror-processhacker/2.x/trunk/plugins/UserNotes/main.c
T
wj32 af2413f452 UserNotes: save DB when changing priority
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@5281 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2013-02-07 00:22:59 +00:00

1206 lines
37 KiB
C

#include <phdk.h>
#include <phappresource.h>
#include <windowsx.h>
#include "db.h"
#include "resource.h"
#define INTENT_PROCESS_COMMENT 1
#define INTENT_PROCESS_PRIORITY_CLASS 2
#define PROCESS_SAVE_ID 1
#define PROCESS_SAVE_FOR_THIS_COMMAND_LINE_ID 2
#define COMMENT_COLUMN_ID 1
typedef struct _PROCESS_EXTENSION
{
LIST_ENTRY ListEntry;
PPH_PROCESS_ITEM ProcessItem;
BOOLEAN Valid;
PPH_STRING Comment;
} PROCESS_EXTENSION, *PPROCESS_EXTENSION;
typedef struct _PROCESS_COMMENT_PAGE_CONTEXT
{
PPH_STRING OriginalComment;
} PROCESS_COMMENT_PAGE_CONTEXT, *PPROCESS_COMMENT_PAGE_CONTEXT;
typedef struct _SERVICE_EXTENSION
{
LIST_ENTRY ListEntry;
BOOLEAN Valid;
PPH_STRING Comment;
} SERVICE_EXTENSION, *PSERVICE_EXTENSION;
typedef struct _SERVICE_COMMENT_PAGE_CONTEXT
{
PPH_SERVICE_ITEM ServiceItem;
PH_LAYOUT_MANAGER LayoutManager;
} SERVICE_COMMENT_PAGE_CONTEXT, *PSERVICE_COMMENT_PAGE_CONTEXT;
INT_PTR CALLBACK OptionsDlgProc(
__in HWND hwndDlg,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
);
INT_PTR CALLBACK ProcessCommentPageDlgProc(
__in HWND hwndDlg,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
);
INT_PTR CALLBACK ServiceCommentPageDlgProc(
__in HWND hwndDlg,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
);
LRESULT CALLBACK MainWndSubclassProc(
__in HWND hWnd,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam,
__in UINT_PTR uIdSubclass,
__in DWORD_PTR dwRefData
);
PPH_PLUGIN PluginInstance;
PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration;
PH_CALLBACK_REGISTRATION TreeNewMessageCallbackRegistration;
PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ServiceTreeNewInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessModifiedCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
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;
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);
}
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)
{
DeleteDbObject(Object);
}
}
VOID NTAPI LoadCallback(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_STRING path;
PPH_STRING realPath;
path = PhGetStringSetting(L"ProcessHacker.UserNotes.DatabasePath");
realPath = PhExpandEnvironmentStrings(&path->sr);
PhDereferenceObject(path);
path = realPath;
if (RtlDetermineDosPathNameType_U(path->Buffer) == RtlPathTypeRelative)
{
PPH_STRING directory;
directory = PhGetApplicationDirectory();
realPath = PhConcatStringRef2(&directory->sr, &path->sr);
PhDereferenceObject(directory);
PhDereferenceObject(path);
path = realPath;
}
SetDbPath(path);
PhDereferenceObject(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_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_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;
}
}
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
{
PhSwapReference(&Extension->Comment, NULL);
}
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
{
PhSwapReference(&Extension->Comment, NULL);
}
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
)
{
SetWindowSubclass(PhMainWndHandle, MainWndSubclassProc, 0, 0);
}
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 ProcessMenuInitializingCallback(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
PPH_PROCESS_ITEM processItem;
PPH_EMENU_ITEM priorityMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Priority", 0);
PPH_EMENU_ITEM saveMenuItem;
PPH_EMENU_ITEM saveForCommandLineMenuItem;
PDB_OBJECT object;
if (!priorityMenuItem)
return;
if (menuInfo->u.Process.NumberOfProcesses != 1)
return;
processItem = menuInfo->u.Process.Processes[0];
PhInsertEMenuItem(priorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, L"", NULL), -1);
PhInsertEMenuItem(priorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_SAVE_ID, PhaFormatString(L"Save for %s", processItem->ProcessName->Buffer)->Buffer, NULL), -1);
PhInsertEMenuItem(priorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_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();
}
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 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 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;
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);
}
}
}
listEntry = listEntry->Flink;
}
UnlockDb();
PhReleaseQueuedLockExclusive(&ProcessListLock);
}
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;
PhSwapReference(&extension->Comment, NULL);
PhAcquireQueuedLockExclusive(&ProcessListLock);
RemoveEntryList(&extension->ListEntry);
PhReleaseQueuedLockExclusive(&ProcessListLock);
}
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;
PhSwapReference(&extension->Comment, NULL);
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;
PluginInstance = PhRegisterPlugin(L"ProcessHacker.UserNotes", Instance, &info);
if (!PluginInstance)
return FALSE;
info->DisplayName = L"User Notes";
info->Description = L"Allows the user to add comments for processes and services. Also allows the user to save process priority.";
info->Author = L"wj32";
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, 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(GeneralCallbackServiceTreeNewInitializing),
ServiceTreeNewInitializingCallback, NULL, &ServiceTreeNewInitializingCallbackRegistration);
PhRegisterCallback(&PhProcessModifiedEvent,
ProcessModifiedCallback, NULL, &ProcessModifiedCallbackRegistration);
PhRegisterCallback(&PhProcessesUpdatedEvent,
ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration);
PhPluginSetObjectExtension(PluginInstance, EmProcessItemType, sizeof(PROCESS_EXTENSION),
ProcessItemCreateCallback, ProcessItemDeleteCallback);
PhPluginSetObjectExtension(PluginInstance, EmServiceItemType, sizeof(SERVICE_EXTENSION),
ServiceItemCreateCallback, ServiceItemDeleteCallback);
{
static PH_SETTING_CREATE settings[] =
{
{ StringSettingType, L"ProcessHacker.UserNotes.DatabasePath", L"%APPDATA%\\Process Hacker 2\\usernotesdb.xml" }
};
PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE));
}
}
return TRUE;
}
INT_PTR CALLBACK OptionsDlgProc(
__in HWND hwndDlg,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
PPH_STRING path;
path = PhGetStringSetting(L"ProcessHacker.UserNotes.DatabasePath");
SetDlgItemText(hwndDlg, IDC_DATABASE, path->Buffer);
PhDereferenceObject(path);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDOK:
{
PhSetStringSetting2(L"ProcessHacker.UserNotes.DatabasePath",
&PHA_GET_DLGITEM_TEXT(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 = PhGetFileName(PHA_GET_DLGITEM_TEXT(hwndDlg, IDC_DATABASE));
PhSetFileDialogFileName(fileDialog, fileName->Buffer);
PhDereferenceObject(fileName);
if (PhShowFileDialog(hwndDlg, fileDialog))
{
fileName = PhGetFileDialogFileName(fileDialog);
SetDlgItemText(hwndDlg, IDC_DATABASE, fileName->Buffer);
PhDereferenceObject(fileName);
}
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));
propPageContext->Context = context;
// Load the comment.
SendMessage(GetDlgItem(hwndDlg, IDC_COMMENT), EM_SETLIMITTEXT, UNICODE_STRING_MAX_CHARS, 0);
LockDb();
if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_COMMENT))
{
comment = object->Comment;
PhReferenceObject(comment);
if (processItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->Comment->Length != 0)
{
Button_SetCheck(GetDlgItem(hwndDlg, IDC_MATCHCOMMANDLINE), BST_CHECKED);
}
}
else
{
comment = PhReferenceEmptyString();
}
UnlockDb();
SetDlgItemText(hwndDlg, IDC_COMMENT, comment->Buffer);
context->OriginalComment = comment;
if (!processItem->CommandLine)
EnableWindow(GetDlgItem(hwndDlg, IDC_MATCHCOMMANDLINE), FALSE);
}
break;
case WM_DESTROY:
{
PDB_OBJECT object;
PPH_STRING comment;
BOOLEAN matchCommandLine;
BOOLEAN done = FALSE;
comment = PhGetWindowText(GetDlgItem(hwndDlg, IDC_COMMENT));
matchCommandLine = Button_GetCheck(GetDlgItem(hwndDlg, IDC_MATCHCOMMANDLINE)) == BST_CHECKED;
if (!processItem->CommandLine)
matchCommandLine = FALSE;
LockDb();
if (processItem->CommandLine && !matchCommandLine)
{
PDB_OBJECT objectForProcessName;
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))
{
PPH_STRING message;
message = PhFormatString(
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 (MessageBox(hwndDlg, message->Buffer, L"Comment", MB_ICONQUESTION | MB_YESNO) == IDNO)
{
done = TRUE;
}
PhDereferenceObject(message);
}
if (object)
{
PhSwapReference2(&object->Comment, PhReferenceEmptyString());
DeleteDbObjectForProcessIfUnused(object);
}
}
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)))
)
{
PhSwapReference2(&object->Comment, PhReferenceEmptyString());
DeleteDbObjectForProcessIfUnused(object);
}
}
}
UnlockDb();
PhDereferenceObject(comment);
PhDereferenceObject(context->OriginalComment);
PhFree(context);
PhPropPageDlgProcDestroy(hwndDlg);
SaveDb();
InvalidateProcessComments();
}
break;
case WM_SHOWWINDOW:
{
PPH_LAYOUT_ITEM dialogItem;
if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))
{
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMMENT), dialogItem, PH_ANCHOR_ALL);
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_REVERT), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_MATCHCOMMANDLINE), 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(GetDlgItem(hwndDlg, IDC_REVERT), TRUE);
}
break;
case IDC_REVERT:
{
SetDlgItemText(hwndDlg, IDC_COMMENT, context->OriginalComment->Buffer);
SendMessage(GetDlgItem(hwndDlg, IDC_COMMENT), EM_SETSEL, 0, -1);
SetFocus(GetDlgItem(hwndDlg, IDC_COMMENT));
EnableWindow(GetDlgItem(hwndDlg, IDC_REVERT), FALSE);
}
break;
}
}
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;
PhReferenceObject(comment);
}
else
{
comment = PhReferenceEmptyString();
}
UnlockDb();
SetDlgItemText(hwndDlg, IDC_COMMENT, comment->Buffer);
PhDereferenceObject(comment);
}
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 = 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();
PhDereferenceObject(comment);
SaveDb();
InvalidateServiceComments();
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
}
return TRUE;
}
}
break;
}
return FALSE;
}
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;
}
LRESULT CALLBACK MainWndSubclassProc(
__in HWND hWnd,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam,
__in UINT_PTR uIdSubclass,
__in DWORD_PTR dwRefData
)
{
switch (uMsg)
{
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
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:
{
PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem();
if (processItem)
{
PDB_OBJECT object;
BOOLEAN changed = FALSE;
LockDb();
if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_PRIORITY_CLASS))
{
ULONG newPriorityClass = GetPriorityClassFromId(LOWORD(wParam));
if (object->PriorityClass != newPriorityClass)
{
object->PriorityClass = newPriorityClass;
changed = TRUE;
}
}
UnlockDb();
if (changed)
SaveDb();
}
}
break;
}
}
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
//DefaultWndProc:
// return DefWindowProc(hWnd, uMsg, wParam, lParam);
}