go my file uploader
This commit is contained in:
709
plugins/ExtendedServices/recovery.c
Normal file
709
plugins/ExtendedServices/recovery.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user