【问题标题】:Confusion about CTRL_SHUTDOWN_EVENT handling in DLLs and WM_QUERYENDSESSION对 DLL 和 WM_QUERYENDSESSION 中的 CTRL_SHUTDOWN_EVENT 处理感到困惑
【发布时间】:2015-08-23 04:05:43
【问题描述】:

我的 UI 在 DLL 中。现在,DLL 和使用它的 EXE 都被编译为控制台程序,因此我可以在开发过程中使用 stdout 和 stderr 进行调试和错误报告。其中一件事是我有一个uninit() 函数,可以确保 DLL 没有泄漏内存。

因此,我有一个由 DLL 设置的控制处理程序,以便 CTRL_LOGOFF_EVENTCTRL_SHUTDOWN_EVENT 模拟用户单击“文件”菜单中的“退出”选项:它确实是 PostQuitMessage(0) ,在消息泵返回后发生清理代码。

我知道通常CTRL_SHUTDOWN_EVENT 不能被忽略,并且程序在处理程序例程返回后终止,无论它返回什么。但是根据MSDN

请注意,第三方库或 DLL 可以为您的应用程序安装控制台控制处理程序。如果是这样,此处理程序将覆盖默认处理程序,并可能导致应用程序在用户注销时退出。

如果我没看错,这说明由 DLL 安装的控制处理程序会覆盖导致我的程序在处理程序函数返回时退出的处理程序。我错了吗?我的 DLL 的处理程序函数只返回 TRUE,我假设它会进一步阻止任何其他默认值运行,因为上面的简介。

为什么?我注意到奇怪的行为:

在 Windows Vista 上,无论我做什么,程序都会关闭。在这种情况下,我想知道简介是否错误以及终止进程的处理程序是否仍在运行。无论我是否致电ShutdownBlockReasonCreate(),都会发生这种情况。

然而,在 Windows 7 上,我的程序的主窗口似乎获得了 WM_QUERYENDSESSION,并且 Windows 会相应地响应它。这意味着如果我在退出函数中说“不,不要退出(不要调用PostQuitMessage(0))”,Windows 会弹出“应用程序正在阻止关闭”屏幕,说我的主窗口正在阻止关闭。在这种情况下,上面的简介似乎是正确的,因为程序不会在从控制台处理程序返回时退出(如果它甚至被调用!)。

如果我改为说“是,调用PostQuitMessage(0),程序正常退出。但是,我丢失了stdout和stderr上的调试输出,所以我无法判断它是否真的正常退出。调用我的程序作为

new.exe > out.txt 2> err.txt

cmd.exe 上产生两个空文件;我不知道为什么在系统关闭时输出没有保存(谷歌搜索没有显示任何信息)。

那么有人可以帮我解决一下我的困惑,以便我可以正确地实现这个(包括ShutdownBlockReasonCreate())吗?谢谢。

【问题讨论】:

    标签: c winapi console shutdown


    【解决方案1】:

    当您从注册的处理程序返回 TRUE 时,Windows 会立即终止该进程。当您返回 FALSE 时,将调用前一个处理程序。最终这将成为默认处理程序,它会立即终止进程。

    所以你要做的就是在你开心之前不要返回和阻止。这需要与泵送消息循环的线程同步。您将使用一个事件,抽水线程可以在其消息循环之后调用 SetEvent(),并且您的处理程序可以在调用 PostQuitMessage() 之后调用 WaitForSingleEvent() 来阻止。

    然而这是一场线程竞赛,您的 UI 线程可能是由 main() 启动的,并且 CRT 将在 main() 返回时终止程序。哪一个会先到达那里是不可预知的。


    感觉自己做错了什么?嗯,你是。控制台窗口并不是显示调试输出的好方法。不知道你为什么这样做,但我知道你的工具链是不寻常的,我永远无法让你的任何代码 sn-ps 编译和运行。正确的方法是 OutputDebugString()。该函数与您的调试器对话并让它显示文本。即使您的调试器无法显示此类文本,您仍然可以回退到 SysInternals 的 DebugView 实用程序。

    您可能正在使用 printf() 并且不喜欢修复所有调试语句,只需在 CRT 之前编写您自己的链接版本,使用 vprintf() 和 OutputDebugStringA()。

    【讨论】:

    • 对,看看我是否做错了什么是导致这个问题的一部分。我很好奇你不能编译我的例子。我现在的工具链是 MinGW-w64,虽然我尽量不使用任何特定的东西,并希望使这个和其他一些项目也可以与微软的编译器(和其他)编译。绝对值得研究...我会考虑切换到 OutputDebugString()。我使用控制台的主要原因是方便,我打算在以后的开发中关闭控制台;在那之前我可以使用 dbgview(我已经有了)。谢谢。
    • 好吧,我试过dbgview和windbg和gdb;在我的PostQuitMessage(0)(验证内存已被释放)之后,它们都没有持续足够长的时间来告诉我任何调试消息。这是系统关闭的预期不确定性吗?我是否应该费心测试这种边缘情况(在系统关闭时正确清理我的库)?我想我想这样做是因为我作为图书馆作者有责任清理自己......
    • 嗯,不,没有像样的方法可以查看操作系统关闭时发生的情况。没关系,反正所有这些都是奇闻趣事。重要的是您对关闭做出响应,不这样做很容易看出。您只关心程序终止时的适当清理,因此您可以很好地诊断泄漏。正常终止,而不是操作系统关闭强制终止的那种。
    • 好的;那样的话我就不用担心了。谢谢。 (我仍然需要调查为什么我的代码示例不能在我当前的环境之外工作......)
    猜你喜欢
    • 2021-10-22
    • 1970-01-01
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    相关资源
    最近更新 更多