_win.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. from __future__ import absolute_import
  2. import os
  3. __all__ = ["get_processtree_pids", "kill_processtree"]
  4. # psutil is painfully slow in win32. So to avoid adding big
  5. # dependencies like pywin32 a ctypes based solution is preferred
  6. # Code based on the winappdbg project http://winappdbg.sourceforge.net/
  7. # (BSD License)
  8. from ctypes import byref, sizeof, windll, Structure, WinError, POINTER
  9. from ctypes.wintypes import DWORD, c_size_t, LONG, c_char, c_void_p
  10. ERROR_NO_MORE_FILES = 18
  11. INVALID_HANDLE_VALUE = c_void_p(-1).value
  12. class PROCESSENTRY32(Structure):
  13. _fields_ = [
  14. ('dwSize', DWORD),
  15. ('cntUsage', DWORD),
  16. ('th32ProcessID', DWORD),
  17. ('th32DefaultHeapID', c_size_t),
  18. ('th32ModuleID', DWORD),
  19. ('cntThreads', DWORD),
  20. ('th32ParentProcessID', DWORD),
  21. ('pcPriClassBase', LONG),
  22. ('dwFlags', DWORD),
  23. ('szExeFile', c_char * 260),
  24. ]
  25. LPPROCESSENTRY32 = POINTER(PROCESSENTRY32)
  26. def CreateToolhelp32Snapshot(dwFlags=2, th32ProcessID=0):
  27. hSnapshot = windll.kernel32.CreateToolhelp32Snapshot(dwFlags,
  28. th32ProcessID)
  29. if hSnapshot == INVALID_HANDLE_VALUE:
  30. raise WinError()
  31. return hSnapshot
  32. def Process32First(hSnapshot):
  33. pe = PROCESSENTRY32()
  34. pe.dwSize = sizeof(PROCESSENTRY32)
  35. success = windll.kernel32.Process32First(hSnapshot, byref(pe))
  36. if not success:
  37. if windll.kernel32.GetLastError() == ERROR_NO_MORE_FILES:
  38. return None
  39. raise WinError()
  40. return pe
  41. def Process32Next(hSnapshot, pe=None):
  42. if pe is None:
  43. pe = PROCESSENTRY32()
  44. pe.dwSize = sizeof(PROCESSENTRY32)
  45. success = windll.kernel32.Process32Next(hSnapshot, byref(pe))
  46. if not success:
  47. if windll.kernel32.GetLastError() == ERROR_NO_MORE_FILES:
  48. return None
  49. raise WinError()
  50. return pe
  51. def get_all_processes_pids():
  52. """Return a dictionary with all processes pids as keys and their
  53. parents as value. Ignore processes with no parents.
  54. """
  55. h = CreateToolhelp32Snapshot()
  56. parents = {}
  57. pe = Process32First(h)
  58. while pe:
  59. if pe.th32ParentProcessID:
  60. parents[pe.th32ProcessID] = pe.th32ParentProcessID
  61. pe = Process32Next(h, pe)
  62. return parents
  63. def get_processtree_pids(pid, include_parent=True):
  64. """Return a list with all the pids of a process tree"""
  65. parents = get_all_processes_pids()
  66. all_pids = parents.keys()
  67. pids = set([pid])
  68. while True:
  69. pids_new = pids.copy()
  70. for _pid in all_pids:
  71. if parents[_pid] in pids:
  72. pids_new.add(_pid)
  73. if pids_new == pids:
  74. break
  75. pids = pids_new.copy()
  76. if not include_parent:
  77. pids.remove(pid)
  78. return list(pids)
  79. def kill_processtree(pid, signum):
  80. """Kill a process and all its descendants"""
  81. family_pids = get_processtree_pids(pid)
  82. for _pid in family_pids:
  83. os.kill(_pid, signum)