[英]How can I detect if a reboot is scheduled in the future after calling InitiateSystemShutdownW?
我目前正在使用Windows API调用InitiateSystemShutdownW
触发重新InitiateSystemShutdownW
。 我正在传递dwTimeout
值(10分钟)。 我想检测是否已计划重新启动(或任何其他重新启动):
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool InitiateSystemShutdownW([MarshalAs(UnmanagedType.LPWStr)]String lpMachineName, [MarshalAs(UnmanagedType.LPWStr)]String lpMessage, int dwTimeout, bool bForceAppsClosed, bool bRebootAfterShutdown);
我知道如果再次调用它,将会收到一条错误消息,告诉我它已被调度(通过GetLastWin32Error
),但是我需要执行此操作而无需再次调用重新启动(因为此时我可能不想实际触发重新启动) 。
我尝试使用参数SM_SHUTTINGDOWN
调用GetSystemMetrics
,但是即使我知道这已计划,它也会返回false
/ 0
。 我以为这是一次实际的关机,没有按计划进行。
无论如何,无论是否计划重新启动,我是否都能检测到该呼叫正在进行中?
我正在使用C#/ DllImport
/ interop调用这些方法,因此我需要可以从ac#进程访问的api。
您可以使用Windows事件日志API来访问“系统”通道上的日志条目。 该日志记录了登录名请求以关闭系统并中止系统关闭。
此代码显示如何使用P / Invoke获取查询之前指定时间范围内的系统关闭和关闭中止请求的数量(以毫秒为单位)。 因此,如果您在过去一个小时内有2个计划的关机请求和1个中止请求,则您有一个挂起的关机正在进行中。
如果您确实想要有关已记录的关机请求的所有详细信息,则可以使用EvtRender函数提取XML数据并进行解析。 这段代码没有做到这一点。
using System;
using System.Runtime.InteropServices;
namespace WindowsEventLogChecker
{
// partial list from "winerror.h"
public enum ERROR
{
ERROR_SUCCESS,
ERROR_NO_MORE_ITEMS = 259,
ERROR_EVT_CHANNEL_NOT_FOUND = 15007,
ERROR_EVT_INVALID_QUERY = 15001
}
// this is our own enum
public enum SystemEventType
{
Shutdown,
Abort
}
// these are from "winevt.h"
public enum EVT_QUERY_FLAGS
{
EvtQueryChannelPath = 0x1,
EvtQueryFilePath = 0x2,
EvtQueryForwardDirection = 0x100,
EvtQueryReverseDirection = 0x200,
EvtQueryTolerateQueryErrors = 0x1000
}
class Program
{
[DllImport("wevtapi.dll", EntryPoint = "EvtQuery", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern IntPtr EvtQuery(IntPtr session, [MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] string query, int flags);
[DllImport("wevtapi.dll", EntryPoint = "EvtNext", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern bool EvtNext(IntPtr resultSet, int batchSize, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] eventBatch, int timeout, int flags, ref int nReturned);
[DllImport("wevtapi.dll", EntryPoint = "EvtClose", CallingConvention = CallingConvention.StdCall)]
public static extern bool EvtClose(IntPtr handle);
[DllImport("kernel32.dll", EntryPoint = "GetLastError", CallingConvention = CallingConvention.StdCall)]
public static extern int GetLastError();
static void Main(string[] args)
{
// get the number of scheduled shutdowns in the last hour
int nShutdowns = GetEventCount(SystemEventType.Shutdown, 3600000);
// get the number of aborted shutdowns in the last hour
int nAborts = GetEventCount(SystemEventType.Abort, 3600000);
}
private static int GetEventCount(SystemEventType evtType, int timeSpanMs)
{
ERROR status = ERROR.ERROR_SUCCESS;
IntPtr hResult = IntPtr.Zero;
IntPtr[] eventBatch = new IntPtr[10];
// these 2 event id's, along with 'USER32' event source, denote requested
// shutdown and abort, respectively
string shutDownId = "1074";
string abortId = "1075";
// XPath query to get the event id, event source, and timespan in ms from now
// back to when the event was posted to the event log.
string format = "*[System[(EventID = {0}) and Provider[@Name=\"USER32\"] and TimeCreated[timediff(@SystemTime) <= {1}]]]";
// The "System" event channel
string channelPath = "System";
int nEvents = 0;
int count = 0;
string evtQuery;
switch (evtType)
{
case SystemEventType.Shutdown:
evtQuery = string.Format(format, shutDownId, timeSpanMs);
break;
case SystemEventType.Abort:
evtQuery = string.Format(format, abortId, timeSpanMs);
break;
default:
throw new InvalidOperationException();
}
hResult = EvtQuery(IntPtr.Zero, channelPath, evtQuery, (int)(EVT_QUERY_FLAGS.EvtQueryChannelPath | EVT_QUERY_FLAGS.EvtQueryReverseDirection));
if (IntPtr.Zero == hResult)
{
status = (ERROR)GetLastError();
if (status == ERROR.ERROR_EVT_CHANNEL_NOT_FOUND)
{
// log error
return 0;
}
else if (status == ERROR.ERROR_EVT_INVALID_QUERY)
{
// log error
return 0;
}
else
{
// log error
return 0;
}
}
while (EvtNext(hResult, 10, eventBatch, 1000, 0, ref nEvents))
{
for (int i = 0; i < nEvents; i++)
{
count++;
if (eventBatch[i] != IntPtr.Zero)
{
EvtClose(eventBatch[i]);
}
}
}
status = (ERROR)GetLastError();
if (status != ERROR.ERROR_NO_MORE_ITEMS)
{
// log error here and cleanup any remaining events
for (int i = 0; i < nEvents; i++)
{
if (eventBatch[i] != IntPtr.Zero)
{
EvtClose(eventBatch[i]);
}
}
}
if (hResult != null)
{
EvtClose(hResult);
}
return count;
}
}
}
这里的答案有关于通过Powershell检查Windows注册表以查看是否计划重新启动的信息:
Test-Path 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending'
除此之外, ExitWindowsEx
超时时间非常长(最大为315360000
-10年),然后检查ERROR_SHUTDOWN_IS_SCHEDULED
如果命令成功,那么您将(当然) AbortSystemShutdown
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.