2

This is my first post to the community, but I've been learning what I can by searching for about 2 weeks now. I seem to have hit a dead end that I can't seem to find the answer by trial and error or reading through others posts.

All I'm trying to do at this point is kill the process that is created by Popen and the shell itself. I must add that I am new to programming, and this is my first "real" world side task.

The solutions I've seen say to create a group ID, but that is for Unix and I am on windows. Popen.kill() and Popen.terminate() do not kill the children of the shell. The program started by this code does not quit, it's PID is different then the PID of the shell. I am open to suggestions as I'm using this as both a learning tool and something that will be productive. Some of the other solutions just don't kill the process. I am able to kill it by DOS and the Python Interpreter, however I have to manually look up the PID from the TASKLIST and then type it in. I need to kill it from this program.

I'm building this code to save multiple documents of a MathCad template that reads in values of excel documents, and spits out a saved document with the new file name. Thanks in advance. Please forgive any newbie coding things you may see as I'm just trying to get my feet wet.

Additional tasks tried and updates (2/26/2014):

Tried killing the programs using subprocess.call('TASKKILL ...) instead of subprocess.Popen. It does not kill the child created by the shell. Tried replacing proc = subprocess.Popen(' ....' shell=True ) with subprocess.call('....', shell=True) and the SendKeys functions no longer work. Tried the psutil function with the kill_proc_tree function and an "EOFError: [WinError 10054] An existing connection was forcibly closed by the remote host" pop up window. The child program still does not close.

If I remove the kill/terminate/close commands and just let the program run, the proc.pid is different than the os.getpid(). If I use the psutil.Process(proc.pid) - it says the process does not exist when the Python Interpreter will return its PID. If I get the MathCadPrime.exe PID = e.g. 1111 from TASKLIST and use psutil.Process(1111).parent, it shows no parents. This may be the reason why doing a TASKKILL on the shell doesn't close the children? I have posted my code exactly as I have it written to see if you gurus see something I don't.

#def kill_proc_tree(pid, including_parent=True):
#    parent = psutil.Process(pid)
#    for child in parent.get_children(recursive=True):
#        child.kill()
#    if including_parent:
#        parent.kill()

import subprocess
import win32api
import win32com.client
import time
import os
import signal
import psutil

# User files
file = "C:\Directory\SubDirectory\file.mcdx"


# Command line function
# /B /D - No command line window or explorer window    
proc = subprocess.Popen('start /B /D                                            \
        "C:\Program Files\PTC\Mathcad\Mathcad Prime 2.0\" "MathcadPrime.exe"    \
        "C:\Directory\SubDirectory\file.mcdx"', shell=True)

# Set and test for active window
    focus = False
    while (focus == False):
            focus = shell.AppActivate("MathCad Prime 2.0 - " + file)
            time.sleep(1)
            if (focus == True):
                break

# Send MathCad Prime commands
shell.SendKeys('%', 0)
time.sleep(0.5)
shell.SendKeys('c', 0)
time.sleep(0.1)
shell.SendKeys('c', 0)
time.sleep(2.0)
shell.SendKeys('%', 0)
time.sleep(0.5)
shell.SendKeys('f', 0)
time.sleep(0.1)
shell.SendKeys('s', 0)
time.sleep(4.0)



#Other methods to tried to kill children:

#Method 1:
#subprocess.call("TASKKILL /F /T /PID {pid}".format(pid=proc.pid))

#Method 2:
#subprocess.Popen("TASKKILL /F /T /PID {pid}".format(pid=proc.pid))

#Method 3:
#if (int(proc.pid) > 0):
#    os.kill(proc.pid, signal.SIGTERM)

#Method 4 (used with kill_proc_tree):
#proc1 = os.getpid()
#kill_proc_tree(proc1)
Jack of Hearts
  • 63
  • 2
  • 10
  • 1
    have you [read the docs](http://docs.python.org/2/library/subprocess.html#subprocess.Popen.terminate) on it? – mhlester Feb 25 '14 at 17:29
  • 1
    Yes. Popen.kill() and Popen.terminate() do not kill the children of the shell. The program started by this code does not quit, it's PID is different then the PID of the shell. – Jack of Hearts Feb 25 '14 at 17:35
  • do you want to kill the whole *process tree*: the shell, its children, etc? What issues do you have with your current code? – jfs Feb 25 '14 at 19:19
  • @J.F.Sebastian I've updated the question. Killing the shell and it's children would be ideal at this point, as I intend to loop this code. I just piece-wise what I can to make it work until I become more proficient with programming (I have had moderate amount of time to program in between design projects). – Jack of Hearts Feb 25 '14 at 19:32
  • related: [subprocess: deleting child processes in Windows](http://stackoverflow.com/q/1230669/4279) – jfs Feb 25 '14 at 19:34
  • what errors if any do you get when you call `TASKKILL`? – jfs Feb 25 '14 at 19:36
  • It does nothing when I run the program as you see the code above. It acts as if the last Popen code wasn't written. No errors displayed. The PID in the python interpreter for proc.pid is e.g. 1980, TASKLIST shows the child of this program as e.g. 5492. – Jack of Hearts Feb 25 '14 at 19:42
  • @J.F.Sebastian Maybe the shell is being killed, but the process that it created is not, which is ultimately what I'm wanting to close. The program does everything I want it to, except for closing. – Jack of Hearts Feb 25 '14 at 19:54
  • Does it help if you use `subprocess.call("taskkill...")` instead of `Popen()` (`call()` waits for `taskkill` to finish)? Have you tried [`psutil` solution from the link I've provided](http://stackoverflow.com/a/4229404/4279)? – jfs Feb 25 '14 at 20:01
  • I will tinker and get back with you. Thanks for the help. – Jack of Hearts Feb 25 '14 at 20:13
  • 1
    Try adding /t to taskkill, which should kill all children of the killed process as well. – Heikki Toivonen Feb 26 '14 at 00:15
  • Thanks for the response Heikki, it is in the code above, tried, and failed. – Jack of Hearts Feb 26 '14 at 02:38
  • unrelated: use raw string literal for Windows paths e.g., `r"C:\Users\natalie"`: without `r""` prefix it introduces a newline (`"\n"` escape) and `"\U"` may be interpreted as a start of Unicode escape (string literals define Unicode strings on Python 3). – jfs Feb 28 '14 at 00:04
  • @J.F.Sebastian Roger that, I actually have encountered that error before ... good points. – Jack of Hearts Feb 28 '14 at 03:37

2 Answers2

3

Thanks for all the help guys, you helped me come to a conclusion. Slightly different than suggested, but gets the job done every time. I'm at home, and not at work (so I'm writing this off the top of my head), but essentially all I did was write the TASKLIST to a text file and filter out just one string of code:

os.chdir('C:\Code')
subprocess.call('TASKLIST /fi "IMAGENAME eq MathcadPrime.exe" /nh /fo csv > task.txt)

Then parse out the PID:

doc = open('task.txt', 'rt')
parse = doc.read()
listing = parse.split(",")
PID = listing[1]
PID = int(PID.replace('"','').replace("'",""))
os.kill(PID, signal.SIGTERM)

I hope this may help someone else.

Jack of Hearts
  • 63
  • 2
  • 10
  • note: It kills a process named `"MathcadPrime.exe"` (an analog of `pkill processname` on Unix). It is a different problem from killing a process tree. What do you do if `MathcadPrime.exe` also leaves child processes behind if it is killed? – jfs Feb 28 '14 at 00:07
  • @J.F.Sebastian Good question J.F., for that I do not know. I don't believe that Mathcad spawning any other processes the way I'm using it. It is a simple open, do a couple of processes, and then save/close. I'm definitely open to solutions to make the code tighter. I would have tried killing the whole process tree, but I didn't know how to get around the problems I posted up earlier. – Jack of Hearts Feb 28 '14 at 03:36
  • 1
    [`psutil`-based solution](http://stackoverflow.com/questions/22021701/kill-the-popen-child-process?noredirect=1#comment33387964_22021701) should work. – jfs Feb 28 '14 at 04:45
  • Tasklist is not available on all versions of windows. – Marichyasana Mar 24 '14 at 02:38
2

I tried following code and it's working for me:

import subprocess
import os,signal
proc = subprocess.Popen('dir /S', shell=True)
if (int(proc.pid) > 0):
    print "killing ",proc.pid
    print os.kill(proc.pid, signal.SIGTERM)

Also what i have observed is that, if the launched program from Popen responds to "Ctrl+C", you can use signal.CTRL_C_EVENT to close the program. If launched program does not respond to the event, then it has to be closed manually. I think, my above code works because cmd.exe responds to the event.

venpa
  • 4,268
  • 21
  • 23
  • I'm getting "[WinError5] Access is denied" error. Not sure if it is with my company's administrative rights or something else. I'll have to do more research and get back with you, i'll try it at home to tell me for sure about the admin rights. – Jack of Hearts Feb 25 '14 at 19:16
  • You could also try SIGKILL. You can determine whether your user account is privileged by trying to kill the process outside of python. – amos Feb 25 '14 at 23:40