28 typedef struct _SERVICE_RECOVERY_CONTEXT
32 ULONG NumberOfActions;
33 BOOLEAN EnableFlagCheckBox;
41 #define SIP(String, Integer) { (String), (PVOID)(Integer) }
45 SIP(L
"Take no action", SC_ACTION_NONE),
46 SIP(L
"Restart the service", SC_ACTION_RESTART),
47 SIP(L
"Run a program", SC_ACTION_RUN_COMMAND),
48 SIP(L
"Restart the computer", SC_ACTION_REBOOT)
59 _In_ HWND ComboBoxHandle
65 ComboBox_AddString(ComboBoxHandle, (PWSTR)ServiceActionPairs[i].
Key);
83 _In_ SC_ACTION_TYPE ActionType
94 static SC_ACTION_TYPE ComboBoxToServiceAction(
95 _In_ HWND ComboBoxHandle
98 SC_ACTION_TYPE actionType;
104 return SC_ACTION_NONE;
112 static VOID ServiceActionToComboBox(
113 _In_ HWND ComboBoxHandle,
114 _In_ SC_ACTION_TYPE ActionType
125 static VOID EspFixControls(
130 SC_ACTION_TYPE action1;
131 SC_ACTION_TYPE action2;
132 SC_ACTION_TYPE actionS;
133 BOOLEAN enableRestart;
134 BOOLEAN enableReboot;
135 BOOLEAN enableCommand;
143 enableRestart = action1 == SC_ACTION_RESTART || action2 == SC_ACTION_RESTART || actionS == SC_ACTION_RESTART;
144 enableReboot = action1 == SC_ACTION_REBOOT || action2 == SC_ACTION_REBOOT || actionS == SC_ACTION_REBOOT;
145 enableCommand = action1 == SC_ACTION_RUN_COMMAND || action2 == SC_ACTION_RUN_COMMAND || actionS == SC_ACTION_RUN_COMMAND;
156 EnableWindow(GetDlgItem(hwndDlg,
IDC_BROWSE), enableCommand);
165 NTSTATUS status = STATUS_SUCCESS;
166 SC_HANDLE serviceHandle;
167 LPSERVICE_FAILURE_ACTIONS failureActions;
168 SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag;
169 SC_ACTION_TYPE lastType;
173 if (!(serviceHandle =
PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)))
174 return NTSTATUS_FROM_WIN32(GetLastError());
178 CloseServiceHandle(serviceHandle);
179 return NTSTATUS_FROM_WIN32(GetLastError());
184 Context->NumberOfActions = failureActions->cActions;
186 if (failureActions->cActions != 0 && failureActions->cActions != 3)
187 status = STATUS_SOME_NOT_MAPPED;
192 lastType = SC_ACTION_NONE;
195 failureActions->cActions >= 1 ? (lastType = failureActions->lpsaActions[0].Type) : lastType);
197 failureActions->cActions >= 2 ? (lastType = failureActions->lpsaActions[1].Type) : lastType);
199 failureActions->cActions >= 3 ? (lastType = failureActions->lpsaActions[2].Type) : lastType);
209 for (i = 0; i < failureActions->cActions; i++)
211 if (failureActions->lpsaActions[i].Type == SC_ACTION_RESTART)
213 if (failureActions->lpsaActions[i].Delay != 0)
216 failureActions->lpsaActions[i].Delay / (1000 * 60),
FALSE);
228 SERVICE_CONFIG_FAILURE_ACTIONS_FLAG,
229 (BYTE *)&failureActionsFlag,
230 sizeof(SERVICE_FAILURE_ACTIONS_FLAG),
235 failureActionsFlag.fFailureActionsOnNonCrashFailures ? BST_CHECKED : BST_UNCHECKED);
236 Context->EnableFlagCheckBox =
TRUE;
240 Context->EnableFlagCheckBox =
FALSE;
245 Context->RebootAfter = 1 * 1000 * 60;
247 for (i = 0; i < failureActions->cActions; i++)
249 if (failureActions->lpsaActions[i].Type == SC_ACTION_REBOOT)
251 if (failureActions->lpsaActions[i].Delay != 0)
252 Context->RebootAfter = failureActions->lpsaActions[i].Delay;
258 if (failureActions->lpRebootMsg && failureActions->lpRebootMsg[0] != 0)
265 SetDlgItemText(hwndDlg,
IDC_RUNPROGRAM, failureActions->lpCommand);
268 CloseServiceHandle(serviceHandle);
282 if (uMsg == WM_INITDIALOG)
287 SetProp(hwndDlg, L
"Context", (HANDLE)context);
293 if (uMsg == WM_DESTROY)
294 RemoveProp(hwndDlg, L
"Context");
305 LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
308 context->ServiceItem = serviceItem;
316 if (status == STATUS_SOME_NOT_MAPPED)
318 if (context->NumberOfActions > 3)
322 L
"The service has %lu failure actions configured, but this program only supports editing 3. "
323 L
"If you save the recovery information using this program, the additional failure actions will be lost.",
324 context->NumberOfActions
334 context->EnableFlagCheckBox =
TRUE;
338 PhShowWarning(hwndDlg, L
"Unable to query service recovery information: %s",
342 EspFixControls(hwndDlg, context);
344 context->Ready =
TRUE;
355 switch (LOWORD(wParam))
361 if (HIWORD(wParam) == CBN_SELCHANGE)
363 EspFixControls(hwndDlg, context);
382 { L
"Executable files (*.exe;*.cmd;*.bat)", L
"*.exe;*.cmd;*.bat" },
383 { L
"All files (*.*)", L
"*.*" }
406 context->Dirty =
TRUE;
411 switch (HIWORD(wParam))
417 context->Dirty =
TRUE;
425 LPNMHDR header = (LPNMHDR)lParam;
427 switch (header->code)
431 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT,
FALSE);
438 SC_HANDLE serviceHandle;
439 ULONG restartServiceAfter;
440 SERVICE_FAILURE_ACTIONS failureActions;
441 SC_ACTION actions[3];
443 BOOLEAN enableRestart =
FALSE;
445 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
457 failureActions.cActions = 3;
458 failureActions.lpsaActions = actions;
460 actions[0].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg,
IDC_FIRSTFAILURE));
461 actions[1].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg,
IDC_SECONDFAILURE));
466 for (i = 0; i < 3; i++)
468 switch (actions[i].Type)
470 case SC_ACTION_RESTART:
471 actions[i].Delay = restartServiceAfter;
472 enableRestart =
TRUE;
474 case SC_ACTION_REBOOT:
475 actions[i].Delay = context->RebootAfter;
477 case SC_ACTION_RUN_COMMAND:
478 actions[i].Delay = 0;
487 SERVICE_CHANGE_CONFIG | (enableRestart ? SERVICE_START : 0)
492 if (ChangeServiceConfig2(
494 SERVICE_CONFIG_FAILURE_ACTIONS,
498 if (context->EnableFlagCheckBox)
500 SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag;
502 failureActionsFlag.fFailureActionsOnNonCrashFailures =
505 ChangeServiceConfig2(
507 SERVICE_CONFIG_FAILURE_ACTIONS_FLAG,
512 CloseServiceHandle(serviceHandle);
516 CloseServiceHandle(serviceHandle);
522 if (GetLastError() == ERROR_ACCESS_DENIED && !
PhElevated)
529 SERVICE_CONFIG_FAILURE_ACTIONS,
533 if (context->EnableFlagCheckBox)
535 SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag;
537 failureActionsFlag.fFailureActionsOnNonCrashFailures =
542 SERVICE_CONFIG_FAILURE_ACTIONS_FLAG,
559 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
572 MB_ICONERROR | MB_RETRYCANCEL,
573 L
"Unable to change service recovery information: %s",
577 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
608 if (uMsg == WM_INITDIALOG)
611 SetProp(hwndDlg, L
"Context", (HANDLE)context);
617 if (uMsg == WM_DESTROY)
618 RemoveProp(hwndDlg, L
"Context");
629 Button_SetCheck(GetDlgItem(hwndDlg,
IDC_ENABLERESTARTMESSAGE), context->RebootMessage ? BST_CHECKED : BST_UNCHECKED);
638 switch (LOWORD(wParam))
641 EndDialog(hwndDlg, IDCANCEL);
652 context->Dirty =
TRUE;
654 EndDialog(hwndDlg, IDOK);
662 BOOLEAN allocated =
TRUE;
667 computerName = PhAllocate((bufferSize + 1) *
sizeof(WCHAR));
669 if (!GetComputerName(computerName, &bufferSize))
672 computerName = PhAllocate((bufferSize + 1) *
sizeof(WCHAR));
674 if (!GetComputerName(computerName, &bufferSize))
677 computerName = L
"(unknown)";
685 L
"Your computer is connected to the computer named %s. "
686 L
"The %s service on %s has ended unexpectedly. "
687 L
"%s will restart automatically, and then you can reestablish the connection.",
689 context->ServiceItem->Name->Buffer,
704 if (HIWORD(wParam) == EN_CHANGE)
708 GetWindowTextLength(GetDlgItem(hwndDlg,
IDC_RESTARTMESSAGE)) != 0 ? BST_CHECKED : BST_UNCHECKED);