Windows: how to get a list of all visible windows? Windows: how to get a list of all visible windows? windows windows

Windows: how to get a list of all visible windows?


To enumerate the top-level windows, you should use EnumWindows rather than GetTopWindow/GetNextWindow, since EnumWindows returns a consistent view of the window state. You risk getting inconsistent information (such as reporting on deleted windows) or infinite loops using GetTopWindow/GetNextWindow, when windows change z-order during iteration.

The EnumWindows uses a callback. On each call of the callback you get a window handle. The screen co-ordinates of the window can be fetched by passing that handle to GetWindowRect. Your callback builds a list of the window positions in z-order.

You can use polling, and build the window list repeatedly. Or, you set up a CBTHook to receive notifications of window changes. Not all CBT notifications will result in changes to order,position or visibility of top level windows, so it's wise to rerun EnmWindows to build a new list of window positions in z-order and compare this to the previous list before processing the list further, so that futher processing is done only when a real change has occurred.

Note that with hooking, you cannot mix 32- and 64-bit. If you are running a 32-bit app, then you will get notifications from 32-bit processes. Similarly for 64-bit. Thus, if you want to monitor the entire system on a 64-bit machine, it would seem that it's necessary to run two apps. My reasoning comes from reading this:

SetWindowsHookEx can be used to inject a DLL into another process. A 32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL cannot be injected into a 32-bit process. If an application requires the use of hooks in other processes, it is required that a 32-bit application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit processes, and a 64-bit application call SetWindowsHookEx to inject a 64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have different names. (From the SetWindowsHookEx api page.)

As you're implementing this in Java, you might want to look at JNA - it makes writing access to native libraries much simpler (calling code in java) and removes the need for your own native JNI DLL.

EDIT: You asked how much code it is and how long to write. Here's the code in java

import com.sun.jna.Native;import com.sun.jna.Structure;import com.sun.jna.win32.StdCallLibrary;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;public class Main {    public static void main(String[] args) {        Main m = new Main();        final List<WindowInfo> inflList = new ArrayList<WindowInfo>();        final List<Integer> order = new ArrayList<Integer>();        int top = User32.instance.GetTopWindow(0);        while (top != 0) {            order.add(top);            top = User32.instance.GetWindow(top, User32.GW_HWNDNEXT);        }        User32.instance.EnumWindows(new WndEnumProc() {            public boolean callback(int hWnd, int lParam) {                if (User32.instance.IsWindowVisible(hWnd)) {                    RECT r = new RECT();                    User32.instance.GetWindowRect(hWnd, r);                    if (r.left > -32000) {     // If it's not minimized                        byte[] buffer = new byte[1024];                        User32.instance.GetWindowTextA(hWnd, buffer, buffer.length);                        String title = Native.toString(buffer);                        inflList.add(new WindowInfo(hWnd, r, title));                    }                }                return true;            }        }, 0);        Collections.sort(inflList, new Comparator<WindowInfo>() {            public int compare(WindowInfo o1, WindowInfo o2) {                return order.indexOf(o1.hwnd)-order.indexOf(o2.hwnd);            }        });        for (WindowInfo w : inflList) {            System.out.println(w);        }    }    public static interface WndEnumProc extends StdCallLibrary.StdCallCallback {        boolean callback(int hWnd, int lParam);    }    public static interface User32 extends StdCallLibrary {        final User32 instance = (User32) Native.loadLibrary ("user32", User32.class);        final int GW_HWNDNEXT = 2;        boolean EnumWindows(WndEnumProc wndenumproc, int lParam);        boolean IsWindowVisible(int hWnd);        int GetWindowRect(int hWnd, RECT r);        void GetWindowTextA(int hWnd, byte[] buffer, int buflen);        int GetTopWindow(int hWnd);        int GetWindow(int hWnd, int flag);    }    public static class RECT extends Structure {        public int left, top, right, bottom;    }    public static class WindowInfo {        public final int hwnd;        public final RECT rect;        public final String title;        public WindowInfo(int hwnd, RECT rect, String title) {            this.hwnd = hwnd;            this.rect = rect;            this.title = title;        }        public String toString() {            return String.format("(%d,%d)-(%d,%d) : \"%s\"",                rect.left, rect.top,                rect.right, rect.bottom,                title);        }    }}

I've made most of the related classes and interfaces inner classes to keep the example compact and pasteable for immediate compilation. In a real implementation, they would be regular top-level classes. The command line app prints out the visible windows and their position. I ran it on both 32-bit jvm and 64-bit, and got the same results for each.

EDIT2: Updated code to include z-order. It does use GetNextWindow. In a production application, you should probably call GetNextWindow twice for the next and previous values and check they are consistent and are valid window handles.


can this be done?

Yes, though you'd have to register a hook in order to get what you want with regards to a callback. You would probably need to use a CBTProc Callback Hook, which is called whenever:

activating, creating, destroying, minimizing, maximizing, moving, or sizing a window; before completing a system command; before removing a mouse or keyboard event from the system message queue; before setting the keyboard focus; or before synchronizing with the system message queue

Note however that I don't believe such hooks work on Console windows because they are the domain of the kernel, not Win32.

are there well documented Windows APIs (and working as per their specs) allowing to do that?

Yes. You can use the GetTopWindow and GetNextWindow functions to get all the window handles on the desktop in correct Z order.

is it easy to register a callback everytime a window changes? (if it is resized, moved, brought to back/front or if a new window pops-up, etc.)

See first answer :)

what would the gotchas be?

See first answer :)

Bonus question: imagine you'd need to write a tiny .exe writing the windows names/position/size to a temporary file everytime there's a window change on screen, how long would such a program be approximately in your language of choice and how long would you need to write it?

A few hundred lines of C, and a couple hours. Though I'd have to use some form of polling -- I've never done hooks before myself. If I'd need the hooks it'd take somewhat longer.


I remember back in 2006 there was a utility WinObj as part of sysinternals that possibly did what you want. Part of these utilities were provided with source code by author (Mark Russinovich).

Since that time, his company was bought by Microsoft so I do not know whether the source would be still available.

Also the following may be worth checking:

http://msdn.microsoft.com/en-us/library/aa264396(VS.60).aspx

http://www.codeproject.com/KB/dialog/windowfinder.aspx