Sending ^C to Python subprocess objects on Windows

前端 未结 6 1222
离开以前
离开以前 2020-12-07 19:06

I have a test harness (written in Python) that needs to shut down the program under test (written in C) by sending it ^C. On Unix,

proc.send_sign         


        
6条回答
  •  悲&欢浪女
    2020-12-07 19:54

    I have a single file solution with the following advantages: - No external libraries. (Other than ctypes) - Doesn't require the process to be opened in a specific way.

    The solution is adapted from this stack overflow post, but I think it's much more elegant in python.

    import os
    import signal
    import subprocess
    import sys
    import time
    
    # Terminates a Windows console app sending Ctrl-C
    def terminateConsole(processId: int, timeout: int = None) -> bool:
        currentFilePath = os.path.abspath(__file__)
        # Call the below code in a separate process. This is necessary due to the FreeConsole call.
        try:
            code = subprocess.call('{} {} {}'.format(sys.executable, currentFilePath, processId), timeout=timeout)
            if code == 0: return True
        except subprocess.TimeoutExpired:
            pass
    
        # Backup plan
        subprocess.call('taskkill /F /PID {}'.format(processId))
    
    
    if __name__ == '__main__':
        pid = int(sys.argv[1])
    
        import ctypes
        kernel = ctypes.windll.kernel32
    
        r = kernel.FreeConsole()
        if r == 0: exit(-1)
        r = kernel.AttachConsole(pid)
        if r == 0: exit(-1)
        r = kernel.SetConsoleCtrlHandler(None, True)
        if r == 0: exit(-1)
        r = kernel.GenerateConsoleCtrlEvent(0, 0)
        if r == 0: exit(-1)
        r = kernel.FreeConsole()
        if r == 0: exit(-1)
    
        # use tasklist to wait while the process is still alive.
        while True:
            time.sleep(1)
            # We pass in stdin as PIPE because there currently is no Console, and stdin is currently invalid.
            searchOutput: bytes = subprocess.check_output('tasklist /FI "PID eq {}"'.format(pid), stdin=subprocess.PIPE)
            if str(pid) not in searchOutput.decode(): break;
    
        # The following two commands are not needed since we're about to close this script.
        # You can leave them here if you want to do more console operations.
        r = kernel.SetConsoleCtrlHandler(None, False)
        if r == 0: exit(-1)
        r = kernel.AllocConsole()
        if r == 0: exit(-1)
    
        exit(0)
    

提交回复
热议问题