簡體   English   中英

如何檢測Windows是否正在關閉或重新啟動

[英]How to detect whether Windows is shutting down or restarting

我知道Windows關閉時,它將向每個應用程序發送WM_QUERYENDSESSION消息。 這樣可以輕松檢測Windows何時關閉。 但是,有可能知道計算機是要關閉電源還是要在Windows關閉后重新啟動。

考慮到MSDN上的文檔對WM_QUERYENDSESSION這么說,我並不是特別希望:“ ...無法確定正在發生的事件,”但是stackoverflow的累積智能永遠不會令我感到驚奇。

在Windows 7中(可能在Vista / 8 / Server中),您可以使用系統事件來跟蹤Windows是否正在關閉(並關閉計算機電源)或只是重新啟動。 每次啟動關閉/重新啟動(通過任何方式-單擊“開始”菜單中的按鈕,或以編程方式單擊)時,Windows 7都會在系統日志中寫入一個或兩個事件,源USER32,事件ID為1074。您可以從管理工具中打開事件查看器(過濾系統日志以僅查看ID 1074)。 這些事件的描述(消息)包含關閉類型。 因此,您可以解析這種類型的最新事件的描述(在啟動關閉之后),尋找必要的單詞(關閉,重新啟動/重新啟動)。

使用電源按鈕正常關閉Windows時,我沒有嘗試查看事件中寫入的關閉類型(我通常禁用此功能),但是某些網站建議它聲明為“關閉電源”類型,而不是“關閉”-因此,如果需要確定,請檢查出來。 或者只是尋找“重新啟動”類型-如果找不到,則假定為“關機”類型。

在Windows XP中,根據我的經驗,僅當以編程方式(例如,在程序安裝過程中或使用shutdown.exe實用程序)完成關閉/重新啟動時,才會記錄事件1074。 因此,它不會注冊從外殼程序(Explorer)啟動的關閉程序,但是您可能可以將此方法與另一個答案中建議的從注冊表中讀取值結合使用。 另外,請記住,在WinXP中,無論關閉的實際類型是什么,事件1074的消息都包含單詞“ restart”,因此您應該查看“ Shutdown Type:”字段,其中將顯示“ shutdown”或“ shutdown” “重啟”。

與此相關的是,每當Windows由於某種原因無法關閉/重新啟動時(例如,如果應用程序不允許關閉作為對WM_QUERYENDSESSION的響應),都會記錄事件ID 1073。 在這種情況下,該消息還將包含WinXP中的“關閉”,“重新引導”或“關閉電源”字樣。 對於Win7,這種類型的事件在我們的案例中用處不大,因為它在關閉和重新啟動之間沒有任何區別。 但是對於WinXP-如果您只需要攔截關閉/重新啟動,請執行一些操作,然后繼續執行相應的關閉或重新啟動過程-它應該可以正常工作。

這里

您可以從“ HKCU \\ Software \\ Microsoft \\ Windows \\ CurrentVersion \\ Explorer \\ Shutdown設置”中讀取DWORD值,以確定用戶最近一次從“關閉”對話框中選擇的內容。

有點a回的解決方案,但應該可以解決問題。

通常有效的技巧是捕獲WM_ENDSESSION並將其記錄下來。 現在跟蹤時間。 如果系統在合理的周期內恢復正常(例如5分鍾)。 然后那是重新啟動,而不是關機。

提示 :如果系統在5分鍾內重新啟動,那么用戶單擊“關閉”還是“重新啟動” 真的有關系嗎?

如果您確實需要檢測到關機(我認為唯一需要這樣做的原因是,如果您依賴於關機與重新啟動之間行為軟件之間的模糊區別),可以調查ExitWindowsEx和相關的API hooking功能,但我不推薦這種方法。 重新考慮是否真的需要直接檢測到這一點。

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寫入事件日志的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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM