0

I am trying to mimic what the following command line in QProcess, but I do not know how to pass/send the control-c by using QProcess. Any help would be greatly appreciated:

NOTE: Can't use QProcess.kill(), QProcess.terminate()

#!/usr/bin/python

import sys, time


def main(argv):
   print ('enter main')
   time.sleep(20)
   print ('exit main')

if __name__ == "__main__":
   main(sys.argv[1:]) 

The command line looks like this with control-c hit -

C:\>python tt.py
enter main
Traceback (most recent call last):
  File "tt.py", line 12, in <module>
    main(sys.argv[1:])
  File "tt.py", line 8, in main
    time.sleep(20)
KeyboardInterrupt

C:\>
cnm
  • 113
  • 11

1 Answers1

0

Let's try to implement a solution based on this answer. The current process's console is preserved in a dummy helper process. This isn't ideal.

Ideally, we'd want to follow this answer, create a helper process in its own process group, and have it launch the desired process - so that the GenerateConsoleCtrlEvent can signal the target process directly without messing with the current console. Alas, this would require support of QProcess:: setCreateProcessArgumentsModifier in PyQt5 - and that's not available yet :(

One option would be to generate a C++ helper process that does that.

import win32console, win32process, win32api, win32con

def signalCtrl(qProcess, ctrlEvent=None)
  if ctrlEvent is None:
    ctrlEvent = win32con.CTRL_C_EVENT

  has_console=False
  try:
    win32console.AllocConsole()
  except win32api.error:
    has_console=True

  if !has_console:
    # free the dummy console
    try:
      win32console.FreeConsole()
    except win32api.error:
      return False

  if has_console:
    # preserve the console in a dummy process
    try:
      hProc, _, pid, _ = win32process.CreateProcess(
        None, "cmd.exe", None, None, True, win32con.DETACHED_PROCESS, 
        None, 'c:\\', win32process.STARTUPINFO())
      win32console.FreeConsole()
    except win32api.error:
      return False

  try:
    # attach to the process's console and generate the event
    win32console.AttachConsole(qProcess.processId())
    # Add a fake Ctrl-C handler for avoid instant kill is this console
    win32api.SetConsoleCtrlHandler(lambda x: True, True)
    win32console.GenerateConsoleCtrlEvent(ctrlEvent, 0)
    win32console.FreeConsole()
  except win32api.error:
    return False

  if !has_console:
    # we have no console to restore
    return True

  try:
    # attach to the dummy process's console and end the process
    win32console.AttachConsole(pid)
    win32process.TerminateProcess(hProc, 1)
  except win32api.error:
    return False

  return True

This is very much untested.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313