A customer wanted to know whether their MFC program can determine why their window is closing, similar to how WinForms does.
The source code for WinForms is online. You can see how they do it, and then translate that to MFC.
Many of the CloseReason
values refer to actions that occurred within WinForms itself, so those are naturally generated by WinForms. Three of the reasons are external to WinForms.
UserClosing
: This is generated in response to theWM_
SYSCOMMAND
when the code isSC_
CLOSE
. This happens when the user closes the window by clicking the × in the upper right corner, or by double-clicking the system icon, or by selecting Close from the system menu.WindowsShutDown
: This is generated in response to theWM_
QUERYENDSESSION
andWM_
ENDSESSION
messages.TaskManagerClosing
: This is generated in response to theWM_
CLOSE
message, provided it wasn’t already set by someone else with better information.
The “provided it wasn’t already set by someone else with better information” is important, because many of the window closing scenarios lead to WM_
CLOSE
. For example, the default handling for the SC_
CLOSE
system menu command is to send the WM_
CLOSE
message, so you will see the SC_
CLOSE
first, followed by the WM_
CLOSE
message.
Note that TaskManagerClosing
is inferred by the fact a WM_
CLOSE
message arrives without any of the known preliminaries. While it’s true that Task Manager uses the WM_
CLOSE
message to encourage an app to exit, it’s not the only program that does it.
A better name might be External
or Programmatic
.
I’d say any program that programmatically posts quit message to apps can be thought as a task manager. BTW, WindowsShutdown is really LoggingOff, but that naming doesn’t sound as urgent as shutting down.
The problem with Task Manager’s WM_CLOSE is that, besides giving the target process more opportunity to do extra damage, it might route the target’s code through a “clean” pathway that persists the messed-up situation for future processes. Kill has to mean kill.
Also, something that gets overlooked in frameworks is a property saying if a close is already in progress.
Which is why Task Manager gives you another option: Task Manager sends WM_CLOSE when you use the Processes tab (formerly known as the Applications tab), but when you use the Details tab (formerly known as the Processes tab) or if the window’s message pump isn’t responding, it injects a thread that calls TerminateProcess(). Which really does mean kill.
I set a breakpoint at KERNELBASE!TerminateProcess in the Task Manager process on Win10 1809 and told it to end a process. The breakpoint was hit on the main thread of Task Manager. If older versions used to inject a thread to the process being killed, I’m curious why.