Как определить, завершается ли Windows или перезагружается
Вопрос
Я знаю, что когда Windows завершает работу, она отправляет WM_QUERYENDSESSION сообщение для каждого приложения.Это позволяет легко определить, когда Windows завершает работу.Однако возможно ли узнать, отключится ли компьютер или он перезагрузится после завершения работы Windows?
Я не особенно надеюсь, учитывая, что в документации в MSDN об этом говорится WM_QUERYENDSESSION
:"... невозможно определить, какое событие происходит", но совокупная сообразительность stackoverflow никогда не перестает меня удивлять.
Решение
От здесь:
Вы можете прочитать значение DWORD из "HKCU\Software\ Microsoft\ Windows\CurrentVersion\ Explorer\Shutdown Настройка", чтобы определить, что пользователь последним выбирал в диалоговом окне Shutdown .
Немного обходное решение, но оно должно сработать.
Другие советы
В Windows 7 (и, возможно, также в Vista/8/Server) вы можете использовать системные события, чтобы отслеживать, завершает работу Windows (и выключает компьютер) или просто перезагружается.Каждый раз, когда инициируется выключение/перезагрузка (любым способом — нажатием кнопки в меню «Пуск» или программно), Windows 7 записывает одно или два события в системный журнал, источник USER32, идентификатор события 1074.Вы можете увидеть эти записанные события, если откроете средство просмотра событий из инструментов администрирования (отфильтруйте системный журнал, чтобы увидеть только идентификатор 1074).В описании (сообщении) этих событий указан тип отключения.Таким образом, вы можете разобрать описание самого последнего события такого типа (после того, как было инициировано выключение), ища нужное слово (выключение, перезагрузка/перезапуск).
Я не пытался увидеть тип выключения, написанный в событии при использовании кнопки питания для корректного выключения Windows (я обычно отключаю эту функцию), но на некоторых сайтах предлагается указать тип «выключения» вместо «выключения» - так что проверьте это, если вам нужно быть уверенным.Или просто ищите тип "перезагрузка" - если он не найден, то предполагается тип "выключение".
В Windows XP, по моему опыту, событие 1074 записывается только в том случае, если выключение/перезагрузка производится программно (например.во время установки программы или с помощью утилиты Shutdown.exe).Таким образом, он не регистрирует завершение работы, инициированное оболочкой (Проводник), но, возможно, вы могли бы объединить этот метод с чтением значения из реестра, как предложено в другом ответе.Также имейте в виду, что в WinXP сообщение о событии 1074 содержит слово «перезагрузка» независимо от реального типа завершения работы, поэтому вам следует посмотреть поле «Тип завершения работы:», в котором будет указано либо «выключение», либо «выключение». "перезагрузить".
В связи с этим событие с идентификатором 1073 записывается всякий раз, когда Windows по какой-либо причине не завершает работу или не перезагружается (например,если приложение не позволяет завершить работу в ответ на WM_QUERYENDSESSION).В этом случае сообщение также будет содержать слова «выключение», «перезагрузка» или «выключение» - в WinXP.Для Win7 этот тип событий в нашем случае менее полезен, поскольку он не имеет никакого значения между завершением работы и перезагрузкой.А вот для WinXP - если вам нужно только перехватить выключение/перезагрузку, выполнить какие-то действия, а затем продолжить соответствующий процесс выключения или перезагрузки - должно работать как положено.
Уловка, которая обычно работает, состоит в том, чтобы поймать WM_ENDSESSION
и зарегистрируйте это.Теперь следите за временем.Если система снова заработает в течение разумного периода времени (скажем, 5 минут).Тогда это была перезагрузка, а не выключение.
Идея:Если система восстанавливается в течение 5 минут, это происходит? Действительно имеет значение, нажал ли пользователь «выключение» или «перезагрузка»?
Если вам действительно нужно обнаружить завершение работы (и единственная причина, по которой я думаю, что вам нужно это сделать, это если вы зависите от неясной разницы в поведении программного обеспечения между завершением работы и перезагрузкой), вы можете исследовать API hooking
из ExitWindowsEx
и связанные функции, но я не рекомендую этот подход.Подумайте еще раз, действительно ли вам нужно обнаружить это напрямую.
Возможным экспериментальным решением для 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();
}
}
}
}
Ниже приведен пример 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>