#609 Python won't exit if win32ui is imported

win32 (141)
Steven T. Snyder

Environment: Windows 7 64-bit, Python 2.7.3 32-bit, PyWin32-217

This is a weird one. If you run the attached script (you'll need to manually close the file chooser), you'll find that Python does not exit when the script is done.

However, if you remove win32ui from the list of imports, the script exits just fine.

Also, if the script consists solely of "import win32gui, win32ui", it exits cleanly.

I printed a list of threads and it's just the main thread in both cases.

Another user on Stack Overflow found that this problem is reproducible by creating and destroying a GTK Window instead of opening a file chooser like I did. See: http://stackoverflow.com/questions/10467225/why-script-doesnt-quit-when-win32ui-is-imported-and-gtk-quits


  • Script which demonstrates the problem

  • Roger Upole
    Roger Upole

    I can't reproduce this. How are you launching the script ?

  • I launched the script by double-clicking on it in Windows. The Python process and console will stay open.

    Running it from the command line also works: "python test_gfrs240.py". The Python process will stay open instead of returning to the prompt.

  • I can't reproduce it on Windows 2008 Server 32-bit SP2 with a fresh install of Python 2.7.3 32-bit and PyWin32-217.

    I can't reproduce it on my laptop with Windows 7 64-bit SP1 Home Premium, Python 2.7.3 32-bit, and PyWin32-216 nor with Pywin32-217.

    Any suggestions on obtaining additional information from the hung Python instance I can reproduce on my primary workstation?

  • Mark Hammond
    Mark Hammond

    > Any suggestions on obtaining additional information from the hung Python
    > instance I can reproduce on my primary workstation?

    Only to break into it with msvc or similar debugger - and without debug symbols (ie, without having built it yourself) even that may not give many clues.

  • Stefan Schukat
    Stefan Schukat

    I reproduced the behavior on my system and the error occurs due to the windows hooking mechanism in win32ui. On shutdown a message should be processed an and since the windows hook in win32ui is still active it is called. Inside the hook function the GIL should be acquired which waits forever since Python was already shut down. See WinDbg log
    0027fb7c 750a149d 000000c8 00000000 00000000 ntdll!NtWaitForSingleObject+0x15
    0027fc54 1e108002 00000000 00000000 00000000 python27!PyThreadState_New+0xc
    0027fc64 1e2d128d 0027fd0c 0027fd0c 00000000 python27!PyGILState_Ensure+0x22
    0027fce8 75586a58 00040000 00000000 0027fd0c win32ui!Python_check_message+0x3d
    0027fd1c 75526e44 00976550 00000000 00000002 USER32!fnHkINLPCWPSTRUCTA+0x66
    0027fd58 7710010a 0027fd70 00000000 0027fdcc USER32!__fnDWORD+0x2b
    0027fd6c 00976550 00000000 00000002 00000000 ntdll!KiUserCallbackDispatcher+0x2e
    0027fddc 75155a20 3d24bba6 00496590 00000002 0x976550
    0027fe0c 77129ab1 0027dc34 7efde000 7efdd000 MSCTF!CicFlsCallback+0x98
    0027fe28 7713d608 00496580 77413563 771f20c0 ntdll!RtlProcessFlsData+0x57
    0027fec0 7713d554 02063b88 02063b84 00000001 ntdll!LdrShutdownProcess+0xbd

    The changed behavior was introduced in Rev 3266. If checking the window before acquiring the Python lock the deadlock does not occur anymore. I attached a diff which fixes this problem.

    • Thanks for looking into this Stefan! I'm glad someone else was able to reproduce it. I hope to see your fix implemented soon.

  • Hey, is there a binary distribution build with this patch? I've this problem too and I can't compile the pywin32 with the patch,

  • Stefan Schukat
    Stefan Schukat

    No, there is no version available. The only binary distributions I know are the from Mark and ActiveState and these do not contain the fix until today.

  • I came up with a temporary workaround so my processes at least will terminate when I use win32ui. This is not a good clean exit though.

    import atexit, os
    def taskkill_this():
        # kill this process
        current_pid = os.getpid()
        os.system("taskkill /pid %s /f" % current_pid)