#183 - Add core logic for the DelayedStart option support (#205)

* #183 - Add core logic for the DelayedStart option support

* #183 - Add unit tests

* #183 - Update documentation and the configuration sample

* #183 - Use API calls to set the DelayedAutoStart flag as @jtnord proposed

* #183 - Refactor the project to use `delayedAutoStart`
pull/209/head
Oleg Nenashev 2017-04-18 23:23:52 +02:00 committed by GitHub
parent 5c71911e7b
commit d192c03638
8 changed files with 96 additions and 4 deletions

View File

@ -53,12 +53,24 @@ This gets displayed in Windows service manager when the service is selected.
This element specifies the executable to be launched.
It can be either absolute path, or you can just specify the executable name and let it be searched from `PATH` (although note that the services often run in a different user account and therefore it might have different `PATH` than your shell does.)
### startmode - Optional Element
### startmode
This element specifies the start mode of the Windows service.
It can be one of the following values: Boot, System, Automatic, or Manual.
See [MSDN](https://msdn.microsoft.com/en-us/library/aa384896%28v=vs.85%29.aspx) for details.
The default value is `Automatic`.
### delayedAutoStart
This Boolean option enables the delayed start mode if the `Automatic` start mode is defined.
More information about this mode is provided [here](https://blogs.technet.microsoft.com/askperf/2008/02/02/ws2008-startup-processes-and-delayed-automatic-start/).
Please note that this startup mode will not take affect on old Windows versions older than Windows 7 and Windows Server 2008.
Windows service installation may fail in such case.
```xml
<delayedAutoStart/>
```
### depend
Specify IDs of other services that this service depends on.
When service `X` depends on service `Y`, `X` can only run if `Y` is running.

View File

@ -162,6 +162,13 @@ SECTION: Service management
-->
<startmode>Automatic</startmode>
<!--
OPTION: delayedAutoStart
Enables the Delayed Automatic Start if 'Automatic' is specified in the 'startmode' field.
See the WinSW documentation to get info about supported platform versions and limitations.
-->
<!--<delayedAutoStart/>-->
<!--
OPTION: depend
Optionally specifies services that must start before this service starts.

View File

@ -606,13 +606,24 @@ namespace winsw
.OpenSubKey(d.Id, true).SetValue("Description", d.Description);
var actions = d.FailureActions;
if (actions.Count > 0)
{// set the failure actions
var isDelayedAutoStart = d.StartMode == StartMode.Automatic && d.DelayedAutoStart;
if (actions.Count > 0 || isDelayedAutoStart)
{
using (ServiceManager scm = new ServiceManager())
{
using (Service sc = scm.Open(d.Id))
{
sc.ChangeConfig(d.ResetFailureAfter, actions);
// Delayed auto start
if (isDelayedAutoStart)
{
sc.SetDelayedAutoStart(true);
}
// Set the failure actions
if (actions.Count > 0)
{
sc.ChangeConfig(d.ResetFailureAfter, actions);
}
}
}
}

View File

@ -49,6 +49,7 @@ namespace winsw.Configuration
// Service management
public StartMode StartMode { get { return StartMode.Automatic; } }
public bool DelayedAutoStart { get { return false; } }
public string[] ServiceDependencies { get { return new string[0]; } }
public TimeSpan WaitHint { get { return TimeSpan.FromSeconds(15); } }
public TimeSpan SleepTime { get { return TimeSpan.FromSeconds(1); } }

View File

@ -79,6 +79,26 @@ namespace winsw.Native
}
}
/// <summary>
/// Sets the DelayedAutoStart flag.
/// It will be applioed to services with Automatic startup mode only.
/// If the platform does not support this flag, an exception may be thrown.
/// </summary>
/// <param name="enabled">Value to set</param>
/// <exception cref="Exception">Operation failure, e.g. the OS does not support this flag</exception>
public void SetDelayedAutoStart(bool enabled)
{
SERVICE_DELAYED_AUTO_START settings = new SERVICE_DELAYED_AUTO_START
{
fDelayedAutostart = enabled
};
if (!Advapi32.ChangeServiceConfig2(Handle, SERVICE_CONFIG_INFOLEVEL.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, ref settings))
{
throw new Exception("Failed to change the DelayedAutoStart setting", new Win32Exception());
}
}
public void Dispose()
{
if (Handle!=IntPtr.Zero)
@ -261,6 +281,10 @@ namespace winsw.Native
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, ref SERVICE_FAILURE_ACTIONS sfa);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, ref SERVICE_DELAYED_AUTO_START sfa);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
@ -569,4 +593,12 @@ namespace winsw.Native
public int cActions;
public IntPtr/*SC_ACTION[]*/ lpsaActions;
}
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms685155(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SERVICE_DELAYED_AUTO_START
{
[MarshalAs(UnmanagedType.Bool)]
public bool fDelayedAutostart;
}
}

View File

@ -475,6 +475,18 @@ namespace winsw
}
}
/// <summary>
/// True if the service should be installed with the DelayedAutoStart flag.
/// This setting will be applyed only during the install command and only when the Automatic start mode is configured.
/// </summary>
public bool DelayedAutoStart
{
get
{
return dom.SelectSingleNode("//delayedAutoStart") != null;
}
}
/// <summary>
/// True if the service should beep when finished on shutdown.
/// This doesn't work on some OSes. See http://msdn.microsoft.com/en-us/library/ms679277%28VS.85%29.aspx

View File

@ -355,5 +355,17 @@ namespace winswTests
.ToServiceDescriptor(true);
Assert.That(sd.Arguments, Is.EqualTo(" --arg2=123 --arg3=null"));
}
[TestCase(true)]
[TestCase(false)]
public void DelayedStart_RoundTrip(bool enabled)
{
var bldr = ConfigXmlBuilder.create();
if (enabled) {
bldr = bldr.WithDelayedAutoStart();
}
var sd = bldr.ToServiceDescriptor();
Assert.That(sd.DelayedAutoStart, Is.EqualTo(enabled));
}
}
}

View File

@ -144,5 +144,10 @@ namespace winswTests.Util
return WithRawEntry(str.ToString());
}
public ConfigXmlBuilder WithDelayedAutoStart()
{
return WithRawEntry("<delayedAutoStart/>");
}
}
}