2014-04-24 15 views
5

Sto tentando di impostare un servizio già installato per l'avvio ritardato automatico in C#. Come faccio a impostare un servizio di Windows perImpostare il servizio esistente su "Auto (avvio ritardato)"

Automatic (Delayed Start) 

Non riesci a trovare quel valore nel enum ServiceStartMode.

Edit: 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; 
    } 
} 

Questo è come lo chiamo io:

var controller = new ServiceController(s.ServiceName); 
var autoDelay = new ServiceAutoStartInfo(); 
autoDelay.ChangeDelayedAutoStart(controller.ServiceHandle.DangerousGetHandle(), true); 

Ma senza alcun risultato.

+0

Perché non cambiarne l'avvio nei servizi MMC? –

+0

@OverKiller sto costruendo un gestore di distribuzione automatico per il mio progetto, quindi sto cercando di cambiarlo in codice. – Tan

+2

@oleksii Non credo che sia un problema qui perché questa domanda è per un servizio * già installato * e quello a cui si collega sta parlando * durante il processo di installazione * –

risposta

8

Guardate nel chiamare la funzione di Windows ChangeServiceConfig2, con dwInfoLevel di SERVICE_CONFIG_DELAYED_AUTO_START_INFO e un SERVICE_DELAYED_AUTO_START_INFO struct con fDelayedAutostart set per TRUE.

In alternativa, è possibile farlo con la riga di comando:

sc.exe config <servicename> start= delayed-auto 
+0

Ho provato l'approccio ChangeServiceConfig2 ma senza risultato posso modificare il mio post con il codice. – Tan

+0

@Tan Restituisce un valore diverso da zero (che indica il successo) o, in caso negativo, qual è il codice di errore?Il tuo processo è elevato o hai altrimenti il ​​permesso di modificare la configurazione del servizio? –

+0

Sono autorizzato ad usare un account amministratore. Non restituisce alcun errore. Ma il tipo di avvio jsut non verrà aggiornato dal manuale al ritardo automatico. – Tan

0

Aggiornamento: Questo funziona solo per la creazione di nuovi servizi e non è quello che il PO ha chiesto:

È possibile utilizzare la proprietà DelayedAutoStart del ServiceInstaller.

installer.DelayedAutoStart = true; 

+1

Non ho un serviceinstaller perché il servizio è già installato. – Tan

+0

Ops, scusa ... - fammi controllare per un'altra soluzione. – ChrFin

+0

Non ho trovato nulla di diverso dalla soluzione lc. già pubblicato ... – ChrFin

0

Credo che è necessario combinare entrambi i metodi ChangeServiceConfig e ChangeServiceConfig2.

pseudo-codice segue:

public static void ChangeServiceStartupType(ServiceStartupType type, ...) 
{ 
    if (type == AutomaticDelayed) 
    { 
     if (ChangeServiceConfig2(.., DelayedAutoStart, ..)) 
     { 
      ChangeServiceConfig(.., Automatic, ..); 
     } 
    } 
    else 
    { 
     ChangeServiceConfig2(.., !DelayedAutoStart, ..) 
     ChangeServiceConfig(.., type, ..) 
    } 
} 

edit: è anche necessario rimuovere "ritardata automatico" al momento della richiesta non ritardato avvio-tipo. Altrimenti non sarà possibile impostare il tipo "automatico". ("Automatico-ritardata" ha la precedenza "automatico")

1

Sto utilizzando il seguente, che lavora per me su Windows 7 (quando viene eseguito come amministratore):

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 
    } 
} 

Si chiama così:

var serviceController = new ServiceController("Windows Update"); 
try 
{ 
    serviceController.SetStartMode(ServiceStartModeEx.DelayedAutomatic); 
} 
finally 
{ 
    serviceController.Close(); 
} 
Problemi correlati