117 ('srWindow', _SMALL_RECT), |
117 ('srWindow', _SMALL_RECT), |
118 ('dwMaximumWindowSize', _COORD)] |
118 ('dwMaximumWindowSize', _COORD)] |
119 |
119 |
120 _STD_ERROR_HANDLE = _DWORD(-12).value |
120 _STD_ERROR_HANDLE = _DWORD(-12).value |
121 |
121 |
|
122 # CreateToolhelp32Snapshot, Process32First, Process32Next |
|
123 _TH32CS_SNAPPROCESS = 0x00000002 |
|
124 _MAX_PATH = 260 |
|
125 |
|
126 class _tagPROCESSENTRY32(ctypes.Structure): |
|
127 _fields_ = [('dwsize', _DWORD), |
|
128 ('cntUsage', _DWORD), |
|
129 ('th32ProcessID', _DWORD), |
|
130 ('th32DefaultHeapID', ctypes.c_void_p), |
|
131 ('th32ModuleID', _DWORD), |
|
132 ('cntThreads', _DWORD), |
|
133 ('th32ParentProcessID', _DWORD), |
|
134 ('pcPriClassBase', _LONG), |
|
135 ('dwFlags', _DWORD), |
|
136 ('szExeFile', ctypes.c_char * _MAX_PATH)] |
|
137 |
|
138 def __init__(self): |
|
139 super(_tagPROCESSENTRY32, self).__init__() |
|
140 self.dwsize = ctypes.sizeof(self) |
|
141 |
|
142 |
122 # types of parameters of C functions used (required by pypy) |
143 # types of parameters of C functions used (required by pypy) |
123 |
144 |
124 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p, |
145 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p, |
125 _DWORD, _DWORD, _HANDLE] |
146 _DWORD, _DWORD, _HANDLE] |
126 _kernel32.CreateFileA.restype = _HANDLE |
147 _kernel32.CreateFileA.restype = _HANDLE |
183 _user32.ShowWindow.restype = _BOOL |
204 _user32.ShowWindow.restype = _BOOL |
184 |
205 |
185 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM) |
206 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM) |
186 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM] |
207 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM] |
187 _user32.EnumWindows.restype = _BOOL |
208 _user32.EnumWindows.restype = _BOOL |
|
209 |
|
210 _kernel32.CreateToolhelp32Snapshot.argtypes = [_DWORD, _DWORD] |
|
211 _kernel32.CreateToolhelp32Snapshot.restype = _BOOL |
|
212 |
|
213 _kernel32.Process32First.argtypes = [_HANDLE, ctypes.c_void_p] |
|
214 _kernel32.Process32First.restype = _BOOL |
|
215 |
|
216 _kernel32.Process32Next.argtypes = [_HANDLE, ctypes.c_void_p] |
|
217 _kernel32.Process32Next.restype = _BOOL |
188 |
218 |
189 def _raiseoserror(name): |
219 def _raiseoserror(name): |
190 err = ctypes.WinError() |
220 err = ctypes.WinError() |
191 raise OSError(err.errno, '%s: %s' % (name, err.strerror)) |
221 raise OSError(err.errno, '%s: %s' % (name, err.strerror)) |
192 |
222 |
307 screenbuf, ctypes.byref(csbi)): |
337 screenbuf, ctypes.byref(csbi)): |
308 return width |
338 return width |
309 width = csbi.srWindow.Right - csbi.srWindow.Left |
339 width = csbi.srWindow.Right - csbi.srWindow.Left |
310 return width |
340 return width |
311 |
341 |
|
342 def _1stchild(pid): |
|
343 '''return the 1st found child of the given pid |
|
344 |
|
345 None is returned when no child is found''' |
|
346 pe = _tagPROCESSENTRY32() |
|
347 |
|
348 # create handle to list all processes |
|
349 ph = _kernel32.CreateToolhelp32Snapshot(_TH32CS_SNAPPROCESS, 0) |
|
350 if ph == _INVALID_HANDLE_VALUE: |
|
351 raise ctypes.WinError |
|
352 try: |
|
353 r = _kernel32.Process32First(ph, ctypes.byref(pe)) |
|
354 # loop over all processes |
|
355 while r: |
|
356 if pe.th32ParentProcessID == pid: |
|
357 # return first child found |
|
358 return pe.th32ProcessID |
|
359 r = _kernel32.Process32Next(ph, ctypes.byref(pe)) |
|
360 finally: |
|
361 _kernel32.CloseHandle(ph) |
|
362 if _kernel32.GetLastError() != _ERROR_NO_MORE_FILES: |
|
363 raise ctypes.WinError |
|
364 return None # no child found |
|
365 |
|
366 class _tochildpid(int): # pid is _DWORD, which always matches in an int |
|
367 '''helper for spawndetached, returns the child pid on conversion to string |
|
368 |
|
369 Does not resolve the child pid immediately because the child may not yet be |
|
370 started. |
|
371 ''' |
|
372 def childpid(self): |
|
373 '''returns the child pid of the first found child of the process |
|
374 with this pid''' |
|
375 return _1stchild(self) |
|
376 def __str__(self): |
|
377 # run when the pid is written to the file |
|
378 ppid = self.childpid() |
|
379 if ppid is None: |
|
380 # race, child has exited since check |
|
381 # fall back to this pid. Its process will also have disappeared, |
|
382 # raising the same error type later as when the child pid would |
|
383 # be returned. |
|
384 return " %d" % self |
|
385 return str(ppid) |
|
386 |
312 def spawndetached(args): |
387 def spawndetached(args): |
313 # No standard library function really spawns a fully detached |
388 # No standard library function really spawns a fully detached |
314 # process under win32 because they allocate pipes or other objects |
389 # process under win32 because they allocate pipes or other objects |
315 # to handle standard streams communications. Passing these objects |
390 # to handle standard streams communications. Passing these objects |
316 # to the child process requires handle inheritance to be enabled |
391 # to the child process requires handle inheritance to be enabled |
337 None, args, None, None, False, _CREATE_NO_WINDOW, |
412 None, args, None, None, False, _CREATE_NO_WINDOW, |
338 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi)) |
413 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi)) |
339 if not res: |
414 if not res: |
340 raise ctypes.WinError |
415 raise ctypes.WinError |
341 |
416 |
342 return pi.dwProcessId |
417 # _tochildpid because the process is the child of COMSPEC |
|
418 return _tochildpid(pi.dwProcessId) |
343 |
419 |
344 def unlink(f): |
420 def unlink(f): |
345 '''try to implement POSIX' unlink semantics on Windows''' |
421 '''try to implement POSIX' unlink semantics on Windows''' |
346 |
422 |
347 if os.path.isdir(f): |
423 if os.path.isdir(f): |