how to delay shutdown and run a process in window service
Asked Answered
J

5

8

I have to run a process ie a application on windows shutdown, is there any method to delay the windows shutdown and run the application in windows service...

protected override void OnShutdown()
{
    // Add your save code here
    // Add your save code here
    StreamWriter str = new StreamWriter("D:\\Log.txt", true);
    str.WriteLine("Service stoped due to on" + DateTime.Now.ToString());
    str.Close();

    base.OnShutdown();
}

I have used function above which overrides the shutdown and i was able to write a log entry to a text file but i was not able to run an application after that On searching i found that the delay was below only some seconds after user fires shutdown

this.RequestAdditionalTime(250000);

this gives an addition time delay of 25 seconds on shutdown event but i was not able to run the application. Can anyone suggest method or ideas to run application on shutdown.

Ji answered 7/3, 2011 at 8:2 Comment(8)
It is typically not a good idea to delay shutdown when the user has confirmed his request to shutdown. Furthermore, Windows refuses various actions during shutdown. One of those actions is starting a windows service. To get your process to actually start, you may need a lot of engineering and hacking.Issie
You need to redesign your system - trying to start new processes when windows wants to shutdown seems a fairly poor design - what state is your system in if windows crashes and restarts?Mancy
then can i abort shutdown in window service and open a application on the application exit shutdown the system..Ji
@deepu: No, you can't. There's no reliable way to abort a shutdown, and a Windows Service can't spawn user-mode applications. My answer provides more details, but the summary is that you need to find a different approach. Maybe if you explained what you're trying to accomplish, instead of your proposed solution, we could give you some better advice.Biracial
@CodyGray: thanks for your answer below...i will briefly describe what i am trying to accomplish..I am proposed to make a application that logs the time user log on and shutdown the system in windows xp. i was able to run the application on start up where i get the details of system up time to Db,But i have to execute the application on shutdown, to log when the system was shutdown and whats is the reason for shutting down. I have done a .net window application in c# and called the application using window service. Please suggest some ideas to make it workoutJi
I think @Ji wants something similar to the "Reason for shutdown" window Windows Server 2003 has. See my answer below.Serow
on searching i found that we can run script on shutdown/start up in windows.Is it a nice method to run my application(exe) file on this.. if i run so will i be able to update the DB with the values in the application.Ji
@deepu: Maybe on the next start up.Serow
B
11

The ability of applications to block a pending system shutdown was severely restricted in Windows Vista. The details are summarized in two handy articles on MSDN: Shutdown Changes for Windows Vista and Application Shutdown Changes in Windows Vista.

As that page indicates, you shouldn't rely on the ability to block shutdown for any longer than 5 seconds. If you wish to attempt to block a pending shutdown event, your application should use the new ShutdownBlockReasonCreate function, which allows you to register a string that explains to the user the reason why you think the shutdown should be blocked. The user reserves the ability to heed your advice and cancel the shutdown, or throw caution to the wind and cancel anyway.

As soon as your application finishes doing whatever it is that should not be interrupted by a shutdown, you should call the corresponding ShutdownBlockReasonDestroy function, which frees the reason string and indicates that the system can now be shut down.

Also remember that Windows Services now run in an isolated session and are prohibited from interacting with the user. My answer here also provides more details, as well as a pretty diagram.

Basically, this is impossible. Windows is going to fight you tooth and nail over starting up a separate process from your Service, as well as any attempt you make to block a pending shutdown. Ultimately, the user has the power to override anything you try to pull. This sounds like something you should solve using security policies, rather than an application—ask questions about that on Server Fault.

Biracial answered 7/3, 2011 at 8:20 Comment(2)
+1 When the user says they want to shutdown, you now need to respect that wish.Perfidious
@David: What's the point of being a programmer if we allow the user to have control over their machine? Boring.Biracial
S
5

On Windows Vista SP1 and higher, the new SERVICE_CONTROL_PRESHUTDOWN is available. Unfortunately it is not supported by .NET framework yet, but here is workaround using reflection. Just inherit your service class from ServicePreshutdownBase, override OnStop and periodically call RequestAdditionalTime(). Note that CanShutdown should be set to false.

public class ServicePreshutdownBase : ServiceBase
{
    public bool Preshutdown { get; private set; }

    public ServicePreshutdownBase()
    {
        Version versionWinVistaSp1 = new Version(6, 0, 6001);
        if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version >= versionWinVistaSp1)
        {
            var acceptedCommandsField = typeof (ServiceBase).GetField("acceptedCommands", BindingFlags.Instance | BindingFlags.NonPublic);
            if (acceptedCommandsField == null)
                throw new InvalidOperationException("Private field acceptedCommands not found on ServiceBase");

            int acceptedCommands = (int) acceptedCommandsField.GetValue(this);
            acceptedCommands |= 0x00000100; //SERVICE_ACCEPT_PRESHUTDOWN;
            acceptedCommandsField.SetValue(this, acceptedCommands);
        }
    }

    protected override void OnCustomCommand(int command)
    {
        // command is SERVICE_CONTROL_PRESHUTDOWN
        if (command == 0x0000000F)
        {
            var baseCallback = typeof(ServiceBase).GetMethod("ServiceCommandCallback", BindingFlags.Instance | BindingFlags.NonPublic);
            if (baseCallback == null)
                throw new InvalidOperationException("Private method ServiceCommandCallback not found on ServiceBase");
            try
            {
                Preshutdown = true;
                //now pretend stop was called 0x00000001
                baseCallback.Invoke(this, new object[] {0x00000001});
            }
            finally
            {
                Preshutdown = false;
            }
        }
    }
}

Here is example usage:

public partial class Service1 : ServicePreshutdownBase
{
    public Service1()
    {
        InitializeComponent();
        this.CanShutdown = false;
    }
    protected override void OnStop()
    {
        WriteLog(Preshutdown ? "Service OnPreshutdown" : "Service OnStop");
        for (int i = 0; i < 180; i++)
        {
            Thread.Sleep(1000);
            WriteLog("Service stop in progress...");
            RequestAdditionalTime(2000);
        }
        WriteLog(Preshutdown ? "Service preshutdown completed" : "Service stop completed");
    }
}

This will work for 3min 20s, if you need more time, then you need to configure service. The best place to do so is during installation. Just use the ServicePreshutdownInstaller instead of ServiceInstaller and set the PreshutdownTimeout to maximum time you will ever need.

public class ServicePreshutdownInstaller : ServiceInstaller
{
    private int _preshutdownTimeout = 200000;

    /// <summary>
    /// Gets or sets the preshutdown timeout for the service.
    /// </summary>
    /// 
    /// <returns>
    /// The preshutdown timeout of the service. The default is 200000ms (200s).
    /// </returns>
    [DefaultValue(200000)]
    [ServiceProcessDescription("ServiceInstallerPreshutdownTimeout")]
    public int PreshutdownTimeout
    {
        get
        {
            return _preshutdownTimeout;
        }
        set
        {
            _preshutdownTimeout = value;
        }
    }

    public override void Install(System.Collections.IDictionary stateSaver)
    {
        base.Install(stateSaver);

        Version versionWinVistaSp1 = new Version(6, 0, 6001);
        if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version < versionWinVistaSp1)
        {
            //Preshutdown is not supported
            return;
        }

        Context.LogMessage(string.Format("Setting preshutdown timeout {0}ms to service {1}", PreshutdownTimeout, ServiceName));
        IntPtr service = IntPtr.Zero;
        IntPtr sCManager = IntPtr.Zero;
        try
        {
            // Open the service control manager
            sCManager = OpenSCManager(null, null, ServiceControlAccessRights.SC_MANAGER_CONNECT);
            if (sCManager == IntPtr.Zero)
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Unable to open Service Control Manager.");
            // Open the service
            service = OpenService(sCManager, ServiceName, ServiceAccessRights.SERVICE_CHANGE_CONFIG);
            if (service == IntPtr.Zero) throw new Win32Exception();
            // Set up the preshutdown timeout structure
            SERVICE_PRESHUTDOWN_INFO preshutdownInfo = new SERVICE_PRESHUTDOWN_INFO();
            preshutdownInfo.dwPreshutdownTimeout = (uint)_preshutdownTimeout;
            // Make the change
            int changeResult = ChangeServiceConfig2(
                service,
                ServiceConfig2InfoLevel.SERVICE_CONFIG_PRESHUTDOWN_INFO,
                ref preshutdownInfo);
            // Check that the change occurred
            if (changeResult == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Unable to change the Service configuration.");
            }

            Context.LogMessage(string.Format("Preshutdown timeout {0}ms set to service {1}", PreshutdownTimeout, ServiceName));
        }
        finally
        {
            // Clean up
            if (service != IntPtr.Zero)CloseServiceHandle(service);
            if (sCManager != IntPtr.Zero)Marshal.FreeHGlobal(sCManager);
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SERVICE_PRESHUTDOWN_INFO
    {
        public UInt32 dwPreshutdownTimeout;
    }

    [Flags]
    public enum ServiceControlAccessRights : int
    {
        SC_MANAGER_CONNECT = 0x0001, // Required to connect to the service control manager. 
        SC_MANAGER_CREATE_SERVICE = 0x0002, // Required to call the CreateService function to create a service object and add it to the database. 
        SC_MANAGER_ENUMERATE_SERVICE = 0x0004, // Required to call the EnumServicesStatusEx function to list the services that are in the database. 
        SC_MANAGER_LOCK = 0x0008, // Required to call the LockServiceDatabase function to acquire a lock on the database. 
        SC_MANAGER_QUERY_LOCK_STATUS = 0x0010, // Required to call the QueryServiceLockStatus function to retrieve the lock status information for the database
        SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020, // Required to call the NotifyBootConfigStatus function. 
        SC_MANAGER_ALL_ACCESS = 0xF003F // Includes STANDARD_RIGHTS_REQUIRED, in addition to all access rights in this table. 
    }

    [Flags]
    public enum ServiceAccessRights : int
    {
        SERVICE_QUERY_CONFIG = 0x0001, // Required to call the QueryServiceConfig and QueryServiceConfig2 functions to query the service configuration. 
        SERVICE_CHANGE_CONFIG = 0x0002, // Required to call the ChangeServiceConfig or ChangeServiceConfig2 function to change the service configuration. Because this grants the caller the right to change the executable file that the system runs, it should be granted only to administrators. 
        SERVICE_QUERY_STATUS = 0x0004, // Required to call the QueryServiceStatusEx function to ask the service control manager about the status of the service. 
        SERVICE_ENUMERATE_DEPENDENTS = 0x0008, // Required to call the EnumDependentServices function to enumerate all the services dependent on the service. 
        SERVICE_START = 0x0010, // Required to call the StartService function to start the service. 
        SERVICE_STOP = 0x0020, // Required to call the ControlService function to stop the service. 
        SERVICE_PAUSE_CONTINUE = 0x0040, // Required to call the ControlService function to pause or continue the service. 
        SERVICE_INTERROGATE = 0x0080, // Required to call the ControlService function to ask the service to report its status immediately. 
        SERVICE_USER_DEFINED_CONTROL = 0x0100, // Required to call the ControlService function to specify a user-defined control code.
        SERVICE_ALL_ACCESS = 0xF01FF // Includes STANDARD_RIGHTS_REQUIRED in addition to all access rights in this table. 
    }

    public enum ServiceConfig2InfoLevel : int
    {
        SERVICE_CONFIG_DESCRIPTION = 0x00000001, // The lpBuffer parameter is a pointer to a SERVICE_DESCRIPTION structure.
        SERVICE_CONFIG_FAILURE_ACTIONS = 0x00000002, // The lpBuffer parameter is a pointer to a SERVICE_FAILURE_ACTIONS structure.
        SERVICE_CONFIG_PRESHUTDOWN_INFO = 0x00000007 // The lpBuffer parameter is a pointer to a SERVICE_PRESHUTDOWN_INFO structure.
    }

    [DllImport("advapi32.dll", EntryPoint = "OpenSCManager")]
    public static extern IntPtr OpenSCManager(
        string machineName,
        string databaseName,
        ServiceControlAccessRights desiredAccess);

    [DllImport("advapi32.dll", EntryPoint = "CloseServiceHandle")]
    public static extern int CloseServiceHandle(IntPtr hSCObject);

    [DllImport("advapi32.dll", EntryPoint = "OpenService")]
    public static extern IntPtr OpenService(
        IntPtr hSCManager,
        string serviceName,
        ServiceAccessRights desiredAccess);

    [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")]
    public static extern int ChangeServiceConfig2(
        IntPtr hService,
        ServiceConfig2InfoLevel dwInfoLevel,
        ref SERVICE_PRESHUTDOWN_INFO lpInfo);
}
Swelling answered 9/9, 2014 at 20:28 Comment(0)
H
1

I have a similar problem, and there is one trick that might work in your case. You can start application in question before shutdown is initiated with CREATE_SUSPENDED flag (see this). This will ensure that the process will be created, but never run. On shutdown you can ResumeThread that process, and it will go on with execution.

Note, that it might be possible that the process will not be able to initialize and run anyway, since during shutdown some OS functions will fail.

Another implication is: the process which is supposed to run on shutdown will show in task manager. It would be possible to kill that process.

Halation answered 5/12, 2011 at 19:58 Comment(5)
In this Scenario, how do you Resume that thread in C#? Because the process created I don't see access to that thread.Immersionism
@StevenHernandez I don't think it's possible to do purely in c#. You will need to either use a c++ snippet, or use p-invoke if you want to do it from .NET. Look here for an example: pinvoke.net/default.aspx/kernel32/ResumeThread.htmlHalation
Yeah through p/invoke I mean because I do know its impossible to do it through .Net entirely.Immersionism
But thanks forgot to mention that I got it working with p/invoke. However it didn't solve my problem. I need to be able to stop shutdown/restart/sessionend do my stop the actions of my process and resume the shutdown/restart/sessionend.Immersionism
my problem... Maybe you can help me.Immersionism
S
0

Here is an article on the Shutdown Event Tracker. You can activate it in Windows XP. It prompts the user for a reason for shutdown.

Serow answered 7/3, 2011 at 11:18 Comment(9)
@Serow :i don't want to know what error caused the system to shutdown.actually what i meant was when the user shutdowns the system normally then my application will run where the user give the reason for shutting down the system like "I have to attend a meeting","Lunch Break","going home- work at office is over"..etc hope you get the idea.Ji
I think that's what Shutdown Event Tracker is for, not errors but basically logging any shutdown.Serow
That being said, I don't ever want to work at a place that has such a system in place.Serow
@MPelletier:ya,it reports all the shutdown events..But my intention is to load a application on shutdown.. :)Ji
@MPelletier:yes,i totally agree to your comment...But have to see these things are possible or not to run an application before shutdown.Ji
@deepu: Please take a look at this discussion. It's VB, but maybe you can adapt it.Serow
@MPelletier: i checked the discussion you have mention it uses the hook methods to override shutdown but it possible on forms.I am using window service.i don't have any idea about how to use it in service...Ji
@deepu: If you want to look more into Shotdown Event Tracker, apparently it can be customized. The simplest thing I can see is using this, then on restart have a program run that sends the latest logs to your DB.Serow
@MPelletier: my intention is to update database with time and reason by the user so i cannot relay on event tracker,ie i cannot update db with system reasons.Ji
W
0
namespace WindowsService1
{
    [StructLayout(LayoutKind.Sequential)]
    public struct SERVICE_STATUS
    {
        public int serviceType;
        public int currentState;
        public int controlsAccepted;
        public int win32ExitCode;
        public int serviceSpecificExitCode;
        public int checkPoint;
        public int waitHint;
    }

    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
    }

    public enum ControlsAccepted
    {
        ACCEPT_STOP = 1,
        ACCEPT_PAUSE_CONTINUE = 2,
        ACCEPT_SHUTDOWN = 4,
        ACCEPT_PRESHUTDOWN = 0xf,
        ACCEPT_POWER_EVENT = 64,
        ACCEPT_SESSION_CHANGE = 128
    }

    [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 INFO_LEVEL : uint
    {
        SERVICE_CONFIG_DESCRIPTION = 0x00000001,
        SERVICE_CONFIG_FAILURE_ACTIONS = 0x00000002,
        SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 0x00000003,
        SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 0x00000004,
        SERVICE_CONFIG_SERVICE_SID_INFO = 0x00000005,
        SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 0x00000006,
        SERVICE_CONFIG_PRESHUTDOWN_INFO = 0x00000007,
        SERVICE_CONFIG_TRIGGER_INFO = 0x00000008,
        SERVICE_CONFIG_PREFERRED_NODE = 0x00000009
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SERVICE_PRESHUTDOWN_INFO
    {
        public UInt32 dwPreshutdownTimeout;
    }

    [Flags]
    public enum SERVICE_ACCESS : uint
    {
        STANDARD_RIGHTS_REQUIRED = 0xF0000,
        SERVICE_QUERY_CONFIG = 0x00001,
        SERVICE_CHANGE_CONFIG = 0x00002,
        SERVICE_QUERY_STATUS = 0x00004,
        SERVICE_ENUMERATE_DEPENDENTS = 0x00008,
        SERVICE_START = 0x00010,
        SERVICE_STOP = 0x00020,
        SERVICE_PAUSE_CONTINUE = 0x00040,
        SERVICE_INTERROGATE = 0x00080,
        SERVICE_USER_DEFINED_CONTROL = 0x00100,
        SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
          SERVICE_QUERY_CONFIG |
          SERVICE_CHANGE_CONFIG |
          SERVICE_QUERY_STATUS |
          SERVICE_ENUMERATE_DEPENDENTS |
          SERVICE_START |
          SERVICE_STOP |
          SERVICE_PAUSE_CONTINUE |
          SERVICE_INTERROGATE |
          SERVICE_USER_DEFINED_CONTROL)
    }

    [Flags]
    public enum SCM_ACCESS : uint
    {
        STANDARD_RIGHTS_REQUIRED = 0xF0000,
        SC_MANAGER_CONNECT = 0x00001,
        SC_MANAGER_CREATE_SERVICE = 0x00002,
        SC_MANAGER_ENUMERATE_SERVICE = 0x00004,
        SC_MANAGER_LOCK = 0x00008,
        SC_MANAGER_QUERY_LOCK_STATUS = 0x00010,
        SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020,
        SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
          SC_MANAGER_CONNECT |
          SC_MANAGER_CREATE_SERVICE |
          SC_MANAGER_ENUMERATE_SERVICE |
          SC_MANAGER_LOCK |
          SC_MANAGER_QUERY_LOCK_STATUS |
          SC_MANAGER_MODIFY_BOOT_CONFIG
    }

    public partial class Service1 : ServiceBase
    {        
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);

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

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool ChangeServiceConfig2(IntPtr hService, int dwInfoLevel, IntPtr lpInfo);

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

        const int SERVICE_ACCEPT_PRESHUTDOWN = 0x100;
        const int SERVICE_CONTROL_PRESHUTDOWN = 0xf;

        public Service1()
        {
            InitializeComponent();
            CanShutdown = true;
            tim = new Timer();
            tim.Interval = 5000;
            tim.Elapsed += tim_Elapsed;
            FieldInfo acceptedCommandsFieldInfo = typeof(ServiceBase).GetField("acceptedCommands", BindingFlags.Instance | BindingFlags.NonPublic);
            int value = (int)acceptedCommandsFieldInfo.GetValue(this);
            acceptedCommandsFieldInfo.SetValue(this, value | SERVICE_ACCEPT_PRESHUTDOWN);
            StreamWriter writer = new StreamWriter("D:\\LogConst.txt", true);
            try
            {
                IntPtr hMngr = OpenSCManager("localhost", null, (uint)SCM_ACCESS.SC_MANAGER_ALL_ACCESS);
                IntPtr hSvc = OpenService(hMngr, "WindowsService1", (uint)SCM_ACCESS.SC_MANAGER_ALL_ACCESS);
                SERVICE_PRESHUTDOWN_INFO spi = new SERVICE_PRESHUTDOWN_INFO();
                spi.dwPreshutdownTimeout = 5000;

                IntPtr lpInfo = Marshal.AllocHGlobal(Marshal.SizeOf(spi));
                if (lpInfo == IntPtr.Zero)
                {
                    writer.WriteLine(String.Format("Unable to allocate memory for service action, error was: 0x{0:X} -- {1}", Marshal.GetLastWin32Error(), DateTime.Now.ToLongTimeString()));
                }
                Marshal.StructureToPtr(spi, lpInfo, false);
                // apply the new timeout value
                if (!ChangeServiceConfig2(hSvc, (int)INFO_LEVEL.SERVICE_CONFIG_PRESHUTDOWN_INFO, lpInfo))
                    writer.WriteLine(DateTime.Now.ToLongTimeString() + " Failed to change service timeout");
                else
                    writer.WriteLine(DateTime.Now.ToLongTimeString() + " change service timeout : " + spi.dwPreshutdownTimeout);
            }
            catch (Exception ex)
            {
                writer.WriteLine(DateTime.Now.ToLongTimeString() + " " + ex.Message);
            }
            writer.Close();
        }

        void tim_Elapsed(object sender, ElapsedEventArgs e)
        {
            result = false;
            StreamWriter writer = new StreamWriter("D:\\hede.txt", true);
            writer.WriteLine(DateTime.Now.ToLongTimeString());
            //System.Threading.Thread.Sleep(5000);
            writer.Close();
            result = true;
            tim.Stop();
        }

        Timer tim;
        bool result = false;

        protected override void OnStart(string[] args)
        {
            RequestAdditionalTime(1000);
            tim.Start();
        }

        protected override void OnStop()
        {
        }

        protected override void OnCustomCommand(int command)
        {
            StreamWriter writer = new StreamWriter("D:\\Log.txt", true);
            try
            {
                if (command == SERVICE_CONTROL_PRESHUTDOWN)
                {
                    int checkpoint = 1;
                    writer.WriteLine(DateTime.Now.ToLongTimeString());
                    while (!result)
                    {
                        SERVICE_STATUS myServiceStatus = new SERVICE_STATUS();
                        myServiceStatus.currentState = (int)SERVICE_STATE.SERVICE_STOP_PENDING;

                        myServiceStatus.serviceType = 16;
                        myServiceStatus.serviceSpecificExitCode = 0;
                        myServiceStatus.checkPoint = checkpoint;
                        SetServiceStatus(this.ServiceHandle, ref myServiceStatus);
                        checkpoint++;
                    }
                    writer.WriteLine(DateTime.Now.ToLongTimeString());
                }
            }
            catch (Exception ex)
            {
                writer.WriteLine(DateTime.Now.ToLongTimeString() + " " + ex.Message);
            }
            writer.Close();
            base.OnCustomCommand(command);
        }
    }
}
Weever answered 26/9, 2013 at 11:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.