Implemented support for setting the Windows Service description

This commit is contained in:
Kenneth Skovhede
2024-08-27 14:08:52 +02:00
parent c10fd170fd
commit 2a817fe093
3 changed files with 80 additions and 60 deletions
+2 -2
View File
@@ -83,7 +83,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, "\"" + selfexec + "\"" + " " + commandline);
ServiceInstaller.InstallService(ServiceControl.SERVICE_NAME, ServiceControl.DISPLAY_NAME, ServiceControl.SERVICE_DESCRIPTION, "\"" + selfexec + "\"" + " " + commandline);
Console.WriteLine("Duplicati service installation succeeded.");
}
catch (Exception ex)
@@ -95,7 +95,7 @@ namespace Duplicati.WindowsService
}
else
{
ServiceBase.Run(new ServiceBase[] { new ServiceControl(args) });
ServiceBase.Run([new ServiceControl(args)]);
}
return 0;
+29 -28
View File
@@ -1,39 +1,39 @@
// Copyright (C) 2024, 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.
// Copyright (C) 2024, 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 Duplicati.Service;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Versioning;
namespace Duplicati.WindowsService
{
[SupportedOSPlatform("windows")]
public class ServiceControl : System.ServiceProcess.ServiceBase
{
private const string LOG_SOURCE = "Duplicati";
private const string LOG_NAME = "Application";
public const string SERVICE_NAME = "Duplicati";
public const string DISPLAY_NAME = "Duplicati service";
public const string SERVICE_DESCRIPTION = "Duplicati running as a Windows Service";
private readonly System.Diagnostics.EventLog m_eventLog;
@@ -46,12 +46,13 @@ namespace Duplicati.WindowsService
{
this.ServiceName = SERVICE_NAME;
m_eventLog = new System.Diagnostics.EventLog();
if (!System.Diagnostics.EventLog.SourceExists(LOG_SOURCE))
System.Diagnostics.EventLog.CreateEventSource(LOG_SOURCE, LOG_NAME);
m_eventLog.Source = LOG_SOURCE;
m_eventLog.Log = LOG_NAME;
m_eventLog = new System.Diagnostics.EventLog
{
Source = LOG_SOURCE,
Log = LOG_NAME
};
m_verbose_messages = args != null && args.Any(x => string.Equals("--debug-service", x, StringComparison.OrdinalIgnoreCase));
m_cmdargs = (args ?? new string[0]).Where(x => !string.Equals("--debug-service", x, StringComparison.OrdinalIgnoreCase)).ToArray();
@@ -78,7 +79,7 @@ namespace Duplicati.WindowsService
if (m_verbose_messages)
m_eventLog.WriteEntry("Starting...");
lock(m_lock)
lock (m_lock)
if (m_runner == null)
{
if (m_verbose_messages)
+49 -30
View File
@@ -1,28 +1,26 @@
// Copyright (C) 2024, 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.
// Copyright (C) 2024, 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.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
namespace Duplicati.WindowsService
{
@@ -48,6 +46,18 @@ namespace Duplicati.WindowsService
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteService(IntPtr hService);
private const int SERVICE_CONFIG_DESCRIPTION = 0x01;
[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);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct SERVICE_DESCRIPTION
{
public string lpDescription;
}
/// <summary>
/// Access to the service. Before granting the requested access, the
/// system checks the access token of the calling process.
@@ -391,21 +401,30 @@ namespace Duplicati.WindowsService
GENERIC_ALL = SC_MANAGER_ALL_ACCESS,
}
public static void InstallService(string ServiceName, string DisplayName, string Path)
public static void InstallService(string ServiceName, string DisplayName, string Description, string Path)
{
var scMgrHandle = OpenSCManager(null, null, (uint)SCM_ACCESS.SC_MANAGER_ALL_ACCESS);
try
{
if (scMgrHandle == IntPtr.Zero)
throw new Exception($"Win32 error { Marshal.GetLastWin32Error().ToString() } during install service (OpenSCManager)");
throw new Exception($"Win32 error {Marshal.GetLastWin32Error().ToString()} during install service (OpenSCManager)");
var serviceHandle = CreateService(scMgrHandle, ServiceName, DisplayName, (uint)SERVICE_ACCESS.SERVICE_ALL_ACCESS, (uint)SERVICE_TYPE.SERVICE_WIN32_OWN_PROCESS,
(uint)SERVICE_START.SERVICE_AUTO_START, (uint)SERVICE_ERROR.SERVICE_ERROR_NORMAL, Path, null, null, null, null, null);
if (serviceHandle == IntPtr.Zero)
throw new Exception($"Win32 error { Marshal.GetLastWin32Error().ToString() } during install service (CreateService)");
throw new Exception($"Win32 error {Marshal.GetLastWin32Error().ToString()} during install service (CreateService)");
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()}");
CloseServiceHandle(serviceHandle);
}
finally
@@ -421,17 +440,17 @@ namespace Duplicati.WindowsService
try
{
if (scMgrHandle == IntPtr.Zero)
throw new Exception($"Win32 error { Marshal.GetLastWin32Error().ToString() } during delete service (OpenSCManager)");
throw new Exception($"Win32 error {Marshal.GetLastWin32Error().ToString()} during delete service (OpenSCManager)");
var serviceHandle = OpenService(scMgrHandle, ServiceName, (uint)SERVICE_ACCESS.SERVICE_ALL_ACCESS);
if (serviceHandle == IntPtr.Zero)
throw new Exception($"Win32 error { Marshal.GetLastWin32Error().ToString() } during delete service (OpenService)");
throw new Exception($"Win32 error {Marshal.GetLastWin32Error().ToString()} during delete service (OpenService)");
try
{
if (DeleteService(serviceHandle) == false)
throw new Exception($"Win32 error { Marshal.GetLastWin32Error().ToString() } during delete service (DeleteService)");
throw new Exception($"Win32 error {Marshal.GetLastWin32Error().ToString()} during delete service (DeleteService)");
}
finally
{