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();
                }
            }
        }
Ejemplo n.º 2
0
        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);
            }
        }
Ejemplo n.º 4
0
        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);
            }
        }