mirror of https://github.com/winsw/winsw
Add `dev list` command
parent
2401b42dfb
commit
144cff7f19
|
@ -37,6 +37,8 @@ namespace WinSW.Native
|
||||||
_ = LookupAccountName(null, accountName, IntPtr.Zero, ref sidSize, null, ref domainNameLength, out _);
|
_ = LookupAccountName(null, accountName, IntPtr.Zero, ref sidSize, null, ref domainNameLength, out _);
|
||||||
|
|
||||||
IntPtr sid = Marshal.AllocHGlobal(sidSize);
|
IntPtr sid = Marshal.AllocHGlobal(sidSize);
|
||||||
|
try
|
||||||
|
{
|
||||||
string? domainName = domainNameLength == 0 ? null : new string('\0', domainNameLength - 1);
|
string? domainName = domainNameLength == 0 ? null : new string('\0', domainNameLength - 1);
|
||||||
|
|
||||||
if (!LookupAccountName(null, accountName, sid, ref sidSize, domainName, ref domainNameLength, out _))
|
if (!LookupAccountName(null, accountName, sid, ref sidSize, domainName, ref domainNameLength, out _))
|
||||||
|
@ -52,6 +54,12 @@ namespace WinSW.Native
|
||||||
|
|
||||||
return sid;
|
return sid;
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(sid);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <exception cref="Win32Exception" />
|
/// <exception cref="Win32Exception" />
|
||||||
private static void AddAccountRight(IntPtr sid, string rightName)
|
private static void AddAccountRight(IntPtr sid, string rightName)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
using System.ServiceProcess;
|
using System.ServiceProcess;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -56,9 +56,9 @@ namespace WinSW.Native
|
||||||
private ServiceManager(IntPtr handle) => this.handle = handle;
|
private ServiceManager(IntPtr handle) => this.handle = handle;
|
||||||
|
|
||||||
/// <exception cref="CommandException" />
|
/// <exception cref="CommandException" />
|
||||||
internal static ServiceManager Open()
|
internal static ServiceManager Open(ServiceManagerAccess access = ServiceManagerAccess.All)
|
||||||
{
|
{
|
||||||
IntPtr handle = OpenSCManager(null, null, ServiceManagerAccess.ALL_ACCESS);
|
IntPtr handle = OpenSCManager(null, null, access);
|
||||||
if (handle == IntPtr.Zero)
|
if (handle == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Throw.Command.Win32Exception("Failed to open the service control manager database.");
|
Throw.Command.Win32Exception("Failed to open the service control manager database.");
|
||||||
|
@ -81,7 +81,7 @@ namespace WinSW.Native
|
||||||
this.handle,
|
this.handle,
|
||||||
serviceName,
|
serviceName,
|
||||||
displayName,
|
displayName,
|
||||||
ServiceAccess.ALL_ACCESS,
|
ServiceAccess.All,
|
||||||
ServiceType.Win32OwnProcess,
|
ServiceType.Win32OwnProcess,
|
||||||
startMode,
|
startMode,
|
||||||
ServiceErrorControl.Normal,
|
ServiceErrorControl.Normal,
|
||||||
|
@ -100,7 +100,58 @@ namespace WinSW.Native
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <exception cref="CommandException" />
|
/// <exception cref="CommandException" />
|
||||||
internal Service OpenService(string serviceName, ServiceAccess access = ServiceAccess.ALL_ACCESS)
|
internal unsafe (IntPtr Services, int Count) EnumerateServices()
|
||||||
|
{
|
||||||
|
int resume = 0;
|
||||||
|
_ = EnumServicesStatus(
|
||||||
|
this.handle,
|
||||||
|
ServiceType.Win32OwnProcess,
|
||||||
|
ServiceState.All,
|
||||||
|
IntPtr.Zero,
|
||||||
|
0,
|
||||||
|
out int bytesNeeded,
|
||||||
|
out _,
|
||||||
|
ref resume);
|
||||||
|
|
||||||
|
IntPtr services = Marshal.AllocHGlobal(bytesNeeded);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!EnumServicesStatus(
|
||||||
|
this.handle,
|
||||||
|
ServiceType.Win32OwnProcess,
|
||||||
|
ServiceState.All,
|
||||||
|
services,
|
||||||
|
bytesNeeded,
|
||||||
|
out _,
|
||||||
|
out int count,
|
||||||
|
ref resume))
|
||||||
|
{
|
||||||
|
Throw.Command.Win32Exception("Failed to enumerate services.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (services, count);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(services);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <exception cref="CommandException" />
|
||||||
|
internal unsafe Service OpenService(char* serviceName, ServiceAccess access = ServiceAccess.All)
|
||||||
|
{
|
||||||
|
IntPtr serviceHandle = ServiceApis.OpenService(this.handle, serviceName, access);
|
||||||
|
if (serviceHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Throw.Command.Win32Exception("Failed to open the service.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Service(serviceHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <exception cref="CommandException" />
|
||||||
|
internal Service OpenService(string serviceName, ServiceAccess access = ServiceAccess.All)
|
||||||
{
|
{
|
||||||
IntPtr serviceHandle = ServiceApis.OpenService(this.handle, serviceName, access);
|
IntPtr serviceHandle = ServiceApis.OpenService(this.handle, serviceName, access);
|
||||||
if (serviceHandle == IntPtr.Zero)
|
if (serviceHandle == IntPtr.Zero)
|
||||||
|
@ -113,7 +164,7 @@ namespace WinSW.Native
|
||||||
|
|
||||||
internal bool ServiceExists(string serviceName)
|
internal bool ServiceExists(string serviceName)
|
||||||
{
|
{
|
||||||
IntPtr serviceHandle = ServiceApis.OpenService(this.handle, serviceName, ServiceAccess.ALL_ACCESS);
|
IntPtr serviceHandle = ServiceApis.OpenService(this.handle, serviceName, ServiceAccess.All);
|
||||||
if (serviceHandle == IntPtr.Zero)
|
if (serviceHandle == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -140,6 +191,39 @@ namespace WinSW.Native
|
||||||
|
|
||||||
internal Service(IntPtr handle) => this.handle = handle;
|
internal Service(IntPtr handle) => this.handle = handle;
|
||||||
|
|
||||||
|
/// <exception cref="CommandException" />
|
||||||
|
internal unsafe string ExecutablePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_ = QueryServiceConfig(
|
||||||
|
this.handle,
|
||||||
|
IntPtr.Zero,
|
||||||
|
0,
|
||||||
|
out int bytesNeeded);
|
||||||
|
|
||||||
|
IntPtr config = Marshal.AllocHGlobal(bytesNeeded);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!QueryServiceConfig(
|
||||||
|
this.handle,
|
||||||
|
config,
|
||||||
|
bytesNeeded,
|
||||||
|
out _))
|
||||||
|
{
|
||||||
|
Throw.Command.Win32Exception("Failed to query service config.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Marshal.PtrToStringUni((IntPtr)((QUERY_SERVICE_CONFIG*)config)->BinaryPathName)!;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <exception cref="CommandException" />
|
||||||
internal unsafe int ProcessId
|
internal unsafe int ProcessId
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
@ -60,12 +60,29 @@ namespace WinSW.Native
|
||||||
[DllImport(Libraries.Advapi32, SetLastError = true)]
|
[DllImport(Libraries.Advapi32, SetLastError = true)]
|
||||||
internal static extern bool DeleteService(IntPtr serviceHandle);
|
internal static extern bool DeleteService(IntPtr serviceHandle);
|
||||||
|
|
||||||
|
[DllImport(Libraries.Advapi32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "EnumServicesStatusW")]
|
||||||
|
internal static extern unsafe bool EnumServicesStatus(
|
||||||
|
IntPtr databaseHandle,
|
||||||
|
ServiceType serviceType,
|
||||||
|
ServiceState serviceState,
|
||||||
|
IntPtr services,
|
||||||
|
int bufferSize,
|
||||||
|
out int bytesNeeded,
|
||||||
|
out int servicesReturned,
|
||||||
|
ref int resumeHandle);
|
||||||
|
|
||||||
[DllImport(Libraries.Advapi32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "OpenSCManagerW")]
|
[DllImport(Libraries.Advapi32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "OpenSCManagerW")]
|
||||||
internal static extern IntPtr OpenSCManager(string? machineName, string? databaseName, ServiceManagerAccess desiredAccess);
|
internal static extern IntPtr OpenSCManager(string? machineName, string? databaseName, ServiceManagerAccess desiredAccess);
|
||||||
|
|
||||||
|
[DllImport(Libraries.Advapi32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "OpenServiceW")]
|
||||||
|
internal static unsafe extern IntPtr OpenService(IntPtr databaseHandle, char* serviceName, ServiceAccess desiredAccess);
|
||||||
|
|
||||||
[DllImport(Libraries.Advapi32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "OpenServiceW")]
|
[DllImport(Libraries.Advapi32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "OpenServiceW")]
|
||||||
internal static extern IntPtr OpenService(IntPtr databaseHandle, string serviceName, ServiceAccess desiredAccess);
|
internal static extern IntPtr OpenService(IntPtr databaseHandle, string serviceName, ServiceAccess desiredAccess);
|
||||||
|
|
||||||
|
[DllImport(Libraries.Advapi32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "QueryServiceConfigW")]
|
||||||
|
internal static extern bool QueryServiceConfig(IntPtr serviceHandle, IntPtr serviceConfig, int bufferSize, out int bytesNeeded);
|
||||||
|
|
||||||
[DllImport(Libraries.Advapi32, SetLastError = true)]
|
[DllImport(Libraries.Advapi32, SetLastError = true)]
|
||||||
internal static extern bool QueryServiceStatus(IntPtr serviceHandle, out SERVICE_STATUS serviceStatus);
|
internal static extern bool QueryServiceStatus(IntPtr serviceHandle, out SERVICE_STATUS serviceStatus);
|
||||||
|
|
||||||
|
@ -88,27 +105,27 @@ namespace WinSW.Native
|
||||||
[Flags]
|
[Flags]
|
||||||
internal enum ServiceAccess : uint
|
internal enum ServiceAccess : uint
|
||||||
{
|
{
|
||||||
QUERY_CONFIG = 0x0001,
|
QueryConfig = 0x0001,
|
||||||
CHANGE_CONFIG = 0x0002,
|
ChangeConfig = 0x0002,
|
||||||
QUERY_STATUS = 0x0004,
|
QueryStatus = 0x0004,
|
||||||
ENUMERATE_DEPENDENTS = 0x0008,
|
EnumerateDependents = 0x0008,
|
||||||
START = 0x0010,
|
Start = 0x0010,
|
||||||
STOP = 0x0020,
|
Stop = 0x0020,
|
||||||
PAUSE_CONTINUE = 0x0040,
|
PauseContinue = 0x0040,
|
||||||
INTERROGATE = 0x0080,
|
Interrogate = 0x0080,
|
||||||
USER_DEFINED_CONTROL = 0x0100,
|
UserDefinedControl = 0x0100,
|
||||||
|
|
||||||
ALL_ACCESS =
|
All =
|
||||||
SecurityApis.StandardAccess.REQUIRED |
|
SecurityApis.StandardAccess.REQUIRED |
|
||||||
QUERY_CONFIG |
|
QueryConfig |
|
||||||
CHANGE_CONFIG |
|
ChangeConfig |
|
||||||
QUERY_STATUS |
|
QueryStatus |
|
||||||
ENUMERATE_DEPENDENTS |
|
EnumerateDependents |
|
||||||
START |
|
Start |
|
||||||
STOP |
|
Stop |
|
||||||
PAUSE_CONTINUE |
|
PauseContinue |
|
||||||
INTERROGATE |
|
Interrogate |
|
||||||
USER_DEFINED_CONTROL,
|
UserDefinedControl,
|
||||||
}
|
}
|
||||||
|
|
||||||
// SERVICE_CONFIG_
|
// SERVICE_CONFIG_
|
||||||
|
@ -140,21 +157,29 @@ namespace WinSW.Native
|
||||||
[Flags]
|
[Flags]
|
||||||
internal enum ServiceManagerAccess : uint
|
internal enum ServiceManagerAccess : uint
|
||||||
{
|
{
|
||||||
CONNECT = 0x0001,
|
Connect = 0x0001,
|
||||||
CREATE_SERVICE = 0x0002,
|
CreateService = 0x0002,
|
||||||
ENUMERATE_SERVICE = 0x0004,
|
EnumerateService = 0x0004,
|
||||||
LOCK = 0x0008,
|
Lock = 0x0008,
|
||||||
QUERY_LOCK_STATUS = 0x0010,
|
QueryLockStatus = 0x0010,
|
||||||
MODIFY_BOOT_CONFIG = 0x0020,
|
ModifyBootConfig = 0x0020,
|
||||||
|
|
||||||
ALL_ACCESS =
|
All =
|
||||||
SecurityApis.StandardAccess.REQUIRED |
|
SecurityApis.StandardAccess.REQUIRED |
|
||||||
CONNECT |
|
Connect |
|
||||||
CREATE_SERVICE |
|
CreateService |
|
||||||
ENUMERATE_SERVICE |
|
EnumerateService |
|
||||||
LOCK |
|
Lock |
|
||||||
QUERY_LOCK_STATUS |
|
QueryLockStatus |
|
||||||
MODIFY_BOOT_CONFIG,
|
ModifyBootConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
// SERVICE_
|
||||||
|
internal enum ServiceState : uint
|
||||||
|
{
|
||||||
|
Active = 0x00000001,
|
||||||
|
Inactive = 0x00000002,
|
||||||
|
All = 0x00000003,
|
||||||
}
|
}
|
||||||
|
|
||||||
// SC_STATUS_
|
// SC_STATUS_
|
||||||
|
@ -163,6 +188,38 @@ namespace WinSW.Native
|
||||||
ProcessInfo = 0,
|
ProcessInfo = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal readonly unsafe struct ENUM_SERVICE_STATUS
|
||||||
|
{
|
||||||
|
public readonly char* ServiceName;
|
||||||
|
public readonly char* DisplayName;
|
||||||
|
public readonly SERVICE_STATUS ServiceStatus;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var serviceName = new ReadOnlySpan<char>(this.ServiceName, new ReadOnlySpan<char>(this.ServiceName, 256).IndexOf('\0'));
|
||||||
|
var displayName = new ReadOnlySpan<char>(this.DisplayName, new ReadOnlySpan<char>(this.DisplayName, 256).IndexOf('\0'));
|
||||||
|
|
||||||
|
#if NETCOREAPP
|
||||||
|
return string.Concat(displayName, " (", serviceName, ")");
|
||||||
|
#else
|
||||||
|
return string.Concat(displayName.ToString(), " (", serviceName.ToString(), ")");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal unsafe struct QUERY_SERVICE_CONFIG
|
||||||
|
{
|
||||||
|
public ServiceType ServiceType;
|
||||||
|
public ServiceStartMode StartType;
|
||||||
|
public ServiceErrorControl ErrorControl;
|
||||||
|
public char* BinaryPathName;
|
||||||
|
public char* LoadOrderGroup;
|
||||||
|
public uint TagId;
|
||||||
|
public char* Dependencies;
|
||||||
|
public char* ServiceStartName;
|
||||||
|
public char* DisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
internal struct SERVICE_DELAYED_AUTO_START_INFO
|
internal struct SERVICE_DELAYED_AUTO_START_INFO
|
||||||
{
|
{
|
||||||
public bool DelayedAutostart;
|
public bool DelayedAutostart;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="log4net" Version="2.0.8" />
|
<PackageReference Include="log4net" Version="2.0.8" />
|
||||||
<PackageReference Include="stylecop.analyzers" Version="1.2.0-beta.*">
|
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.*">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -32,6 +32,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net5.0'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'net5.0'">
|
||||||
|
<PackageReference Include="System.Memory" Version="4.5.4" />
|
||||||
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||||
<Reference Include="System.ServiceProcess" />
|
<Reference Include="System.ServiceProcess" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@ namespace WinSW.Tests.Util
|
||||||
var hitsField = this.hitsField = trackerType.GetField("HitsArray", BindingFlags.Public | BindingFlags.Static);
|
var hitsField = this.hitsField = trackerType.GetField("HitsArray", BindingFlags.Public | BindingFlags.Static);
|
||||||
Assert.NotNull(hitsField);
|
Assert.NotNull(hitsField);
|
||||||
|
|
||||||
using var scm = ServiceManager.Open();
|
using var scm = ServiceManager.Open(ServiceApis.ServiceManagerAccess.Connect);
|
||||||
using var sc = scm.OpenService(serviceName, ServiceApis.ServiceAccess.QUERY_STATUS);
|
using var sc = scm.OpenService(serviceName, ServiceApis.ServiceAccess.QueryStatus);
|
||||||
|
|
||||||
int processId = sc.ProcessId;
|
int processId = sc.ProcessId;
|
||||||
Assert.True(processId >= 0);
|
Assert.True(processId >= 0);
|
||||||
|
|
|
@ -9,6 +9,7 @@ using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.ServiceProcess;
|
using System.ServiceProcess;
|
||||||
|
@ -22,6 +23,7 @@ using log4net.Layout;
|
||||||
using WinSW.Logging;
|
using WinSW.Logging;
|
||||||
using WinSW.Native;
|
using WinSW.Native;
|
||||||
using WinSW.Util;
|
using WinSW.Util;
|
||||||
|
using static WinSW.Native.ServiceApis;
|
||||||
using Process = System.Diagnostics.Process;
|
using Process = System.Diagnostics.Process;
|
||||||
using TimeoutException = System.ServiceProcess.TimeoutException;
|
using TimeoutException = System.ServiceProcess.TimeoutException;
|
||||||
|
|
||||||
|
@ -271,29 +273,43 @@ namespace WinSW
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var dev = new Command("dev", "Experimental commands.")
|
var dev = new Command("dev", "Experimental commands.");
|
||||||
{
|
|
||||||
config,
|
|
||||||
noElevate,
|
|
||||||
};
|
|
||||||
|
|
||||||
root.Add(dev);
|
root.Add(dev);
|
||||||
|
|
||||||
|
{
|
||||||
var ps = new Command("ps", "Draws the process tree associated with the service.")
|
var ps = new Command("ps", "Draws the process tree associated with the service.")
|
||||||
{
|
{
|
||||||
Handler = CommandHandler.Create<string?, bool>(DevPs),
|
Handler = CommandHandler.Create<string?>(DevPs),
|
||||||
};
|
};
|
||||||
|
|
||||||
dev.Add(ps);
|
ps.Add(config);
|
||||||
|
|
||||||
|
dev.Add(ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
var kill = new Command("kill", "Terminates the service if it has stopped responding.")
|
var kill = new Command("kill", "Terminates the service if it has stopped responding.")
|
||||||
{
|
{
|
||||||
Handler = CommandHandler.Create<string?, bool>(DevKill),
|
Handler = CommandHandler.Create<string?, bool>(DevKill),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
kill.Add(config);
|
||||||
|
kill.Add(noElevate);
|
||||||
|
|
||||||
dev.Add(kill);
|
dev.Add(kill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var list = new Command("list", "Lists services managed by the current executable.")
|
||||||
|
{
|
||||||
|
Handler = CommandHandler.Create(DevList),
|
||||||
|
};
|
||||||
|
|
||||||
|
dev.Add(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new CommandLineBuilder(root)
|
return new CommandLineBuilder(root)
|
||||||
.UseVersionOption()
|
.UseVersionOption()
|
||||||
.UseHelp()
|
.UseHelp()
|
||||||
|
@ -374,7 +390,7 @@ namespace WinSW
|
||||||
|
|
||||||
Log.Info($"Installing service '{config.Format()}'...");
|
Log.Info($"Installing service '{config.Format()}'...");
|
||||||
|
|
||||||
using ServiceManager scm = ServiceManager.Open();
|
using ServiceManager scm = ServiceManager.Open(ServiceManagerAccess.CreateService);
|
||||||
|
|
||||||
if (scm.ServiceExists(config.Name))
|
if (scm.ServiceExists(config.Name))
|
||||||
{
|
{
|
||||||
|
@ -499,7 +515,7 @@ namespace WinSW
|
||||||
|
|
||||||
Log.Info($"Uninstalling service '{config.Format()}'...");
|
Log.Info($"Uninstalling service '{config.Format()}'...");
|
||||||
|
|
||||||
using ServiceManager scm = ServiceManager.Open();
|
using ServiceManager scm = ServiceManager.Open(ServiceManagerAccess.Connect);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using Service sc = scm.OpenService(config.Name);
|
using Service sc = scm.OpenService(config.Name);
|
||||||
|
@ -822,7 +838,7 @@ namespace WinSW
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using ServiceManager scm = ServiceManager.Open();
|
using ServiceManager scm = ServiceManager.Open(ServiceManagerAccess.Connect);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using Service sc = scm.OpenService(config.Name);
|
using Service sc = scm.OpenService(config.Name);
|
||||||
|
@ -864,18 +880,12 @@ namespace WinSW
|
||||||
Log.Info($"Service '{config.Format()}' was refreshed successfully.");
|
Log.Info($"Service '{config.Format()}' was refreshed successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevPs(string? pathToConfig, bool noElevate)
|
static void DevPs(string? pathToConfig)
|
||||||
{
|
{
|
||||||
XmlServiceConfig config = CreateConfig(pathToConfig);
|
XmlServiceConfig config = CreateConfig(pathToConfig);
|
||||||
|
|
||||||
if (!elevated)
|
using ServiceManager scm = ServiceManager.Open(ServiceManagerAccess.Connect);
|
||||||
{
|
using Service sc = scm.OpenService(config.Name, ServiceAccess.QueryStatus);
|
||||||
Elevate(noElevate);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using ServiceManager scm = ServiceManager.Open();
|
|
||||||
using Service sc = scm.OpenService(config.Name);
|
|
||||||
|
|
||||||
int processId = sc.ProcessId;
|
int processId = sc.ProcessId;
|
||||||
if (processId >= 0)
|
if (processId >= 0)
|
||||||
|
@ -938,6 +948,28 @@ namespace WinSW
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsafe void DevList()
|
||||||
|
{
|
||||||
|
using var scm = ServiceManager.Open(ServiceManagerAccess.EnumerateService);
|
||||||
|
(IntPtr services, int count) = scm.EnumerateServices();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var status = (ServiceApis.ENUM_SERVICE_STATUS*)services + i;
|
||||||
|
using var sc = scm.OpenService(status->ServiceName, ServiceAccess.QueryConfig);
|
||||||
|
if (sc.ExecutablePath.StartsWith($"\"{ExecutablePath}\""))
|
||||||
|
{
|
||||||
|
Console.WriteLine(status->ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(services);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void Customize(string output, string manufacturer)
|
static void Customize(string output, string manufacturer)
|
||||||
{
|
{
|
||||||
if (Resources.UpdateCompanyName(ExecutablePath, output, manufacturer))
|
if (Resources.UpdateCompanyName(ExecutablePath, output, manufacturer))
|
||||||
|
|
|
@ -502,7 +502,7 @@ namespace WinSW
|
||||||
private void SignalStopped()
|
private void SignalStopped()
|
||||||
{
|
{
|
||||||
using ServiceManager scm = ServiceManager.Open();
|
using ServiceManager scm = ServiceManager.Open();
|
||||||
using Service sc = scm.OpenService(this.ServiceName, ServiceApis.ServiceAccess.QUERY_STATUS);
|
using Service sc = scm.OpenService(this.ServiceName, ServiceApis.ServiceAccess.QueryStatus);
|
||||||
|
|
||||||
sc.SetStatus(this.ServiceHandle, ServiceControllerStatus.Stopped);
|
sc.SetStatus(this.ServiceHandle, ServiceControllerStatus.Stopped);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue