Beispiel #1
0
        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);
                }
            }
        }