【问题标题】:detect shutdown in window service检测窗口服务中的关闭
【发布时间】:2011-03-05 06:22:29
【问题描述】:

我有一个 Windows 服务,它可以获取用户详细信息并将结果保存到日志文本文件中。而且,我的问题是当我关闭或注销系统时,我还想将关闭系统的时间保存到该日志文件中。但是,我不知道该怎么做。

我检查了 winproc 方法来检测关机操作,但我无法在窗口服务上使用它,谷歌搜索发现它只能与表单一起使用。我们如何检测用户已单击关机或注销并执行某些操作。 所以,请给我一些想法或建议。

我已经用它来注销,但是当我注销系统时会进行日志条目

  protected override void OnSessionChange(SessionChangeDescription changeDescription)
  {
     this.RequestAdditionalTime(250000); //gives a 25 second delay on Logoff
     if (changeDescription.Reason == SessionChangeReason.SessionLogoff)
     {
        // Add your save code here
        StreamWriter str = new StreamWriter("D:\\Log.txt", true);
        str.WriteLine("Service stoped due to " + changeDescription.Reason.ToString() + "on" + DateTime.Now.ToString());
        str.Close();
     }
     base.OnSessionChange(changeDescription);
 }

【问题讨论】:

    标签: c# .net windows-services


    【解决方案1】:

    对于关机,覆盖 OnShutdown 方法:

    protected override void OnShutdown()
    {
        //your code here
        base.OnShutdown();
    }
    

    注销:

    首先,在 Service Constructor 中为 Microsoft.Win32.SystemEvents.SessionEnded 添加一个事件处理程序:

    public MyService()
    {
        InitializeComponent;
        Microsoft.Win32.SystemEvents.SessionEnded += new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);
    }
    

    然后添加处理程序:

    void SystemEvents_SessionEnded(object sender, Microsoft.Win32.SessionEndedEventArgs e)
    {
        //your code here
    }
    

    这应该捕获任何结束的会话,包括控制台本身(运行服务的那个)。

    【讨论】:

    • 这是哪个操作系统?如果是 Vista 和 Win7,那么这是预期的行为,因为服务在会话 0 中启动,并且任何用户登录都会启动另一个会话。 Check here for details
    • 在 windows 服务中不会触发注销,您需要运行消息泵,您可以通过向控制台应用程序添加隐藏表单来获得此功能
    • 不适用于 Windows 10 或服务器 2012/2016。没有任何事件被触发。即使添加消息泵仍然不会触发事件。
    • @jjxtra Windows 10 有一个名为快速启动的选项,它不会调用OnShutdownCheck here for details
    【解决方案2】:

    Tl;博士

    在您的服务集中

    CanShutdown = true;
    

    然后覆盖

    protected override void OnShutdown()
    {
        //Your code here
    
        //Don't forget to call ServiceBase OnShutdown()
        base.OnShutdown();
    }
    

    现在是扩展答案

    我知道我是从死里复活的,但我发现它很有帮助,并希望对这个话题有所补充。我正在实现一个托管在 Windows 服务中的 WCF 双工库并遇到了这个线程,因为我需要从 Windows 服务中检测用户何时注销或关闭计算机。我在 Windows 7 和 Windows 10 上使用 .Net Framework 4.6.1。就像之前建议的关机一样,对我有用的是覆盖 ServiceBase.OnShutdown(),如下所示:

    protected override void OnShutdown()
    {
        //Your code here
    
        //Don't forget to call ServiceBase OnShutdown()
        base.OnShutdown();
    }
    

    请记住将以下内容添加到服务的构造函数中以允许捕获关闭事件:

    CanShutdown = true;
    

    然后要捕获用户注销、锁定屏幕、切换用户等的时间。您可以像这样覆盖OnSessionChange 方法:

    protected override void OnSessionChange(SessionChangeDescription changeDescription)
    {
        if (changeDescription.Reason == SessionChangeReason.SessionLogoff)
        {
            //Your code here...
    
            //I called a static method in my WCF inbound interface class to do stuff...
        }
    
        //Don't forget to call ServiceBase OnSessionChange()
        base.OnSessionChange(changeDescription);
    }
    

    当然记得在服务的构造函数中添加以下内容,以允许捕获会话更改事件:

    CanHandleSessionChangeEvent = true;
    

    【讨论】:

    • 这些都不适合我。设置两个属性,实现两个功能,附加调试器。代码未运行。
    • @jjxtra Windows 10 有一个名为快速启动的选项,它不会调用OnShutdownCheck here for details
    【解决方案3】:

    你应该在你的服务中覆盖OnShutdown

    // When system shuts down
    protected override void OnShutdown()
    {
        // Add your save code here
        base.OnShutdown();
    }
    

    您可能还想覆盖OnStop

    // When the user presses stops your service from the control panel
    protected override void OnStop()
    {
        // Add your save code here too
        base.OnStop();
    }
    

    编辑:
    如果你真的想听关机事件Microsoft.Win32.SystemEvents.SessionEnding是要走的路。

    【讨论】:

    • @deepu,您有合理的时间(我认为是 30 秒)来保存您的状态,如果这还不够,您可以致电 RequestAddtionalTime
    【解决方案4】:

    免责声明

    当 Windows 更改 再次关闭 行为 再次 时,此答案可能不会有用。

    计算机关机时会出现哪些通知?

    据我所知,计算机关闭时会出现三个通知:

    • SessionLogoff
    • SessionLock
    • Suspend

    前两个是OnSessionChange(),最后一个是OnPowerEvent()

    当然,很自然的选择是Suspend,但要注意当计算机被发送到睡眠时也会发送此通知。

    如何获得通知?

    要获得上面发布的通知,您必须在服务构造函数中允许通知如下:

    public Service1()
    {
        InitializeComponent();
    
        CanHandlePowerEvent = true;
        CanHandleSessionChangeEvent = true;
    }
    

    然后覆盖各自的

    protected override void OnSessionChange(SessionChangeDescription changeDescription)
    {
        // Do something
        base.OnSessionChange(changeDescription);
    }
    
    protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
    {
        // Do something
        return base.OnPowerEvent(powerStatus);
    }
    

    ServiceBase.OnShutdown() 呢?

    嗯,当计算机通过单击电源选项中的“关闭”关闭时不会调用此方法。

    确实,如this official post中所写,

    当您关闭计算机时,您的计算机实际上会进入休眠状态,而不是完全关机。

    还有,根据the documentation

    使用 OnShutdown 指定系统关闭时发生的处理。

    此事件仅在操作系统关闭时发生,而不是在计算机关闭时发生。

    当 CanShutdown 属性为 true 时,应覆盖 OnShutdown。

    那么,如果手动关闭电脑并没有真正关闭电脑,而是让电脑进入休眠状态,那么有什么办法可以关闭电脑呢?

    post quoted above又有答案了:

    仅当您重新启动计算机或其他事件导致计算机处理完全关闭时才会发生完全关闭。

    确实,我可以通过设置在我的服务上调用OnShutdown() 方法

    CanShutdown = true;
    

    并覆盖到 OnShutdown

    protected override void OnShutdown()
    {
        // Do something
        base.OnShutdown();
    }
    

    然后重启我的电脑。


    好吧,这篇文章就够了。我只希望 Windows 的关闭行为不会很快改变......

    【讨论】:

    • 应该是正确答案
    【解决方案5】:

    也许你可以使用this。时不时地轮询有问题的方法(1 秒间隔),你就可以做你想做的事了。

    您需要RegisterServiceCtrlHandlerEx API 调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-04
      • 2012-01-25
      • 2013-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多