Skip to content

[ctypes] Enable handling logoff and shutdown Windows console events #85470

Closed

Description

@eryksun
BPO 41298
Nosy @pfmoore, @tjguk, @zware, @eryksun, @zooba

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2020-07-14.22:02:26.943>
labels = ['3.9', '3.10', 'extension-modules', 'ctypes', 'type-feature', 'library', 'OS-windows']
title = 'Enable handling logoff and shutdown Windows console events'
updated_at = <Date 2020-07-14.22:02:26.943>
user = 'https://github.com/eryksun'

bugs.python.org fields:

activity = <Date 2020-07-14.22:02:26.943>
actor = 'eryksun'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Extension Modules', 'Library (Lib)', 'Windows', 'ctypes']
creation = <Date 2020-07-14.22:02:26.943>
creator = 'eryksun'
dependencies = []
files = []
hgrepos = []
issue_num = 41298
keywords = []
message_count = 1.0
messages = ['373659']
nosy_count = 5.0
nosy_names = ['paul.moore', 'tim.golden', 'zach.ware', 'eryksun', 'steve.dower']
pr_nums = []
priority = 'normal'
resolution = None
stage = 'needs patch'
status = 'open'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue41298'
versions = ['Python 3.9', 'Python 3.10']

Linked PRs

Activity

  1. eryksun commented on Jul 14, 2020

    @eryksun
    ContributorAuthor

    A console script should be able to handle Windows console logoff and shutdown events with relatively simple ctypes code, such as the following:

        import ctypes
        kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
    
        CTRL_C_EVENT = 0
        CTRL_BREAK_EVENT = 1
        CTRL_CLOSE_EVENT = 2
        CTRL_LOGOFF_EVENT = 5
        CTRL_SHUTDOWN_EVENT = 6
    
        @ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_ulong)
        def console_ctrl_handler(event):
            if event == CTRL_SHUTDOWN_EVENT:
                return handle_shutdown()
            if event == CTRL_LOGOFF_EVENT:
                return handle_logoff()
            if event == CTRL_CLOSE_EVENT:
                return handle_close()
            if event == CTRL_BREAK_EVENT:
                return handle_break()
            if event == CTRL_C_EVENT:
                return handle_cancel()
            return False # chain to next handler
    
        if not kernel32.SetConsoleCtrlHandler(console_ctrl_handler, True):
            raise ctypes.WinError(ctypes.get_last_error())

    As of 3.9, it's not possible for python.exe to receive the above logoff and shutdown events via ctypes. In these two cases, the console doesn't even get to send a close event, so a console script cannot exit gracefully.

    The session server (csrss.exe) doesn't send the logoff and shutdown console events to python.exe because it's seen as a GUI process, which is expected to handle WM_QUERYENDSESSION and WM_ENDSESSION instead. That requires creating a hidden window and running a message loop, which is not nearly as simple as a console control handler.

    The system registers python.exe as a GUI process because user32.dll is loaded, which means the process is ready to interact with the desktop in every way, except for the final step of actually creating UI objects. In particular, loading user32.dll causes the system to extend the process and its threads with additional kernel data structures for use by win32k.sys (e.g. a message queue for each thread). It also opens handles for and connects to the session's "WinSta0" interactive window station (a container for an atom table, clipboard, and desktops) and "Default" desktop (a container for UI objects such as windows, menus, and hooks). (The process can connect to a different desktop or window station if set in the lpDesktop field of the process startup info. Also, if the process access token is for a service or batch logon, by default it connects to a non-interactive window station that's named for the logon ID. For example, the SYSTEM logon ID is 0x3e7, so a SYSTEM service or batch process gets connected to "Service-0x0-3e7$".)

    Prior to 3.9, python3x.dll loads shlwapi.dll (the lightweight shell API) to access the Windows path functions PathCanonicalizeW and PathCombineW. shlwapi.dll in turn loads user32.dll. 3.9+ is one step closer to the non-GUI goal because it no longer depends on shlwapi.dll. Instead it always uses the newer PathCchCanonicalizeEx and PathCchCombineEx functions from api-ms-win-core-path-l1-1-0.dll, which is implemented by the base API (kernelbase.dll) instead of the shell API.

    The next hurdle is extension modules, especially the _ctypes extension module, since it's needed for the console control handler. _ctypes.pyd loads ole32.dll, which in turn loads user32.dll. This is just to call ProgIDFromCLSID, which is rarely used. I see no reason that ole32.dll can't be delay loaded or just manually link to ProgIDFromCLSID on first use via GetModuleHandleW / LoadLibraryExW and GetProcAddress. I did a quick patch to implement the latter, and, since user32.dll no longer gets loaded, the console control handler is enabled for console logoff and shutdown events. So this is the minimal fix to resolve this issue in 3.9+.


    Additional modules

    winsound loads user32.dll for MessageBeep. The Beep and PlaySound functions don't require user32.dll, so winsound is still useful if it gets delay loaded.

    _ssl and _hashlib depend on libcrypto, which loads user32.dll for MessageBoxW, GetProcessWindowStation and GetUserObjectInformationW. The latter two are called in OPENSSL_isservice 1 in order to get the window station name. If StandardError isn't a valid file handle, OPENSSL_isservice determines whether an error should be reported as an event or interactively shown with a message box. user32.dll can be delay loaded for this, which, if I'm reading the source right, will never occur as long as StandardError is a valid file.

  2. transferred this issue fromon Apr 10, 2022
  3. changed the title [-]Enable handling logoff and shutdown Windows console events[/-] [+][ctypes] Enable handling logoff and shutdown Windows console events[/+] on Aug 8, 2022
  4. added a commit that references this issue on Aug 29, 2026
  5. added a commit that references this issue on Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions