2009-06-11 10 views
14

So che quando Windows si sta spegnendo, invia un messaggio WM_QUERYENDSESSION a ciascuna applicazione. Questo rende facile rilevare quando Windows si sta spegnendo. Tuttavia, è possibile sapere se il computer si spegnerà o si riavvierà dopo l'arresto di Windows.Come rilevare se Windows è spegnere o riavviare

Non sono particolarmente fiducioso, considerando che la documentazione di MSDN ha da dire su WM_QUERYENDSESSION: "... non è possibile determinare quale evento si sta verificando", ma l'astuzia cumulativa di StackOverflow non smette mai di stupirmi.

risposta

5

Da here:

è possibile leggere il valore DWORD dal "HKCU \ Software \ Microsoft \ Windows \ CurrentVersion \ Explorer \ Shutdown Setting" per determinare ciò che l'utente ultima selezionato dalla sessione di lavoro dialog.

Un po 'una soluzione di rotatoria, ma dovrebbe fare il trucco.

+11

Ovviamente si presume che il sistema si stia arrestando perché l'utente corrente l'ha avviato e lo ha fatto in Esplora risorse. Se si tratta di uno spegnimento programmatico, spegnimento da un'altra app o spegnimento da parte di un altro utente, si otterrà il motivo per un arresto precedente. – MSalters

+5

-1 Perché la risposta è incompleta e specifica per Windows Explorer. Sembra anche essere ** rimosso ** in Windows 7. – unixman83

+1

Funziona bene con WindowsXP ma non con Windows7 – conceptacid

5

Un trucco che funziona di solito è per intrappolare WM_ENDSESSION e di accedervi. Ora tieni traccia del tempo. Se il sistema viene ripristinato entro un ragionevole peroide (diciamo 5 minuti). Quindi è stato un riavvio, non un arresto.

Idea: Se il sistema è di nuovo entro 5 minuti, non importa davvero se l'utente ha cliccato 'shutdown' o 'reboot'?

Se avete veramente bisogno di rilevare un arresto (e l'unico motivo penso che avresti bisogno di fare questo è se si sta a seconda del software di una differenza comportamentale oscuro tra un arresto contro un riavvio) si potrebbe indagare API hooking di ExitWindowsEx e relative funzioni, ma non consiglio questo approccio. Ripensa se hai davvero bisogno di rilevarlo direttamente.

+1

+1 per il suggerimento di aggancio dell'API. Il suggerimento per il controllo del tempo è pura congettura. –

+0

@Joe, con la moderna gestione energetica ACPI: sospensione, sospensione, riattivazione LAN e così via. La definizione di riavvio (o avvio a caldo) sta diventando difficile da definire. Ciò che la maggior parte delle persone intende per riavvio (o abbastanza vicino) è che il sistema non era in uno stato normale per un periodo molto * breve * di tempo. – unixman83

6

In Windows 7 (e probabilmente anche in Vista/8/Server) è possibile utilizzare gli eventi di sistema per tenere traccia se Windows si sta spegnendo (e spegnere il computer) o semplicemente riavviare. Ogni volta che viene avviato uno spegnimento/riavvio (con qualsiasi mezzo, facendo clic sul pulsante nel menu Start o programmaticamente), Windows 7 scrive uno o due eventi nel registro di sistema, origine USER32, ID evento 1074. È possibile vedere questi eventi registrati se apri il Visualizzatore eventi da Strumenti di amministrazione (filtra il registro di sistema per vedere solo ID 1074). La descrizione (messaggio) di questi eventi contiene il tipo di arresto. Quindi è possibile analizzare la descrizione dell'evento più recente di questo tipo (dopo l'avvio dello spegnimento), cercando la parola necessaria (arresto, riavvio/riavvio).

Non ho provato a vedere il tipo di spegnimento scritto nell'evento quando si utilizza il pulsante di accensione per arrestare con garbo Windows (solitamente disattivo questa funzione), ma alcuni siti suggeriscono di indicare un tipo di spegnimento invece di "shutdown" - quindi dai un'occhiata, se hai bisogno di essere sicuro. O semplicemente cerca un tipo di "riavvio" - se non viene trovato, si presume un tipo di "arresto".

In Windows XP, dalla mia esperienza, un evento 1074 viene registrato solo se l'arresto/riavvio viene eseguito a livello di codice (ad esempio durante l'installazione di un programma o l'utilizzo dell'utilità shutdown.exe). Quindi non registra gli arresti avviati dalla shell (Explorer), ma forse potresti combinare questo metodo con la lettura del valore dal registro come proposto in un'altra risposta. Inoltre, tieni presente che in WinXP il messaggio dell'evento 1074 contiene la parola "restart" indipendentemente dal vero tipo di arresto, quindi dovresti controllare il campo "Shutdown Type:", che indicherà "shutdown" o "reboot".

In relazione a ciò, un ID evento 1073 viene registrato ogni volta che Windows non riesce a spegnersi/riavviarsi per qualche motivo (ad esempio se un'applicazione non consente l'arresto come risposta a WM_QUERYENDSESSION). In quel caso il messaggio conterrà anche parole come "shutdown", "reboot" o "power off" - in WinXP. Per Win7 questo tipo di evento è meno utile nel nostro caso, dal momento che non farà alcuna differenza tra shutdown e riavvio. Ma per WinXP - se devi solo intercettare lo spegnimento/riavvio, eseguire alcune azioni, quindi continuare il processo di spegnimento o riavvio corrispondente - dovrebbe funzionare come previsto.

+1

È importante notare che EventLog mostra i messaggi localizzati in modo che le parole chiave come "shutdown" o "reboot" siano diverse a seconda della localizzazione del sistema operativo. – tpx86

1

Possibile soluzione sperimentale per Windows7 potrebbe essere il seguente. (Non sono sicuro se questo funziona bene con gli altri localizzazioni, perciò io la chiamerei una soluzione alternativa)

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(); 
     } 
    } 
} 
} 

Il seguente è un esempio di XML che è scritto nel registro eventi quando un PC viene riavviato:

- <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>