mirror of https://github.com/winsw/winsw
* #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
parent
5c71911e7b
commit
d192c03638
|
@ -53,12 +53,24 @@ This gets displayed in Windows service manager when the service is selected.
|
||||||
This element specifies the executable to be launched.
|
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.)
|
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.
|
This element specifies the start mode of the Windows service.
|
||||||
It can be one of the following values: Boot, System, Automatic, or Manual.
|
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.
|
See [MSDN](https://msdn.microsoft.com/en-us/library/aa384896%28v=vs.85%29.aspx) for details.
|
||||||
The default value is `Automatic`.
|
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
|
### depend
|
||||||
Specify IDs of other services that this service depends on.
|
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.
|
When service `X` depends on service `Y`, `X` can only run if `Y` is running.
|
||||||
|
|
|
@ -162,6 +162,13 @@ SECTION: Service management
|
||||||
-->
|
-->
|
||||||
<startmode>Automatic</startmode>
|
<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
|
OPTION: depend
|
||||||
Optionally specifies services that must start before this service starts.
|
Optionally specifies services that must start before this service starts.
|
||||||
|
|
|
@ -606,16 +606,27 @@ namespace winsw
|
||||||
.OpenSubKey(d.Id, true).SetValue("Description", d.Description);
|
.OpenSubKey(d.Id, true).SetValue("Description", d.Description);
|
||||||
|
|
||||||
var actions = d.FailureActions;
|
var actions = d.FailureActions;
|
||||||
if (actions.Count > 0)
|
var isDelayedAutoStart = d.StartMode == StartMode.Automatic && d.DelayedAutoStart;
|
||||||
{// set the failure actions
|
if (actions.Count > 0 || isDelayedAutoStart)
|
||||||
|
{
|
||||||
using (ServiceManager scm = new ServiceManager())
|
using (ServiceManager scm = new ServiceManager())
|
||||||
{
|
{
|
||||||
using (Service sc = scm.Open(d.Id))
|
using (Service sc = scm.Open(d.Id))
|
||||||
|
{
|
||||||
|
// Delayed auto start
|
||||||
|
if (isDelayedAutoStart)
|
||||||
|
{
|
||||||
|
sc.SetDelayedAutoStart(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the failure actions
|
||||||
|
if (actions.Count > 0)
|
||||||
{
|
{
|
||||||
sc.ChangeConfig(d.ResetFailureAfter, actions);
|
sc.ChangeConfig(d.ResetFailureAfter, actions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (args[0] == "uninstall")
|
if (args[0] == "uninstall")
|
||||||
|
|
|
@ -49,6 +49,7 @@ namespace winsw.Configuration
|
||||||
|
|
||||||
// Service management
|
// Service management
|
||||||
public StartMode StartMode { get { return StartMode.Automatic; } }
|
public StartMode StartMode { get { return StartMode.Automatic; } }
|
||||||
|
public bool DelayedAutoStart { get { return false; } }
|
||||||
public string[] ServiceDependencies { get { return new string[0]; } }
|
public string[] ServiceDependencies { get { return new string[0]; } }
|
||||||
public TimeSpan WaitHint { get { return TimeSpan.FromSeconds(15); } }
|
public TimeSpan WaitHint { get { return TimeSpan.FromSeconds(15); } }
|
||||||
public TimeSpan SleepTime { get { return TimeSpan.FromSeconds(1); } }
|
public TimeSpan SleepTime { get { return TimeSpan.FromSeconds(1); } }
|
||||||
|
|
|
@ -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()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Handle!=IntPtr.Zero)
|
if (Handle!=IntPtr.Zero)
|
||||||
|
@ -261,6 +281,10 @@ namespace winsw.Native
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, ref SERVICE_FAILURE_ACTIONS sfa);
|
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)]
|
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
internal static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
|
internal static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
|
||||||
|
|
||||||
|
@ -569,4 +593,12 @@ namespace winsw.Native
|
||||||
public int cActions;
|
public int cActions;
|
||||||
public IntPtr/*SC_ACTION[]*/ lpsaActions;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
/// <summary>
|
||||||
/// True if the service should beep when finished on shutdown.
|
/// 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
|
/// This doesn't work on some OSes. See http://msdn.microsoft.com/en-us/library/ms679277%28VS.85%29.aspx
|
||||||
|
|
|
@ -355,5 +355,17 @@ namespace winswTests
|
||||||
.ToServiceDescriptor(true);
|
.ToServiceDescriptor(true);
|
||||||
Assert.That(sd.Arguments, Is.EqualTo(" --arg2=123 --arg3=null"));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,5 +144,10 @@ namespace winswTests.Util
|
||||||
|
|
||||||
return WithRawEntry(str.ToString());
|
return WithRawEntry(str.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConfigXmlBuilder WithDelayedAutoStart()
|
||||||
|
{
|
||||||
|
return WithRawEntry("<delayedAutoStart/>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue