Come rilevare se Windows si sta arrestando o riavviando

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, è ansible sapere se il computer si spegnerà o si riavvierà dopo l’arresto di Windows.

Non sono particolarmente fiducioso, considerando che la documentazione di MSDN ha a che fare con WM_QUERYENDSESSION : “… non è ansible determinare quale evento si sta verificando”, ma l’astuzia cumulativa di StackOverflow non smette mai di stupirmi.

Da qui :

È ansible leggere il valore DWORD da “HKCU \ Software \ Microsoft \ Windows \ CurrentVersion \ Explorer \ Shutdown Setting” per determinare quale ultimo utente è stato selezionato dalla finestra di dialogo Arresta.

Un po ‘una soluzione rotonda, ma dovrebbe fare il trucco.

In Windows 7 (e probabilmente anche in Vista / 8 / Server) è ansible utilizzare gli eventi di sistema per verificare se Windows sta spegnendo (e spegnendo il computer) o semplicemente riavviandosi. 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. È ansible 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 è ansible 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 grazia Windows (di solito disabilito questa funzione), ma alcuni siti suggeriscono che indichi un tipo “spento” invece di “spegnimento” – 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 programmazione (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.

Un trucco che di solito funziona è quello di intrappolare WM_ENDSESSION e registrarlo. 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 viene ripristinato entro 5 minuti, è davvero importante se l’utente ha fatto clic su “Arresta” o “Riavvia”?

Se hai davvero bisogno di rilevare uno spegnimento (e l’unica ragione per cui penso che avresti bisogno di fare questo è se stai dipendendo da una oscura differenza di software comportamentale tra uno spegnimento e un riavvio) potresti studiare l’ API hooking di ExitWindowsEx e relativo funzioni ma non consiglio questo approccio. Ripensa se hai davvero bisogno di rilevarlo direttamente.

La ansible soluzione sperimentale per Windows 7 potrebbe essere la seguente. (Non sono sicuro che funzioni bene con altre localizzazioni, quindi la definirei 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( 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 xPathEnum = xPathRefs; EventLogPropertySelector logPropertyContext = new EventLogPropertySelector(xPathEnum); IList 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(); } } } } 

Di seguito è riportato un esempio di XML che viene scritto nel registro eventi quando viene riavviato un PC:

 -  -   1074 4 0 0x80000000000000  90416 System WIN7PC   -  C:\Windows\system32\winlogon.exe (WIN7PC) WIN7PC No title for this reason could be found 0x500ff restart  WIN7PC\WIN7PCUser FF00050000000000000000000000000000000000000000000000000000000000