2009-06-11 49 views
14

Sé que cuando Windows se está cerrando, envía un mensaje WM_QUERYENDSESSION a cada aplicación. Esto hace que sea fácil detectar cuando Windows se está cerrando. Sin embargo, es posible saber si la computadora va a apagarse o si se reiniciará después de que Windows se haya apagado.Cómo detectar si Windows se está cerrando o reiniciando

No tengo ninguna esperanza, teniendo en cuenta que la documentación en MSDN tiene esto que decir sobre WM_QUERYENDSESSION: "... no es posible determinar qué evento está ocurriendo", pero la inteligencia acumulativa de stackoverflow nunca deja de sorprenderme.

Respuesta

5

De here:

se puede leer el valor DWORD de "HKCU \ Software \ Microsoft \ Windows \ CurrentVersion \ Explorer \ Shutdown Setting" para determinar que el usuario última seleccionada del Apagar diálogo.

Solución un tanto indirecta, pero debería ser el truco.

+11

Por supuesto, suponiendo que el sistema se está cerrando ahora porque el usuario actual lo inició, y lo hizo en el Explorador. Si se trata de un apagado programático, cierre desde otra aplicación o apagado por otro usuario, obtendría el motivo de un apagado anterior. – MSalters

+5

-1 Porque la respuesta es incompleta y específica para Windows Explorer. También parece estar ** eliminado ** en Windows 7. – unixman83

+1

Funciona bien bajo WindowsXP pero no bajo Windows7 – conceptacid

5

Un truco que generalmente funciona es atrapar WM_ENDSESSION y registrarlo. Ahora realiza un seguimiento de la hora. Si el sistema vuelve a aparecer dentro de un peroid razonable (digamos 5 minutos). Entonces eso fue un reinicio, no un cierre.

Idea: Si el sistema vuelve a subir dentro de los 5 minutos, lo hace realmente importa si el usuario hace clic en 'apagado' o 'reinicio'?

Si realmente necesita detectar un apagado (y la única razón por la que creo que tendría que hacer esto es si está dependiendo de una oscura diferencia de software de comportamiento entre un apagado o un reinicio) podría investigar API hooking de ExitWindowsEx y funciones relacionadas pero no recomiendo este enfoque. Repensar si realmente necesita detectar esto directamente.

+1

+1 para la sugerencia de enganche API. La sugerencia de control del tiempo es pura conjetura. –

+0

@Joe, con administración de energía ACPI moderna: suspensión, hibernación, Wake On LAN, etc. La definición de reinicio (o arranque en caliente) se está volviendo difícil de definir. Lo que la mayoría de las personas quiere decir con el reinicio (o lo suficientemente cerca) es que el sistema no se encontraba en un estado normal durante un muy * corto período de tiempo. – unixman83

6

En Windows 7 (y probablemente también en Vista/8/Server) puede usar los eventos del sistema para rastrear si Windows se está apagando (y apagando la computadora) o simplemente reiniciándose. Cada vez que se inicia un apagado/reinicio (por cualquier medio, haciendo clic en el botón en el menú Inicio o programáticamente), Windows 7 escribe uno o dos eventos en el registro del sistema, origen USER32, evento ID 1074. Puede ver estos eventos grabados si abre el Visor de eventos desde Herramientas administrativas (filtra el registro del sistema para ver solo la ID 1074). La descripción (mensaje) de estos eventos contiene el tipo de apagado. Por lo tanto, podría analizar la descripción del evento más reciente de este tipo (después de que se inició el apagado), buscando la palabra necesaria (apagado, reinicio/reinicio).

No intenté ver el tipo de apagado escrito en el evento cuando utilicé el botón de encendido para cerrar Windows correctamente (normalmente desactivo esta función), pero algunos sitios sugieren que indica un tipo de "apagado" en lugar de "shutdown" - así que échale un vistazo, si necesitas estar seguro. O simplemente busque un tipo de "reinicio" - si no se encuentra, entonces se asume el tipo de "apagado".

En Windows XP, desde mi experiencia, un evento 1074 se registra solo si el apagado/reinicio se realiza mediante programación (por ejemplo, durante la instalación de un programa o usando la utilidad shutdown.exe). Por lo tanto, no registra los cierres iniciados desde el shell (Explorer), pero quizás podría combinar este método con la lectura del valor del registro como se propone en otra respuesta. Además, tenga en cuenta que en WinXP el mensaje del evento 1074 contiene la palabra "reiniciar" sin importar cuál sea el tipo real de apagado, por lo que debe mirar el campo "Tipo de apagado:", que indicará "apagado" o "reiniciar".

En relación con esto, se registra un evento ID 1073 siempre que Windows no se apaga/reinicia por alguna razón (por ejemplo, si una aplicación no permite apagarla como respuesta a WM_QUERYENDSESSION). En ese caso, el mensaje también contendrá palabras como "apagar", "reiniciar" o "apagar" - en WinXP. Para Win7, este tipo de evento es menos útil en nuestro caso, ya que no hará ninguna diferencia entre el apagado y el reinicio. Pero para WinXP: si solo necesita interceptar el apagado/reinicio, realizar algunas acciones y luego continuar con el proceso de apagado o reinicio correspondiente, debería funcionar como se esperaba.

+1

Es importante tener en cuenta que EventLog muestra mensajes localizados por lo que las palabras clave como "apagado" o "reinicio" serán diferentes dependiendo de la localización del sistema operativo. – tpx86

1

Posible solución experimental para Windows7 podría ser la siguiente. (No estoy seguro de si esto funciona bien con otras localizaciones, por lo tanto, yo diría que es una solución)

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

El siguiente es un ejemplo de XML que se escribe en el registro de eventos cuando se reinicia el PC:

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