C# 将现有服务设置为";自动(延迟启动)“;
我正在尝试在C#中将已安装的windows服务设置为自动延迟启动。如何将windows服务设置为C# 将现有服务设置为";自动(延迟启动)“;,c#,service,C#,Service,我正在尝试在C#中将已安装的windows服务设置为自动延迟启动。如何将windows服务设置为 Automatic (Delayed Start) 在ServiceStartMode枚举中找不到该值 编辑:1 public class ServiceAutoStartInfo { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct SERVICE_DELAYED_AUTO_
Automatic (Delayed Start)
在ServiceStartMode枚举中找不到该值
编辑:1
public class ServiceAutoStartInfo
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct SERVICE_DELAYED_AUTO_START_INFO
{
public bool fDelayedAutostart;
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ChangeServiceConfig2(IntPtr hService, int dwInfoLevel, IntPtr lpInfo);
// Service configuration parameter
const int SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3;
public bool ChangeDelayedAutoStart(IntPtr hService, bool delayed)
{
// Validate service handle
if (hService != IntPtr.Zero)
{
// Create
SERVICE_DELAYED_AUTO_START_INFO info = new SERVICE_DELAYED_AUTO_START_INFO();
// Set the DelayedAutostart property
info.fDelayedAutostart = delayed;
// Allocate necessary memory
IntPtr hInfo = Marshal.AllocHGlobal(Marshal.SizeOf(
typeof(SERVICE_DELAYED_AUTO_START_INFO)));
// Convert structure to pointer
Marshal.StructureToPtr(info, hInfo, true);
// Change the configuration
bool result = ChangeServiceConfig2(hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, hInfo);
// Release memory
Marshal.FreeHGlobal(hInfo);
return result;
}
return false;
}
}
我这样称呼它:
var controller = new ServiceController(s.ServiceName);
var autoDelay = new ServiceAutoStartInfo();
autoDelay.ChangeDelayedAutoStart(controller.ServiceHandle.DangerousGetHandle(), true);
但是没有结果。更新:这只适用于设置新服务,而不是OP要求的: 您可以使用
ServiceInstaller
的属性
installer.DelayedAutoStart = true;
研究调用Windows函数,将
SERVICE\u CONFIG\u DELAYED\u AUTO\u START\u INFO
的dwInfoLevel
和SERVICE\u DELAYED\u AUTO\u START\u INFO
结构设置为TRUE
或者,可以使用命令行执行此操作:
sc.exe config <servicename> start= delayed-auto
sc.exe配置启动=延迟自动
我认为您需要将ChangeServiceConfig和ChangeServiceConfig2这两种方法结合起来
伪代码如下:
public static void ChangeServiceStartupType(ServiceStartupType type, ...)
{
if (type == AutomaticDelayed)
{
if (ChangeServiceConfig2(.., DelayedAutoStart, ..))
{
ChangeServiceConfig(.., Automatic, ..);
}
}
else
{
ChangeServiceConfig2(.., !DelayedAutoStart, ..)
ChangeServiceConfig(.., type, ..)
}
}
编辑:在请求非延迟启动类型时,还需要删除“延迟自动”。否则将无法设置“自动”类型。(“自动延迟”覆盖“自动”)我正在使用以下功能,这在Windows 7上适用(以管理员身份运行时):
服务\u延迟\u自动\u启动\u信息结构文档状态: fDelayedAutostart 如果此成员为TRUE,则在其他自动启动后启动服务 服务启动加上短暂的延迟。否则,服务将被取消 在系统引导期间启动 除非服务是自动启动服务,否则将忽略此设置
因此我认为如果服务不是自动启动,它不会将其更改为自动延迟,你必须使用sc.exe为什么不在MMC服务中更改它的启动?@OverKiller我正在为我的项目构建一个自动部署管理器,所以我试图在代码中更改它。@oleksii我不相信这是一个重复,因为这个问题是针对一个已经安装的服务,而你链接到的那个是在安装过程中谈论的process@lc收回我的voteI没有服务安装程序,因为服务已经安装。操作,抱歉…-让我检查另一个解决方案。我尝试了ChangeServiceConfig2方法,但没有结果,我可以用代码编辑我的帖子。@Tan它是否返回非零值(表示成功),或者如果不是,错误代码是什么?您的进程是否已提升,或者您是否有权修改服务的配置?我有权使用管理员帐户进行即时通讯。它不会返回任何错误。但是启动类型jsut不会从手动更新为自动延迟。@Tan我不确定这是否仍然相关,但建议您可能需要在它出现更新之前重新启动。我是否读取了文档错误,或者不是映射到
uint
的DWORD?因为在这种情况下,他应该通过3
IMO。。。
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.ServiceProcess;
namespace ServiceManager
{
/// <summary>
/// Extensions to the ServiceController class.
/// </summary>
public static class ServiceControlerExtensions
{
/// <summary>
/// Set the start mode for the service.
/// </summary>
/// <param name="serviceController">The service controller.</param>
/// <param name="mode">The desired start mode.</param>
public static void SetStartMode(this ServiceController serviceController, ServiceStartModeEx mode)
{
IntPtr serviceManagerHandle = OpenServiceManagerHandle();
IntPtr serviceHandle = OpenServiceHandle(serviceController, serviceManagerHandle);
try
{
if (mode == ServiceStartModeEx.DelayedAutomatic)
{
ChangeServiceStartType(serviceHandle, ServiceStartModeEx.Automatic);
ChangeDelayedAutoStart(serviceHandle, true);
}
else
{
// Delayed auto-start overrides other settings, so it must be set first.
ChangeDelayedAutoStart(serviceHandle, false);
ChangeServiceStartType(serviceHandle, mode);
}
}
finally
{
if (serviceHandle != IntPtr.Zero)
{
CloseServiceHandle(serviceHandle);
}
if (serviceHandle != IntPtr.Zero)
{
CloseServiceHandle(serviceManagerHandle);
}
}
}
private static IntPtr OpenServiceHandle(ServiceController serviceController, IntPtr serviceManagerHandle)
{
var serviceHandle = OpenService(
serviceManagerHandle,
serviceController.ServiceName,
SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);
if (serviceHandle == IntPtr.Zero)
{
throw new ExternalException("Open Service Error");
}
return serviceHandle;
}
private static IntPtr OpenServiceManagerHandle()
{
IntPtr serviceManagerHandle = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
if (serviceManagerHandle == IntPtr.Zero)
{
throw new ExternalException("Open Service Manager Error");
}
return serviceManagerHandle;
}
private static void ChangeServiceStartType(IntPtr serviceHandle, ServiceStartModeEx mode)
{
bool result = ChangeServiceConfig(
serviceHandle,
SERVICE_NO_CHANGE,
(uint)mode,
SERVICE_NO_CHANGE,
null,
null,
IntPtr.Zero,
null,
null,
null,
null);
if (result == false)
{
ThrowLastWin32Error("Could not change service start type");
}
}
private static void ChangeDelayedAutoStart(IntPtr hService, bool delayed)
{
// Create structure that contains DelayedAutoStart property.
SERVICE_DELAYED_AUTO_START_INFO info = new SERVICE_DELAYED_AUTO_START_INFO();
// Set the DelayedAutostart property in that structure.
info.fDelayedAutostart = delayed;
// Allocate necessary memory.
IntPtr hInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SERVICE_DELAYED_AUTO_START_INFO)));
// Convert structure to pointer.
Marshal.StructureToPtr(info, hInfo, true);
// Change the configuration.
bool result = ChangeServiceConfig2(hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, hInfo);
// Release memory.
Marshal.FreeHGlobal(hInfo);
if (result == false)
{
ThrowLastWin32Error("Could not set service to delayed automatic");
}
}
private static void ThrowLastWin32Error(string messagePrefix)
{
int nError = Marshal.GetLastWin32Error();
var win32Exception = new Win32Exception(nError);
string message = string.Format("{0}: {1}", messagePrefix, win32Exception.Message);
throw new ExternalException(message);
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr OpenService(
IntPtr hSCManager,
string lpServiceName,
uint dwDesiredAccess);
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode,
SetLastError = true)]
private static extern IntPtr OpenSCManager(
string machineName,
string databaseName,
uint dwAccess);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern Boolean ChangeServiceConfig(
IntPtr hService,
UInt32 nServiceType,
UInt32 nStartType,
UInt32 nErrorControl,
String lpBinaryPathName,
String lpLoadOrderGroup,
IntPtr lpdwTagId,
[In] char[] lpDependencies,
String lpServiceStartName,
String lpPassword,
String lpDisplayName);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ChangeServiceConfig2(
IntPtr hService,
int dwInfoLevel,
IntPtr lpInfo);
[DllImport("advapi32.dll", EntryPoint = "CloseServiceHandle")]
private static extern int CloseServiceHandle(IntPtr hSCObject);
private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF;
private const uint SERVICE_QUERY_CONFIG = 0x00000001;
private const uint SERVICE_CHANGE_CONFIG = 0x00000002;
private const uint SC_MANAGER_ALL_ACCESS = 0x000F003F;
private const int SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct SERVICE_DELAYED_AUTO_START_INFO
{
public bool fDelayedAutostart;
}
}
}
namespace ServiceManager
{
public enum ServiceStartModeEx
{
Automatic = 2,
Manual = 3,
Disabled = 4,
DelayedAutomatic = 99
}
}
var serviceController = new ServiceController("Windows Update");
try
{
serviceController.SetStartMode(ServiceStartModeEx.DelayedAutomatic);
}
finally
{
serviceController.Close();
}