Copiar 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 heartbeatThread;
private ManualResetEvent heartbeatStopped;
private ManualResetEvent heartbeatActive;
private ManualResetEvent terminationPending;
private uint waitHintMilliseconds;
private int heartbeatMilliseconds;
public ServiceControl (ServiceBase aServiceBase, uint aWaitHintMilliseconds, int aHeartbeatMilliseconds)
{
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;
heartbeatMilliseconds = aHeartbeatMilliseconds;
serviceStatus = new SERVICE_STATUS ();
Interop.QueryServiceStatus (serviceHandle, ref serviceStatus);
serviceStatus.WaitHint = waitHintMilliseconds;
Interop.SetServiceStatus (statusHandle, ref serviceStatus);
terminationPending = new ManualResetEvent (false);
heartbeatStopped = new ManualResetEvent (true);
heartbeatActive = new ManualResetEvent (false);
heartbeatThread = new Thread (IncrementHeartbeat);
heartbeatThread.SetApartmentState (ApartmentState.MTA);
heartbeatThread.Name = "Heartbeat_$" + Guid.NewGuid ().ToString ().Replace ('-', '_');
heartbeatThread.Start ();
}
private SERVICE_STATUS DoQueryServiceStatus ()
{
SERVICE_STATUS serviceStatus = new SERVICE_STATUS();
Interop.QueryServiceStatus (serviceHandle, ref serviceStatus);
return serviceStatus;
}
public void StopHeartbeat ()
{
heartbeatActive.Reset ();
heartbeatStopped.Set ();
}
public void StartHeartbeat ()
{
heartbeatStopped.Reset ();
heartbeatActive.Set ();
}
private void IncrementHeartbeat ()
{
bool terminating = false;
WaitHandle[] dispatchHandles = new WaitHandle[] { heartbeatStopped, heartbeatActive, terminationPending };
WaitHandle[] activeHeartbeatHandles = new WaitHandle[] { heartbeatStopped, terminationPending };
WaitHandle[] inactiveHeartbeatHandles = new WaitHandle[] { heartbeatActive, terminationPending };
while (!terminating)
{
switch (WaitHandle.WaitAny (dispatchHandles))
{
case 0:
WaitHandle.WaitAny (inactiveHeartbeatHandles);
break;
case 1:
if (WaitHandle.WaitAny (activeHeartbeatHandles, heartbeatMilliseconds, 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;
heartbeatStopped.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()
{
heartbeatActive.Reset ();
heartbeatStopped.Reset ();
terminationPending.Set ();
heartbeatStopped.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.StartHeartbeat ();
//TODO: Add pause code here ...
serviceControl.StopHeartbeat ();
}
private void InitializeComponent()
{
this.CanPauseAndContinue = true;
this.ServiceName = "TestService";
}
protected override void OnStop()
{
serviceControl = new ServiceControl (this, 60000, 10000);
serviceControl.StartHeartbeat ();
//TODO: Add stop code here ...
serviceControl.StopHeartbeat ();
}
}
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);
}
}