对 DLL 和 WM_QUERYENDSESSION 中的 CTRL_SHUTDOWN_EVENT 处理感到困惑

标签 c winapi console shutdown

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

因此,我通过 DLL 设置了一个控制处理程序,这样 CTRL_LOGOFF_EVENTCTRL_SHUTDOWN_EVENT 模拟用户单击“退出”选项从文件菜单:它执行 PostQuitMessage(0),在消息泵返回后发生清理代码。

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

Note that a third-party library or DLL can install a console control handler for your application. If it does, this handler overrides the default handler, and can cause the application to exit when the user logs off.

如果我没看错的话,这表示 DLL 安装的控制处理程序覆盖了导致我的程序在处理程序函数返回时退出的处理程序。我错了吗?我的 DLL 的处理程序函数只返回 TRUE,我认为这将进一步阻止任何其他默认设置在上面的简介中运行。

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

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

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

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

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

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

那么有人可以帮我理清思路,以便我可以正确地实现它(包括 ShutdownBlockReasonCreate())吗?谢谢。

最佳答案

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

所以你要做的就是不返回并阻塞,直到你高兴为止。这需要与泵送消息循环的线程同步。您将使用一个事件,泵送线程可以在其消息循环之后调用 SetEvent(),并且您的处理程序可以在调用 PostQuitMessage() 之后调用 WaitForSingleEvent() 进行阻塞。

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


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

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

关于对 DLL 和 WM_QUERYENDSESSION 中的 CTRL_SHUTDOWN_EVENT 处理感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30713399/

相关文章:

c# - 覆盖控制台关闭

c - C中的二进制搜索实现

c - 多个线程调用同一个 rand() 函数,如何让它们调用自己的 rand() 函数实例?

c++ - 如何处理: redeclaration of C++ built-in type ‘char16_t’

windows - RegDeleteKey 和 RegDeleteKeyEx

c++ - 在 windows xp 中获取所有已注册的 usb hid 设备的列表

c++ - 如何在控制台应用程序中使用 GetMessage() 使用 Windows API 识别 C++ 中的键盘输入?

c - Project Euler Number 160 - C 语言尝试

c++ - 以编程方式更改组合框

javascript - 在javascript中设置输出颜色