gh-89545: Adds internal _wmi module on Windows for directly querying OS properties by zooba · Pull Request #96289 · python/cpython
It probably makes more sense to document it in
signal, which is what someone would have to use to take a reliance on the feature that loading user32 might disable.
Currently the signal module doesn't support CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, or CTRL_SHUTDOWN_EVENT. Of the three, CTRL_CLOSE_EVENT is probably the most important to support since it gets sent whether or not "user32.dll" is loaded. The C runtime maps these events to SIGBREAK, but the C signal_handler() function just sets a flag and returns. Then the system terminates the process.
These three control events could be supported if the signal module had its own control handler. Given a SIGBREAK handler is set, the control handler would call trip_signal(SIGBREAK) and wait forever, but only for the close, logoff, and shutdown events for which the process must exit. Otherwise return FALSE to have the system call the next control handler, which is probably the C runtime's control handler.
This is all for naught, however, whenever "python[w].exe" gets executed by "py[w].exe" or "venv[w]launcher.exe". The behavior of the launchers is probably worth fixing, but it's not critical. They're primarily intended for development, not deployment of applications and services.
"py[w].exe" and "venvwlauncher.exe" load "user32.dll". Since they don't create a hidden window that handles WM_QUERYENDSESSION and WM_ENDSESSION, the system immediately terminates them at logoff and shutdown. Because of the job object, the child "python[w].exe" process also gets terminated abruptly.
Also, the control handler for the launchers returns TRUE for CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT. The latter two events are only seen by "venvlauncher.exe", since it doesn't load "user32.dll". On the other hand, the control event from closing the console window or terminal tab is always seen. Returning true for these control events means the process is ready to be terminated, and the system does so immediately. Because of the job object, the child "python.exe" process also gets terminated abruptly.
A simple way to handle these cases is to remove the child process from the job object when either the session is known to be ending or the console window/tab is closing. In these cases, both the launcher and Python either have to exit on their own or eventually get terminated, so coupling them with a job object no longer matters.