10

I want to get the handle of every new Dialog which pops up from a specific application.
I understand I should set a hook with SetWinEventHook which is in user32.dll in windows, but I don't know how to do that in python. Would you give me an example ?

kissgyorgy
  • 2,947
  • 2
  • 32
  • 54
  • You might find the [pyHook](http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=Main_Page) python wrapper useful. – martineau Apr 06 '13 at 12:44
  • it is only useful for mouse and keyboard events and the main logic is hidden in a .pyd file :( – kissgyorgy Apr 06 '13 at 23:39
  • 1
    PyHook is open-source, so you can look at the source code for an example. There are others out there, like [pyconsole](http://code.google.com/p/pyconsole/source/browse/trunk/pyconsole.py?r=5) you can also look at, just use [Google](https://www.google.com/search?hl=en&as_q=python&as_epq=SetWinEventHook&as_oq=&as_eq=&as_nlo=&as_nhi=&lr=&cr=&as_qdr=all&as_sitesearch=&as_occt=any&safe=images&tbs=&as_filetype=&as_rights=). Unless you write or use a C extension module, you're likely going to need to learn about and use several of the built-in `win32xxx` modules and `ctypes.windll.user32`. – martineau Apr 07 '13 at 17:19

1 Answers1

13

Here's a very simple example that prints to the console the window text for each dialog that is opened:

import sys
import time
import ctypes
import ctypes.wintypes

EVENT_SYSTEM_DIALOGSTART = 0x0010
WINEVENT_OUTOFCONTEXT = 0x0000

user32 = ctypes.windll.user32
ole32 = ctypes.windll.ole32

ole32.CoInitialize(0)

WinEventProcType = ctypes.WINFUNCTYPE(
    None, 
    ctypes.wintypes.HANDLE,
    ctypes.wintypes.DWORD,
    ctypes.wintypes.HWND,
    ctypes.wintypes.LONG,
    ctypes.wintypes.LONG,
    ctypes.wintypes.DWORD,
    ctypes.wintypes.DWORD
)

def callback(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime):
    length = user32.GetWindowTextLengthA(hwnd)
    buff = ctypes.create_string_buffer(length + 1)
    user32.GetWindowTextA(hwnd, buff, length + 1)
    print buff.value

WinEventProc = WinEventProcType(callback)

user32.SetWinEventHook.restype = ctypes.wintypes.HANDLE
hook = user32.SetWinEventHook(
    EVENT_SYSTEM_DIALOGSTART,
    EVENT_SYSTEM_DIALOGSTART,
    0,
    WinEventProc,
    0,
    0,
    WINEVENT_OUTOFCONTEXT
)
if hook == 0:
    print 'SetWinEventHook failed'
    sys.exit(1)

msg = ctypes.wintypes.MSG()
while user32.GetMessageW(ctypes.byref(msg), 0, 0, 0) != 0:
    user32.TranslateMessageW(msg)
    user32.DispatchMessageW(msg)

user32.UnhookWinEvent(hook)
ole32.CoUninitialize()
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • nice and clean! Thank you ! One last question: what happens if I don't `UnhookWinEvent` (for example, my app crashes or something) – kissgyorgy Apr 09 '13 at 12:08
  • 1
    The system will clean it up for you. If you need the hook to be active for the entire duration of the process, then you don't need to bother calling `UnhookWinEvent` or `CoUninitialize`. – David Heffernan Apr 09 '13 at 12:09
  • Thank you very much ! Very satisfying answer! – kissgyorgy Apr 09 '13 at 12:12
  • 1
    Can this be used to monitor every window of all programs? – HellOfACode Apr 08 '15 at 06:18
  • 1
    @HellOfACode Replace EVENT_SYSTEM_DIALOGSTART, with EVENT_OBJECT_FOCUS where EVENT_OBJECT_FOCUS = 0x8005. – Carel Aug 02 '15 at 15:24
  • 1
    See [here](https://msdn.microsoft.com/en-us/library/windows/desktop/dd318066(v=vs.85).aspx) for various values for the min/max arguments. – Carel Aug 02 '15 at 16:18
  • is there a way to listen for hotkeys, specifically Ctrl+C in order to kill the console? – faustus Mar 16 '22 at 11:40