Skip to content
This repository has been archived by the owner on Jul 26, 2022. It is now read-only.

WhenPowerEvent does not react to SystemEvents.PowerModeChanged #384

Closed
MovGP0 opened this issue Jul 15, 2017 · 3 comments · Fixed by #537
Closed

WhenPowerEvent does not react to SystemEvents.PowerModeChanged #384

MovGP0 opened this issue Jul 15, 2017 · 3 comments · Fixed by #537

Comments

@MovGP0
Copy link

MovGP0 commented Jul 15, 2017

When the computer goes to Standby, the WhenPowerEvent does not react. Also, I might want to have a reference to the service in order to start and stop it on standby.


Workaround

  1. Keep a reference to the service
private static ILogger Log => ...;
private IMyService MyService { get; set; } 
  1. Implement the event handler
private void OnPowerChange(object s, PowerModeChangedEventArgs e)
{
    switch (e.Mode)
    {
        case PowerModes.Resume:
            Log.Information("Resuming");
            MyService.Start();
            break;
        case PowerModes.Suspend:
            Log.Information("Suspending");
            MyService.Stop();
            break;
        case PowerModes.StatusChange:
            Log.Information("Power changed"); // ie. weak battery
            break;
        default:
            throw new ArgumentOutOfRangeException();
    }
}
  1. Keep a reference to the service and hook up events
s.ConstructUsing(name => myServiceFactory());
s.WhenStarted(s=>
{
    Log.Information("Starting...");
    MyService = s;
    SystemEvents.PowerModeChanged += OnPowerChange;
    s.Start();
});
s.WhenStopped(s=>
{
    Log.Information("Stopping...");
    MyService = s;
    SystemEvents.PowerModeChanged -= OnPowerChange;
    s.Stop();
});
@Peter-Optiway
Copy link

Im having the same problem

class Program
{

    public static void Log(string message)
    {
        var content = DateTime.Now.ToString("G") + " " + message + Environment.NewLine;
        Console.Write(content);
        System.IO.File.AppendAllText("Log.log", content);
    }

    static void Main(string[] args)
    {
        var rc = HostFactory.Run(x =>
        {
            //Setup topshelf logging
            x.Service<Service>(s =>
            {
                s.ConstructUsing(name => new Service());
                s.WhenStarted(sw => sw.Start());
                s.WhenStopped(sw => sw.Stop());
                s.WhenPowerEvent((sw, host, arg) => {
                    Log($"Power event {arg.EventCode}");
                    return true;
                });
            });

            x.RunAsLocalSystem();
            x.StartAutomatically();
            x.SetStopTimeout(TimeSpan.FromSeconds(20));

            x.EnableServiceRecovery(r =>
            {
                r.OnCrashOnly();
                r.RestartService(0);
                r.SetResetPeriod(1);
            });

            x.AfterUninstall(() =>
            {
                Log("AfterUninstall");
            });
        });

        var exitCode = (int)Convert.ChangeType(rc, rc.GetTypeCode());
        Environment.ExitCode = exitCode;
    }
}

class Service
{
    public void Start()
    {
        Program.Log("Start");
    }

    public void Stop()
    {
        Program.Log("Stop");
    }
}

No Power event is logged, what am i doing wrong? (Going with the workaround until this is fixed)

@ryanvs
Copy link

ryanvs commented Mar 28, 2019

I haven't used Topshelf and came across this issue while looking for PowerModeChanged, but I think I know why it isn't working. The service needs a message pump in order to process system events. Here are a couple of links:
StackOverflow: Message pump in .NET Windows service
Connect: detecting a wm_timechange event in a .net windows service

@RoadTrain
Copy link

RoadTrain commented Jul 3, 2019

I'm wondering why HostConfigurator doesn't have an EnablePowerEvents() method while it has EnableShutdown(). According to https://docs.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicebase.onpowerevent?view=netframework-4.8

OnPowerEvent is expected to be overridden when the CanHandlePowerEvent property is true.

And I can't find a place in the codebase where I can set this to true.
EnableShutdown basically sets one setting to true and this _settings instance is then passed to a service builder.

        public void EnableShutdown()
        {
            _settings.CanShutdown = true;
        }

See also #170

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants