[Tutor] How to log process handles and GDI objects in python
eryksun
eryksun at gmail.com
Mon Feb 11 12:23:49 CET 2013
On Sun, Feb 10, 2013 at 11:25 PM, Pai, Yogesh M
<Yogesh.M.Pai at tektronix.com> wrote:
> I want to log the process threads and GDI objects (the one you see in
> the Windows task manager) in my python code- The idea is to use this
> data to generate a plot to check if the application leaks memory in a
> long run. Although I can use a third-party app to log this, is it
> possible to import certain library in python and log these windows
> attributes during the execution?
psutil can query the number of handles and threads for a Windows
process, but not GDI objects.
http://code.google.com/p/psutil
Getting the number of handles and gdi/user objects via the Win32 API
isn't too hard. Required functions:
OpenProcess
http://msdn.microsoft.com/en-us/library/ms684320
CloseHandle
http://msdn.microsoft.com/en-us/library/ms724211
GetProcessHandleCount
http://msdn.microsoft.com/en-us/library/ms683214
GetGuiResources
http://msdn.microsoft.com/en-us/library/ms683192
Here's a basic example with ctypes. In practice, set argtypes for each
function call (a TypeError is better than a segfault) and error check
the return value per the above docs. You can map the last error (i.e.
GetLastError) to an exception using ctypes.WinError.
(I haven't checked, but all of this is probably simple using pywin32.
Just search around the net for examples.)
>>> import os
>>> from ctypes import *
>>> from ctypes.wintypes import *
>>> PQI = 0x400 # PROCESS_QUERY_INFORMATION
>>> pid = os.getpid()
>>> h = windll.kernel32.OpenProcess(PQI, 0, pid)
>>> hndcnt = DWORD()
>>> windll.kernel32.GetProcessHandleCount(h, byref(hndcnt))
1
>>> hndcnt.value
72L
>>> GR_GDIOBJECTS, GR_USEROBJECTS = 0, 1
>>> windll.user32.GetGuiResources(h, GR_GDIOBJECTS)
4
>>> windll.user32.GetGuiResources(h, GR_USEROBJECTS)
1
>>> windll.kernel32.CloseHandle(h)
1
The number of threads can be found by iterating over a system snapshot
up to the desired PID. Here are the required functions and data
struct:
CreateToolhelp32Snapshot
http://msdn.microsoft.com/en-us/library/ms682489
Process32First[W]
http://msdn.microsoft.com/en-us/library/ms684834
Process32Next[W]
http://msdn.microsoft.com/en-us/library/ms684836
PROCESSENTRTY32
http://msdn.microsoft.com/en-us/library/ms684839
class PROCESSENTRY32(Structure):
_fields_ = [
('dwSize', DWORD),
('cntUsage', DWORD),
('th32ProcessID', DWORD),
('th32DefaultHeapID', c_void_p),
('th32ModuleID', DWORD),
('cntThreads', DWORD),
('th32ParentProcessID', DWORD),
('pcPriClassBase', c_long),
('dwFlags', DWORD),
('szExeFile', WCHAR * MAX_PATH),
]
def __init__(self, *args, **kwds):
Structure.__init__(self, *args, **kwds)
self.dwSize = sizeof(self)
TH32CS_SNAPPROCESS = 2
th32cs = windll.kernel32.CreateToolhelp32Snapshot
def get_num_threads(pid):
num_threads = 0
hsnap = th32cs(TH32CS_SNAPPROCESS, 0)
pe = PROCESSENTRY32()
r = windll.kernel32.Process32FirstW(hsnap, byref(pe))
while r:
if pe.th32ProcessID == pid:
num_threads = int(pe.cntThreads)
break
r = windll.kernel32.Process32NextW(hsnap, byref(pe))
windll.kernel32.CloseHandle(hsnap)
return num_threads
Example:
>>> from threading import Timer
>>> pid = os.getpid()
>>> get_num_threads(pid)
1
>>> for i in range(30): Timer(30, lambda: None).start()
>>> get_num_threads(pid)
31
More information about the Tutor
mailing list