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);