Files
mirror-processhacker/2.x/trunk/plugins/UserNotes/main.c
T
wj32 57e77756e7 * fixed PhIntegerToString64
* added UserNotes plugin

git-svn-id: svn://svn.code.sf.net/p/processhacker/code@4774 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2011-10-29 02:32:03 +00:00

816 lines
24 KiB
C

#include <phdk.h>
#include "db.h"
#include "resource.h"
#define COMMENT_COLUMN_ID 1
typedef struct _PROCESS_EXTENSION
{
LIST_ENTRY ListEntry;
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
);
PPH_PLUGIN PluginInstance;
PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration;
PH_CALLBACK_REGISTRATION TreeNewMessageCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ServiceTreeNewInitializingCallbackRegistration;
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;
VOID NTAPI LoadCallback(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_STRING path;
PPH_STRING realPath;
InitializeDb();
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 ShowOptionsCallback(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
DialogBox(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_OPTIONS),
(HWND)Parameter,
OptionsDlgProc
);
}
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 = FindDbObject(FILE_TAG, &Node->ProcessItem->ProcessName->sr))
{
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;
}
}
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 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 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);
}
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 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);
}
}
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 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));
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 comments for processes and services.";
info->Author = L"wj32";
info->HasOptions = TRUE;
PhRegisterCallback(PhGetPluginCallback(PluginInstance, PluginCallbackLoad),
LoadCallback, NULL, &PluginLoadCallbackRegistration);
PhRegisterCallback(PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions),
ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration);
PhRegisterCallback(PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage),
TreeNewMessageCallback, NULL, &TreeNewMessageCallbackRegistration);
PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing),
ProcessPropertiesInitializingCallback, NULL, &ProcessPropertiesInitializingCallbackRegistration);
PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing),
ServicePropertiesInitializingCallback, NULL, &ServicePropertiesInitializingCallbackRegistration);
PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing),
ProcessTreeNewInitializingCallback, NULL, &ProcessTreeNewInitializingCallbackRegistration);
PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing),
ServiceTreeNewInitializingCallback, NULL, &ServiceTreeNewInitializingCallbackRegistration);
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 = FindDbObject(FILE_TAG, &processItem->ProcessName->sr))
{
comment = object->Comment;
PhReferenceObject(comment);
}
else
{
comment = PhReferenceEmptyString();
}
UnlockDb();
SetDlgItemText(hwndDlg, IDC_COMMENT, comment->Buffer);
context->OriginalComment = comment;
}
break;
case WM_DESTROY:
{
PDB_OBJECT object;
PPH_STRING comment;
comment = PhGetWindowText(GetDlgItem(hwndDlg, IDC_COMMENT));
LockDb();
if (comment->Length != 0)
{
CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, comment);
}
else
{
if (object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr))
DeleteDbObject(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);
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;
}