public static extern bool FailureActionsOnNonCrashFailures( SafeServiceHandle hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_FAILURE_ACTIONS_FLAG lpInfo);
/// <summary> /// Change the recovery property of a Windows service. /// </summary> /// <param name="scName">The name of the Windows service</param> /// <param name="scActions"> /// A list of SC_ACTION representing the actions that the service control /// manager can perform. /// </param> /// <param name="resetPeriod"> /// The time after which to reset the failure count to zero if there are no /// failures, in seconds. /// </param> /// <param name="command"> /// The command line of the process for the CreateProcess function to execute /// in response to the SC_ACTION_RUN_COMMAND service controller action. This /// process runs under the same account as the service. /// </param> /// <param name="fFailureActionsOnNonCrashFailures"> /// If this member is true and the service has configured failure actions, /// the failure actions are queued if the service process terminates without /// reporting a status of SERVICE_STOPPED or if it enters the SERVICE_STOPPED /// state but the dwWin32ExitCode member of the SERVICE_STATUS structure is /// not ERROR_SUCCESS (0). If this member is false and the service has /// configured failure actions, the failure actions are queued only if the /// service terminates without reporting a status of SERVICE_STOPPED. /// </param> /// <param name="rebootMsg"> /// The message to be broadcast to server users before rebooting in response /// to the SC_ACTION_REBOOT service controller action. /// </param> public static void ChangeRecoveryProperty(string scName, List <SC_ACTION> scActions, int resetPeriod, string command, bool fFailureActionsOnNonCrashFailures, string rebootMsg) { SafeServiceHandle hSCManager = null; SafeServiceHandle hService = null; IntPtr hGlobal = IntPtr.Zero; try { // Open the service control manager. hSCManager = Win32.OpenSCManager(null, null, Win32.SERVICE_QUERY_CONFIG); if (hSCManager.IsInvalid) { throw new Win32Exception(); } // Open the service. hService = Win32.OpenService(hSCManager, scName, Win32.SERVICE_ALL_ACCESS); if (hService.IsInvalid) { throw new Win32Exception(); } int numActions = scActions.Count; int[] falureActions = new int[numActions * 2]; bool needShutdownPrivilege = false; int i = 0; // We need to copy the actions in scFailureActionArray to an // unmanaged memory through Marshal.Copy. foreach (SC_ACTION scAction in scActions) { falureActions[i] = scAction.Type; falureActions[++i] = scAction.Delay; i++; if (scAction.Type == (int)SC_ACTION_TYPE.RebootComputer) { needShutdownPrivilege = true; } } // If we need shutdown privilege, then grant it to this process. if (needShutdownPrivilege) { GrantShutdownPrivilege(); } // Allocate memory. hGlobal = Marshal.AllocHGlobal(falureActions.Length * Marshal.SizeOf(typeof(int))); // Copies data from a one-dimensional, managed 32-bit signed integer // array to an unmanaged memory pointer. Marshal.Copy(falureActions, 0, hGlobal, falureActions.Length); // Set the SERVICE_FAILURE_ACTIONS struct. SERVICE_FAILURE_ACTIONS scFailureActions = new SERVICE_FAILURE_ACTIONS(); scFailureActions.cActions = numActions; scFailureActions.dwResetPeriod = resetPeriod; scFailureActions.lpCommand = command; scFailureActions.lpRebootMsg = rebootMsg; scFailureActions.lpsaActions = hGlobal; // Call the ChangeServiceFailureActions function abstraction of the // ChangeServiceConfig2 function. if (!Win32.ChangeServiceFailureActions(hService, Win32.SERVICE_CONFIG_FAILURE_ACTIONS, ref scFailureActions)) { throw new Win32Exception(); } // Restart Computer Options.... SERVICE_FAILURE_ACTIONS_FLAG flag = new SERVICE_FAILURE_ACTIONS_FLAG(); flag.fFailureActionsOnNonCrashFailures = fFailureActionsOnNonCrashFailures; // Call the FailureActionsOnNonCrashFailures function, the // abstraction of the ChangeServiceConfig2 function. if (!Win32.FailureActionsOnNonCrashFailures(hService, Win32.SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, ref flag)) { throw new Win32Exception(); } } finally { // Close the service control manager handle. if (hSCManager != null && !hSCManager.IsInvalid) { hSCManager.Dispose(); hSCManager = null; } // Close the service handle. if (hService != null && !hService.IsInvalid) { hService.Dispose(); hService = null; } // Free the unmanaged memory. if (hGlobal != IntPtr.Zero) { Marshal.FreeHGlobal(hGlobal); hGlobal = IntPtr.Zero; } } }