Python / Windows / ctypes:如何在调用WaitForMultipleObjects之后获取进程返回状态?

Python/Windows/ctypes: How to get process return status after calling WaitForMultipleObjects?

我和这个人有相同的用例,我真的很喜欢这个答案,除了我有一个额外的要求:我需要从子进程中获取返回状态。

这是我尝试修改他的程序的尝试。我是Windows-land和Python ctypes的旅行者,所以希望我没有做任何愚蠢的事情...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import ctypes, subprocess
from random import randint
import os
SYNCHRONIZE=0x00100000
PROCESS_QUERY_INFORMATION=0x0400
INFINITE = -1
numprocs = 5
handles = {}

class Err(BaseException): pass

for i in xrange(numprocs):
    sleeptime = randint(5,10)
    p = subprocess.Popen([r"c:\\MinGW\\msys\\1.0\\bin\\sleep.exe", str(sleeptime)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
    h = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, False, p.pid)
    handles[h] = p.pid
    print"Spawned Process %d" % p.pid

while len(handles) > 0:
    print"Waiting for %d children..." % len(handles)
    arrtype = ctypes.c_long * len(handles)
    handle_array = arrtype(*handles.keys())
    ret = ctypes.windll.kernel32.WaitForMultipleObjects(len(handle_array), handle_array, False, INFINITE)
    h = handle_array[ret]
    print"Process %d done" % handles[h]
    i = ctypes.c_int(0)
    pi = ctypes.pointer(i)
    if ctypes.windll.kernel32.GetExitCodeProcess(h, pi) == 0:
    err = ctypes.windll.kernel32.GetLastError()
        raise Err("GetExitCodeProcess: %d" % (err))
    print"Status code is: %d" % (i)
    if ctypes.windll.kernel32.CloseHandle(h) == 0:
    err = ctypes.windll.kernel32.GetLastError()
    raise Err("CloseHandle: %d" % (err))
    del handles[h]
print"All done!

但是当我运行它时,我失败了:

1
2
3
4
Traceback (most recent call last):
  File"test.py", line 30, in <module>
    raise Err("GetExitCodeProcess: %d" % (err))
__main__.Err: GetExitCodeProcess: 6

似乎错误6是ERROR_INVALID_HANDLE。但是我不确定为什么手柄无效。我请求了PROCESS_QUERY_INFORMATION权限,并且如果我注释了GetExitCodeProcess()调用,则CloseHandle()调用可以正常工作。

有什么想法吗?等待一堆进程后如何获取状态码?


使用此确切的Python代码(与您相同的只是一些缩进已修复,并删除了sleep.exe的路径):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import ctypes, subprocess
from random import randint
import os
SYNCHRONIZE=0x00100000
PROCESS_QUERY_INFORMATION=0x0400
INFINITE = -1
numprocs = 5
handles = {}

class Err(BaseException): pass

for i in xrange(numprocs):
    sleeptime = randint(5,10)
    p = subprocess.Popen([r"sleep.exe", str(sleeptime)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
    h = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, False, p.pid)
    handles[h] = p.pid
    print"Spawned Process %d" % p.pid

while len(handles) > 0:
    print"Waiting for %d children..." % len(handles)
    arrtype = ctypes.c_long * len(handles)
    handle_array = arrtype(*handles.keys())
    ret = ctypes.windll.kernel32.WaitForMultipleObjects(len(handle_array), handle_array, False, INFINITE)
    h = handle_array[ret]
    print"Process %d done" % handles[h]
    i = ctypes.c_int(0)
    pi = ctypes.pointer(i)
    if ctypes.windll.kernel32.GetExitCodeProcess(h, pi) == 0:
        err = ctypes.windll.kernel32.GetLastError()
        raise Err("GetExitCodeProcess: %d" % (err))
    print"Status code is: %d" % i.value
    if ctypes.windll.kernel32.CloseHandle(h) == 0:
        err = ctypes.windll.kernel32.GetLastError()
        raise Err("CloseHandle: %d" % (err))
    del handles[h]

print"All done!"

给出以下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
C:\\tmp\\pyt>python -V
Python 2.7.3

C:\\tmp\\pyt>python a.py
Spawned Process 4368
Spawned Process 268
Spawned Process 5792
Spawned Process 4744
Spawned Process 4484
Waiting for 5 children...
Process 5792 done
Status code is: 0
Waiting for 4 children...
Process 4484 done
Status code is: 0
Waiting for 3 children...
Process 268 done
Status code is: 0
Waiting for 2 children...
Process 4368 done
Status code is: 0
Waiting for 1 children...
Process 4744 done
Status code is: 0
All done!

因此它似乎正在工作。您的问题不是在其他地方吗?您正在使用什么操作系统(Vista是我的操作系统)?您是否拥有最新版本的Python(2.7.3)?您的\\" sleep.exe \\"是否以某种方式损坏了?您是否尝试了其他命令?