17

Windowsがシャットダウンすると、各アプリケーションにWM_QUERYENDSESSIONメッセージが送信されることを知っています。これにより、Windowsがシャットダウンしていることを簡単に検出できます。ただし、コンピュータの電源がオフになるのか、Windowsのシャットダウン後に再起動するのかを知ることはできますか。

MSDNのドキュメントに「...どのイベントが発生しているかを判断することはできません」と書かれていることを考えると、私は特に期待してWM_QUERYENDSESSIONいませんが、stackoverflowの累積的な巧妙さは私を驚かせ続けます。

4

4 に答える 4

9

Windows 7(およびおそらくVista / 8 /サーバー)では、システムイベントを使用して、Windowsがシャットダウンしている(そしてコンピューターの電源を切っている)か、単に再起動しているかを追跡できます。シャットダウン/再起動が開始されるたびに([スタート]メニューのボタンをクリックするか、プログラムで)、Windows 7は1つまたは2つのイベントをシステムログ、ソースUSER32、イベントID1074に書き込みます。管理ツールからイベントビューアを開きます(システムログをフィルタリングしてID 1074のみを表示します)。これらのイベントの説明(メッセージ)には、シャットダウンタイプが含まれています。したがって、このタイプの最新のイベントの説明を解析して(シャットダウンが開始された後)、必要な単語(シャットダウン、再起動/再起動)を探すことができます。

電源ボタンを使用してWindowsを正常にシャットダウンするときにイベントに書き込まれるシャットダウンタイプを確認しようとしませんでしたが(通常はこの機能を無効にします)、一部のサイトでは、「シャットダウン」ではなく「電源オフ」タイプが示されていると示唆されています。確認が必要な場合は、チェックしてください。または、単に「再起動」タイプを探します。見つからない場合は、「シャットダウン」タイプが想定されます。

Windows XPでは、私の経験から、シャットダウン/再起動がプログラムで実行された場合にのみイベント1074が記録されます(たとえば、プログラムのインストール中またはshutdown.exeユーティリティの使用中)。したがって、シェル(Explorer)から開始されたシャットダウンは登録されませんが、別の回答で提案されているように、この方法をレジストリからの値の読み取りと組み合わせることができます。また、WinXPでは、実際のシャットダウンの種類に関係なく、イベント1074のメッセージに「restart」という単語が含まれていることに注意してください。「ShutdownType:」フィールドには、「shutdown」または「shutdown」のいずれかが表示されます。 "リブート"。

これに関連して、Windowsが何らかの理由でシャットダウン/再起動に失敗するたびにイベントID 1073が記録されます(たとえば、アプリケーションがWM_QUERYENDSESSIONへの応答としてシャットダウンを許可しない場合)。その場合、メッセージには、WinXPでは「シャットダウン」、「再起動」、「電源オフ」などの単語も含まれます。Win7の場合、このタイプのイベントは、シャットダウンと再起動の間に違いがないため、この場合はあまり役に立ちません。ただし、WinXPの場合(シャットダウン/再起動をインターセプトするだけでよい場合は、いくつかのアクションを実行してから、対応するシャットダウンまたは再起動プロセスを続行します)、期待どおりに機能するはずです。

于 2013-12-25T02:29:56.450 に答える
6

ここから:

「HKCU\Software \ Microsoft \ Windows \ CurrentVersion \ Explorer \ ShutdownSetting」からDWORD値を読み取って、ユーザーが[シャットダウン]ダイアログから最後に選択したものを判別できます。

少し回り道の解決策ですが、それでうまくいくはずです。

于 2009-06-11T14:13:35.900 に答える
5

通常は機能するトリックは、トラップWM_ENDSESSIONしてログに記録することです。今、時間を追跡します。システムが妥当な期間内に復旧した場合(たとえば5分)。その後、それは再起動であり、シャットダウンではありませんでした。

アイデア:システムが5分以内に復旧した場合、ユーザーが[シャットダウン]または[再起動]をクリックしたかどうかは本当に重要ですか?

本当にシャットダウンを検出する必要がある場合(そして、これを行う必要があると思う唯一の理由は、シャットダウンと再起動のあいまいな動作ソフトウェアの違いに依存している場合です)、関連する機能を調査できますが、私API hookingExitWindowsExこのアプローチはお勧めしません。これを直接検出する必要があるかどうかを再考してください。

于 2011-01-07T18:45:35.830 に答える
2

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>
于 2015-12-16T14:40:41.887 に答える