如何检测Windows是否正在关闭或重新启动

发布于 2024-07-23 12:07:48 字数 358 浏览 11 评论 0原文

我知道当 Windows 关闭时,它会发送 WM_QUERYENDSESSION< /a> 向每个应用程序发送消息。 这样可以轻松检测 Windows 何时关闭。 但是,是否有可能知道计算机是否将要关闭或 Windows 关闭后是否将重新启动。

我并不是特别抱有希望,考虑到 MSDN 上的文档对 WM_QUERYENDSESSION 有这样的说法:“...不可能确定正在发生哪个事件”,但 stackoverflow 的累积智慧永远不会停止让我惊讶。

I know that when Windows is shutting down, it sends a WM_QUERYENDSESSION message to each application. This makes it easy to detect when Windows is shutting down. However, is it possible to know if the computer going to power-off or is it going to restart after Windows has shutdown.

I am not particularly hopeful, considering the documentation at MSDN has this to say about WM_QUERYENDSESSION: "...it is not possible to determine which event is occurring," but the cumulative cleverness of stackoverflow never ceases to amaze me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

若有似无的小暗淡 2024-07-30 12:07:48

在 Windows 7 中(也可能在 Vista / 8 / Server 中),您可以使用系统事件来跟踪 Windows 是正在关闭(并关闭计算机电源)还是只是重新启动。 每次启动关闭/重新启动(通过任何方式 - 单击“开始”菜单中的按钮,或以编程方式),Windows 7 都会在系统日志中写入一两个事件,源 USER32,事件 ID 1074。如果满足以下条件,您可以看到记录的这些事件:从管理工具中打开事件查看器(过滤系统日志以仅查看 ID 1074)。 这些事件的描述(消息)包含关闭类型。 因此,您可以解析此类最近事件的描述(启动关闭后),查找必要的单词(关闭、重新启动/重新启动)。

当使用电源按钮正常关闭 Windows 时,我没有尝试查看事件中写入的关闭类型(我通常禁用此功能),但某些网站建议它指出“关闭电源”类型而不是“关闭” -如果您需要确定的话,请检查一下。 或者只是查找“重新启动”类型 - 如果未找到,则假定为“关闭”类型。

根据我的经验,在 Windows XP 中,仅当以编程方式完成关闭/重新启动时(例如在程序安装期间或使用 shutdown.exe 实用程序期间)才会记录事件 1074。 因此,它不会注册从 shell(资源管理器)启动的关闭,但也许您可以将此方法与另一个答案中建议的从注册表读取值结合起来。 另外,请记住,在 WinXP 中,无论真正的关机类型是什么,事件 1074 的消息都包含“重新启动”一词,因此您应该查看“关机类型:”字段,该字段将说明“关机”或“重启”。

与此相关的是,只要 Windows 由于某种原因无法关闭/重新启动(例如,如果应用程序不允许关闭作为对 WM_QUERYENDSESSION 的响应),就会记录事件 ID 1073。 在这种情况下,该消息还将包含“关机”、“重新启动”或“关闭电源”等字样 - 在 WinXP 中。 对于 Win7,这种类型的事件在我们的例子中不太有用,因为它不会在关机和重新启动之间产生任何区别。 但对于 WinXP - 如果您只需要拦截关机/重新启动,执行一些操作,然后继续相应的关机或重新启动过程 - 它应该按预期工作。

In Windows 7 (and probably also in Vista / 8 / Server) you could use the system events to track whether Windows is shutting down (and powering off the computer) or just restarting. Every time a shutdown/reboot is initiated (by any means - clicking the button in Start menu, or programmatically), Windows 7 writes one or two events in the System log, source USER32, event ID 1074. You can see these events recorded if you open the Event Viewer from Administrative Tools (filter the System log to see only ID 1074). The description (message) of these events contains the shutdown type. So you could parse the description of the most recent event of this type (after the shutdown was initiated), looking for the necessary word (shutdown, reboot/restart).

I didn't try to see the shutdown type written in the event when using the power button to gracefully shutdown Windows (I usually disable this function), but some site suggests that it states a "power off" type instead of "shutdown" - so check it out, if you need to be sure. Or simply look for a "reboot" type - if it's not found, then a "shutdown" type is assumed.

In Windows XP, from my experience, an event 1074 is recorded only if the shutdown/reboot is done programmatically (e.g. during a program install or using the shutdown.exe utility). So it does not register the shutdowns initiated from the shell (Explorer), but perhaps you could combine this method with reading the value from registry as proposed in another answer. Also, keep in mind that in WinXP the message of event 1074 contains the word "restart" no matter what the real type of shutdown is, so you should look at the "Shutdown Type:" field, which will state either "shutdown" or "reboot".

Related to this, an event ID 1073 is recorded whenever Windows fails to shutdown/reboot for some reason (e.g. if an application doesn't allow to shutdown as a response to WM_QUERYENDSESSION). In that case the message will also contain words as "shutdown", "reboot" or "power off" - in WinXP. For Win7 this type of event is less useful in our case, since it won't make any difference between shutdown and reboot. But for WinXP - if you only need to intercept the shutdown/reboot, perform some actions, then continue the corresponding shutdown or reboot process - it should work as expected.

疧_╮線 2024-07-30 12:07:48

来自此处

您可以从以下位置读取 DWORD 值
“HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shutdown
设置”来确定用户的内容
最后从“关机”中选择
对话框。

有点迂回的解决方案,但它应该可以解决问题。

From here:

You can read the DWORD value from
"HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shutdown
Setting" to determine what the user
last selected from the Shut Down
dialog.

A bit of a roundabout solution, but it should do the trick.

背叛残局 2024-07-30 12:07:48

通常有效的技巧是捕获 WM_ENDSESSION 并记录它。 现在记下时间。 如果系统在合理的时间内(例如 5 分钟)恢复正常。 然后是重新启动,而不是关闭。

想法:如果系统在 5 分钟内恢复正常,用户单击“关机”或“重新启动”是否真的很重要?

如果您确实需要检测关闭(我认为您需要这样做的唯一原因是,如果您依赖于关闭与重新启动之间的模糊行为软件差异),您可以调查API hooking< /code> ExitWindowsEx 及相关函数,但我不推荐这种方法。 重新考虑一下您是否确实需要直接检测到这一点。

A trick that usually works is to trap WM_ENDSESSION and log it. Now keep track of the time. If the system comes back up within a reasonable peroid (say 5 minutes). Then that was a reboot, not a shutdown.

Idea: If the system comes back up within 5 minutes, does it really matter if the user clicked 'shutdown' or 'reboot'?

If you really need to detect a shutdown (and the only reason I think you'd need to do this is if you're depending upon an obscure behavioral software difference between a shutdown vs a reboot) you could investigate API hooking of ExitWindowsEx and related functions but I don't recommend this approach. Rethink if you really need to detect this directly.

我最亲爱的 2024-07-30 12:07:48

Windows7 的可能实验解决方案如下。 (我不确定这是否适用于其他本地化,因此我将其称为解决方法)

using System.Diagnostics.Eventing.Reader;

namespace MyApp
{
public class RestartDetector : IDisposable
{
    public delegate void OnShutdownRequsted(bool restart);
    public OnShutdownRequsted onShutdownRequsted;

    private EventLogWatcher watcher = null;

    public RestartDetector()
    {
        try
        {
            EventLogQuery subscriptionQuery = new EventLogQuery(
                "System", PathType.LogName, "*[System[Provider[@Name='USER32'] and (EventID=1074)]]");

            watcher = new EventLogWatcher(subscriptionQuery);

            // Make the watcher listen to the EventRecordWritten
            // events.  When this event happens, the callback method
            // (EventLogEventRead) is called.
            watcher.EventRecordWritten +=
                new EventHandler<EventRecordWrittenEventArgs>(
                    EventLogEventRead);

            // Activate the subscription
            watcher.Enabled = true;
        }
        catch (EventLogReadingException e)
        {
        }
    }

    public void EventLogEventRead(object obj, EventRecordWrittenEventArgs arg)
    {
        bool restart = false;
        try
        {
            // Make sure there was no error reading the event.
            if (arg.EventRecord != null)
            {
                String[] xPathRefs = new String[1];
                xPathRefs[0] = "Event/EventData/Data";
                IEnumerable<String> xPathEnum = xPathRefs;

                EventLogPropertySelector logPropertyContext = new EventLogPropertySelector(xPathEnum);
                IList<object> logEventProps = ((EventLogRecord)arg.EventRecord).GetPropertyValues(logPropertyContext);

                string[] eventData = (string[])logEventProps[0];

                foreach (string attribute in eventData)
                {
                    if (attribute.Contains("restart")) { restart = true; break; }
                }
            }
        }
        catch (Exception e)
        {
        }
        finally
        {
            if (onShutdownRequsted != null) { onShutdownRequsted(restart); }
        }   
    }

    public void Dispose()
    {
        // Stop listening to events
        if (watcher != null)
        {
            watcher.Enabled = false;
            watcher.Dispose();
        }
    }
}
}

以下是在 PC 重新启动时写入事件日志的 XML 示例:

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
  <Provider Name="USER32" /> 
  <EventID Qualifiers="32768">1074</EventID> 
  <Level>4</Level> 
  <Task>0</Task> 
  <Keywords>0x80000000000000</Keywords> 
  <TimeCreated SystemTime="2015-12-15T11:10:43.000000000Z" /> 
  <EventRecordID>90416</EventRecordID> 
  <Channel>System</Channel> 
  <Computer>WIN7PC</Computer> 
  <Security UserID="S-1-5-21-1257383181-1549154685-2724014583-1000" /> 
  </System>
- <EventData>
  <Data>C:\Windows\system32\winlogon.exe (WIN7PC)</Data> 
  <Data>WIN7PC</Data> 
  <Data>No title for this reason could be found</Data> 
  <Data>0x500ff</Data> 
  <Data>restart</Data> 
  <Data /> 
  <Data>WIN7PC\WIN7PCUser</Data> 
 <Binary>FF00050000000000000000000000000000000000000000000000000000000000</Binary> 
  </EventData>
  </Event>

Possible experimental solution for Windows7 could be the following. (I'm not sure if this works well with other localizations, therefore I would call it a workaround)

using System.Diagnostics.Eventing.Reader;

namespace MyApp
{
public class RestartDetector : IDisposable
{
    public delegate void OnShutdownRequsted(bool restart);
    public OnShutdownRequsted onShutdownRequsted;

    private EventLogWatcher watcher = null;

    public RestartDetector()
    {
        try
        {
            EventLogQuery subscriptionQuery = new EventLogQuery(
                "System", PathType.LogName, "*[System[Provider[@Name='USER32'] and (EventID=1074)]]");

            watcher = new EventLogWatcher(subscriptionQuery);

            // Make the watcher listen to the EventRecordWritten
            // events.  When this event happens, the callback method
            // (EventLogEventRead) is called.
            watcher.EventRecordWritten +=
                new EventHandler<EventRecordWrittenEventArgs>(
                    EventLogEventRead);

            // Activate the subscription
            watcher.Enabled = true;
        }
        catch (EventLogReadingException e)
        {
        }
    }

    public void EventLogEventRead(object obj, EventRecordWrittenEventArgs arg)
    {
        bool restart = false;
        try
        {
            // Make sure there was no error reading the event.
            if (arg.EventRecord != null)
            {
                String[] xPathRefs = new String[1];
                xPathRefs[0] = "Event/EventData/Data";
                IEnumerable<String> xPathEnum = xPathRefs;

                EventLogPropertySelector logPropertyContext = new EventLogPropertySelector(xPathEnum);
                IList<object> logEventProps = ((EventLogRecord)arg.EventRecord).GetPropertyValues(logPropertyContext);

                string[] eventData = (string[])logEventProps[0];

                foreach (string attribute in eventData)
                {
                    if (attribute.Contains("restart")) { restart = true; break; }
                }
            }
        }
        catch (Exception e)
        {
        }
        finally
        {
            if (onShutdownRequsted != null) { onShutdownRequsted(restart); }
        }   
    }

    public void Dispose()
    {
        // Stop listening to events
        if (watcher != null)
        {
            watcher.Enabled = false;
            watcher.Dispose();
        }
    }
}
}

The following is an example of XML which is written to the event log when a PC is restarted:

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
  <Provider Name="USER32" /> 
  <EventID Qualifiers="32768">1074</EventID> 
  <Level>4</Level> 
  <Task>0</Task> 
  <Keywords>0x80000000000000</Keywords> 
  <TimeCreated SystemTime="2015-12-15T11:10:43.000000000Z" /> 
  <EventRecordID>90416</EventRecordID> 
  <Channel>System</Channel> 
  <Computer>WIN7PC</Computer> 
  <Security UserID="S-1-5-21-1257383181-1549154685-2724014583-1000" /> 
  </System>
- <EventData>
  <Data>C:\Windows\system32\winlogon.exe (WIN7PC)</Data> 
  <Data>WIN7PC</Data> 
  <Data>No title for this reason could be found</Data> 
  <Data>0x500ff</Data> 
  <Data>restart</Data> 
  <Data /> 
  <Data>WIN7PC\WIN7PCUser</Data> 
 <Binary>FF00050000000000000000000000000000000000000000000000000000000000</Binary> 
  </EventData>
  </Event>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文