Merge pull request #7045 from JamBalaya56562/fix/windows-service-delayed-start
Delay Windows service startup to avoid boot timeout
This commit is contained in:
@@ -113,7 +113,7 @@ namespace Duplicati.WindowsService
|
||||
//The path can also include arguments for an auto-start service. For example, "d:\myshare\myservice.exe arg1 arg2". These arguments are passed to the service entry point (typically the main function).
|
||||
try
|
||||
{
|
||||
ServiceInstaller.InstallService(ServiceControl.SERVICE_NAME, ServiceControl.DISPLAY_NAME, ServiceControl.SERVICE_DESCRIPTION, "\"" + selfexec + "\"" + " SERVER " + commandline);
|
||||
ServiceInstaller.InstallService(ServiceControl.SERVICE_NAME, ServiceControl.DISPLAY_NAME, ServiceControl.SERVICE_DESCRIPTION, "\"" + selfexec + "\"" + " SERVER " + commandline, delayedAutoStart: true);
|
||||
Console.WriteLine("Duplicati service installation succeeded.");
|
||||
if (!args.Any(x => string.Equals("install-only", x, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
@@ -166,7 +166,7 @@ namespace Duplicati.WindowsService
|
||||
//The path can also include arguments for an auto-start service. For example, "d:\myshare\myservice.exe arg1 arg2". These arguments are passed to the service entry point (typically the main function).
|
||||
try
|
||||
{
|
||||
ServiceInstaller.InstallService(ServiceControl.SERVICE_NAME_AGENT, ServiceControl.DISPLAY_NAME_AGENT, ServiceControl.SERVICE_DESCRIPTION_AGENT, "\"" + selfexec + "\"" + " AGENT " + commandline);
|
||||
ServiceInstaller.InstallService(ServiceControl.SERVICE_NAME_AGENT, ServiceControl.DISPLAY_NAME_AGENT, ServiceControl.SERVICE_DESCRIPTION_AGENT, "\"" + selfexec + "\"" + " AGENT " + commandline, delayedAutoStart: true);
|
||||
Console.WriteLine("Duplicati agent service installation succeeded.");
|
||||
if (!args.Any(x => string.Equals("install-only-agent", x, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
// Copyright (C) 2026, The Duplicati Team
|
||||
// https://duplicati.com, hello@duplicati.com
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// Copyright (C) 2026, The Duplicati Team
|
||||
// https://duplicati.com, hello@duplicati.com
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -47,17 +47,29 @@ namespace Duplicati.WindowsService
|
||||
private static extern bool DeleteService(IntPtr hService);
|
||||
|
||||
private const int SERVICE_CONFIG_DESCRIPTION = 0x01;
|
||||
private const int SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 0x03;
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool ChangeServiceConfig2(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_DESCRIPTION lpInfo);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool ChangeServiceConfig2(IntPtr hService, int dwInfoLevel, ref SERVICE_DELAYED_AUTO_START_INFO lpInfo);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
private struct SERVICE_DESCRIPTION
|
||||
{
|
||||
public string lpDescription;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct SERVICE_DELAYED_AUTO_START_INFO
|
||||
{
|
||||
[MarshalAs(UnmanagedType.Bool)]
|
||||
public bool fDelayedAutostart;
|
||||
}
|
||||
|
||||
private enum SC_STATUS_TYPE : int
|
||||
{
|
||||
SC_STATUS_PROCESS_INFO = 0
|
||||
@@ -446,7 +458,7 @@ namespace Duplicati.WindowsService
|
||||
GENERIC_ALL = SC_MANAGER_ALL_ACCESS,
|
||||
}
|
||||
|
||||
public static void InstallService(string ServiceName, string DisplayName, string Description, string Path)
|
||||
public static void InstallService(string ServiceName, string DisplayName, string Description, string Path, bool delayedAutoStart)
|
||||
{
|
||||
var scMgrHandle = OpenSCManager(null, null, (uint)SCM_ACCESS.SC_MANAGER_ALL_ACCESS);
|
||||
|
||||
@@ -461,16 +473,36 @@ namespace Duplicati.WindowsService
|
||||
if (serviceHandle == IntPtr.Zero)
|
||||
throw new Exception($"Win32 error {Marshal.GetLastWin32Error().ToString()} during install service (CreateService)");
|
||||
|
||||
var pinfo = new SERVICE_DESCRIPTION
|
||||
try
|
||||
{
|
||||
lpDescription = Description
|
||||
};
|
||||
var pinfo = new SERVICE_DESCRIPTION
|
||||
{
|
||||
lpDescription = Description
|
||||
};
|
||||
|
||||
var res = ChangeServiceConfig2(serviceHandle, SERVICE_CONFIG_DESCRIPTION, ref pinfo);
|
||||
if (!res)
|
||||
System.Diagnostics.Trace.WriteLine($"Failed to set decription: {Marshal.GetLastWin32Error().ToString()}");
|
||||
var res = ChangeServiceConfig2(serviceHandle, SERVICE_CONFIG_DESCRIPTION, ref pinfo);
|
||||
if (!res)
|
||||
System.Diagnostics.Trace.WriteLine($"Failed to set description: {Marshal.GetLastWin32Error().ToString()}");
|
||||
|
||||
CloseServiceHandle(serviceHandle);
|
||||
if (delayedAutoStart)
|
||||
{
|
||||
var delayedInfo = new SERVICE_DELAYED_AUTO_START_INFO
|
||||
{
|
||||
fDelayedAutostart = true
|
||||
};
|
||||
|
||||
if (!ChangeServiceConfig2(serviceHandle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, ref delayedInfo))
|
||||
{
|
||||
var error = Marshal.GetLastWin32Error();
|
||||
DeleteService(serviceHandle);
|
||||
throw new Exception($"Win32 error {error.ToString()} during install service (ChangeServiceConfig2 delayed auto-start)");
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseServiceHandle(serviceHandle);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user