如何取消PC的关机事件?

时间:2013-06-30 09:57:10

标签: c# winforms systemevent

我正在创建一个应用程序,我希望在系统关闭之前执行一些数据库查询。我正在使用此代码 -

static void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
        e.Cancel = true;
        MessageBox.Show("Shut down canceled");
}

我确实执行了这个应用程序并试图关闭系统并且此代码也捕获了关闭事件,但问题是在显示消息框之后它还显示了此屏幕 - [我无法发布图像,因为我不会得10分。]

它显示了我的应用程序的名称,它停止系统关闭,它还提供“强制关闭按钮”,我不希望显示此屏幕,因为用户可以在执行完成之前强制关闭系统我的疑问。

需要专家的建议,非常感谢。

2 个答案:

答案 0 :(得分:1)

简短可靠答案:

在任何最新的Windows版本中,您可以尝试取消关机,但Windows可能会决定忽略您;这很可悲的是设计。如果您必须在流程终止之前完成操作,那么在SessionEnded处理程序中执行此操作的正确位置。如果在进程终止之前有必须完成的任务,那么一定不能从SessionEnded处理程序返回,直到完成所有工作(因此您的查询等已经完成)。 )

所以不要(或者,如果你愿意)处理SessionEnding,处理SessionEnded并在那里工作:

static void SystemEvents_SessionEnded(object sender, SessionEndedEventArgs e)
{
    WaitForQueriesToFinishOrSaveState(); // new code
}

如何实施等待取决于您的申请;如果你需要重新运行查询,你可以在其中执行它们,或者你可能需要Thread.Join()或者等待后台任务完成;但它必须是阻塞等待(所以你需要在完成之前不要从函数返回)。

由于无法绝对停止关机,在这种情况下尝试取消可能没什么意义,所以我建议不要在SessionEnding中设置e.Cancel。在较旧的Windows版本中,这更有意义,现在不幸的是,现在更不用了。

还建议the API docs 而不是在SessionEnding(包括消息框)中做任何重要的工作,但要设置你需要立即返回的任何标志,然后在SessionEnded中完成工作。 (未经证实:我怀疑如果你没有足够快地返回,这可能加速了“程序行为不端,你想要杀死它们”的外观,因为Windows认为你不玩再好了。)

幕后故事:

设置e.Cancel表示您喜欢会话不会结束;但用户仍然可以查看;并且Windows可能会因任何合理的原因而决定忽略您的请求。这就是饼干粉碎的方式。您可能会发现在情境上工作的黑客,但没有微软批准的API或方法,因此现在和将来都可以保持一致。

在幕后,Windows正在向您的进程'窗口发送一条WM_QUERYENDSESSION消息,.NET收到该消息并转换为SessionEnding事件)并将您的取消(或缺少)传递回Windows;如果你不取消,则返回TRUE,否则返回FALSE。

在此之后,Windows会查看所有进程的请求,并且取决于关闭的原因,尽管有这些请求,其他因素仍可能决定继续进行。如果进程不合作,它也可以提醒用户,并为他们提供杀死进程的选项。

无论你是否处理WM_QUERYENDSESSION(SessionEnding),你总是有最后一次机会清理:你发送了一条WM_ENDSESSION消息(翻译成SessionEnded)。棘手的部分是你必须在所有SessionEnded处理程序返回之前完成所有重要任务!

一旦Windows从其WM_ENDSESSION(SessionEnded)调用中回复,就应用程序的生命周期而言,所有投注均已关闭,Windows可以随时终止您的进程。

雷蒙德·陈(Raymond Chen)非常熟练地介绍了这一点。

http://blogs.msdn.com/b/oldnewthing/archive/2013/06/27/10429232.aspx

作为脚注,SystemEvents.SessionEnded是一个方便;如果您有一个顶级应用程序窗口,您可以完全绕过它并实现相同的目的:

protected override void WndProc(ref Message m)
{
    if (m.Msg == 0x16) // WM_ENDSESSION
    {
        WaitForQueriesToFinishOrSaveState();
        m.Result = IntPtr.Zero;
        return;
    }
    base.WndProc(ref m);
}

答案 1 :(得分:0)

在shutdown命令中有一个中止关闭的开关。你必须用你的c#代码

来调用这个命令
        Process cmd = new Process();
        cmd.StartInfo.FileName = "cmd.exe";
        cmd.StartInfo.RedirectStandardInput = true;
        cmd.StartInfo.RedirectStandardOutput = true;
        cmd.StartInfo.CreateNoWindow = false;
        cmd.StartInfo.UseShellExecute = false;

        cmd.Start();



        cmd.StandardInput.WriteLine(@"shutdown -a");
        cmd.StandardInput.Flush();
        cmd.StandardInput.Close();
        Console.WriteLine(cmd.StandardOutput.ReadToEnd());