Re: [ctypes-users] finding PID through handle with Ctypes
Brought to you by:
theller
From: eryk s. <er...@gm...> - 2017-09-25 07:48:50
|
On Sun, Sep 24, 2017 at 3:08 PM, Michael C <mys...@gm...> wrote: > I tried this, but it returns zero, is it because I need to initiate the > variable, PID, in DWORD, somehow? > > [...] > > PID = 0 > print(User32.GetWindowThreadProcessId(handle, PID)) > print(PID) The second argument, lpdwProcessId, should be a pointer to a DWORD. For example: pid = wintypes.DWORD() tid = user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid)) print(pid.value) lpdwProcessId is optional, however, and can be NULL if you don't need the process ID. The ctypes equivalent to NULL is passing None. Passing the integer 0, as you did, is undefined behavior, especially with 64-bit Python. The default conversion is to a 32-bit C int, and ctypes doesn't guarantee that the value will be cast to uintptr_t, though recent versions of Python 3 do implement this. There's a chance in Python 2 that the high DWORD will be random garbage, which may cause your program to fail with an access violation. Note that GetWindowThreadProcessId [1] tells a white lie for console applications. A console keeps track of the process and thread ID of every application that's attached to it. You can get the list of attached processes by calling GetConsoleProcessList [2]. Additionally a console stores the process and thread identifiers of its nominal owner as window data at offsets 0 and 4, respectively, which you can query by calling GetWindowLongW. When the window manager sees that you're asking for the owner of a console window, instead of returning the window's *true* owner (i.e. conhost.exe), it returns the console's *nominal* owner. For example: >>> hwnd = kernel32.GetConsoleWindow() >>> con_pid = user32.GetWindowLongW(hwnd, 0) >>> con_tid = user32.GetWindowLongW(hwnd, 4) >>> con_pid, con_tid (3556, 3948) >>> tid = user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid)) >>> (pid.value, tid) (3556, 3948) Process ID 3556 is the instance of CMD from which I ran Python. In this case, the console only has two attached processes. If I kill CMD, the console will make Python its new nominal owner. For example: Terminate CMD: >>> hp = kernel32.OpenProcess(1, 0, 3556) >>> kernel32.TerminateProcess(hp, 1) 1 Verify that the console promoted my current Python process as its owner: >>> py_pid = kernel32.GetCurrentProcessId() >>> py_tid = kernel32.GetCurrentThreadId() >>> py_pid, py_tid (4888, 3008) >>> con_pid = user32.GetWindowLongW(hwnd, 0) >>> con_tid = user32.GetWindowLongW(hwnd, 4) >>> con_pid, con_tid (4888, 3008) >>> tid = user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid)) >>> (pid.value, tid) (4888, 3008) [1]: https://msdn.microsoft.com/en-us/library/ms633522 [2]: https://docs.microsoft.com/en-us/windows/console/getconsoleprocesslist |