[python-win32] Global Window Messages

Tim Roberts timr at probo.com
Mon Jan 21 20:17:23 CET 2008


Rickey, Kyle W wrote:
>
> I’m not sure if this is the right place to ask, but here goes. I would 
> like to monitor system wide window messages to see when windows are 
> created/destroyed. The reason being I am writing a small app that will 
> reposition windows automatically. I thought of a couple of different 
> approaches.
>
>  
>
> First:
>
> In a loop: use win32gui.EnumWindows() to see what windows are 
> currently displayed and in the next iteration of the loop, see what 
> windows have changed since the last run. This somewhat worked, but 
> doesn’t catch only new windows. For example, some programs may change 
> their title bar text while they are displaying, causing some problems.
>
>  
>
> Second:
>
> Also in a loop enumerate running processes. If I see a new process 
> that I want to find windows for, act accordingly. However, this ate up 
> bunches of CPU enumerating processes over and over.
>

No, polling is not the answer.  You need a windows hook.  Note, however, 
that create and destroy are not the right things to look for; at the 
point a window is created, it isn't yet visible and doesn't have a 
location assigned. 

What you probably want is a WH_CBT hook so that you can catch 
WM_ACTIVATE and WM_DEACTIVATE.

> So then I thought there must be a way to receive a message when a new 
> window is created so I can act accordingly. After some research it 
> appears that SetWindowsHookEx is what I’m after, however it is not 
> wrapped by python-win32.
>

Right, and there's a reason for this.  When you create a windows hook, 
you are "injecting" your code into every process in the system.  If it 
is Python code, that means the Python interpreter DLL and any of the 
DLLs it requires will become part of the other processes.  Your hook 
code will be executed for every window message in the system, and that 
can be very, very expensive.

I suggest you look at the pyAA package from 
http://www.cs.unc.edu/Research/assist/.  I suspect they have enough 
stuff for you to do what you want, in their NotifyOnClose and 
NotifyOnOpen events.


> I’m not sure where to go from here though. The following runs without 
> error, but doesn’t show any messages. I know I need to setup a loop, 
> but how do I get the messages? Do I need to create a window with the 
> win32gui functions and read it’s messages? Any help would be greatly 
> appreciated.
>
>  
>
> import win32con, win32gui, ctypes
>
>  
>
> hwnd = win32gui.GetActiveWindow()
>
> msgShellHook = ctypes.windll.user32.RegisterWindowMessageA("SHELLHOOK")
>
> hShellLib = ctypes.windll.kernel32.LoadLibraryA("shell32") 
> #GetModuleHandleA also return the same value
>
> lpfnHookProc = ctypes.windll.kernel32.GetProcAddress(hShellLib, 
> "ShellHookProc")
>
> ctypes.windll.user32.RegisterShellHookWindow(hwnd)
>
> hHook = ctypes.windll.user32.SetWindowsHookExA(win32con.WH_SHELL, 
> lpfnHookProc, hShellLib, 0)
>

No, this does something that SOUNDS like what you want, but isn't.  What 
this does is tells the system to call ShellHookProc inside shell32.dll 
every time that the shell application (i.e., Explorer) is about to start 
or stop.  It doesn't call your own function, and it doesn't hook the 
right events.

-- 
Tim Roberts, timr at probo.com
Providenza & Boekelheide, Inc.



More information about the python-win32 mailing list