我知道当Windows关闭时,它会向每个应用程序发送一条WM_QUERYENDSESSION消息。这样可以轻松检测Windows何时关闭。但是,是否有可能知道计算机是否要关闭电源,或者是否在Windows关闭后重新启动。
我并不是特别有希望,考虑到MSDN上的文档有关于WM_QUERYENDSESSION
的说法:“......无法确定发生了哪个事件,”但堆栈溢出的累积聪明从未停止过让我感到惊讶。
答案 0 :(得分:8)
在Windows 7中(也可能在Vista / 8 / Server中),您可以使用系统事件来跟踪Windows是否正在关闭(以及关闭计算机电源)或只是重新启动。每次启动关闭/重启(无论如何 - 单击“开始”菜单中的按钮或以编程方式),Windows 7都会在系统日志中写入一个或两个事件,源USER32,事件ID 1074.您可以看到这些事件已记录,如果从管理工具打开事件查看器(筛选系统日志以仅查看ID 1074)。这些事件的描述(消息)包含关闭类型。因此,您可以解析此类型的最新事件的描述(在启动关闭之后),查找必要的字(关闭,重新启动/重新启动)。
当使用电源按钮正常关闭Windows时,我没有尝试查看事件中写入的关闭类型(我通常会禁用此功能),但有些网站建议它说明关闭电源" #34;键入而不是" shutdown" - 如果你需要确定的话,请检查一下。或者只是寻找一个" reboot"类型 - 如果找不到,那么"关闭"假定类型。
在Windows XP中,根据我的经验,只有在以编程方式完成关闭/重启时(例如在程序安装期间或使用shutdown.exe实用程序),才会记录事件1074。因此它不会注册从shell(Explorer)启动的关闭,但是也许您可以将此方法与从另一个答案中建议的读取注册表中的值结合使用。另外,请记住,在WinXP中,事件1074的消息包含单词" restart"无论真正的关机类型是什么,所以你应该看看"关机类型:"字段,将指出" shutdown"或者"重启"。
与此相关,只要Windows由于某种原因无法关闭/重启(例如,如果应用程序不允许关闭作为对WM_QUERYENDSESSION的响应),则会记录事件ID 1073。在这种情况下,该消息还将包含单词" shutdown"," reboot"或者"断电" - 在WinXP中。对于Win7,这种类型的事件在我们的情况下不太有用,因为它在关闭和重启之间没有任何区别。但是对于WinXP - 如果你只需要拦截关机/重启,执行一些操作,然后继续相应的关机或重启过程 - 它应该按预期工作。
答案 1 :(得分:6)
来自here:
您可以从中读取DWORD值 “HKCU \软件\微软\的Windows \ CurrentVersion \ Explorer中\关机 设置“确定用户是什么 最后从关机中选择 对话框。
有点迂回的解决方案,但应该可以解决这个问题。
答案 2 :(得分:5)
通常有效的技巧是捕获WM_ENDSESSION
并记录它。现在跟踪时间。如果系统恢复到合理的范围内(比如5分钟)。那是重启,而不是关机。
想法:如果系统在5分钟内恢复,如果用户点击“关机”或“重新启动”,真的是否重要?
如果你真的需要检测关机(我认为你需要这样做的唯一原因是,如果你依赖于关机与重启之间模糊的行为软件差异)你可以调查{{1 } API hooking
和相关函数,但我不推荐这种方法。重新思考,如果你真的需要直接检测到这一点。
答案 3 :(得分: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>