From 7078bf2fafaf6ca5641dfc3a02efebbd70aa2004 Mon Sep 17 00:00:00 2001 From: wj32 Date: Thu, 23 Sep 2010 06:34:56 +0000 Subject: [PATCH] * switched service and network menus to use EMENU * added plugin support for EMENU * ExtendedServices now adds a Restart menu item git-svn-id: svn://svn.code.sf.net/p/processhacker/code@3661 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- 2.x/trunk/CHANGELOG.txt | 1 + 2.x/trunk/ProcessHacker/include/phplug.h | 47 ++++ 2.x/trunk/ProcessHacker/mainwnd.c | 209 ++++++++++++------ 2.x/trunk/ProcessHacker/plugin.c | 49 ++++ 2.x/trunk/ProcessHacker/resource.h | 3 +- 2.x/trunk/ProcessHacker/sdk/phdk.h | 2 +- 2.x/trunk/build/sdk/makesdk.cmd | 1 + 2.x/trunk/phlib/emenu.c | 19 +- 2.x/trunk/phlib/include/emenu.h | 30 ++- .../plugins/ExtendedServices/CHANGELOG.txt | 1 + .../ExtendedServices/ExtendedServices.rc | 18 ++ .../ExtendedServices/ExtendedServices.vcproj | 4 + 2.x/trunk/plugins/ExtendedServices/extsrv.h | 8 + 2.x/trunk/plugins/ExtendedServices/main.c | 91 +++++++- 2.x/trunk/plugins/ExtendedServices/resource.h | 11 +- 2.x/trunk/plugins/ExtendedServices/srvprgrs.c | 171 ++++++++++++++ 16 files changed, 591 insertions(+), 74 deletions(-) create mode 100644 2.x/trunk/plugins/ExtendedServices/srvprgrs.c diff --git a/2.x/trunk/CHANGELOG.txt b/2.x/trunk/CHANGELOG.txt index 32e8ba8d5..3d146fc9d 100644 --- a/2.x/trunk/CHANGELOG.txt +++ b/2.x/trunk/CHANGELOG.txt @@ -2,6 +2,7 @@ Process Hacker 2.6 * NEW/IMPROVED: + * Updated ExtendedServices plugin * Performance improvements * FIXED: * Fixed service handle leak diff --git a/2.x/trunk/ProcessHacker/include/phplug.h b/2.x/trunk/ProcessHacker/include/phplug.h index f615c537d..8556bb704 100644 --- a/2.x/trunk/ProcessHacker/include/phplug.h +++ b/2.x/trunk/ProcessHacker/include/phplug.h @@ -18,6 +18,9 @@ typedef enum _PH_GENERAL_CALLBACK GeneralCallbackNotifyEvent = 6, // PPH_PLUGIN_NOTIFY_EVENT Data [main thread] GeneralCallbackServicePropertiesInitializing = 7, // PPH_PLUGIN_OBJECT_PROPERTIES Data [properties thread] GeneralCallbackHandlePropertiesInitializing = 8, // PPH_PLUGIN_OBJECT_PROPERTIES Data [properties thread] + GeneralCallbackProcessMenuInitializing = 9, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] + GeneralCallbackServiceMenuInitializing = 10, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] + GeneralCallbackNetworkMenuInitializing = 11, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] GeneralCallbackMaximum } PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK; @@ -83,6 +86,32 @@ typedef struct _PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT PPH_HANDLE_ITEM HandleItem; } PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT, *PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT; +typedef struct _PH_EMENU_ITEM *PPH_EMENU_ITEM, *PPH_EMENU; + +typedef struct _PH_PLUGIN_MENU_INFORMATION +{ + PPH_EMENU Menu; + + union + { + struct + { + PPH_PROCESS_ITEM *Processes; + ULONG NumberOfProcesses; + } Process; + struct + { + PPH_SERVICE_ITEM *Services; + ULONG NumberOfServices; + } Service; + struct + { + PPH_NETWORK_ITEM *NetworkItems; + ULONG NumberOfNetworkItems; + } Network; + } u; +} PH_PLUGIN_MENU_INFORMATION, *PPH_PLUGIN_MENU_INFORMATION; + typedef enum _PH_PLUGIN_CALLBACK { PluginCallbackLoad = 0, // [main thread] @@ -207,6 +236,24 @@ PhPluginGetSystemStatistics( __out PPH_PLUGIN_SYSTEM_STATISTICS Statistics ); +PHAPPAPI +PPH_EMENU_ITEM +NTAPI +PhPluginCreateEMenuItem( + __in PPH_PLUGIN Plugin, + __in ULONG Flags, + __in ULONG Id, + __in PWSTR Text, + __in_opt PVOID Context + ); + +PHAPPAPI +BOOLEAN +NTAPI +PhPluginTriggerEMenuItem( + __in PPH_EMENU_ITEM Item + ); + #ifdef __cplusplus } #endif diff --git a/2.x/trunk/ProcessHacker/mainwnd.c b/2.x/trunk/ProcessHacker/mainwnd.c index 3505ee504..ac919e3a5 100644 --- a/2.x/trunk/ProcessHacker/mainwnd.c +++ b/2.x/trunk/ProcessHacker/mainwnd.c @@ -3320,8 +3320,8 @@ VOID PhpInitializeProcessMenu( if (PH_IS_FAKE_PROCESS_ID(Processes[0]->ProcessId)) { PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - PhSetFlagsEMenuItem(Menu, ID_PROCESS_PROPERTIES, PH_EMENU_DISABLED, 0); - PhSetFlagsEMenuItem(Menu, ID_PROCESS_SEARCHONLINE, PH_EMENU_DISABLED, 0); + PhEnableEMenuItem(Menu, ID_PROCESS_PROPERTIES, TRUE); + PhEnableEMenuItem(Menu, ID_PROCESS_SEARCHONLINE, TRUE); } } else @@ -3351,9 +3351,7 @@ VOID PhpInitializeProcessMenu( if (WindowsVersion < WINDOWS_VISTA) { // Remove I/O priority. - item = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, L"I/O Priority", 0); - - if (item) + if (item = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, L"I/O Priority", 0)) PhRemoveEMenuItem(NULL, item, 0); } @@ -3418,11 +3416,11 @@ VOID PhpInitializeProcessMenu( GetWindowPlacement(SelectedProcessWindowHandle, &placement); if (placement.showCmd == SW_MINIMIZE) - PhSetFlagsEMenuItem(item, ID_WINDOW_MINIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhEnableEMenuItem(item, ID_WINDOW_MINIMIZE, FALSE); else if (placement.showCmd == SW_MAXIMIZE) - PhSetFlagsEMenuItem(item, ID_WINDOW_MAXIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhEnableEMenuItem(item, ID_WINDOW_MAXIMIZE, FALSE); else if (placement.showCmd == SW_NORMAL) - PhSetFlagsEMenuItem(item, ID_WINDOW_RESTORE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhEnableEMenuItem(item, ID_WINDOW_RESTORE, FALSE); } else { @@ -3434,9 +3432,7 @@ VOID PhpInitializeProcessMenu( if (!WINDOWS_HAS_UAC) { - item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_VIRTUALIZATION); - - if (item) + if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_VIRTUALIZATION)) PhRemoveEMenuItem(NULL, item, 0); } } @@ -3461,7 +3457,18 @@ VOID PhShowProcessContextMenu( PhpInitializeProcessMenu(menu, processes, numberOfProcesses); - MapWindowPoints(ProcessTreeListHandle, NULL, &Location, 1); + if (PhPluginsEnabled) + { + PH_PLUGIN_MENU_INFORMATION menuInfo; + + menuInfo.Menu = menu; + menuInfo.u.Process.Processes = processes; + menuInfo.u.Process.NumberOfProcesses = numberOfProcesses; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), &menuInfo); + } + + ClientToScreen(ProcessTreeListHandle, &Location); item = PhShowEMenu( menu, @@ -3474,7 +3481,13 @@ VOID PhShowProcessContextMenu( if (item) { - SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0); + BOOLEAN handled = FALSE; + + if (PhPluginsEnabled) + handled = PhPluginTriggerEMenuItem(item); + + if (!handled) + SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0); } PhDestroyEMenu(menu); @@ -3484,24 +3497,24 @@ VOID PhShowProcessContextMenu( } VOID PhpInitializeServiceMenu( - __in HMENU Menu, + __in PPH_EMENU Menu, __in PPH_SERVICE_ITEM *Services, __in ULONG NumberOfServices ) { if (NumberOfServices == 0) { - PhEnableAllMenuItems(Menu, FALSE); + PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); } else if (NumberOfServices == 1) { if (!Services[0]->ProcessId) - PhEnableMenuItem(Menu, ID_SERVICE_GOTOPROCESS, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_GOTOPROCESS, FALSE); } else { - PhEnableAllMenuItems(Menu, FALSE); - PhEnableMenuItem(Menu, ID_SERVICE_COPY, TRUE); + PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhEnableEMenuItem(Menu, ID_SERVICE_COPY, TRUE); } if (NumberOfServices == 1) @@ -3510,29 +3523,29 @@ VOID PhpInitializeServiceMenu( { case SERVICE_RUNNING: { - PhEnableMenuItem(Menu, ID_SERVICE_START, FALSE); - PhEnableMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE); - PhEnableMenuItem(Menu, ID_SERVICE_PAUSE, + PhEnableEMenuItem(Menu, ID_SERVICE_START, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, Services[0]->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); - PhEnableMenuItem(Menu, ID_SERVICE_STOP, + PhEnableEMenuItem(Menu, ID_SERVICE_STOP, Services[0]->ControlsAccepted & SERVICE_ACCEPT_STOP); } break; case SERVICE_PAUSED: { - PhEnableMenuItem(Menu, ID_SERVICE_START, FALSE); - PhEnableMenuItem(Menu, ID_SERVICE_CONTINUE, + PhEnableEMenuItem(Menu, ID_SERVICE_START, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, Services[0]->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); - PhEnableMenuItem(Menu, ID_SERVICE_PAUSE, FALSE); - PhEnableMenuItem(Menu, ID_SERVICE_STOP, + PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_STOP, Services[0]->ControlsAccepted & SERVICE_ACCEPT_STOP); } break; case SERVICE_STOPPED: { - PhEnableMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE); - PhEnableMenuItem(Menu, ID_SERVICE_PAUSE, FALSE); - PhEnableMenuItem(Menu, ID_SERVICE_STOP, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_STOP, FALSE); } break; case SERVICE_START_PENDING: @@ -3540,18 +3553,22 @@ VOID PhpInitializeServiceMenu( case SERVICE_PAUSE_PENDING: case SERVICE_STOP_PENDING: { - PhEnableMenuItem(Menu, ID_SERVICE_START, FALSE); - PhEnableMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE); - PhEnableMenuItem(Menu, ID_SERVICE_PAUSE, FALSE); - PhEnableMenuItem(Menu, ID_SERVICE_STOP, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_START, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, FALSE); + PhEnableEMenuItem(Menu, ID_SERVICE_STOP, FALSE); } break; } if (!(Services[0]->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE)) { - DeleteMenu(Menu, ID_SERVICE_CONTINUE, 0); - DeleteMenu(Menu, ID_SERVICE_PAUSE, 0); + PPH_EMENU_ITEM item; + + if (item = PhFindEMenuItem(Menu, 0, NULL, ID_SERVICE_CONTINUE)) + PhRemoveEMenuItem(NULL, item, 0); + if (item = PhFindEMenuItem(Menu, 0, NULL, ID_SERVICE_PAUSE)) + PhRemoveEMenuItem(NULL, item, 0); } } } @@ -3577,22 +3594,51 @@ VOID PhMainWndServiceListViewOnNotify( if (numberOfServices != 0) { - HMENU menu; - HMENU subMenu; + PPH_EMENU menu; + PPH_EMENU_ITEM item; + POINT location; - menu = LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_SERVICE)); - subMenu = GetSubMenu(menu, 0); + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_SERVICE), 0); + PhSetFlagsEMenuItem(menu, ID_SERVICE_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); - SetMenuDefaultItem(subMenu, ID_SERVICE_PROPERTIES, FALSE); - PhpInitializeServiceMenu(subMenu, services, numberOfServices); + PhpInitializeServiceMenu(menu, services, numberOfServices); - PhShowContextMenu( + if (PhPluginsEnabled) + { + PH_PLUGIN_MENU_INFORMATION menuInfo; + + menuInfo.Menu = menu; + menuInfo.u.Service.Services = services; + menuInfo.u.Service.NumberOfServices = numberOfServices; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceMenuInitializing), &menuInfo); + } + + location = itemActivate->ptAction; + ClientToScreen(ServiceListViewHandle, &location); + + item = PhShowEMenu( + menu, PhMainWndHandle, - ServiceListViewHandle, - subMenu, - itemActivate->ptAction + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + location.x, + location.y ); - DestroyMenu(menu); + + if (item) + { + BOOLEAN handled = FALSE; + + if (PhPluginsEnabled) + handled = PhPluginTriggerEMenuItem(item); + + if (!handled) + SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0); + } + + PhDestroyEMenu(menu); } PhFree(services); @@ -3640,31 +3686,35 @@ VOID PhMainWndServiceListViewOnNotify( } VOID PhpInitializeNetworkMenu( - __in HMENU Menu, + __in PPH_EMENU Menu, __in PPH_NETWORK_ITEM *NetworkItems, __in ULONG NumberOfNetworkItems ) { ULONG i; + PPH_EMENU_ITEM item; if (NumberOfNetworkItems == 0) { - PhEnableAllMenuItems(Menu, FALSE); + PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); } else if (NumberOfNetworkItems == 1) { if (!NetworkItems[0]->ProcessId) - PhEnableMenuItem(Menu, ID_NETWORK_GOTOPROCESS, FALSE); + PhEnableEMenuItem(Menu, ID_NETWORK_GOTOPROCESS, FALSE); } else { - PhEnableAllMenuItems(Menu, FALSE); - PhEnableMenuItem(Menu, ID_NETWORK_CLOSE, TRUE); - PhEnableMenuItem(Menu, ID_NETWORK_COPY, TRUE); + PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhEnableEMenuItem(Menu, ID_NETWORK_CLOSE, TRUE); + PhEnableEMenuItem(Menu, ID_NETWORK_COPY, TRUE); } if (WindowsVersion >= WINDOWS_VISTA) - DeleteMenu(Menu, ID_NETWORK_VIEWSTACK, 0); + { + if (item = PhFindEMenuItem(Menu, 0, NULL, ID_NETWORK_VIEWSTACK)) + PhRemoveEMenuItem(NULL, item, 0); + } // Close if (NumberOfNetworkItems != 0) @@ -3684,7 +3734,7 @@ VOID PhpInitializeNetworkMenu( } if (!closeOk) - PhEnableMenuItem(Menu, ID_NETWORK_CLOSE, FALSE); + PhEnableEMenuItem(Menu, ID_NETWORK_CLOSE, FALSE); } } @@ -3709,22 +3759,51 @@ VOID PhMainWndNetworkListViewOnNotify( if (numberOfNetworkItems != 0) { - HMENU menu; - HMENU subMenu; + PPH_EMENU menu; + PPH_EMENU_ITEM item; + POINT location; - menu = LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_NETWORK)); - subMenu = GetSubMenu(menu, 0); + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_NETWORK), 0); + PhSetFlagsEMenuItem(menu, ID_NETWORK_GOTOPROCESS, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); - SetMenuDefaultItem(subMenu, ID_NETWORK_GOTOPROCESS, FALSE); - PhpInitializeNetworkMenu(subMenu, networkItems, numberOfNetworkItems); + PhpInitializeNetworkMenu(menu, networkItems, numberOfNetworkItems); - PhShowContextMenu( + if (PhPluginsEnabled) + { + PH_PLUGIN_MENU_INFORMATION menuInfo; + + menuInfo.Menu = menu; + menuInfo.u.Network.NetworkItems = networkItems; + menuInfo.u.Network.NumberOfNetworkItems = numberOfNetworkItems; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkMenuInitializing), &menuInfo); + } + + location = itemActivate->ptAction; + ClientToScreen(NetworkListViewHandle, &location); + + item = PhShowEMenu( + menu, PhMainWndHandle, - NetworkListViewHandle, - subMenu, - itemActivate->ptAction + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + location.x, + location.y ); - DestroyMenu(menu); + + if (item) + { + BOOLEAN handled = FALSE; + + if (PhPluginsEnabled) + handled = PhPluginTriggerEMenuItem(item); + + if (!handled) + SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0); + } + + PhDestroyEMenu(menu); } PhFree(networkItems); diff --git a/2.x/trunk/ProcessHacker/plugin.c b/2.x/trunk/ProcessHacker/plugin.c index f148b85ed..1e8def428 100644 --- a/2.x/trunk/ProcessHacker/plugin.c +++ b/2.x/trunk/ProcessHacker/plugin.c @@ -22,6 +22,7 @@ #include #include +#include #include #define CINTERFACE #define COBJMACROS @@ -435,3 +436,51 @@ VOID PhPluginGetSystemStatistics( Statistics->MaxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0)); Statistics->MaxIoProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0)); } + +static VOID NTAPI PhpPluginEMenuItemDeleteFunction( + __in PPH_EMENU_ITEM Item + ) +{ + PhFree(Item->Context); +} + +PPH_EMENU_ITEM PhPluginCreateEMenuItem( + __in PPH_PLUGIN Plugin, + __in ULONG Flags, + __in ULONG Id, + __in PWSTR Text, + __in_opt PVOID Context + ) +{ + PPH_EMENU_ITEM item; + PPH_PLUGIN_MENU_ITEM pluginMenuItem; + + item = PhCreateEMenuItem(Flags, ID_PLUGIN_MENU_ITEM, Text, NULL, NULL); + + pluginMenuItem = PhAllocate(sizeof(PH_PLUGIN_MENU_ITEM)); + pluginMenuItem->Plugin = Plugin; + pluginMenuItem->Id = Id; + pluginMenuItem->RealId = 0; + pluginMenuItem->Context = Context; + + item->Context = pluginMenuItem; + item->DeleteFunction = PhpPluginEMenuItemDeleteFunction; + + return item; +} + +BOOLEAN PhPluginTriggerEMenuItem( + __in PPH_EMENU_ITEM Item + ) +{ + PPH_PLUGIN_MENU_ITEM pluginMenuItem; + + if (Item->Id != ID_PLUGIN_MENU_ITEM) + return FALSE; + + pluginMenuItem = Item->Context; + + PhInvokeCallback(PhGetPluginCallback(pluginMenuItem->Plugin, PluginCallbackMenuItem), pluginMenuItem); + + return TRUE; +} diff --git a/2.x/trunk/ProcessHacker/resource.h b/2.x/trunk/ProcessHacker/resource.h index 4d2df4311..33d8852d3 100644 --- a/2.x/trunk/ProcessHacker/resource.h +++ b/2.x/trunk/ProcessHacker/resource.h @@ -40,6 +40,7 @@ #define IDD_INFORMATION 129 #define IDD_FINDOBJECTS 130 #define IDD_OBJTOKEN 131 +#define ID_PLUGIN_MENU_ITEM 131 #define IDD_HEAPS 132 #define IDR_PRIVILEGE 133 #define IDR_FINDOBJ 134 @@ -620,6 +621,6 @@ #define _APS_NEXT_RESOURCE_VALUE 191 #define _APS_NEXT_COMMAND_VALUE 40234 #define _APS_NEXT_CONTROL_VALUE 1271 -#define _APS_NEXT_SYMED_VALUE 131 +#define _APS_NEXT_SYMED_VALUE 132 #endif #endif diff --git a/2.x/trunk/ProcessHacker/sdk/phdk.h b/2.x/trunk/ProcessHacker/sdk/phdk.h index cf73ea952..58f8d6957 100644 --- a/2.x/trunk/ProcessHacker/sdk/phdk.h +++ b/2.x/trunk/ProcessHacker/sdk/phdk.h @@ -12,8 +12,8 @@ #include "providers.h" #include "treelist.h" +#include "emenu.h" #include "phapppub.h" - #include "phplug.h" #endif diff --git a/2.x/trunk/build/sdk/makesdk.cmd b/2.x/trunk/build/sdk/makesdk.cmd index 5e7c5c85b..72a5ef0de 100644 --- a/2.x/trunk/build/sdk/makesdk.cmd +++ b/2.x/trunk/build/sdk/makesdk.cmd @@ -19,6 +19,7 @@ for %%a in ( circbuf_h.h dltmgr.h dspick.h + emenu.h fastlock.h graph.h hexedit.h diff --git a/2.x/trunk/phlib/emenu.c b/2.x/trunk/phlib/emenu.c index cc4f09c85..083b1c567 100644 --- a/2.x/trunk/phlib/emenu.c +++ b/2.x/trunk/phlib/emenu.c @@ -53,7 +53,7 @@ PPH_EMENU_ITEM PhCreateEMenuItem( __in ULONG Id, __in PWSTR Text, __in_opt PWSTR Bitmap, - __in PVOID Context + __in_opt PVOID Context ) { PPH_EMENU_ITEM item; @@ -78,6 +78,9 @@ VOID PhDestroyEMenuItem( __in PPH_EMENU_ITEM Item ) { + if (Item->DeleteFunction) + Item->DeleteFunction(Item); + if (Item->Flags & PH_EMENU_TEXT_OWNED) PhFree(Item->Text); @@ -153,6 +156,17 @@ PPH_EMENU_ITEM PhFindEMenuItem( return NULL; } +ULONG PhIndexOfEMenuItem( + __in PPH_EMENU_ITEM Parent, + __in PPH_EMENU_ITEM Item + ) +{ + if (!Parent->Items) + return -1; + + return PhFindItemList(Parent->Items, Item); +} + VOID PhInsertEMenuItem( __inout PPH_EMENU_ITEM Parent, __inout PPH_EMENU_ITEM Item, @@ -166,6 +180,9 @@ VOID PhInsertEMenuItem( if (!Parent->Items) Parent->Items = PhCreateList(16); + if (Index > Parent->Items->Count) + Index = Parent->Items->Count; + if (Index == -1) PhAddItemList(Parent->Items, Item); else diff --git a/2.x/trunk/phlib/include/emenu.h b/2.x/trunk/phlib/include/emenu.h index ded6a2a6d..6454269a7 100644 --- a/2.x/trunk/phlib/include/emenu.h +++ b/2.x/trunk/phlib/include/emenu.h @@ -16,6 +16,12 @@ #define PH_EMENU_TEXT_OWNED 0x80000000 #define PH_EMENU_BITMAP_OWNED 0x40000000 +struct _PH_EMENU_ITEM; + +typedef VOID (NTAPI *PPH_EMENU_ITEM_DELETE_FUNCTION)( + __in struct _PH_EMENU_ITEM *Item + ); + typedef struct _PH_EMENU_ITEM { ULONG Flags; @@ -25,6 +31,8 @@ typedef struct _PH_EMENU_ITEM PVOID Parameter; PVOID Context; + PPH_EMENU_ITEM_DELETE_FUNCTION DeleteFunction; + PVOID Reserved; struct _PH_EMENU_ITEM *Parent; PPH_LIST Items; @@ -37,9 +45,10 @@ PPH_EMENU_ITEM PhCreateEMenuItem( __in ULONG Id, __in PWSTR Text, __in_opt PWSTR Bitmap, - __in PVOID Context + __in_opt PVOID Context ); +PHLIBAPI VOID PhDestroyEMenuItem( __in PPH_EMENU_ITEM Item ); @@ -47,6 +56,7 @@ VOID PhDestroyEMenuItem( #define PH_EMENU_FIND_DESCEND 0x1 #define PH_EMENU_FIND_STARTSWITH 0x2 +PHLIBAPI PPH_EMENU_ITEM PhFindEMenuItem( __in PPH_EMENU_ITEM Item, __in ULONG Flags, @@ -54,18 +64,27 @@ PPH_EMENU_ITEM PhFindEMenuItem( __in_opt ULONG Id ); +PHLIBAPI +ULONG PhIndexOfEMenuItem( + __in PPH_EMENU_ITEM Parent, + __in PPH_EMENU_ITEM Item + ); + +PHLIBAPI VOID PhInsertEMenuItem( __inout PPH_EMENU_ITEM Parent, __inout PPH_EMENU_ITEM Item, __in ULONG Index ); +PHLIBAPI BOOLEAN PhRemoveEMenuItem( __inout_opt PPH_EMENU_ITEM Parent, __in_opt PPH_EMENU_ITEM Item, __in_opt ULONG Index ); +PHLIBAPI VOID PhRemoveAllEMenuItems( __inout PPH_EMENU_ITEM Parent ); @@ -130,6 +149,15 @@ BOOLEAN PhSetFlagsEMenuItem( __in ULONG Value ); +FORCEINLINE BOOLEAN PhEnableEMenuItem( + __in PPH_EMENU_ITEM Item, + __in ULONG Id, + __in BOOLEAN Enable + ) +{ + return PhSetFlagsEMenuItem(Item, Id, PH_EMENU_DISABLED, Enable ? 0 : PH_EMENU_DISABLED); +} + VOID PhSetFlagsAllEMenuItems( __in PPH_EMENU_ITEM Item, __in ULONG Mask, diff --git a/2.x/trunk/plugins/ExtendedServices/CHANGELOG.txt b/2.x/trunk/plugins/ExtendedServices/CHANGELOG.txt index 59cc5790c..33c51dd82 100644 --- a/2.x/trunk/plugins/ExtendedServices/CHANGELOG.txt +++ b/2.x/trunk/plugins/ExtendedServices/CHANGELOG.txt @@ -1,4 +1,5 @@ 1.1 + * Added Restart menu item for services * Fixed service handle leak 1.0 diff --git a/2.x/trunk/plugins/ExtendedServices/ExtendedServices.rc b/2.x/trunk/plugins/ExtendedServices/ExtendedServices.rc index c4fa70ef3..d8ad8308b 100644 --- a/2.x/trunk/plugins/ExtendedServices/ExtendedServices.rc +++ b/2.x/trunk/plugins/ExtendedServices/ExtendedServices.rc @@ -151,6 +151,16 @@ BEGIN CTEXT "If this service fails, the computer will restart.\nRecovery actions are not supported for this service.",IDC_STATIC,51,80,179,21 END +IDD_SRVPROGRESS DIALOGEX 0, 0, 204, 61 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Progress" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,147,40,50,14 + LTEXT "Progress",IDC_MESSAGE,7,7,190,8,SS_ENDELLIPSIS + CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,21,190,14 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -191,6 +201,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 176 END + + IDD_SRVPROGRESS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 197 + TOPMARGIN, 7 + BOTTOMMARGIN, 54 + END END #endif // APSTUDIO_INVOKED diff --git a/2.x/trunk/plugins/ExtendedServices/ExtendedServices.vcproj b/2.x/trunk/plugins/ExtendedServices/ExtendedServices.vcproj index b3fe48eb4..0e0677fca 100644 --- a/2.x/trunk/plugins/ExtendedServices/ExtendedServices.vcproj +++ b/2.x/trunk/plugins/ExtendedServices/ExtendedServices.vcproj @@ -348,6 +348,10 @@ RelativePath=".\main.c" > + + Id) + { + case ID_SERVICE_RESTART: + { + PPH_SERVICE_ITEM serviceItem = menuItem->Context; + SC_HANDLE serviceHandle; + ULONG win32Result = 0; + + if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP)) + { + EsRestartServiceWithProgress(PhMainWndHandle, serviceItem->Name->Buffer, serviceHandle); + CloseServiceHandle(serviceHandle); + } + else + { + win32Result = GetLastError(); + } + + if (win32Result != 0) + { + PhShowStatus( + PhMainWndHandle, + PhaFormatString(L"Unable to restart %s", serviceItem->Name->Buffer)->Buffer, + 0, + win32Result + ); + } + } + break; + } +} + VOID NTAPI ServicePropertiesInitializingCallback( __in_opt PVOID Parameter, __in_opt PVOID Context @@ -152,3 +215,29 @@ VOID NTAPI ServicePropertiesInitializingCallback( objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); } } + +VOID NTAPI ServiceMenuInitializingCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_EMENU_ITEM menuItem; + ULONG indexOfMenuItem; + + if (menuInfo->u.Service.NumberOfServices == 1 && menuInfo->u.Service.Services[0]->State == SERVICE_RUNNING) + { + // Insert our Restart menu item after the Stop menu item. + + menuItem = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_STARTSWITH, L"Stop", 0); + + if (menuItem) + indexOfMenuItem = PhIndexOfEMenuItem(menuInfo->Menu, menuItem); + + PhInsertEMenuItem( + menuInfo->Menu, + PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_RESTART, L"Restart", menuInfo->u.Service.Services[0]), + indexOfMenuItem + 1 + ); + } +} diff --git a/2.x/trunk/plugins/ExtendedServices/resource.h b/2.x/trunk/plugins/ExtendedServices/resource.h index 4b66f4556..a06a2b86d 100644 --- a/2.x/trunk/plugins/ExtendedServices/resource.h +++ b/2.x/trunk/plugins/ExtendedServices/resource.h @@ -4,10 +4,11 @@ // #define IDD_SVCLIST 101 #define IDD_SRVLIST 101 +#define ID_SERVICE_RESTART 101 #define IDD_SRVRECOVERY 102 #define IDD_RESTARTCOMP 103 -#define IDD_SRVRECOVERY1 104 #define IDD_SRVRECOVERY2 104 +#define IDD_SRVPROGRESS 105 #define IDC_SERVICES_LAYOUT 1001 #define IDC_MESSAGE 1002 #define IDC_FIRSTFAILURE 1003 @@ -28,14 +29,16 @@ #define IDC_RUNPROGRAM_LABEL 1020 #define IDC_RUNPROGRAM_INFO 1021 #define IDC_USEDEFAULTMESSAGE 1022 +#define IDC_PROGRESS1 1023 +#define IDC_PROGRESS 1023 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_RESOURCE_VALUE 106 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1023 -#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_CONTROL_VALUE 1024 +#define _APS_NEXT_SYMED_VALUE 102 #endif #endif diff --git a/2.x/trunk/plugins/ExtendedServices/srvprgrs.c b/2.x/trunk/plugins/ExtendedServices/srvprgrs.c new file mode 100644 index 000000000..dda6ca70b --- /dev/null +++ b/2.x/trunk/plugins/ExtendedServices/srvprgrs.c @@ -0,0 +1,171 @@ +/* + * Process Hacker Extended Services - + * progress dialog + * + * Copyright (C) 2010 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 "extsrv.h" +#include "resource.h" + +typedef struct _RESTART_SERVICE_CONTEXT +{ + PWSTR ServiceName; + SC_HANDLE ServiceHandle; + BOOLEAN Starting; +} RESTART_SERVICE_CONTEXT, *PRESTART_SERVICE_CONTEXT; + +INT_PTR CALLBACK EspRestartServiceDlgProc( + __in HWND hwndDlg, + __in UINT uMsg, + __in WPARAM wParam, + __in LPARAM lParam + ); + +VOID EsRestartServiceWithProgress( + __in HWND hWnd, + __in PWSTR ServiceName, + __in SC_HANDLE ServiceHandle + ) +{ + RESTART_SERVICE_CONTEXT context; + + context.ServiceName = ServiceName; + context.ServiceHandle = ServiceHandle; + context.Starting = FALSE; + + DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_SRVPROGRESS), + hWnd, + EspRestartServiceDlgProc, + (LPARAM)&context + ); +} + +INT_PTR CALLBACK EspRestartServiceDlgProc( + __in HWND hwndDlg, + __in UINT uMsg, + __in WPARAM wParam, + __in LPARAM lParam + ) +{ + PRESTART_SERVICE_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PRESTART_SERVICE_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PRESTART_SERVICE_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + SERVICE_STATUS serviceStatus; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + // TODO: Use the progress information. + PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); + SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); + + SetDlgItemText(hwndDlg, IDC_MESSAGE, PhaFormatString(L"Attempting to stop %s...", context->ServiceName)->Buffer); + + if (ControlService(context->ServiceHandle, SERVICE_CONTROL_STOP, &serviceStatus)) + { + SetTimer(hwndDlg, 1, 250, NULL); + } + else + { + PhShowStatus( + hwndDlg, + PhaFormatString(L"Unable to stop %s", context->ServiceName)->Buffer, + 0, + GetLastError() + ); + EndDialog(hwndDlg, IDCANCEL); + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + { + EndDialog(hwndDlg, IDCANCEL); + } + break; + } + } + break; + case WM_TIMER: + { + if (wParam == 1) + { + SERVICE_STATUS serviceStatus; + + if (QueryServiceStatus(context->ServiceHandle, &serviceStatus)) + { + if (!context->Starting && serviceStatus.dwCurrentState == SERVICE_STOPPED) + { + // The service is stopped, so start the service now. + + SetDlgItemText(hwndDlg, IDC_MESSAGE, + PhaFormatString(L"Attempting to start %s...", context->ServiceName)->Buffer); + + if (StartService(context->ServiceHandle, 0, NULL)) + { + context->Starting = TRUE; + } + else + { + PhShowStatus( + hwndDlg, + PhaFormatString(L"Unable to start %s", context->ServiceName)->Buffer, + 0, + GetLastError() + ); + EndDialog(hwndDlg, IDCANCEL); + } + } + else if (context->Starting && serviceStatus.dwCurrentState == SERVICE_RUNNING) + { + EndDialog(hwndDlg, IDOK); + } + } + } + } + break; + } + + return FALSE; +}