1

我想在 Windows 上终止 python 脚本时做点什么。

# coding:utf-8
import ctypes
import os

def set_exit_handler():
    def on_exit(event):
        print '=====exit====='

    _BOOL = ctypes.c_long
    _DWORD = ctypes.c_ulong
    _kernel32 = ctypes.windll.kernel32
    _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
    _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
    _kernel32.SetConsoleCtrlHandler.restype = _BOOL

    h = _SIGNAL_HANDLER(on_exit)
    if not _kernel32.SetConsoleCtrlHandler(h, True):
        raise ctypes.WinError()

    print 'register success'

if __name__ == '__main__':
    set_exit_handler()
    while(1):
        pass

请检查我的示例代码。它有问题。当我按 CTRL+C 或关闭 cmd 窗口时。on_exit() 将不会被执行。并且窗口弹出“python.exe 已停止工作,windows 正在检查问题的解决方案”

请在http://msdn.microsoft.com/en-us/library/windows/desktop/ms685049%28v=vs.85%29.aspx检查 windows api

在此先感谢,抱歉英语不好。

4

2 回答 2

3

您应该使用该atexit模块,它允许您在不使用操作系统特定函数调用的情况下注册退出挂钩。

于 2013-11-11T08:19:18.320 回答
3

正如@mata 建议的那样,您应该使用atexit 模块注册一个函数,以便在脚本正常退出时调用,即不是通过未处理的 Windows 异常ExitProcess,或TerminateProcess.

SetConsoleCtrlHandler如果您出于其他原因需要使用,请保留对回调的引用以防止它被垃圾收集。否则进程将崩溃(充其量)。

import ctypes
from ctypes import wintypes

_kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

def _check_bool(result, func, args):
    if not result:
        raise ctypes.WinError(ctypes.get_last_error())
    # else build final result from result, args, outmask, and 
    # inoutmask. Typically it's just result, unless you specify 
    # out/inout parameters in the prototype.
    return args

_HandlerRoutine = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.DWORD)

_kernel32.SetConsoleCtrlHandler.errcheck = _check_bool
_kernel32.SetConsoleCtrlHandler.argtypes = (_HandlerRoutine, 
                                            wintypes.BOOL)

_console_ctrl_handlers = {}

def set_console_ctrl_handler(handler):
    if handler not in _console_ctrl_handlers:
        h = _HandlerRoutine(handler)
        _kernel32.SetConsoleCtrlHandler(h, True)
        _console_ctrl_handlers[handler] = h

您还需要一个unset_console_ctrl_handler功能。


仅供参考,控制台不是“cmd”窗口。cmd.exe 是一个控制台用户界面 (CUI) 程序,通常是%COMSPEC%命令解释器。在这方面,它与 powershell.exe 或 python.exe 或任何其他控制台应用程序没有什么不同。

StandardInput控制台窗口使用、StandardOutput和实现与传统标准 I/O 兼容的字符界面StandardError。还有一个功能 API(与终端控制序列相反)来创建更精细的文本界面。控制台缓冲区中的每个 UCS-2 字符都具有颜色和强度等属性。

在 NT 6.1 之前,每个控制台都由系统服务器进程 csrss.exe 中的一个线程托管。在 NT 6.1+ 中,每个控制台窗口都托管在 conhost.exe 的实例中,这更安全,因为它不是系统进程,并且它为每个控制台窗口提供了单独的进程和安全上下文。在 NT 6.3 之前,进程通过 Windows 本地过程调用 (LPC) 与其(一个也是唯一一个)连接的控制台进行通信。在 NT 6.3+ 中,它改为使用 ConDrv 设备驱动程序。多个进程可以共享同一个控制台窗口。

扩展名为 .pyw 的脚本与 pythonw.exe 相关联,后者构建为不继承或创建控制台窗口的窗口应用程序。AllocConsole如果您在这种情况下需要控制台,您可以使用 ctypes 调用或分配一个新控制台或附加到现有控制台AttachConsole

于 2013-11-11T13:34:16.113 回答