We are starting a tool process using the subprocess.popen
. To stop the tool we are sending ctrl+c
signal so that the tool catches this & does the required clean up & report generation. It is working fine with python / pyinstaller with console.
But not working with pythonw / pyinstaller no console. It is failing with below exception
OSError: [WinError 6] The handle is invalid
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "E:\workspace\git\ABATA-Agent\t1.py", line 59, in <module>
out, err = process.communicate()
File "C:\Program Files\Python311\Lib\subprocess.py", line 1661, in send_signal
os.kill(self.pid, signal.CTRL_BREAK_EVENT)
SystemError: <built-in function kill> returned a result with an exception set
Below is the standalone script to reproduce this issue with pythonw
import logging
import shlex
import signal
import subprocess
import time
import psutil
logging.basicConfig(
filename="pyw_log.txt",
filemode="a",
format="%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s",
datefmt="%Y-%m-%d:%H:%M:%S",
level=logging.DEBUG,
)
logger = logging.getLogger(__name__)
logger.debug(f"===================================================================")
def process_tree(parent_pid):
parent_process = psutil.Process(parent_pid)
for i, child_process in enumerate(parent_process.children(recursive=True)):
logger.debug(f"Child PID: {child_process.pid}, cmd: {child_process.cmdline()}")
print(f"Child PID: {child_process.pid}, cmd: {child_process.cmdline()}")
try:
startup_info = subprocess.STARTUPINFO()
startup_info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
creation_flags = subprocess.CREATE_NEW_PROCESS_GROUP
cmd_line = "netstat"
print(cmd_line)
logger.info(cmd_line)
cmd_line = shlex.split(cmd_line)
logger.debug(cmd_line)
with open("process_log.txt", mode="w", encoding="UTF-8") as file:
process = subprocess.Popen(
cmd_line,
stdout=file,
stderr=file,
stdin=subprocess.DEVNULL,
# shell=True, # no effect
encoding="UTF-8",
startupinfo=startup_info,
creationflags=creation_flags,
)
print(process.pid)
logger.info(process.pid)
time.sleep(2)
process_tree(process.pid)
process.send_signal(signal.CTRL_BREAK_EVENT)
out, err = process.communicate()
logger.debug(f"Ret code: {process.returncode}")
logger.debug(f"Out: {out}")
logger.debug(f"Error: {err}")
print(f"Out: {out}")
except Exception:
logging.exception("")
# raise
finally:
process.kill() # This one doesn't raise any exception when the process already died
logger.debug("Process killed/died automatically")