public void SetServiceRecoveryOptions(HostSettings settings, ServiceRecoveryOptions options) { SCMHandle scmHandle = null; SCMHandle serviceHandle = null; IntPtr lpsaActions = IntPtr.Zero; IntPtr lpInfo = IntPtr.Zero; IntPtr lpFlagInfo = IntPtr.Zero; try { List <NativeMethods.SC_ACTION> actions = options.Actions.Select(x => x.GetAction()).ToList(); if (actions.Count == 0) { throw new TopshelfException("Must be at least one failure action configured"); } scmHandle = NativeMethods.OpenSCManager(null, null, (int)NativeMethods.SCM_ACCESS.SC_MANAGER_ALL_ACCESS); if (scmHandle == null) { throw new TopshelfException("Failed to open service control manager"); } serviceHandle = NativeMethods.OpenService(scmHandle, settings.ServiceName, (int)NativeMethods.SCM_ACCESS.SC_MANAGER_ALL_ACCESS); if (serviceHandle == null) { throw new TopshelfException("Failed to open service: " + settings.ServiceName); } int actionSize = Marshal.SizeOf(typeof(NativeMethods.SC_ACTION)); lpsaActions = Marshal.AllocHGlobal(actionSize * actions.Count + 1); if (lpsaActions == IntPtr.Zero) { throw new TopshelfException("Unable to allocate memory for service recovery actions"); } IntPtr nextAction = lpsaActions; for (int i = 0; i < actions.Count; i++) { Marshal.StructureToPtr(actions[i], nextAction, false); nextAction = (IntPtr)(nextAction.ToInt64() + actionSize); } string rebootMessage = options.Actions.Where(x => x.GetType() == typeof(RestartSystemRecoveryAction)) .OfType <RestartSystemRecoveryAction>().Select(x => x.RestartMessage). FirstOrDefault() ?? ""; string runProgramCommand = options.Actions.Where(x => x.GetType() == typeof(RunProgramRecoveryAction)) .OfType <RunProgramRecoveryAction>().Select(x => x.Command). FirstOrDefault() ?? ""; var failureActions = new NativeMethods.SERVICE_FAILURE_ACTIONS(); failureActions.dwResetPeriod = (int)TimeSpan.FromDays(options.ResetPeriod).TotalSeconds; failureActions.lpRebootMsg = rebootMessage; failureActions.lpCommand = runProgramCommand; failureActions.cActions = actions.Count; failureActions.actions = lpsaActions; lpInfo = Marshal.AllocHGlobal(Marshal.SizeOf(failureActions)); if (lpInfo == IntPtr.Zero) { throw new TopshelfException("Failed to allocate memory for failure actions"); } Marshal.StructureToPtr(failureActions, lpInfo, false); // If user specified a Restart option, get shutdown privileges if (options.Actions.Any(x => x.GetType() == typeof(RestartSystemRecoveryAction))) { RequestShutdownPrivileges(); } if (!NativeMethods.ChangeServiceConfig2(serviceHandle, NativeMethods.SERVICE_CONFIG_FAILURE_ACTIONS, lpInfo)) { throw new TopshelfException(string.Format("Failed to change service recovery options. Windows Error: {0}", new Win32Exception().Message)); } if (false == options.RecoverOnCrashOnly) { var flag = new NativeMethods.SERVICE_FAILURE_ACTIONS_FLAG(); flag.fFailureActionsOnNonCrashFailures = true; lpFlagInfo = Marshal.AllocHGlobal(Marshal.SizeOf(flag)); if (lpFlagInfo == IntPtr.Zero) { throw new TopshelfException("Failed to allocate memory for failure flag"); } Marshal.StructureToPtr(flag, lpFlagInfo, false); try { NativeMethods.ChangeServiceConfig2(serviceHandle, NativeMethods.SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, lpFlagInfo); } catch { // this fails on XP, but we don't care really as it's optional } } } finally { if (lpFlagInfo != IntPtr.Zero) { Marshal.FreeHGlobal(lpFlagInfo); } if (lpInfo != IntPtr.Zero) { Marshal.FreeHGlobal(lpInfo); } if (lpsaActions != IntPtr.Zero) { Marshal.FreeHGlobal(lpsaActions); } if (serviceHandle != null) { serviceHandle.Close(); } if (scmHandle != null) { scmHandle.Close(); } } }
public void SetServiceRecoveryOptions(HostSettings settings, ServiceRecoveryOptions options) { IntPtr scmHandle = IntPtr.Zero; IntPtr serviceHandle = IntPtr.Zero; IntPtr lpsaActions = IntPtr.Zero; IntPtr lpInfo = IntPtr.Zero; try { List <NativeMethods.SC_ACTION> actions = options.Actions.Select(x => x.GetAction()).ToList(); if (actions.Count == 0) { throw new TopshelfException("Must be at least one failure action configured"); } scmHandle = NativeMethods.OpenSCManager(null, null, (int)NativeMethods.SCM_ACCESS.SC_MANAGER_ALL_ACCESS); if (scmHandle == IntPtr.Zero) { throw new TopshelfException("Failed to open service control manager"); } serviceHandle = NativeMethods.OpenService(scmHandle, settings.ServiceName, (int)NativeMethods.SCM_ACCESS.SC_MANAGER_ALL_ACCESS); if (serviceHandle == IntPtr.Zero) { throw new TopshelfException("Failed to open service: " + settings.ServiceName); } int actionSize = Marshal.SizeOf(typeof(NativeMethods.SC_ACTION)); lpsaActions = Marshal.AllocHGlobal(actionSize * actions.Count + 1); if (lpsaActions == IntPtr.Zero) { throw new TopshelfException("Unable to allocate memory for service recovery actions"); } IntPtr nextAction = lpsaActions; for (int i = 0; i < actions.Count; i++) { Marshal.StructureToPtr(actions[i], nextAction, false); nextAction = (IntPtr)(nextAction.ToInt64() + actionSize); } var finalAction = new NativeMethods.SC_ACTION(); finalAction.Type = (int)NativeMethods.SC_ACTION_TYPE.None; finalAction.Delay = (int)TimeSpan.FromMinutes(1).TotalMilliseconds; Marshal.StructureToPtr(finalAction, nextAction, false); string rebootMessage = options.Actions.Where(x => x.GetType() == typeof(RestartSystemRecoveryAction)) .OfType <RestartSystemRecoveryAction>().Select(x => x.RestartMessage). FirstOrDefault() ?? ""; string runProgramCommand = options.Actions.Where(x => x.GetType() == typeof(RunProgramRecoveryAction)) .OfType <RunProgramRecoveryAction>().Select(x => x.Command). FirstOrDefault() ?? ""; var failureActions = new NativeMethods.SERVICE_FAILURE_ACTIONS(); failureActions.dwResetPeriod = (int)TimeSpan.FromDays(options.ResetPeriod).TotalSeconds; failureActions.lpRebootMsg = rebootMessage; failureActions.lpCommand = runProgramCommand; failureActions.cActions = actions.Count + 1; failureActions.actions = lpsaActions; lpInfo = Marshal.AllocHGlobal(Marshal.SizeOf(failureActions)); if (lpInfo == IntPtr.Zero) { throw new TopshelfException("Failed to allocate memory for failure actions"); } Marshal.StructureToPtr(failureActions, lpInfo, false); if (!NativeMethods.ChangeServiceConfig2(serviceHandle, NativeMethods.SERVICE_CONFIG_FAILURE_ACTIONS, lpInfo)) { throw new TopshelfException("Failed to change service recovery options"); } } finally { if (lpInfo != IntPtr.Zero) { Marshal.FreeHGlobal(lpInfo); } if (lpsaActions != IntPtr.Zero) { Marshal.FreeHGlobal(lpsaActions); } if (serviceHandle != IntPtr.Zero) { NativeMethods.CloseServiceHandle(serviceHandle); } if (scmHandle != IntPtr.Zero) { NativeMethods.CloseServiceHandle(scmHandle); } } }
public void SetServiceRecoveryOptions(HostSettings settings, ServiceRecoveryOptions options) { SafeTokenHandle scmHandle = null; SafeTokenHandle serviceHandle = null; IntPtr lpsaActions = IntPtr.Zero; IntPtr lpInfo = IntPtr.Zero; IntPtr lpFlagInfo = IntPtr.Zero; try { List<NativeMethods.SC_ACTION> actions = options.Actions.Select(x => x.GetAction()).ToList(); if (actions.Count == 0) throw new TopshelfException("Must be at least one failure action configured"); scmHandle = NativeMethods.OpenSCManager(null, null, (int)NativeMethods.SCM_ACCESS.SC_MANAGER_ALL_ACCESS); if (scmHandle == null) throw new TopshelfException("Failed to open service control manager"); serviceHandle = NativeMethods.OpenService(scmHandle, settings.ServiceName, (int)NativeMethods.SCM_ACCESS.SC_MANAGER_ALL_ACCESS); if (serviceHandle == null) throw new TopshelfException("Failed to open service: " + settings.ServiceName); int actionSize = Marshal.SizeOf(typeof(NativeMethods.SC_ACTION)); lpsaActions = Marshal.AllocHGlobal(actionSize*actions.Count + 1); if (lpsaActions == IntPtr.Zero) throw new TopshelfException("Unable to allocate memory for service recovery actions"); IntPtr nextAction = lpsaActions; for (int i = 0; i < actions.Count; i++) { Marshal.StructureToPtr(actions[i], nextAction, false); nextAction = (IntPtr)(nextAction.ToInt64() + actionSize); } var finalAction = new NativeMethods.SC_ACTION(); finalAction.Type = (int)NativeMethods.SC_ACTION_TYPE.None; finalAction.Delay = (int)TimeSpan.FromMinutes(1).TotalMilliseconds; Marshal.StructureToPtr(finalAction, nextAction, false); string rebootMessage = options.Actions.Where(x => x.GetType() == typeof(RestartSystemRecoveryAction)) .OfType<RestartSystemRecoveryAction>().Select(x => x.RestartMessage). FirstOrDefault() ?? ""; string runProgramCommand = options.Actions.Where(x => x.GetType() == typeof(RunProgramRecoveryAction)) .OfType<RunProgramRecoveryAction>().Select(x => x.Command). FirstOrDefault() ?? ""; var failureActions = new NativeMethods.SERVICE_FAILURE_ACTIONS(); failureActions.dwResetPeriod = (int)TimeSpan.FromDays(options.ResetPeriod).TotalSeconds; failureActions.lpRebootMsg = rebootMessage; failureActions.lpCommand = runProgramCommand; failureActions.cActions = actions.Count + 1; failureActions.actions = lpsaActions; lpInfo = Marshal.AllocHGlobal(Marshal.SizeOf(failureActions)); if (lpInfo == IntPtr.Zero) throw new TopshelfException("Failed to allocate memory for failure actions"); Marshal.StructureToPtr(failureActions, lpInfo, false); // If user specified a Restart option, get shutdown privileges if(options.Actions.Any(x => x.GetType() == typeof(RestartSystemRecoveryAction))) RequestShutdownPrivileges(); if (!NativeMethods.ChangeServiceConfig2(serviceHandle, NativeMethods.SERVICE_CONFIG_FAILURE_ACTIONS, lpInfo)) { throw new TopshelfException(string.Format("Failed to change service recovery options. Windows Error: {0}", new Win32Exception().Message)); } if (false == options.RecoverOnCrashOnly) { var flag = new NativeMethods.SERVICE_FAILURE_ACTIONS_FLAG(); flag.fFailureActionsOnNonCrashFailures = true; lpFlagInfo = Marshal.AllocHGlobal(Marshal.SizeOf(flag)); if (lpFlagInfo == IntPtr.Zero) throw new TopshelfException("Failed to allocate memory for failure flag"); Marshal.StructureToPtr(flag, lpFlagInfo, false); try { NativeMethods.ChangeServiceConfig2(serviceHandle, NativeMethods.SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, lpFlagInfo); } catch { // this fails on XP, but we don't care really as it's optional } } } finally { if (lpFlagInfo != IntPtr.Zero) Marshal.FreeHGlobal(lpFlagInfo); if (lpInfo != IntPtr.Zero) Marshal.FreeHGlobal(lpInfo); if (lpsaActions != IntPtr.Zero) Marshal.FreeHGlobal(lpsaActions); if (serviceHandle != null) NativeMethods.CloseServiceHandle(serviceHandle); if (scmHandle != null) NativeMethods.CloseServiceHandle(scmHandle); } }
public static void SetServiceRecoveryOptions( string serviceName, ServiceRecoveryOptions recoveryOptions) { if (recoveryOptions == null) { throw new ArgumentNullException("recoveryOptions"); } bool requiresShutdownPriveleges = recoveryOptions.FirstFailureAction == ServiceRecoveryAction.RestartComputer || recoveryOptions.SecondFailureAction == ServiceRecoveryAction.RestartComputer || recoveryOptions.SubsequentFailureAction == ServiceRecoveryAction.RestartComputer; if (requiresShutdownPriveleges) { GrantShutdownPrivileges(); } int actionCount = 3; var restartServiceAfter = (uint)TimeSpan.FromMinutes( recoveryOptions.RestartServiceWaitMinutes).TotalMilliseconds; IntPtr failureActionsPointer = IntPtr.Zero; IntPtr actionPointer = IntPtr.Zero; ServiceController controller = null; try { // Open the service controller = new ServiceController(serviceName); // Set up the failure actions var failureActions = new SERVICE_FAILURE_ACTIONS(); failureActions.dwResetPeriod = (int)TimeSpan.FromDays(recoveryOptions.ResetFailureCountWaitDays).TotalSeconds; failureActions.cActions = (uint)actionCount; failureActions.lpRebootMsg = recoveryOptions.RestartSystemMessage; // allocate memory for the individual actions actionPointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SC_ACTION)) * actionCount); ServiceRecoveryAction[] actions = { recoveryOptions.FirstFailureAction, recoveryOptions.SecondFailureAction, recoveryOptions.SubsequentFailureAction }; for (int i = 0; i < actions.Length; i++) { ServiceRecoveryAction action = actions[i]; SC_ACTION scAction = GetScAction(action, restartServiceAfter); Marshal.StructureToPtr(scAction, (IntPtr)((Int64)actionPointer + (Marshal.SizeOf(typeof(SC_ACTION))) * i), false); } failureActions.lpsaActions = actionPointer; string command = recoveryOptions.RunProgramCommand; if (command != null) { failureActions.lpCommand = command; } failureActionsPointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SERVICE_FAILURE_ACTIONS))); Marshal.StructureToPtr(failureActions, failureActionsPointer, false); // Make the change bool success = ChangeServiceConfig2(controller.ServiceHandle.DangerousGetHandle(), SERVICE_CONFIG_FAILURE_ACTIONS, failureActionsPointer); // Check that the change occurred if (!success) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Unable to change the Service configuration."); } } finally { if (failureActionsPointer != IntPtr.Zero) { Marshal.FreeHGlobal(failureActionsPointer); } if (actionPointer != IntPtr.Zero) { Marshal.FreeHGlobal(actionPointer); } if (controller != null) { controller.Dispose(); } //log.Debug(m => m("Done setting service recovery options.")); } }
public static void SetServiceRecoveryOptions( string serviceName, ServiceRecoveryOptions recoveryOptions) { if (recoveryOptions == null) throw new ArgumentNullException("recoveryOptions"); bool requiresShutdownPriveleges = recoveryOptions.FirstFailureAction == ServiceRecoveryAction.RestartComputer || recoveryOptions.SecondFailureAction == ServiceRecoveryAction.RestartComputer || recoveryOptions.SubsequentFailureAction == ServiceRecoveryAction.RestartComputer; if (requiresShutdownPriveleges) GrantShutdownPrivileges(); int actionCount = 3; var restartServiceAfter = (uint)TimeSpan.FromMinutes( recoveryOptions.RestartServiceWaitMinutes).TotalMilliseconds; IntPtr failureActionsPointer = IntPtr.Zero; IntPtr actionPointer = IntPtr.Zero; ServiceController controller = null; try { // Open the service controller = new ServiceController(serviceName); // Set up the failure actions var failureActions = new SERVICE_FAILURE_ACTIONS(); failureActions.dwResetPeriod = (int)TimeSpan.FromDays(recoveryOptions.ResetFailureCountWaitDays).TotalSeconds; failureActions.cActions = (uint)actionCount; failureActions.lpRebootMsg = recoveryOptions.RestartSystemMessage; // allocate memory for the individual actions actionPointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SC_ACTION)) * actionCount); ServiceRecoveryAction[] actions = { recoveryOptions.FirstFailureAction, recoveryOptions.SecondFailureAction, recoveryOptions.SubsequentFailureAction }; for (int i = 0; i < actions.Length; i++) { ServiceRecoveryAction action = actions[i]; SC_ACTION scAction = GetScAction(action, restartServiceAfter); Marshal.StructureToPtr(scAction, (IntPtr)((Int64)actionPointer + (Marshal.SizeOf(typeof(SC_ACTION))) * i), false); } failureActions.lpsaActions = actionPointer; string command = recoveryOptions.RunProgramCommand; if (command != null) failureActions.lpCommand = command; failureActionsPointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SERVICE_FAILURE_ACTIONS))); Marshal.StructureToPtr(failureActions, failureActionsPointer, false); // Make the change bool success = ChangeServiceConfig2(controller.ServiceHandle.DangerousGetHandle(), SERVICE_CONFIG_FAILURE_ACTIONS, failureActionsPointer); // Check that the change occurred if (!success) throw new Win32Exception(Marshal.GetLastWin32Error(), "Unable to change the Service configuration."); } finally { if (failureActionsPointer != IntPtr.Zero) Marshal.FreeHGlobal(failureActionsPointer); if (actionPointer != IntPtr.Zero) Marshal.FreeHGlobal(actionPointer); if (controller != null) { controller.Dispose(); } //log.Debug(m => m("Done setting service recovery options.")); } }
public void SetServiceRecoveryOptions(HostSettings settings, ServiceRecoveryOptions options) { IntPtr scmHandle = IntPtr.Zero; IntPtr serviceHandle = IntPtr.Zero; IntPtr lpsaActions = IntPtr.Zero; IntPtr lpInfo = IntPtr.Zero; try { List<NativeMethods.SC_ACTION> actions = options.Actions.Select(x => x.GetAction()).ToList(); if (actions.Count == 0) throw new TopshelfException("Must be at least one failure action configured"); scmHandle = NativeMethods.OpenSCManager(null, null, (int)NativeMethods.SCM_ACCESS.SC_MANAGER_ALL_ACCESS); if (scmHandle == IntPtr.Zero) throw new TopshelfException("Failed to open service control manager"); serviceHandle = NativeMethods.OpenService(scmHandle, settings.ServiceName, (int)NativeMethods.SCM_ACCESS.SC_MANAGER_ALL_ACCESS); if (serviceHandle == IntPtr.Zero) throw new TopshelfException("Failed to open service: " + settings.ServiceName); int actionSize = Marshal.SizeOf(typeof(NativeMethods.SC_ACTION)); lpsaActions = Marshal.AllocHGlobal(actionSize*actions.Count + 1); if (lpsaActions == IntPtr.Zero) throw new TopshelfException("Unable to allocate memory for service recovery actions"); IntPtr nextAction = lpsaActions; for (int i = 0; i < actions.Count; i++) { Marshal.StructureToPtr(actions[i], nextAction, false); nextAction = (IntPtr)(nextAction.ToInt64() + actionSize); } var finalAction = new NativeMethods.SC_ACTION(); finalAction.Type = (int)NativeMethods.SC_ACTION_TYPE.None; finalAction.Delay = (int)TimeSpan.FromMinutes(1).TotalMilliseconds; Marshal.StructureToPtr(finalAction, nextAction, false); string rebootMessage = options.Actions.Where(x => x.GetType() == typeof(RestartSystemRecoveryAction)) .OfType<RestartSystemRecoveryAction>().Select(x => x.RestartMessage). FirstOrDefault() ?? ""; string runProgramCommand = options.Actions.Where(x => x.GetType() == typeof(RunProgramRecoveryAction)) .OfType<RunProgramRecoveryAction>().Select(x => x.Command). FirstOrDefault() ?? ""; var failureActions = new NativeMethods.SERVICE_FAILURE_ACTIONS(); failureActions.dwResetPeriod = (int)TimeSpan.FromDays(options.ResetPeriod).TotalSeconds; failureActions.lpRebootMsg = rebootMessage; failureActions.lpCommand = runProgramCommand; failureActions.cActions = actions.Count + 1; failureActions.actions = lpsaActions; lpInfo = Marshal.AllocHGlobal(Marshal.SizeOf(failureActions)); if (lpInfo == IntPtr.Zero) throw new TopshelfException("Failed to allocate memory for failure actions"); Marshal.StructureToPtr(failureActions, lpInfo, false); if (!NativeMethods.ChangeServiceConfig2(serviceHandle, NativeMethods.SERVICE_CONFIG_FAILURE_ACTIONS, lpInfo)) { throw new TopshelfException("Failed to change service recovery options"); } } finally { if (lpInfo != IntPtr.Zero) Marshal.FreeHGlobal(lpInfo); if (lpsaActions != IntPtr.Zero) Marshal.FreeHGlobal(lpsaActions); if (serviceHandle != IntPtr.Zero) NativeMethods.CloseServiceHandle(serviceHandle); if (scmHandle != IntPtr.Zero) NativeMethods.CloseServiceHandle(scmHandle); } }