private void UpdateAdvancedSettings(ServiceController service) { //Set up the failure actions if (FailureActions.HasNondefaultValues()) { NativeMethods.SERVICE_FAILURE_ACTIONS sfa = new NativeMethods.SERVICE_FAILURE_ACTIONS(); try { //Build the SFA structure sfa = new NativeMethods.SERVICE_FAILURE_ACTIONS(FailureActions); //We don't want to leave the handle laying around so trap it using (SafeHandle handle = service.ServiceHandle) { //Update the configuration if (!NativeMethods.ChangeServiceConfig2(handle, NativeMethods.SERVICE_CONFIG_INFOLEVEL.FAILURE_ACTIONS, ref sfa)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } }; } finally { //Clean up sfa.Clear(); }; } ; Context.LogMessage("Updated service '" + ServiceName + "' configuration"); }
internal static void SetServiceFailureActions(this ServiceInstaller serviceInstaller, FailureActions failureActions) { if (serviceInstaller == null) { throw new ArgumentNullException(nameof(serviceInstaller)); } if (failureActions == null) { throw new ArgumentNullException(nameof(failureActions)); } // If any of the of the actions is reboot, // we need to request shutdown priviledges from the system if (failureActions.FirstFailure == RecoveryAction.Reboot | failureActions.SecondFailure == RecoveryAction.Reboot | failureActions.SubsequentFailure == RecoveryAction.Reboot) { RequestShutdownPrivilege(); } var actionsPointer = IntPtr.Zero; var serviceManager = IntPtr.Zero; var serviceLock = IntPtr.Zero; var serviceHandle = IntPtr.Zero; try { var restartServiceAfter = (int)failureActions.RestartServiceAfter.TotalMilliseconds; var actions = new int[6]; // First failure actions[0] = (int)failureActions.FirstFailure; actions[1] = restartServiceAfter; // Second failure actions[2] = (int)failureActions.SecondFailure; actions[3] = restartServiceAfter; // subsequent failure actions[4] = (int)failureActions.SubsequentFailure; actions[5] = restartServiceAfter; actionsPointer = Marshal.AllocHGlobal(24 /* 3 x 2 x 4 */); Marshal.Copy(actions, 0, actionsPointer, 6); var serviceFailureActions = new UnsafeNative.ServiceFailureActions(); serviceFailureActions.cActions = 3; serviceFailureActions.dwResetPeriod = (int)failureActions.ResetFailCountAfter.TotalSeconds; serviceFailureActions.lpCommand = $"{failureActions.RunProgram} {failureActions.RunProgramArguments}"; serviceFailureActions.lpRebootMsg = string.Empty; serviceFailureActions.lpsaActions = actionsPointer.ToInt32(); serviceManager = UnsafeNative.OpenSCManager(null, null, UnsafeNative.SC_MANAGER_ALL_ACCESS); if (serviceManager.ToInt32() <= 0) { throw new ServiceManagerException("Unable to open the service manager."); } serviceLock = UnsafeNative.LockServiceDatabase(serviceManager); if (serviceLock.ToInt32() <= 0) { throw new ServiceManagerException("Unable to lock the service database."); } serviceHandle = UnsafeNative.OpenService(serviceManager, serviceInstaller.ServiceName, UnsafeNative.SERVICE_ALL_ACCESS); if (serviceHandle.ToInt32() <= 0) { throw new ServiceManagerException($"Unable to open the '{serviceInstaller.ServiceName}' service."); } if (!UnsafeNative.ChangeServiceFailureActions(serviceHandle, UnsafeNative.SERVICE_CONFIG_FAILURE_ACTIONS, ref serviceFailureActions)) { var lastError = UnsafeNative.GetLastError(); if (lastError == UnsafeNative.ERROR_ACCESS_DENIED) { throw new UnauthorizedAccessException("Access denied while setting failure actions."); } throw new ServiceManagerException("An error has occured while setting failure actions. Error code: " + lastError); } } catch { throw; } finally { if (serviceManager != IntPtr.Zero && serviceLock != IntPtr.Zero) { UnsafeNative.UnlockServiceDatabase(serviceLock); } if (actionsPointer != IntPtr.Zero) { Marshal.FreeHGlobal(actionsPointer); } if (serviceHandle != IntPtr.Zero) { UnsafeNative.CloseServiceHandle(serviceHandle); } if (serviceManager != IntPtr.Zero) { UnsafeNative.CloseServiceHandle(serviceManager); } } }