Well, first, try breaking it down into pieces instead of trying to guess where in that big expression something went wrong. Print out open.pid
, Process(open.pid)
, Process(open.pid).get_children()
, and Process(open.pid).get_children()[0]
and it should be pretty obvious what the problem is: the start
process has no children.
Second, start
doesn't always launch a new process. It runs the Open
command for a process—which can be a command string, or it can be an OLE thingy or something called via a shell extension DLL, which may end up launching a new process, but it could do something else, most commonly opening the file in an existing process for that app. If, say, you give it a .docx
file, and Word is already open, it asks the existing copy of Word to deal with the file.*
* Although in modern versions of Word, I think it's actually word.exe
that does that, rather than relying on the old OLE mechanisms, in which case that was a bad example…
And even if it does have to start a new process, it doesn't necessarily do so as a controlled child; it may launch a new detached process, then act the same as if it had found one via OLE. I'm pretty sure that detail isn't documented, but it makes sense (imagine how you'd write start
if you were them), and you can test it pretty easily:
- Using the
pskill
tool, or psutil
from within Python, kill the start
process; the app doesn't even notice.
- Use your favorite third-party command-line tool, or just pop up the process explorer GUI thingy, and see who the parent of the app is.
At any rate, if the app isn't a child of start
, you can't find it by looking at the children of start
.
Also, if you look at the Win32 API behind start
(and Python's os.startfile
, ShellExecute
, notice that in modern Windows, it doesn't even return a handle to the process.
So, how can you do this?
Well, as the start
docs explain:
You can run nonexecutable files through their file association by typing the name of the file as a command. For more information about creating these associations in a command script by using assoc
and ftype
…
So, look at assoc
and ftype
. You can run assoc
to get the file type association for your file, then use ftype
to get the command strings for the Open
command for that file type, then fill in the %0
etc. variables yourself, then run it. (If the command isn't a command string, then it's an old OLE-type program, and you can't do this—but then that's exactly the case where you might not be getting a new process in the first place…)
Alternatively, you may have noticed that the ShellExecute
docs say:
To obtain information about the application that is launched as a result of calling ShellExecute
, use ShellExecuteEx
.
If you do that, you can set the SEE_MASK_NOCLOSEPROCESS
in the fMask
flags, and the hProcess
member will be an HINSTANCE
for the process (but only if a new process was launched—if a shell extension found an existing process or whatever, you'll still get NULL here, of course). You can then use the normal Win32 process APIs on it, or just get its pid and use it with psutil
. This is all doable, but probably painful, with ctypes
; you'd probably want to use the pywin32
wrappers.