go my file uploader

This commit is contained in:
AirDog46
2025-05-13 19:45:22 +03:00
commit c5fab8aa94
708 changed files with 343216 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
1.10
* Added service protection and SID information
* Added auto-elevation when saving recovery information, triggers and other service settings
1.9
* Added new trigger data types
1.8
* Fixed some bugs relating to Windows 8
1.7
* Added new triggers for Windows 8
* Fixed bug when restarting services
1.6
* Disabled editing of required privileges for drivers
1.5
* Added support for editing triggers
* Added support for editing preshutdown time-out
* Added support for editing required privileges
* Added elevation support for restarting services
1.4
* Improved Services submenu when there is only one service
1.3
* Added Services submenu for processes
1.2
* Added Other tab
1.1
* Added Restart menu item for services
* Fixed service handle leak
1.0
* Initial release

View File

@@ -0,0 +1,350 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (Australia) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,10,0,0
PRODUCTVERSION 1,10,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "0c0904b0"
BEGIN
VALUE "CompanyName", "wj32"
VALUE "FileDescription", "Extended Services for Process Hacker"
VALUE "FileVersion", "1.10"
VALUE "InternalName", "ExtendedServices"
VALUE "LegalCopyright", "Licensed under the GNU GPL, v3."
VALUE "OriginalFilename", "ExtendedServices.dll"
VALUE "ProductName", "Extended Services for Process Hacker"
VALUE "ProductVersion", "1.10"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0xc09, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_SRVLIST DIALOGEX 0, 0, 282, 183
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "List"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Static",IDC_SERVICES_LAYOUT,7,19,268,157,NOT WS_VISIBLE
LTEXT "Static",IDC_MESSAGE,7,7,268,8
END
IDD_SRVRECOVERY DIALOGEX 0, 0, 282, 183
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Recovery"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "First failure:",IDC_STATIC,7,8,40,8
COMBOBOX IDC_FIRSTFAILURE,85,7,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Second failure:",IDC_STATIC,7,24,49,8
COMBOBOX IDC_SECONDFAILURE,85,23,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Subsequent failures:",IDC_STATIC,7,40,67,8
COMBOBOX IDC_SUBSEQUENTFAILURES,85,39,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Reset fail count after:",IDC_STATIC,7,56,72,8
EDITTEXT IDC_RESETFAILCOUNT,85,55,40,12,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "days",IDC_STATIC,130,56,16,8
LTEXT "Restart service after:",IDC_RESTARTSERVICEAFTER_LABEL,7,72,70,8
EDITTEXT IDC_RESTARTSERVICEAFTER,85,71,40,12,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "minutes",IDC_RESTARTSERVICEAFTER_MINUTES,130,72,26,8
CONTROL "Enable actions for stops with errors",IDC_ENABLEFORERRORSTOPS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,87,129,10
PUSHBUTTON "Restart computer options...",IDC_RESTARTCOMPUTEROPTIONS,7,100,114,14
GROUPBOX "Run program",IDC_RUNPROGRAM_GROUP,7,118,268,45
LTEXT "Program:",IDC_RUNPROGRAM_LABEL,15,132,30,8
EDITTEXT IDC_RUNPROGRAM,50,131,165,12,ES_AUTOHSCROLL
PUSHBUTTON "Browse...",IDC_BROWSE,220,130,50,14
LTEXT "Append /fail=%1% to pass the fail count to the program.",IDC_RUNPROGRAM_INFO,15,148,186,8
END
IDD_RESTARTCOMP DIALOGEX 0, 0, 245, 137
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Restart the computer after:",IDC_STATIC,7,8,90,8
EDITTEXT IDC_RESTARTCOMPAFTER,102,7,40,12,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "minutes",IDC_STATIC,147,8,26,8
CONTROL "Before restarting, send this message to computers on the network:",IDC_ENABLERESTARTMESSAGE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,23,231,10
EDITTEXT IDC_RESTARTMESSAGE,7,36,231,76,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
PUSHBUTTON "Use default message",IDC_USEDEFAULTMESSAGE,7,116,79,14
DEFPUSHBUTTON "OK",IDOK,134,116,50,14
PUSHBUTTON "Cancel",IDCANCEL,188,116,50,14
END
IDD_SRVRECOVERY2 DIALOGEX 0, 0, 282, 183
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Recovery"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
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
IDD_SRVOTHER DIALOGEX 0, 0, 282, 218
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Other"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Preshutdown timeout:",IDC_STATIC,7,8,72,8
EDITTEXT IDC_PRESHUTDOWNTIMEOUT,85,7,75,12,ES_AUTOHSCROLL
LTEXT "milliseconds",IDC_STATIC,166,8,38,8
LTEXT "Service SID:",IDC_STATIC,7,24,40,8
EDITTEXT IDC_SERVICESID,64,23,211,12,ES_AUTOHSCROLL | ES_READONLY
LTEXT "SID type:",IDC_STATIC,7,40,32,8
COMBOBOX IDC_SIDTYPE,64,39,122,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
LTEXT "Protection:",IDC_STATIC,7,57,36,8
COMBOBOX IDC_PROTECTION,64,56,122,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
LTEXT "Required privileges:",IDC_STATIC,7,77,64,8
CONTROL "",IDC_PRIVILEGES,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,268,79
PUSHBUTTON "Add...",IDC_ADD,171,171,50,14
PUSHBUTTON "Remove",IDC_REMOVE,225,171,50,14
END
IDD_OPTIONS DIALOGEX 0, 0, 215, 54
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Options"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "Enable Services submenu for processes",IDC_ENABLESERVICESMENU,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,142,10
DEFPUSHBUTTON "OK",IDOK,105,33,50,14
PUSHBUTTON "Cancel",IDCANCEL,158,33,50,14
END
IDD_SRVTRIGGER DIALOGEX 0, 0, 330, 196
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Trigger"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Type:",IDC_STATIC,7,9,20,8
COMBOBOX IDC_TYPE,52,7,271,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Subtype:",IDC_STATIC,7,26,30,8
COMBOBOX IDC_SUBTYPE,52,24,271,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_SUBTYPECUSTOM,52,41,271,12,ES_AUTOHSCROLL
LTEXT "Action:",IDC_STATIC,7,59,24,8
COMBOBOX IDC_ACTION,52,58,72,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Data items:",IDC_STATIC,7,76,38,8
CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,52,79,217,90
PUSHBUTTON "New...",IDC_NEW,273,79,50,14
PUSHBUTTON "Edit...",IDC_EDIT,273,96,50,14
PUSHBUTTON "Delete",IDC_DELETE,273,113,50,14
DEFPUSHBUTTON "OK",IDOK,219,175,50,14
PUSHBUTTON "Cancel",IDCANCEL,273,175,50,14
END
IDD_VALUE DIALOGEX 0, 0, 267, 167
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Edit Data"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Values (one per line):",IDC_STATIC,7,7,69,8
EDITTEXT IDC_VALUES,7,18,253,124,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL
DEFPUSHBUTTON "OK",IDOK,156,146,50,14
PUSHBUTTON "Cancel",IDCANCEL,210,146,50,14
END
IDD_SRVTRIGGERS DIALOGEX 0, 0, 282, 218
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Triggers"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_TRIGGERS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,268,186
PUSHBUTTON "New...",IDC_NEW,117,197,50,14
PUSHBUTTON "Edit...",IDC_EDIT,171,197,50,14
PUSHBUTTON "Delete",IDC_DELETE,225,197,50,14
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_SRVLIST, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 275
TOPMARGIN, 7
BOTTOMMARGIN, 176
END
IDD_SRVRECOVERY, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 275
TOPMARGIN, 7
BOTTOMMARGIN, 176
END
IDD_RESTARTCOMP, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 238
TOPMARGIN, 7
BOTTOMMARGIN, 130
END
IDD_SRVRECOVERY2, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 275
TOPMARGIN, 7
BOTTOMMARGIN, 176
END
IDD_SRVPROGRESS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 197
TOPMARGIN, 7
BOTTOMMARGIN, 54
END
IDD_SRVOTHER, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 275
TOPMARGIN, 7
BOTTOMMARGIN, 211
END
IDD_OPTIONS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 208
TOPMARGIN, 7
BOTTOMMARGIN, 47
END
IDD_SRVTRIGGER, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 323
TOPMARGIN, 7
BOTTOMMARGIN, 189
END
IDD_VALUE, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 260
TOPMARGIN, 7
BOTTOMMARGIN, 160
END
IDD_SRVTRIGGERS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 275
TOPMARGIN, 7
BOTTOMMARGIN, 211
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// AFX_DIALOG_LAYOUT
//
IDD_OPTIONS AFX_DIALOG_LAYOUT
BEGIN
0
END
#endif // English (Australia) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}</ProjectGuid>
<RootNamespace>ExtendedServices</RootNamespace>
<Keyword>Win32Proj</Keyword>
<ProjectName>ExtendedServices</ProjectName>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Plugins.props" />
</ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Debug32</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Release64</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Release32</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Debug64</LibraryPath>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="depend.c" />
<ClCompile Include="main.c" />
<ClCompile Include="options.c" />
<ClCompile Include="other.c" />
<ClCompile Include="srvprgrs.c" />
<ClCompile Include="recovery.c" />
<ClCompile Include="trigger.c" />
<ClCompile Include="triggpg.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="extsrv.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ExtendedServices.rc" />
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="depend.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="srvprgrs.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="other.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="options.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="trigger.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="triggpg.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="recovery.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="extsrv.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ExtendedServices.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,344 @@
/*
* Process Hacker Extended Services -
* dependencies and dependents
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "extsrv.h"
typedef struct _SERVICE_LIST_CONTEXT
{
HWND ServiceListHandle;
PH_LAYOUT_MANAGER LayoutManager;
} SERVICE_LIST_CONTEXT, *PSERVICE_LIST_CONTEXT;
LPENUM_SERVICE_STATUS EsEnumDependentServices(
_In_ SC_HANDLE ServiceHandle,
_In_opt_ ULONG State,
_Out_ PULONG Count
)
{
LOGICAL result;
PVOID buffer;
ULONG bufferSize;
ULONG returnLength;
ULONG servicesReturned;
if (!State)
State = SERVICE_STATE_ALL;
bufferSize = 0x800;
buffer = PhAllocate(bufferSize);
if (!(result = EnumDependentServices(
ServiceHandle,
State,
buffer,
bufferSize,
&returnLength,
&servicesReturned
)))
{
if (GetLastError() == ERROR_MORE_DATA)
{
PhFree(buffer);
bufferSize = returnLength;
buffer = PhAllocate(bufferSize);
result = EnumDependentServices(
ServiceHandle,
State,
buffer,
bufferSize,
&returnLength,
&servicesReturned
);
}
if (!result)
{
PhFree(buffer);
return NULL;
}
}
*Count = servicesReturned;
return buffer;
}
VOID EspLayoutServiceListControl(
_In_ HWND hwndDlg,
_In_ HWND ServiceListHandle
)
{
RECT rect;
GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect);
MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2);
MoveWindow(
ServiceListHandle,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
TRUE
);
}
INT_PTR CALLBACK EspServiceDependenciesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_LIST_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_LIST_CONTEXT));
memset(context, 0, sizeof(SERVICE_LIST_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_LIST_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;
HWND serviceListHandle;
PPH_LIST serviceList;
SC_HANDLE serviceHandle;
ULONG win32Result = 0;
BOOLEAN success = FALSE;
PPH_SERVICE_ITEM *services;
SetDlgItemText(hwndDlg, IDC_MESSAGE, L"This service depends on the following services:");
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL);
if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG))
{
LPQUERY_SERVICE_CONFIG serviceConfig;
if (serviceConfig = PhGetServiceConfig(serviceHandle))
{
PWSTR dependency;
PPH_SERVICE_ITEM dependencyService;
dependency = serviceConfig->lpDependencies;
serviceList = PH_AUTO(PhCreateList(8));
success = TRUE;
if (dependency)
{
ULONG dependencyLength;
while (TRUE)
{
dependencyLength = (ULONG)PhCountStringZ(dependency);
if (dependencyLength == 0)
break;
if (dependency[0] == SC_GROUP_IDENTIFIER)
goto ContinueLoop;
if (dependencyService = PhReferenceServiceItem(dependency))
PhAddItemList(serviceList, dependencyService);
ContinueLoop:
dependency += dependencyLength + 1;
}
}
services = PhAllocateCopy(serviceList->Items, sizeof(PPH_SERVICE_ITEM) * serviceList->Count);
serviceListHandle = PhCreateServiceListControl(hwndDlg, services, serviceList->Count);
context->ServiceListHandle = serviceListHandle;
EspLayoutServiceListControl(hwndDlg, serviceListHandle);
ShowWindow(serviceListHandle, SW_SHOW);
PhFree(serviceConfig);
}
else
{
win32Result = GetLastError();
}
CloseServiceHandle(serviceHandle);
}
else
{
win32Result = GetLastError();
}
if (!success)
{
SetDlgItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependencies: ",
((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer);
ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW);
}
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&context->LayoutManager);
PhFree(context);
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&context->LayoutManager);
if (context->ServiceListHandle)
EspLayoutServiceListControl(hwndDlg, context->ServiceListHandle);
}
break;
}
return FALSE;
}
INT_PTR CALLBACK EspServiceDependentsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_LIST_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_LIST_CONTEXT));
memset(context, 0, sizeof(SERVICE_LIST_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_LIST_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;
HWND serviceListHandle;
PPH_LIST serviceList;
SC_HANDLE serviceHandle;
ULONG win32Result = 0;
BOOLEAN success = FALSE;
PPH_SERVICE_ITEM *services;
SetDlgItemText(hwndDlg, IDC_MESSAGE, L"The following services depend on this service:");
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL);
if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_ENUMERATE_DEPENDENTS))
{
LPENUM_SERVICE_STATUS dependentServices;
ULONG numberOfDependentServices;
if (dependentServices = EsEnumDependentServices(serviceHandle, 0, &numberOfDependentServices))
{
ULONG i;
PPH_SERVICE_ITEM dependentService;
serviceList = PH_AUTO(PhCreateList(8));
success = TRUE;
for (i = 0; i < numberOfDependentServices; i++)
{
if (dependentService = PhReferenceServiceItem(dependentServices[i].lpServiceName))
PhAddItemList(serviceList, dependentService);
}
services = PhAllocateCopy(serviceList->Items, sizeof(PPH_SERVICE_ITEM) * serviceList->Count);
serviceListHandle = PhCreateServiceListControl(hwndDlg, services, serviceList->Count);
context->ServiceListHandle = serviceListHandle;
EspLayoutServiceListControl(hwndDlg, serviceListHandle);
ShowWindow(serviceListHandle, SW_SHOW);
PhFree(dependentServices);
}
else
{
win32Result = GetLastError();
}
CloseServiceHandle(serviceHandle);
}
else
{
win32Result = GetLastError();
}
if (!success)
{
SetDlgItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependents: ",
((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer);
ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW);
}
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&context->LayoutManager);
PhFree(context);
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&context->LayoutManager);
if (context->ServiceListHandle)
EspLayoutServiceListControl(hwndDlg, context->ServiceListHandle);
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,128 @@
#ifndef ES_EXTSRV_H
#define ES_EXTSRV_H
#include <phdk.h>
#include <windowsx.h>
#include "resource.h"
// main
extern PPH_PLUGIN PluginInstance;
#define PLUGIN_NAME L"ProcessHacker.ExtendedServices"
#define SETTING_NAME_ENABLE_SERVICES_MENU (PLUGIN_NAME L".EnableServicesMenu")
#define SIP(String, Integer) { (String), (PVOID)(Integer) }
// depend
LPENUM_SERVICE_STATUS EsEnumDependentServices(
_In_ SC_HANDLE ServiceHandle,
_In_opt_ ULONG State,
_Out_ PULONG Count
);
INT_PTR CALLBACK EspServiceDependenciesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
INT_PTR CALLBACK EspServiceDependentsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// options
VOID EsShowOptionsDialog(
_In_ HWND ParentWindowHandle
);
// other
typedef NTSTATUS (NTAPI *_RtlCreateServiceSid)(
_In_ PUNICODE_STRING ServiceName,
_Out_writes_bytes_opt_(*ServiceSidLength) PSID ServiceSid,
_Inout_ PULONG ServiceSidLength
);
INT_PTR CALLBACK EspServiceOtherDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// recovery
INT_PTR CALLBACK EspServiceRecoveryDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
INT_PTR CALLBACK EspServiceRecovery2DlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// srvprgrs
VOID EsRestartServiceWithProgress(
_In_ HWND hWnd,
_In_ PPH_SERVICE_ITEM ServiceItem,
_In_ SC_HANDLE ServiceHandle
);
// trigger
struct _ES_TRIGGER_CONTEXT;
struct _ES_TRIGGER_CONTEXT *EsCreateServiceTriggerContext(
_In_ PPH_SERVICE_ITEM ServiceItem,
_In_ HWND WindowHandle,
_In_ HWND TriggersLv
);
VOID EsDestroyServiceTriggerContext(
_In_ struct _ES_TRIGGER_CONTEXT *Context
);
VOID EsLoadServiceTriggerInfo(
_In_ struct _ES_TRIGGER_CONTEXT *Context,
_In_ SC_HANDLE ServiceHandle
);
BOOLEAN EsSaveServiceTriggerInfo(
_In_ struct _ES_TRIGGER_CONTEXT *Context,
_Out_ PULONG Win32Result
);
#define ES_TRIGGER_EVENT_NEW 1
#define ES_TRIGGER_EVENT_EDIT 2
#define ES_TRIGGER_EVENT_DELETE 3
#define ES_TRIGGER_EVENT_SELECTIONCHANGED 4
VOID EsHandleEventServiceTrigger(
_In_ struct _ES_TRIGGER_CONTEXT *Context,
_In_ ULONG Event
);
// triggpg
INT_PTR CALLBACK EspServiceTriggersDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
#endif

View File

@@ -0,0 +1,481 @@
/*
* Process Hacker Extended Services -
* main program
*
* Copyright (C) 2010-2015 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 <http://www.gnu.org/licenses/>.
*/
#include "extsrv.h"
PPH_PLUGIN PluginInstance;
static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration;
static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ServiceMenuInitializingCallbackRegistration;
VOID NTAPI LoadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
// Nothing
}
VOID NTAPI ShowOptionsCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
EsShowOptionsDialog((HWND)Parameter);
}
VOID NTAPI MenuItemCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_ITEM menuItem = Parameter;
switch (menuItem->Id)
{
case ID_SERVICE_GOTOSERVICE:
{
ProcessHacker_SelectTabPage(PhMainWndHandle, 1);
ProcessHacker_SelectServiceItem(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context);
}
break;
case ID_SERVICE_START:
{
PhUiStartService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context);
}
break;
case ID_SERVICE_CONTINUE:
{
PhUiContinueService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context);
}
break;
case ID_SERVICE_PAUSE:
{
PhUiPauseService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context);
}
break;
case ID_SERVICE_STOP:
{
PhUiStopService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context);
}
break;
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))
{
EsRestartServiceWithProgress(PhMainWndHandle, serviceItem, serviceHandle);
CloseServiceHandle(serviceHandle);
}
else
{
win32Result = GetLastError();
}
if (win32Result != 0)
{
PhShowStatus(
PhMainWndHandle,
PhaFormatString(L"Unable to restart %s", serviceItem->Name->Buffer)->Buffer,
0,
win32Result
);
}
}
break;
}
}
static int __cdecl ServiceForServicesMenuCompare(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PPH_SERVICE_ITEM serviceItem1 = *(PPH_SERVICE_ITEM *)elem1;
PPH_SERVICE_ITEM serviceItem2 = *(PPH_SERVICE_ITEM *)elem2;
return PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE);
}
VOID NTAPI ProcessMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
if (
PhGetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU) &&
menuInfo->u.Process.NumberOfProcesses == 1 &&
menuInfo->u.Process.Processes[0]->ServiceList &&
menuInfo->u.Process.Processes[0]->ServiceList->Count != 0
)
{
PPH_PROCESS_ITEM processItem;
PPH_EMENU_ITEM servicesMenuItem = NULL;
ULONG enumerationKey;
PPH_SERVICE_ITEM serviceItem;
PPH_LIST serviceList;
ULONG i;
PPH_EMENU_ITEM priorityMenuItem;
ULONG insertIndex;
processItem = menuInfo->u.Process.Processes[0];
// Create a service list so we can sort it.
serviceList = PH_AUTO(PhCreateList(processItem->ServiceList->Count));
enumerationKey = 0;
PhAcquireQueuedLockShared(&processItem->ServiceListLock);
while (PhEnumPointerList(processItem->ServiceList, &enumerationKey, &serviceItem))
{
PhReferenceObject(serviceItem);
// We need to use the service item when the user chooses a menu item.
PH_AUTO(serviceItem);
PhAddItemList(serviceList, serviceItem);
}
PhReleaseQueuedLockShared(&processItem->ServiceListLock);
// Sort the service list.
qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForServicesMenuCompare);
// If there is only one service:
// * We use the text "Service (Xxx)".
// * There are no extra submenus.
if (serviceList->Count != 1)
{
servicesMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Services", NULL);
}
// Create and add a menu item for each service.
for (i = 0; i < serviceList->Count; i++)
{
PPH_STRING escapedName;
PPH_EMENU_ITEM serviceMenuItem;
PPH_EMENU_ITEM startMenuItem;
PPH_EMENU_ITEM continueMenuItem;
PPH_EMENU_ITEM pauseMenuItem;
PPH_EMENU_ITEM stopMenuItem;
serviceItem = serviceList->Items[i];
escapedName = PH_AUTO(PhEscapeStringForMenuPrefix(&serviceItem->Name->sr));
if (serviceList->Count == 1)
{
// "Service (Xxx)"
escapedName = PhaFormatString(L"Service (%s)", escapedName->Buffer);
}
serviceMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, escapedName->Buffer, NULL);
if (serviceList->Count == 1)
{
// Make this the root submenu that we will insert.
servicesMenuItem = serviceMenuItem;
}
PhInsertEMenuItem(serviceMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_GOTOSERVICE, L"Go to service", serviceItem), -1);
PhInsertEMenuItem(serviceMenuItem, startMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_START, L"Start", serviceItem), -1);
PhInsertEMenuItem(serviceMenuItem, continueMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_CONTINUE, L"Continue", serviceItem), -1);
PhInsertEMenuItem(serviceMenuItem, pauseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_PAUSE, L"Pause", serviceItem), -1);
PhInsertEMenuItem(serviceMenuItem, stopMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_STOP, L"Stop", serviceItem), -1);
// Massive copy and paste from mainwnd.c.
// == START ==
#define SET_MENU_ITEM_ENABLED(MenuItem, Enabled) if (!(Enabled)) (MenuItem)->Flags |= PH_EMENU_DISABLED;
switch (serviceItem->State)
{
case SERVICE_RUNNING:
{
SET_MENU_ITEM_ENABLED(startMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(pauseMenuItem,
serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE);
SET_MENU_ITEM_ENABLED(stopMenuItem,
serviceItem->ControlsAccepted & SERVICE_ACCEPT_STOP);
}
break;
case SERVICE_PAUSED:
{
SET_MENU_ITEM_ENABLED(startMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(continueMenuItem,
serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE);
SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(stopMenuItem,
serviceItem->ControlsAccepted & SERVICE_ACCEPT_STOP);
}
break;
case SERVICE_STOPPED:
{
SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(stopMenuItem, FALSE);
}
break;
case SERVICE_START_PENDING:
case SERVICE_CONTINUE_PENDING:
case SERVICE_PAUSE_PENDING:
case SERVICE_STOP_PENDING:
{
SET_MENU_ITEM_ENABLED(startMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(stopMenuItem, FALSE);
}
break;
}
if (!(serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE))
{
PhDestroyEMenuItem(continueMenuItem);
PhDestroyEMenuItem(pauseMenuItem);
}
// == END ==
if (serviceList->Count != 1)
PhInsertEMenuItem(servicesMenuItem, serviceMenuItem, -1);
}
// Insert our Services menu after the I/O Priority menu.
priorityMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"I/O Priority", 0);
if (!priorityMenuItem)
priorityMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Priority", 0);
if (priorityMenuItem)
insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, priorityMenuItem) + 1;
else
insertIndex = 0;
PhInsertEMenuItem(menuInfo->Menu, servicesMenuItem, insertIndex);
}
}
NTAPI ServicePropertiesInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter;
PROPSHEETPAGE propSheetPage;
PPH_SERVICE_ITEM serviceItem;
serviceItem = objectProperties->Parameter;
// Recovery
if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages)
{
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
propSheetPage.hInstance = PluginInstance->DllBase;
propSheetPage.lParam = (LPARAM)serviceItem;
if (!(serviceItem->Flags & SERVICE_RUNS_IN_SYSTEM_PROCESS))
{
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVRECOVERY);
propSheetPage.pfnDlgProc = EspServiceRecoveryDlgProc;
}
else
{
// Services which run in system processes don't support failure actions.
// Create a different page with a message saying this.
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVRECOVERY2);
propSheetPage.pfnDlgProc = EspServiceRecovery2DlgProc;
}
objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage);
}
// Dependencies
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_SRVLIST);
propSheetPage.pszTitle = L"Dependencies";
propSheetPage.pfnDlgProc = EspServiceDependenciesDlgProc;
propSheetPage.lParam = (LPARAM)serviceItem;
objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage);
}
// Dependents
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_SRVLIST);
propSheetPage.pszTitle = L"Dependents";
propSheetPage.pfnDlgProc = EspServiceDependentsDlgProc;
propSheetPage.lParam = (LPARAM)serviceItem;
objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage);
}
// Other
if (WindowsVersion >= WINDOWS_7 && 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_SRVTRIGGERS);
propSheetPage.pszTitle = L"Triggers";
propSheetPage.pfnDlgProc = EspServiceTriggersDlgProc;
propSheetPage.lParam = (LPARAM)serviceItem;
objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage);
}
// Other
if (WindowsVersion >= WINDOWS_VISTA && 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_SRVOTHER);
propSheetPage.pszTitle = L"Other";
propSheetPage.pfnDlgProc = EspServiceOtherDlgProc;
propSheetPage.lParam = (LPARAM)serviceItem;
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 || menuInfo->u.Service.Services[0]->State == SERVICE_PAUSED)
)
{
// 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);
else
indexOfMenuItem = -1;
PhInsertEMenuItem(
menuInfo->Menu,
PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_RESTART, L"Restart", menuInfo->u.Service.Services[0]),
indexOfMenuItem + 1
);
}
}
LOGICAL DllMain(
_In_ HINSTANCE Instance,
_In_ ULONG Reason,
_Reserved_ PVOID Reserved
)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH:
{
PPH_PLUGIN_INFORMATION info;
PH_SETTING_CREATE settings[] =
{
{ IntegerSettingType, SETTING_NAME_ENABLE_SERVICES_MENU, L"1" }
};
PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info);
if (!PluginInstance)
return FALSE;
info->DisplayName = L"Extended Services";
info->Author = L"wj32";
info->Description = L"Extends service management capabilities.";
info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1113";
info->HasOptions = TRUE;
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackLoad),
LoadCallback,
NULL,
&PluginLoadCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions),
ShowOptionsCallback,
NULL,
&PluginShowOptionsCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem),
MenuItemCallback,
NULL,
&PluginMenuItemCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing),
ProcessMenuInitializingCallback,
NULL,
&ProcessMenuInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing),
ServicePropertiesInitializingCallback,
NULL,
&ServicePropertiesInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackServiceMenuInitializing),
ServiceMenuInitializingCallback,
NULL,
&ServiceMenuInitializingCallbackRegistration
);
PhAddSettings(settings, ARRAYSIZE(settings));
}
break;
}
return TRUE;
}

View File

@@ -0,0 +1,72 @@
/*
* Process Hacker Extended Services -
* options dialog
*
* Copyright (C) 2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "extsrv.h"
INT_PTR CALLBACK OptionsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU), PhGetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU) ? BST_CHECKED : BST_UNCHECKED);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDOK:
{
PhSetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU,
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU)) == BST_CHECKED);
EndDialog(hwndDlg, IDOK);
}
break;
}
}
break;
}
return FALSE;
}
VOID EsShowOptionsDialog(
_In_ HWND ParentWindowHandle
)
{
DialogBox(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_OPTIONS),
ParentWindowHandle,
OptionsDlgProc
);
}

View File

@@ -0,0 +1,732 @@
/*
* Process Hacker Extended Services -
* other information
*
* Copyright (C) 2010-2015 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 <http://www.gnu.org/licenses/>.
*/
#include "extsrv.h"
typedef struct _SERVICE_OTHER_CONTEXT
{
PPH_SERVICE_ITEM ServiceItem;
struct
{
ULONG Ready : 1;
ULONG Dirty : 1;
ULONG PreshutdownTimeoutValid : 1;
ULONG RequiredPrivilegesValid : 1;
ULONG SidTypeValid : 1;
ULONG LaunchProtectedValid : 1;
};
HWND PrivilegesLv;
PPH_LIST PrivilegeList;
ULONG OriginalLaunchProtected;
} SERVICE_OTHER_CONTEXT, *PSERVICE_OTHER_CONTEXT;
static _RtlCreateServiceSid RtlCreateServiceSid_I = NULL;
static PH_KEY_VALUE_PAIR EspServiceSidTypePairs[] =
{
SIP(L"None", SERVICE_SID_TYPE_NONE),
SIP(L"Restricted", SERVICE_SID_TYPE_RESTRICTED),
SIP(L"Unrestricted", SERVICE_SID_TYPE_UNRESTRICTED)
};
static PH_KEY_VALUE_PAIR EspServiceLaunchProtectedPairs[] =
{
SIP(L"None", SERVICE_LAUNCH_PROTECTED_NONE),
SIP(L"Full (Windows)", SERVICE_LAUNCH_PROTECTED_WINDOWS),
SIP(L"Light (Windows)", SERVICE_LAUNCH_PROTECTED_WINDOWS_LIGHT),
SIP(L"Light (Antimalware)", SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT)
};
static WCHAR *EspServiceSidTypeStrings[3] = { L"None", L"Restricted", L"Unrestricted" };
static WCHAR *EspServiceLaunchProtectedStrings[4] = { L"None", L"Full (Windows)", L"Light (Windows)", L"Light (Antimalware)" };
PWSTR EspGetServiceSidTypeString(
_In_ ULONG SidType
)
{
PWSTR string;
if (PhFindStringSiKeyValuePairs(
EspServiceSidTypePairs,
sizeof(EspServiceSidTypePairs),
SidType,
&string
))
return string;
else
return L"Unknown";
}
ULONG EspGetServiceSidTypeInteger(
_In_ PWSTR SidType
)
{
ULONG integer;
if (PhFindIntegerSiKeyValuePairs(
EspServiceSidTypePairs,
sizeof(EspServiceSidTypePairs),
SidType,
&integer
))
return integer;
else
return -1;
}
PWSTR EspGetServiceLaunchProtectedString(
_In_ ULONG LaunchProtected
)
{
PWSTR string;
if (PhFindStringSiKeyValuePairs(
EspServiceLaunchProtectedPairs,
sizeof(EspServiceLaunchProtectedPairs),
LaunchProtected,
&string
))
return string;
else
return L"Unknown";
}
ULONG EspGetServiceLaunchProtectedInteger(
_In_ PWSTR LaunchProtected
)
{
ULONG integer;
if (PhFindIntegerSiKeyValuePairs(
EspServiceLaunchProtectedPairs,
sizeof(EspServiceLaunchProtectedPairs),
LaunchProtected,
&integer
))
return integer;
else
return -1;
}
NTSTATUS EspLoadOtherInfo(
_In_ HWND hwndDlg,
_In_ PSERVICE_OTHER_CONTEXT Context
)
{
NTSTATUS status = STATUS_SUCCESS;
SC_HANDLE serviceHandle;
ULONG returnLength;
SERVICE_PRESHUTDOWN_INFO preshutdownInfo;
LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo;
SERVICE_SID_INFO sidInfo;
SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo;
if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)))
return NTSTATUS_FROM_WIN32(GetLastError());
// Preshutdown timeout
if (QueryServiceConfig2(serviceHandle,
SERVICE_CONFIG_PRESHUTDOWN_INFO,
(PBYTE)&preshutdownInfo,
sizeof(SERVICE_PRESHUTDOWN_INFO),
&returnLength
))
{
SetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, preshutdownInfo.dwPreshutdownTimeout, FALSE);
Context->PreshutdownTimeoutValid = TRUE;
}
// Required privileges
if (requiredPrivilegesInfo = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO))
{
PWSTR privilege;
ULONG privilegeLength;
INT lvItemIndex;
PH_STRINGREF privilegeSr;
PPH_STRING privilegeString;
PPH_STRING displayName;
privilege = requiredPrivilegesInfo->pmszRequiredPrivileges;
if (privilege)
{
while (TRUE)
{
privilegeLength = (ULONG)PhCountStringZ(privilege);
if (privilegeLength == 0)
break;
privilegeString = PhCreateStringEx(privilege, privilegeLength * sizeof(WCHAR));
PhAddItemList(Context->PrivilegeList, privilegeString);
lvItemIndex = PhAddListViewItem(Context->PrivilegesLv, MAXINT, privilege, privilegeString);
privilegeSr.Buffer = privilege;
privilegeSr.Length = privilegeLength * sizeof(WCHAR);
if (PhLookupPrivilegeDisplayName(&privilegeSr, &displayName))
{
PhSetListViewSubItem(Context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer);
PhDereferenceObject(displayName);
}
privilege += privilegeLength + 1;
}
}
ExtendedListView_SortItems(Context->PrivilegesLv);
PhFree(requiredPrivilegesInfo);
Context->RequiredPrivilegesValid = TRUE;
}
// SID type
if (QueryServiceConfig2(serviceHandle,
SERVICE_CONFIG_SERVICE_SID_INFO,
(PBYTE)&sidInfo,
sizeof(SERVICE_SID_INFO),
&returnLength
))
{
PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_SIDTYPE),
EspGetServiceSidTypeString(sidInfo.dwServiceSidType), FALSE);
Context->SidTypeValid = TRUE;
}
// Launch protected
if (QueryServiceConfig2(serviceHandle,
SERVICE_CONFIG_LAUNCH_PROTECTED,
(PBYTE)&launchProtectedInfo,
sizeof(SERVICE_LAUNCH_PROTECTED_INFO),
&returnLength
))
{
PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_PROTECTION),
EspGetServiceLaunchProtectedString(launchProtectedInfo.dwLaunchProtected), FALSE);
Context->LaunchProtectedValid = TRUE;
Context->OriginalLaunchProtected = launchProtectedInfo.dwLaunchProtected;
}
CloseServiceHandle(serviceHandle);
return status;
}
PPH_STRING EspGetServiceSidString(
_In_ PPH_STRINGREF ServiceName
)
{
PSID serviceSid = NULL;
UNICODE_STRING serviceNameUs;
ULONG serviceSidLength = 0;
PPH_STRING sidString = NULL;
if (!RtlCreateServiceSid_I)
{
if (!(RtlCreateServiceSid_I = PhGetModuleProcAddress(L"ntdll.dll", "RtlCreateServiceSid")))
return NULL;
}
PhStringRefToUnicodeString(ServiceName, &serviceNameUs);
if (RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength) == STATUS_BUFFER_TOO_SMALL)
{
serviceSid = PhAllocate(serviceSidLength);
if (NT_SUCCESS(RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength)))
sidString = PhSidToStringSid(serviceSid);
PhFree(serviceSid);
}
return sidString;
}
BOOLEAN EspChangeServiceConfig2(
_In_ PWSTR ServiceName,
_In_opt_ SC_HANDLE ServiceHandle,
_In_ ULONG InfoLevel,
_In_ PVOID Info
)
{
if (ServiceHandle)
{
return !!ChangeServiceConfig2(ServiceHandle, InfoLevel, Info);
}
else
{
NTSTATUS status;
if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig2(ServiceName, InfoLevel, Info)))
{
return TRUE;
}
else
{
SetLastError(PhNtStatusToDosError(status));
return FALSE;
}
}
}
static int __cdecl PrivilegeNameCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PWSTR string1 = *(PWSTR *)elem1;
PWSTR string2 = *(PWSTR *)elem2;
return PhCompareStringZ(string1, string2, TRUE);
}
INT_PTR CALLBACK EspServiceOtherDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_OTHER_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_OTHER_CONTEXT));
memset(context, 0, sizeof(SERVICE_OTHER_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_OTHER_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
NTSTATUS status;
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam;
HWND privilegesLv;
context->ServiceItem = serviceItem;
context->PrivilegesLv = privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES);
PhSetListViewStyle(privilegesLv, FALSE, TRUE);
PhSetControlTheme(privilegesLv, L"explorer");
PhAddListViewColumn(privilegesLv, 0, 0, 0, LVCFMT_LEFT, 140, L"Name");
PhAddListViewColumn(privilegesLv, 1, 1, 1, LVCFMT_LEFT, 220, L"Display name");
PhSetExtendedListView(privilegesLv);
context->PrivilegeList = PhCreateList(32);
if (context->ServiceItem->Type == SERVICE_KERNEL_DRIVER || context->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER)
{
// Drivers don't support required privileges.
EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE);
}
EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), FALSE);
PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_SIDTYPE),
EspServiceSidTypeStrings, sizeof(EspServiceSidTypeStrings) / sizeof(PWSTR));
PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_PROTECTION),
EspServiceLaunchProtectedStrings, sizeof(EspServiceLaunchProtectedStrings) / sizeof(PWSTR));
if (WindowsVersion < WINDOWS_8_1)
EnableWindow(GetDlgItem(hwndDlg, IDC_PROTECTION), FALSE);
SetDlgItemText(hwndDlg, IDC_SERVICESID,
PhGetStringOrDefault(PH_AUTO(EspGetServiceSidString(&serviceItem->Name->sr)), L"N/A"));
status = EspLoadOtherInfo(hwndDlg, context);
if (!NT_SUCCESS(status))
{
PhShowWarning(hwndDlg, L"Unable to query service information: %s",
((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer);
}
context->Ready = TRUE;
}
break;
case WM_DESTROY:
{
if (context->PrivilegeList)
{
PhDereferenceObjects(context->PrivilegeList->Items, context->PrivilegeList->Count);
PhDereferenceObject(context->PrivilegeList);
}
PhFree(context);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_ADD:
{
NTSTATUS status;
LSA_HANDLE policyHandle;
LSA_ENUMERATION_HANDLE enumContext;
PPOLICY_PRIVILEGE_DEFINITION buffer;
ULONG count;
ULONG i;
PPH_LIST choices;
PPH_STRING selectedChoice = NULL;
choices = PH_AUTO(PhCreateList(100));
if (!NT_SUCCESS(status = PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL)))
{
PhShowStatus(hwndDlg, L"Unable to open LSA policy", status, 0);
break;
}
enumContext = 0;
while (TRUE)
{
status = LsaEnumeratePrivileges(
policyHandle,
&enumContext,
&buffer,
0x100,
&count
);
if (status == STATUS_NO_MORE_ENTRIES)
break;
if (!NT_SUCCESS(status))
break;
for (i = 0; i < count; i++)
{
PhAddItemList(choices, PhaCreateStringEx(buffer[i].Name.Buffer, buffer[i].Name.Length)->Buffer);
}
LsaFreeMemory(buffer);
}
LsaClose(policyHandle);
qsort(choices->Items, choices->Count, sizeof(PWSTR), PrivilegeNameCompareFunction);
while (PhaChoiceDialog(
hwndDlg,
L"Add privilege",
L"Select a privilege to add:",
(PWSTR *)choices->Items,
choices->Count,
NULL,
PH_CHOICE_DIALOG_CHOICE,
&selectedChoice,
NULL,
NULL
))
{
BOOLEAN found = FALSE;
PPH_STRING privilegeString;
INT lvItemIndex;
PPH_STRING displayName;
// Check for duplicates.
for (i = 0; i < context->PrivilegeList->Count; i++)
{
if (PhEqualString(context->PrivilegeList->Items[i], selectedChoice, FALSE))
{
found = TRUE;
break;
}
}
if (found)
{
if (PhShowMessage(
hwndDlg,
MB_OKCANCEL | MB_ICONERROR,
L"The selected privilege has already been added."
) == IDOK)
{
continue;
}
else
{
break;
}
}
PhSetReference(&privilegeString, selectedChoice);
PhAddItemList(context->PrivilegeList, privilegeString);
lvItemIndex = PhAddListViewItem(context->PrivilegesLv, MAXINT, privilegeString->Buffer, privilegeString);
if (PhLookupPrivilegeDisplayName(&privilegeString->sr, &displayName))
{
PhSetListViewSubItem(context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer);
PhDereferenceObject(displayName);
}
ExtendedListView_SortItems(context->PrivilegesLv);
context->Dirty = TRUE;
context->RequiredPrivilegesValid = TRUE;
break;
}
}
break;
case IDC_REMOVE:
{
INT lvItemIndex;
PPH_STRING privilegeString;
ULONG index;
lvItemIndex = ListView_GetNextItem(context->PrivilegesLv, -1, LVNI_SELECTED);
if (lvItemIndex != -1 && PhGetListViewItemParam(context->PrivilegesLv, lvItemIndex, (PVOID *)&privilegeString))
{
index = PhFindItemList(context->PrivilegeList, privilegeString);
if (index != -1)
{
PhDereferenceObject(privilegeString);
PhRemoveItemList(context->PrivilegeList, index);
PhRemoveListViewItem(context->PrivilegesLv, lvItemIndex);
context->Dirty = TRUE;
context->RequiredPrivilegesValid = TRUE;
}
}
}
break;
}
switch (HIWORD(wParam))
{
case EN_CHANGE:
case CBN_SELCHANGE:
{
if (context->Ready)
{
context->Dirty = TRUE;
switch (LOWORD(wParam))
{
case IDC_PRESHUTDOWNTIMEOUT:
context->PreshutdownTimeoutValid = TRUE;
break;
case IDC_SIDTYPE:
context->SidTypeValid = TRUE;
break;
case IDC_PROTECTION:
context->LaunchProtectedValid = TRUE;
break;
}
}
}
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:
{
SC_HANDLE serviceHandle = NULL;
ULONG win32Result = 0;
BOOLEAN connectedToPhSvc = FALSE;
PPH_STRING launchProtectedString;
ULONG launchProtected;
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
launchProtectedString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_PROTECTION)));
launchProtected = EspGetServiceLaunchProtectedInteger(launchProtectedString->Buffer);
if (context->LaunchProtectedValid && launchProtected != 0 && launchProtected != context->OriginalLaunchProtected)
{
if (PhShowMessage(
hwndDlg,
MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2,
L"Setting service protection will prevent the service from being controlled, modified, or deleted. Do you want to continue?"
) == IDNO)
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
return TRUE;
}
}
if (context->Dirty)
{
SERVICE_PRESHUTDOWN_INFO preshutdownInfo;
SERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo;
SERVICE_SID_INFO sidInfo;
SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo;
if (!(serviceHandle = PhOpenService(context->ServiceItem->Name->Buffer, SERVICE_CHANGE_CONFIG)))
{
win32Result = GetLastError();
if (win32Result == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated)
{
// Elevate using phsvc.
if (PhUiConnectToPhSvc(hwndDlg, FALSE))
{
win32Result = 0;
connectedToPhSvc = TRUE;
}
else
{
// User cancelled elevation.
win32Result = ERROR_CANCELLED;
goto Done;
}
}
else
{
goto Done;
}
}
if (context->PreshutdownTimeoutValid)
{
preshutdownInfo.dwPreshutdownTimeout = GetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, NULL, FALSE);
if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
SERVICE_CONFIG_PRESHUTDOWN_INFO, &preshutdownInfo))
{
win32Result = GetLastError();
}
}
if (context->RequiredPrivilegesValid)
{
PH_STRING_BUILDER sb;
ULONG i;
PhInitializeStringBuilder(&sb, 100);
for (i = 0; i < context->PrivilegeList->Count; i++)
{
PhAppendStringBuilder(&sb, &((PPH_STRING)context->PrivilegeList->Items[i])->sr);
PhAppendCharStringBuilder(&sb, 0);
}
requiredPrivilegesInfo.pmszRequiredPrivileges = sb.String->Buffer;
if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, &requiredPrivilegesInfo))
{
win32Result = GetLastError();
}
PhDeleteStringBuilder(&sb);
}
if (context->SidTypeValid)
{
PPH_STRING sidTypeString;
sidTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_SIDTYPE)));
sidInfo.dwServiceSidType = EspGetServiceSidTypeInteger(sidTypeString->Buffer);
if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
SERVICE_CONFIG_SERVICE_SID_INFO, &sidInfo))
{
win32Result = GetLastError();
}
}
if (context->LaunchProtectedValid)
{
launchProtectedInfo.dwLaunchProtected = launchProtected;
if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
SERVICE_CONFIG_LAUNCH_PROTECTED, &launchProtectedInfo))
{
// For now, ignore errors here.
// win32Result = GetLastError();
}
}
Done:
if (connectedToPhSvc)
PhUiDisconnectFromPhSvc();
if (serviceHandle)
CloseServiceHandle(serviceHandle);
if (win32Result != 0)
{
if (win32Result == ERROR_CANCELLED || PhShowMessage(
hwndDlg,
MB_ICONERROR | MB_RETRYCANCEL,
L"Unable to change service information: %s",
((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer
) == IDRETRY)
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
}
}
}
return TRUE;
}
break;
case LVN_ITEMCHANGED:
{
if (header->hwndFrom == context->PrivilegesLv)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), ListView_GetSelectedCount(context->PrivilegesLv) == 1);
}
}
break;
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,709 @@
/*
* Process Hacker Extended Services -
* recovery information
*
* Copyright (C) 2010-2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "extsrv.h"
typedef struct _SERVICE_RECOVERY_CONTEXT
{
PPH_SERVICE_ITEM ServiceItem;
ULONG NumberOfActions;
BOOLEAN EnableFlagCheckBox;
ULONG RebootAfter; // in ms
PPH_STRING RebootMessage;
BOOLEAN Ready;
BOOLEAN Dirty;
} SERVICE_RECOVERY_CONTEXT, *PSERVICE_RECOVERY_CONTEXT;
static PH_KEY_VALUE_PAIR ServiceActionPairs[] =
{
SIP(L"Take no action", SC_ACTION_NONE),
SIP(L"Restart the service", SC_ACTION_RESTART),
SIP(L"Run a program", SC_ACTION_RUN_COMMAND),
SIP(L"Restart the computer", SC_ACTION_REBOOT)
};
INT_PTR CALLBACK RestartComputerDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EspAddServiceActionStrings(
_In_ HWND ComboBoxHandle
)
{
ULONG i;
for (i = 0; i < sizeof(ServiceActionPairs) / sizeof(PH_KEY_VALUE_PAIR); i++)
ComboBox_AddString(ComboBoxHandle, (PWSTR)ServiceActionPairs[i].Key);
PhSelectComboBoxString(ComboBoxHandle, (PWSTR)ServiceActionPairs[0].Key, FALSE);
}
SC_ACTION_TYPE EspStringToServiceAction(
_In_ PWSTR String
)
{
ULONG integer;
if (PhFindIntegerSiKeyValuePairs(ServiceActionPairs, sizeof(ServiceActionPairs), String, &integer))
return integer;
else
return 0;
}
PWSTR EspServiceActionToString(
_In_ SC_ACTION_TYPE ActionType
)
{
PWSTR string;
if (PhFindStringSiKeyValuePairs(ServiceActionPairs, sizeof(ServiceActionPairs), ActionType, &string))
return string;
else
return NULL;
}
SC_ACTION_TYPE ComboBoxToServiceAction(
_In_ HWND ComboBoxHandle
)
{
PPH_STRING string;
string = PH_AUTO(PhGetComboBoxString(ComboBoxHandle, ComboBox_GetCurSel(ComboBoxHandle)));
if (!string)
return SC_ACTION_NONE;
return EspStringToServiceAction(string->Buffer);
}
VOID ServiceActionToComboBox(
_In_ HWND ComboBoxHandle,
_In_ SC_ACTION_TYPE ActionType
)
{
PWSTR string;
if (string = EspServiceActionToString(ActionType))
PhSelectComboBoxString(ComboBoxHandle, string, FALSE);
else
PhSelectComboBoxString(ComboBoxHandle, (PWSTR)ServiceActionPairs[0].Key, FALSE);
}
VOID EspFixControls(
_In_ HWND hwndDlg,
_In_ PSERVICE_RECOVERY_CONTEXT Context
)
{
SC_ACTION_TYPE action1;
SC_ACTION_TYPE action2;
SC_ACTION_TYPE actionS;
BOOLEAN enableRestart;
BOOLEAN enableReboot;
BOOLEAN enableCommand;
action1 = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE));
action2 = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SECONDFAILURE));
actionS = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES));
EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), Context->EnableFlagCheckBox);
enableRestart = action1 == SC_ACTION_RESTART || action2 == SC_ACTION_RESTART || actionS == SC_ACTION_RESTART;
enableReboot = action1 == SC_ACTION_REBOOT || action2 == SC_ACTION_REBOOT || actionS == SC_ACTION_REBOOT;
enableCommand = action1 == SC_ACTION_RUN_COMMAND || action2 == SC_ACTION_RUN_COMMAND || actionS == SC_ACTION_RUN_COMMAND;
EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER_LABEL), enableRestart);
EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER), enableRestart);
EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER_MINUTES), enableRestart);
EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTCOMPUTEROPTIONS), enableReboot);
EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_GROUP), enableCommand);
EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_LABEL), enableCommand);
EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM), enableCommand);
EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), enableCommand);
EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_INFO), enableCommand);
}
NTSTATUS EspLoadRecoveryInfo(
_In_ HWND hwndDlg,
_In_ PSERVICE_RECOVERY_CONTEXT Context
)
{
NTSTATUS status = STATUS_SUCCESS;
SC_HANDLE serviceHandle;
LPSERVICE_FAILURE_ACTIONS failureActions;
SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag;
SC_ACTION_TYPE lastType;
ULONG returnLength;
ULONG i;
if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)))
return NTSTATUS_FROM_WIN32(GetLastError());
if (!(failureActions = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS)))
{
CloseServiceHandle(serviceHandle);
return NTSTATUS_FROM_WIN32(GetLastError());
}
// Failure action types
Context->NumberOfActions = failureActions->cActions;
if (failureActions->cActions != 0 && failureActions->cActions != 3)
status = STATUS_SOME_NOT_MAPPED;
// If failure actions are not defined for a particular fail count, the
// last failure action is used. Here we duplicate this behaviour when there
// are fewer than 3 failure actions.
lastType = SC_ACTION_NONE;
ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE),
failureActions->cActions >= 1 ? (lastType = failureActions->lpsaActions[0].Type) : lastType);
ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_SECONDFAILURE),
failureActions->cActions >= 2 ? (lastType = failureActions->lpsaActions[1].Type) : lastType);
ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES),
failureActions->cActions >= 3 ? (lastType = failureActions->lpsaActions[2].Type) : lastType);
// Reset fail count after
SetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, failureActions->dwResetPeriod / (60 * 60 * 24), FALSE); // s to days
// Restart service after
SetDlgItemText(hwndDlg, IDC_RESTARTSERVICEAFTER, L"1");
for (i = 0; i < failureActions->cActions; i++)
{
if (failureActions->lpsaActions[i].Type == SC_ACTION_RESTART)
{
if (failureActions->lpsaActions[i].Delay != 0)
{
SetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER,
failureActions->lpsaActions[i].Delay / (1000 * 60), FALSE); // ms to min
}
break;
}
}
// Enable actions for stops with errors
// This is Vista and above only.
if (WindowsVersion >= WINDOWS_VISTA && QueryServiceConfig2(
serviceHandle,
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG,
(BYTE *)&failureActionsFlag,
sizeof(SERVICE_FAILURE_ACTIONS_FLAG),
&returnLength
))
{
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS),
failureActionsFlag.fFailureActionsOnNonCrashFailures ? BST_CHECKED : BST_UNCHECKED);
Context->EnableFlagCheckBox = TRUE;
}
else
{
Context->EnableFlagCheckBox = FALSE;
}
// Restart computer options
Context->RebootAfter = 1 * 1000 * 60;
for (i = 0; i < failureActions->cActions; i++)
{
if (failureActions->lpsaActions[i].Type == SC_ACTION_REBOOT)
{
if (failureActions->lpsaActions[i].Delay != 0)
Context->RebootAfter = failureActions->lpsaActions[i].Delay;
break;
}
}
if (failureActions->lpRebootMsg && failureActions->lpRebootMsg[0] != 0)
PhMoveReference(&Context->RebootMessage, PhCreateString(failureActions->lpRebootMsg));
else
PhClearReference(&Context->RebootMessage);
// Run program
SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, failureActions->lpCommand);
PhFree(failureActions);
CloseServiceHandle(serviceHandle);
return status;
}
INT_PTR CALLBACK EspServiceRecoveryDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_RECOVERY_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_RECOVERY_CONTEXT));
memset(context, 0, sizeof(SERVICE_RECOVERY_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
NTSTATUS status;
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam;
context->ServiceItem = serviceItem;
EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE));
EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_SECONDFAILURE));
EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES));
status = EspLoadRecoveryInfo(hwndDlg, context);
if (status == STATUS_SOME_NOT_MAPPED)
{
if (context->NumberOfActions > 3)
{
PhShowWarning(
hwndDlg,
L"The service has %lu failure actions configured, but this program only supports editing 3. "
L"If you save the recovery information using this program, the additional failure actions will be lost.",
context->NumberOfActions
);
}
}
else if (!NT_SUCCESS(status))
{
SetDlgItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0");
if (WindowsVersion >= WINDOWS_VISTA)
{
context->EnableFlagCheckBox = TRUE;
EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE);
}
PhShowWarning(hwndDlg, L"Unable to query service recovery information: %s",
((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer);
}
EspFixControls(hwndDlg, context);
context->Ready = TRUE;
}
break;
case WM_DESTROY:
{
PhClearReference(&context->RebootMessage);
PhFree(context);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_FIRSTFAILURE:
case IDC_SECONDFAILURE:
case IDC_SUBSEQUENTFAILURES:
{
if (HIWORD(wParam) == CBN_SELCHANGE)
{
EspFixControls(hwndDlg, context);
}
}
break;
case IDC_RESTARTCOMPUTEROPTIONS:
{
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_RESTARTCOMP),
hwndDlg,
RestartComputerDlgProc,
(LPARAM)context
);
}
break;
case IDC_BROWSE:
{
static PH_FILETYPE_FILTER filters[] =
{
{ L"Executable files (*.exe;*.cmd;*.bat)", L"*.exe;*.cmd;*.bat" },
{ L"All files (*.*)", L"*.*" }
};
PVOID fileDialog;
PPH_STRING fileName;
fileDialog = PhCreateOpenFileDialog();
PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
fileName = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM);
PhSetFileDialogFileName(fileDialog, fileName->Buffer);
if (PhShowFileDialog(hwndDlg, fileDialog))
{
fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));
SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, fileName->Buffer);
}
PhFreeFileDialog(fileDialog);
}
break;
case IDC_ENABLEFORERRORSTOPS:
{
context->Dirty = TRUE;
}
break;
}
switch (HIWORD(wParam))
{
case EN_CHANGE:
case CBN_SELCHANGE:
{
if (context->Ready)
context->Dirty = 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:
{
NTSTATUS status;
PPH_SERVICE_ITEM serviceItem = context->ServiceItem;
SC_HANDLE serviceHandle;
ULONG restartServiceAfter;
SERVICE_FAILURE_ACTIONS failureActions;
SC_ACTION actions[3];
ULONG i;
BOOLEAN enableRestart = FALSE;
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
if (!context->Dirty)
{
return TRUE;
}
// Build the failure actions structure.
failureActions.dwResetPeriod = GetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, NULL, FALSE) * 60 * 60 * 24;
failureActions.lpRebootMsg = PhGetStringOrEmpty(context->RebootMessage);
failureActions.lpCommand = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM)->Buffer;
failureActions.cActions = 3;
failureActions.lpsaActions = actions;
actions[0].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE));
actions[1].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SECONDFAILURE));
actions[2].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES));
restartServiceAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER, NULL, FALSE) * 1000 * 60;
for (i = 0; i < 3; i++)
{
switch (actions[i].Type)
{
case SC_ACTION_RESTART:
actions[i].Delay = restartServiceAfter;
enableRestart = TRUE;
break;
case SC_ACTION_REBOOT:
actions[i].Delay = context->RebootAfter;
break;
case SC_ACTION_RUN_COMMAND:
actions[i].Delay = 0;
break;
}
}
// Try to save the changes.
serviceHandle = PhOpenService(
serviceItem->Name->Buffer,
SERVICE_CHANGE_CONFIG | (enableRestart ? SERVICE_START : 0) // SC_ACTION_RESTART requires SERVICE_START
);
if (serviceHandle)
{
if (ChangeServiceConfig2(
serviceHandle,
SERVICE_CONFIG_FAILURE_ACTIONS,
&failureActions
))
{
if (context->EnableFlagCheckBox)
{
SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag;
failureActionsFlag.fFailureActionsOnNonCrashFailures =
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS)) == BST_CHECKED;
ChangeServiceConfig2(
serviceHandle,
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG,
&failureActionsFlag
);
}
CloseServiceHandle(serviceHandle);
}
else
{
CloseServiceHandle(serviceHandle);
goto ErrorCase;
}
}
else
{
if (GetLastError() == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated)
{
// Elevate using phsvc.
if (PhUiConnectToPhSvc(hwndDlg, FALSE))
{
if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig2(
serviceItem->Name->Buffer,
SERVICE_CONFIG_FAILURE_ACTIONS,
&failureActions
)))
{
if (context->EnableFlagCheckBox)
{
SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag;
failureActionsFlag.fFailureActionsOnNonCrashFailures =
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS)) == BST_CHECKED;
PhSvcCallChangeServiceConfig2(
serviceItem->Name->Buffer,
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG,
&failureActionsFlag
);
}
}
PhUiDisconnectFromPhSvc();
if (!NT_SUCCESS(status))
{
SetLastError(PhNtStatusToDosError(status));
goto ErrorCase;
}
}
else
{
// User cancelled elevation.
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
}
}
else
{
goto ErrorCase;
}
}
return TRUE;
ErrorCase:
if (PhShowMessage(
hwndDlg,
MB_ICONERROR | MB_RETRYCANCEL,
L"Unable to change service recovery information: %s",
((PPH_STRING)PH_AUTO(PhGetWin32Message(GetLastError())))->Buffer
) == IDRETRY)
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
}
}
return TRUE;
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK EspServiceRecovery2DlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
return FALSE;
}
INT_PTR CALLBACK RestartComputerDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_RECOVERY_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = (PSERVICE_RECOVERY_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
SetDlgItemInt(hwndDlg, IDC_RESTARTCOMPAFTER, context->RebootAfter / (1000 * 60), FALSE); // ms to min
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), context->RebootMessage ? BST_CHECKED : BST_UNCHECKED);
SetDlgItemText(hwndDlg, IDC_RESTARTMESSAGE, PhGetString(context->RebootMessage));
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), TRUE);
Edit_SetSel(GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), 0, -1);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDOK:
{
context->RebootAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTCOMPAFTER, NULL, FALSE) * 1000 * 60;
if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE)) == BST_CHECKED)
PhMoveReference(&context->RebootMessage, PhGetWindowText(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE)));
else
PhClearReference(&context->RebootMessage);
context->Dirty = TRUE;
EndDialog(hwndDlg, IDOK);
}
break;
case IDC_USEDEFAULTMESSAGE:
{
PPH_STRING message;
PWSTR computerName;
ULONG bufferSize;
BOOLEAN allocated = TRUE;
// Get the computer name.
bufferSize = 64;
computerName = PhAllocate((bufferSize + 1) * sizeof(WCHAR));
if (!GetComputerName(computerName, &bufferSize))
{
PhFree(computerName);
computerName = PhAllocate((bufferSize + 1) * sizeof(WCHAR));
if (!GetComputerName(computerName, &bufferSize))
{
PhFree(computerName);
computerName = L"(unknown)";
allocated = FALSE;
}
}
// This message is exactly the same as the one in the Services console,
// except the double spaces are replaced by single spaces.
message = PhaFormatString(
L"Your computer is connected to the computer named %s. "
L"The %s service on %s has ended unexpectedly. "
L"%s will restart automatically, and then you can reestablish the connection.",
computerName,
context->ServiceItem->Name->Buffer,
computerName,
computerName
);
SetDlgItemText(hwndDlg, IDC_RESTARTMESSAGE, message->Buffer);
if (allocated)
PhFree(computerName);
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), BST_CHECKED);
}
break;
case IDC_RESTARTMESSAGE:
{
if (HIWORD(wParam) == EN_CHANGE)
{
// A zero length restart message disables it, so we might as well uncheck the box.
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE),
GetWindowTextLength(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE)) != 0 ? BST_CHECKED : BST_UNCHECKED);
}
}
break;
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,73 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by ExtendedServices.rc
//
#define IDD_SVCLIST 101
#define IDD_SRVLIST 101
#define ID_SERVICE_RESTART 101
#define IDD_SRVRECOVERY 102
#define ID_SERVICE_START 102
#define IDD_RESTARTCOMP 103
#define ID_SERVICE_STOP 103
#define IDD_SRVRECOVERY2 104
#define ID_SERVICE_GOTOSERVICE 104
#define IDD_SRVPROGRESS 105
#define ID_SERVICE_CONTINUE 105
#define IDD_SRVOTHER 106
#define ID_SERVICE_PAUSE 106
#define IDD_OPTIONS 107
#define IDD_SRVTRIGGER 108
#define IDD_VALUE 109
#define IDD_SRVTRIGGERS 110
#define IDC_SERVICES_LAYOUT 1001
#define IDC_MESSAGE 1002
#define IDC_FIRSTFAILURE 1003
#define IDC_SECONDFAILURE 1004
#define IDC_SUBSEQUENTFAILURES 1005
#define IDC_RESETFAILCOUNT 1006
#define IDC_RESTARTSERVICEAFTER 1007
#define IDC_RESTARTSERVICEAFTER_LABEL 1008
#define IDC_RESTARTSERVICEAFTER_MINUTES 1009
#define IDC_ENABLEFORERRORSTOPS 1011
#define IDC_RESTARTCOMPUTEROPTIONS 1012
#define IDC_RUNPROGRAM 1014
#define IDC_BROWSE 1015
#define IDC_RESTARTCOMPAFTER 1016
#define IDC_ENABLERESTARTMESSAGE 1017
#define IDC_RESTARTMESSAGE 1018
#define IDC_RUNPROGRAM_GROUP 1019
#define IDC_RUNPROGRAM_LABEL 1020
#define IDC_RUNPROGRAM_INFO 1021
#define IDC_USEDEFAULTMESSAGE 1022
#define IDC_PROGRESS 1023
#define IDC_PRESHUTDOWNTIMEOUT 1024
#define IDC_PRIVILEGES 1025
#define IDC_TRIGGERS 1026
#define IDC_TRIGGERS_LABEL 1027
#define IDC_ENABLESERVICESMENU 1028
#define IDC_TYPE 1029
#define IDC_SUBTYPE 1030
#define IDC_SUBTYPECUSTOM 1031
#define IDC_ACTION 1032
#define IDC_LIST 1033
#define IDC_NEW 1034
#define IDC_EDIT 1035
#define IDC_DELETE 1037
#define IDC_VALUES 1038
#define IDC_REMOVE 1042
#define IDC_ADD 1043
#define IDC_SERVICESID 1044
#define IDC_SIDTYPE 1045
#define IDC_COMBO2 1046
#define IDC_PROTECTION 1046
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 111
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1047
#define _APS_NEXT_SYMED_VALUE 107
#endif
#endif

View File

@@ -0,0 +1,151 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "extsrv.h"
typedef struct _RESTART_SERVICE_CONTEXT
{
PPH_SERVICE_ITEM ServiceItem;
SC_HANDLE ServiceHandle;
BOOLEAN Starting;
BOOLEAN DisableTimer;
} RESTART_SERVICE_CONTEXT, *PRESTART_SERVICE_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:
{
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->ServiceItem->Name->Buffer)->Buffer);
if (PhUiStopService(hwndDlg, context->ServiceItem))
{
SetTimer(hwndDlg, 1, 250, NULL);
}
else
{
EndDialog(hwndDlg, IDCANCEL);
}
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
{
EndDialog(hwndDlg, IDCANCEL);
}
break;
}
}
break;
case WM_TIMER:
{
if (wParam == 1 && !context->DisableTimer)
{
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->ServiceItem->Name->Buffer)->Buffer);
context->DisableTimer = TRUE;
if (PhUiStartService(hwndDlg, context->ServiceItem))
{
context->DisableTimer = FALSE;
context->Starting = TRUE;
}
else
{
EndDialog(hwndDlg, IDCANCEL);
}
}
else if (context->Starting && serviceStatus.dwCurrentState == SERVICE_RUNNING)
{
EndDialog(hwndDlg, IDOK);
}
}
}
}
break;
}
return FALSE;
}
VOID EsRestartServiceWithProgress(
_In_ HWND hWnd,
_In_ PPH_SERVICE_ITEM ServiceItem,
_In_ SC_HANDLE ServiceHandle
)
{
RESTART_SERVICE_CONTEXT context;
context.ServiceItem = ServiceItem;
context.ServiceHandle = ServiceHandle;
context.Starting = FALSE;
context.DisableTimer = FALSE;
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_SRVPROGRESS),
hWnd,
EspRestartServiceDlgProc,
(LPARAM)&context
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,182 @@
/*
* Process Hacker Extended Services -
* triggers page
*
* Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
*/
#include "extsrv.h"
typedef struct _SERVICE_TRIGGERS_CONTEXT
{
PPH_SERVICE_ITEM ServiceItem;
HWND TriggersLv;
struct _ES_TRIGGER_CONTEXT *TriggerContext;
} SERVICE_TRIGGERS_CONTEXT, *PSERVICE_TRIGGERS_CONTEXT;
NTSTATUS EspLoadTriggerInfo(
_In_ HWND hwndDlg,
_In_ PSERVICE_TRIGGERS_CONTEXT Context
)
{
NTSTATUS status = STATUS_SUCCESS;
SC_HANDLE serviceHandle;
if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)))
return NTSTATUS_FROM_WIN32(GetLastError());
EsLoadServiceTriggerInfo(Context->TriggerContext, serviceHandle);
CloseServiceHandle(serviceHandle);
return status;
}
INT_PTR CALLBACK EspServiceTriggersDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_TRIGGERS_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_TRIGGERS_CONTEXT));
memset(context, 0, sizeof(SERVICE_TRIGGERS_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_TRIGGERS_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
NTSTATUS status;
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam;
HWND triggersLv;
context->ServiceItem = serviceItem;
context->TriggersLv = triggersLv = GetDlgItem(hwndDlg, IDC_TRIGGERS);
context->TriggerContext = EsCreateServiceTriggerContext(
context->ServiceItem,
hwndDlg,
triggersLv
);
status = EspLoadTriggerInfo(hwndDlg, context);
if (!NT_SUCCESS(status))
{
PhShowWarning(hwndDlg, L"Unable to query service trigger information: %s",
((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer);
}
}
break;
case WM_DESTROY:
{
EsDestroyServiceTriggerContext(context->TriggerContext);
PhFree(context);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_NEW:
if (context->TriggerContext)
EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_NEW);
break;
case IDC_EDIT:
if (context->TriggerContext)
EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_EDIT);
break;
case IDC_DELETE:
if (context->TriggerContext)
EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_DELETE);
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:
{
ULONG win32Result = 0;
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
if (!EsSaveServiceTriggerInfo(context->TriggerContext, &win32Result))
{
if (win32Result == ERROR_CANCELLED || (PhShowMessage(
hwndDlg,
MB_ICONERROR | MB_RETRYCANCEL,
L"Unable to change service trigger information: %s",
((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer
) == IDRETRY))
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
}
}
return TRUE;
}
break;
case LVN_ITEMCHANGED:
{
if (header->hwndFrom == context->TriggersLv && context->TriggerContext)
{
EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_SELECTIONCHANGED);
}
}
break;
case NM_DBLCLK:
{
if (header->hwndFrom == context->TriggersLv && context->TriggerContext)
{
EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_EDIT);
}
}
break;
}
}
break;
}
return FALSE;
}