我在编写程序时需要一些帮助。我只需要它在默认程序中启动一个文件,并跟踪该程序的PID(这样以后就可以关闭它)。我从这里找到了以下代码:
import psutil
import subprocess
import os
file = os.getcwd() + "\" + input()
open = subprocess.Popen(["start", "/WAIT", file], shell=True)
psutil.Process(open.pid).get_children()[0].kill()
这确实在正确的程序中打开了文件,但它与一起崩溃
IndexError: list index out of range error on the
psutil.Process(open.pid).get_children()[0].kill()
行。
如果有人知道如何实现我的要求,我们将不胜感激!感谢
首先,试着把它分解成碎片,而不是猜测大表达式中哪里出了问题。打印出open.pid
、Process(open.pid)
、Process(open.pid).get_children()
和Process(open.pid).get_children()[0]
,问题应该很明显:start
进程没有子进程。
其次,start
并不总是启动一个新流程。它为进程运行Open
命令,可以是命令字符串,也可以是OLE对象或通过shell扩展DLL调用的对象,最终可能会启动一个新进程,但它也可以执行其他操作,最常见的是在该应用程序的现有进程中打开文件。例如,如果您给它一个.docx
文件,而Word已经打开,它会要求Word的现有副本处理该文件*
*虽然在Word的现代版本中,我认为实际上是word.exe
做到了这一点,而不是依赖于旧的OLE机制,在这种情况下,这是一个糟糕的例子…
即使它确实必须开始一个新的过程,它也不一定是一个受控制的孩子;它可能会启动一个新的分离进程,然后像通过OLE找到一个进程一样进行操作。我很确定这个细节没有被记录下来,但它是有意义的(想象一下,如果你是他们,你会如何编写start
),你可以很容易地测试它:
- 使用
pskill
工具或Python中的psutil
,终止start
进程;该应用程序甚至没有注意到 - 使用您喜欢的第三方命令行工具,或者只需弹出process explorer GUI之类的东西,就可以查看谁是应用程序的父级
无论如何,如果应用程序不是start
的子级,那么通过查看start
的子级是找不到的。
此外,如果您查看start
(以及Python的os.startfile
、ShellExecute
)后面的Win32 API,请注意,在现代Windows中,它甚至不会返回进程的句柄
那么,如何做到这一点?
正如start
文档所解释的:
您可以通过文件关联运行不可执行的文件,方法是键入文件名作为命令。有关使用
assoc
和ftype
在命令脚本中创建这些关联的更多信息…
所以,看看assoc
和ftype
。您可以运行assoc
来获取文件的文件类型关联,然后使用ftype
来获取该文件类型的Open
命令的命令字符串,然后自己填写%0
等变量,然后运行它
或者,您可能已经注意到ShellExecute
文档说:
若要获取有关由于调用
ShellExecute
而启动的应用程序的信息,请使用ShellExecuteEx
。
如果您这样做,您可以在fMask
标志中设置SEE_MASK_NOCLOSEPROCESS
,并且hProcess
成员将是该进程的HINSTANCE
(但前提是启动了新进程——如果shell扩展找到了现有进程或其他什么,那么您在这里仍然会得到NULL)。然后,您可以在它上使用普通的Win32进程API,或者只获取它的pid并将其与psutil
一起使用。对于ctypes
来说,这一切都是可行的,但可能很痛苦;您可能想要使用pywin32
包装器。