Search
Module:
Directory

   Desktop Functions:

   Smart Device Functions:


Show Recent Changes
Subscribe (RSS)
Misc. Pages
Comments
FAQ
Helpful Tools
Playground
Suggested Reading
Website TODO List
Download Visual Studio Add-In

ControlService (advapi32)
 
.
Summary
The ControlService function sends a control code to a service.

C# Signature:

[DllImport("advapi32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool    ControlService( IntPtr         hService,
                       SERVICE_CONTROL    dwControl,
                       ref SERVICE_STATUS    lpServiceStatus
                                                    );

VB Signature:

Declare Function ControlService Lib "advapi32.dll" (ByVal hService As Long, ByVal lControlCode As Long, ByVal lpServiceStatus As SERVICE_STATUS) As Boolean

C# User-Defined Types:

See SERVICE_STATUS definition

[Flags]
public enum SERVICE_CONTROL : uint
{
    STOP           = 0x00000001,
    PAUSE          = 0x00000002,
    CONTINUE           = 0x00000003,
    INTERROGATE        = 0x00000004,
    SHUTDOWN           = 0x00000005,
    PARAMCHANGE        = 0x00000006,
    NETBINDADD         = 0x00000007,
    NETBINDREMOVE      = 0x00000008,
    NETBINDENABLE      = 0x00000009,
    NETBINDDISABLE     = 0x0000000A,
    DEVICEEVENT        = 0x0000000B,
    HARDWAREPROFILECHANGE  = 0x0000000C,
    POWEREVENT         = 0x0000000D,
    SESSIONCHANGE      = 0x0000000E
}

public enum SERVICE_STATE : uint
{
    SERVICE_STOPPED            = 0x00000001,
    SERVICE_START_PENDING          = 0x00000002,
    SERVICE_STOP_PENDING           = 0x00000003,
    SERVICE_RUNNING            = 0x00000004,
    SERVICE_CONTINUE_PENDING           = 0x00000005,
    SERVICE_PAUSE_PENDING          = 0x00000006,
    SERVICE_PAUSED             = 0x00000007
}

[Flags]
public enum SERVICE_ACCEPT : uint
{
    STOP            = 0x00000001,
    PAUSE_CONTINUE      = 0x00000002,
    SHUTDOWN        = 0x00000004,
    PARAMCHANGE         = 0x00000008,
    NETBINDCHANGE       = 0x00000010,
    HARDWAREPROFILECHANGE   = 0x00000020,
    POWEREVENT          = 0x00000040,
    SESSIONCHANGE       = 0x00000080,
}

VB User-Defined Types:

See SERVICE_STATUS definition

Public Enum SERVICE_CONTROL As Integer

    [STOP] = &H1
    PAUSE = &H2
    CONTINUE = &H3
    INTERROGATE = &H4
    SHUTDOWN = &H5
    PARAMCHANGE = &H6
    NETBINDADD = &H7
    NETBINDREMOVE = &H8
    NETBINDENABLE = &H9
    NETBINDDISABLE = &HA
    DEVICEEVENT = &HB
    HARDWAREPROFILECHANGE = &HC
    POWEREVENT = &HD
    SESSIONCHANGE = &HE

End Enum

Public Enum SERVICE_STATE As Integer

    SERVICE_STOPPED = &H1
    SERVICE_START_PENDING = &H2
    SERVICE_STOP_PENDING = &H3
    SERVICE_RUNNING = &H4
    SERVICE_CONTINUE_PENDING = &H5
    SERVICE_PAUSE_PENDING = &H6
    SERVICE_PAUSED = &H7

End Enum

Public Enum SERVICE_ACCEPT As Integer

    [STOP] = &H1
    PAUSE_CONTINUE = &H2
    SHUTDOWN = &H4
    PARAMCHANGE = &H8
    NETBINDCHANGE = &H10
    HARDWAREPROFILECHANGE = &H20
    POWEREVENT = &H40
    SESSIONCHANGE = &H80

End Enum

Notes:

None.

Tips & Tricks:

Sample Code:

C#

IntPtr con = Tools.OpenSCManager("\\\\compname", null, (uint)SCM_ACCESS.SC_MANAGER_ALL_ACCESS);
IntPtr serv = Tools.OpenService(con, "ServiceTest", (uint)SERVICE_ACCESS.SERVICE_ALL_ACCESS);
SERVICE_STATUS stat = new SERVICE_STATUS();
bool res = Tools.ControlService(m_serv, SERVICE_CONTROL.STOP, ref stat);
Console.WriteLine("Stop service result: " + res);
// TODO: Code to halt execution until the service has finally stopped, to continue another task afterwards.

Alternative Managed API:

C#

using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.ServiceProcess;
using System.Threading;


namespace ServiceHelper
{
     /// <summary>
     /// Helper class for service control.
     /// </summary>
     public class ServiceControl : IDisposable
     {
     private int WAIT_TIMEOUT = 0x00000102;

     private IntPtr serviceControlManagerHandle;
     private IntPtr serviceHandle;
     private IntPtr statusHandle;

     private Thread heardbeatThread;

     private ManualResetEvent heardbeatStopped;
     private ManualResetEvent heardbeatActive;
     private ManualResetEvent terminationPending;

     private uint waitHintMilliseconds;
     private int heardbeatMilliseconds;

     public ServiceControl (ServiceBase aServiceBase, uint aWaitHintMilliseconds, int aHeardbeatMilliseconds)
     {
         FieldInfo fieldInfo;
         BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
         SERVICE_STATUS serviceStatus;

         serviceControlManagerHandle = Interop.OpenSCManager (
         null,
         null,
         (uint) SCM_ACCESS.SC_MANAGER_ALL_ACCESS);

         if (serviceControlManagerHandle == IntPtr.Zero)
         {
         throw new Exception (aServiceBase.ServiceName);
         }

         serviceHandle = Interop.OpenService (
         serviceControlManagerHandle,
         aServiceBase.ServiceName,
        (uint) SERVICE_ACCESS.SERVICE_ALL_ACCESS);

         if (serviceHandle == IntPtr.Zero)
         {
         throw new Exception ("aServiceName");
         }

         fieldInfo = typeof (System.ServiceProcess.ServiceBase).GetField ("statusHandle", bindingFlags);

         statusHandle = (IntPtr) (fieldInfo.GetValue (aServiceBase));

         if (statusHandle == IntPtr.Zero)
         throw new Exception ("statusHandle is not valid.");

         waitHintMilliseconds = aWaitHintMilliseconds;
         heardbeatMilliseconds = aHeardbeatMilliseconds;

         serviceStatus = new SERVICE_STATUS ();

         Interop.QueryServiceStatus (serviceHandle, ref serviceStatus);
         serviceStatus.WaitHint = waitHintMilliseconds;
         Interop.SetServiceStatus (statusHandle, ref serviceStatus);

         terminationPending = new ManualResetEvent (false);
         heardbeatStopped = new ManualResetEvent (true);
         heardbeatActive = new ManualResetEvent (false);

         heardbeatThread = new Thread (IncrementHeartbeat);
         heardbeatThread.SetApartmentState (ApartmentState.MTA);
         heardbeatThread.Name = "Heardbeat_$" + Guid.NewGuid ().ToString ().Replace ('-', '_');

         heardbeatThread.Start ();
     }

     private SERVICE_STATUS DoQueryServiceStatus ()
     {
         SERVICE_STATUS serviceStatus = new SERVICE_STATUS();

         Interop.QueryServiceStatus (serviceHandle, ref serviceStatus);

         return serviceStatus;
     }


     public void StopHeardbeat ()
     {
         heardbeatActive.Reset ();
         heardbeatStopped.Set ();
     }

     public void StartHeardbeat ()
     {
         heardbeatStopped.Reset ();
         heardbeatActive.Set ();
     }

     private void IncrementHeartbeat ()
     {
         bool terminating = false;

         WaitHandle[] dispatchHandles = new WaitHandle[] { heardbeatStopped, heardbeatActive, terminationPending };
         WaitHandle[] activeHeardbeatHandles = new WaitHandle[] { heardbeatStopped, terminationPending };
         WaitHandle[] inactiveHeardbeatHandles = new WaitHandle[] { heardbeatActive, terminationPending };
         while (!terminating)
         {
         switch (WaitHandle.WaitAny (dispatchHandles))
         {
             case 0:
             WaitHandle.WaitAny (inactiveHeardbeatHandles);
             break;

             case 1:
             if (WaitHandle.WaitAny (activeHeardbeatHandles, heardbeatMilliseconds, false) == WAIT_TIMEOUT)
             {
                 SERVICE_STATUS serviceStatus = new SERVICE_STATUS ();

                 Interop.QueryServiceStatus (serviceHandle, ref serviceStatus);

                 serviceStatus.CheckPoint++;

                 Interop.SetServiceStatus (statusHandle, ref serviceStatus);
             }
             break;

         case 2:
             terminating = true;
             heardbeatStopped.Set ();
             break;
         }
         }
     }

     private void DoControlService (SERVICE_CONTROL aServiceControl)
     {
         SERVICE_STATUS serviceStatus = new SERVICE_STATUS();

         if (!Interop.ControlService(serviceHandle, aServiceControl, ref serviceStatus))
         {
         throw new Exception (serviceStatus.ToString ());
         }  
     }

     public void Dispose()
     {
         heardbeatActive.Reset ();
         heardbeatStopped.Reset ();
         terminationPending.Set ();

         heardbeatStopped.WaitOne ();

         Interop.CloseServiceHandle (serviceHandle);
         Interop.CloseServiceHandle (serviceControlManagerHandle);
     }
     }

     public class TestService : ServiceBase
     {
     ServiceControl serviceControl;

     public static void Main ()
     {
         ServiceBase.Run (new TestService());
     }

     public TestService()
     {  
         InitializeComponent ();
     }

     protected override void OnPause ()
     {
         serviceControl = new ServiceControl (this, 60000, 10000);
         serviceControl.StartHeardbeat ();
         //TODO: Add pause code here ...
         serviceControl.StopHeardbeat ();
     }

     private void InitializeComponent()
     {
         this.CanPauseAndContinue = true;
         this.ServiceName = "TestService";
     }

     protected override void OnStop()
     {
         serviceControl = new ServiceControl (this, 60000, 10000);
         serviceControl.StartHeardbeat ();
         //TODO: Add stop code here ...
         serviceControl.StopHeardbeat ();        
     }
     }

     internal class Interop
     {
     [DllImport ("advapi32.dll", SetLastError = true)]
     [return: MarshalAs (UnmanagedType.Bool)]
     internal static extern bool ControlService (
         IntPtr hService,
         SERVICE_CONTROL dwControl,
         ref SERVICE_STATUS lpServiceStatus);

     [DllImport ("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
     internal static extern IntPtr OpenSCManager (
         string machineName,
         string databaseName,
         uint dwAccess);

     [DllImport ("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
     internal static extern IntPtr OpenService (IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);

     [DllImport ("advapi32.dll", SetLastError = true)]
     [return: MarshalAs (UnmanagedType.Bool)]
     internal static extern bool CloseServiceHandle (IntPtr hSCObject);

     [DllImport ("advapi32.dll", EntryPoint = "QueryServiceStatus", CharSet = CharSet.Auto)]
     internal static extern bool QueryServiceStatus (IntPtr hService, ref SERVICE_STATUS dwServiceStatus);

     [DllImport ("advapi32.dll")]
     internal static extern bool SetServiceStatus (IntPtr hServiceStatus, ref SERVICE_STATUS lpServiceStatus);
     }
}

Documentation

Please edit this page!

Do you have...

  • helpful tips or sample code to share for using this API in managed code?
  • corrections to the existing content?
  • variations of the signature you want to share?
  • additional languages you want to include?

Select "Edit This Page" on the right hand toolbar and edit it! Or add new pages containing supporting types needed for this API (structures, delegates, and more).

 
Access PInvoke.net directly from VS:
Terms of Use
Find References
Show Printable Version
Revisions