Windows: как получить список всех видимых окон?

(всеми означают, действительно повторно отмечают с соответствующей технологией: Я не знаю, которые они :)

Я, вероятно, приеду позже с более подробными вопросами об определенных деталях, но на данный момент я пытаюсь схватить "большое изображение": я ищу способ перечислить "реальные видимые окна" в Windows. "Реальным видимым окном" я подразумеваю просто что: какой пользователь назвал бы "окно". Мне нужен способ получить список всех этих видимых окон в Z-порядке.

Обратите внимание, что я должен действительно сделать это. Я уже сделал это на OS X (где это - реальная головная боль, чтобы сделать, особенно если Вы хотите поддерживать OS X 10.4, потому что OS X не имеет удобных окон API), и теперь я должен сделать это в соответствии с Windows.

Вот пример, предположите, что существует три видимых окна на экране, как это:

 +------------------------------------------+
 |                                          |
 |           +=============+                |
 |           |             |                |
 |           |    A   +--------------------------+
 |           |        |                          |
 |    C      |        |             B            |
 |           |        +--------------------------+
 |           |             |                |
 +-----------|             |----------------+
             |             |
             +-------------+

Затем я должен возвратить список как это:

 windows B is at (210,40)
 windows A is at (120,20)
 windows C is at (0,0)

Затем, если пользователь (или ОС) выявляет окно A, это становится:

 +------------------------------------------+
 |                                          |
 |           +=============+                |
 |           |             |                |
 |           |    A        |---------------------+
 |           |             |                     |
 |    C      |             |        B            |
 |           |             |---------------------+
 |           |             |                |
 +-----------|             |----------------+
             |             |
             +-------------+

И я получаю (идеально) обратный вызов, дающий мне это:

windows A is at (120,20)
windows B is at (210,40)
windows C is at (0,0)

Выполнение этого под OS X требует использования удивительно странных взломов (как передавание под мандат пользователя для включения, "Включают Доступ для вспомогательного устройства"!), но я сделал это под OS X, и это работает (под OS X, мне не удалось получить обратный вызов каждый раз, некоторые изменения окна происходят, таким образом, я опрашиваю, но я заставил это работать).

Теперь я хочу сделать это в соответствии с Windows (я действительно делаю, никакой вопрос об этом), и у меня есть несколько вопросов:

  • это может быть сделано?

  • существует ли хорошо зарегистрированный Windows APIs (и работающий согласно их спецификациям) позволяющий делать это?

  • действительно ли легко зарегистрировать обратный вызов каждый раз, окно изменяется? (если это изменено, перемещенное, принесенное для поддержания/выхожения или если новое окно открывается, и т.д.),

  • каковы глюки были бы?

Я знаю, что этот вопрос не конкретен, который является, почему я попытался описать свою проблему максимально ясно (включая хорошее ASCII-творчество, для которого Вы можете upvote это): на данный момент я смотрю на "большое изображение". Я хочу знать то, что выполнение такой вещи включает в соответствии с Windows.

Вопрос о премии: предположите, что необходимо было бы записать крошечному .exe запись окон, names/position/size во временный файл каждый раз на экране существует изменение окна, какой длины такая программа была бы приблизительно на предпочтительном языке и сколько времени необходимо будет записать это?

(еще раз я пытаюсь заставить "большое изображение" понимать то, что работает здесь),

43
задан Cyclone 8 July 2010 в 20:25
поделиться

3 ответа

Для перечисления окон верхнего уровня следует использовать EnumWindows , а не GetTopWindow / GetNextWindow, поскольку EnumWindows возвращает согласованное представление состояния окна. Вы рискуете получить противоречивую информацию (например, отчеты об удаленных окнах) или бесконечные циклы с помощью GetTopWindow / GetNextWindow, когда окна изменяют z-порядок во время итерации.

EnumWindows использует обратный вызов. При каждом вызове обратного вызова вы получаете дескриптор окна. Координаты экрана для окна можно получить, передав этот дескриптор в GetWindowRect . Ваш обратный вызов создает список позиций окон в z-порядке.

Вы можете использовать опрос и многократно строить список окон. Или вы настроили CBTHook для получения уведомлений об изменениях окон.Не все уведомления CBT приведут к изменениям порядка, положения или видимости окон верхнего уровня, поэтому разумно повторно запустить EnmWindows, чтобы создать новый список положений окон в z-порядке и сравнить его с предыдущим списком перед дальнейшей обработкой списка, так что дальнейшая обработка выполняется только тогда, когда произошло реальное изменение.

Обратите внимание, что с перехватом нельзя смешивать 32- и 64-разрядные версии. Если вы используете 32-битное приложение, вы будете получать уведомления от 32-битных процессов. Аналогично для 64-битной версии. Таким образом, если вы хотите контролировать всю систему на 64-битной машине, может показаться, что необходимо запустить два приложения. Мое рассуждение основано на чтении этого:

SetWindowsHookEx можно использовать для вставки DLL в другой процесс. 32-битный DLL нельзя внедрить в 64-битную процесс, а 64-битная DLL не может быть внедрен в 32-битный процесс. Если приложение требует использования крючков в других процессах требуется что вызов 32-битного приложения SetWindowsHookEx для внедрения 32-битной DLL в 32-битные процессы, а Вызов 64-битного приложения SetWindowsHookEx для внедрения 64-битной DLL в 64-битные процессы. 32-битный и 64-битные библиотеки DLL должны иметь разные имена. (Со страницы API SetWindowsHookEx.)

Когда вы реализуете это на Java, вы можете захотеть взглянуть на JNA - он значительно упрощает доступ к собственным библиотекам для записи (вызов кода на java) и устраняет необходимость в вашей собственной родной JNI DLL.

РЕДАКТИРОВАТЬ: Вы спросили, сколько это кода и сколько времени нужно писать.Вот код в 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);
        }
    }
}

. Я сделал большинство связанных классов и интерфейсов внутренними классами, чтобы пример оставался компактным и вставляемым для немедленной компиляции. В реальной реализации это были бы обычные классы верхнего уровня. Приложение командной строки распечатывает видимые окна и их положение. Я запускал его как на 32-битном jvm, так и на 64-битном, и получил одинаковые результаты для каждого.

РЕДАКТИРОВАТЬ2: Обновлен код для включения z-порядка. Он действительно использует GetNextWindow. В производственном приложении вам, вероятно, следует дважды вызвать GetNextWindow для следующего и предыдущего значений и проверить, что они согласованы и являются действительными дескрипторами окна.

27
ответ дан 26 November 2019 в 23:09
поделиться

можно ли это сделать?

Да, хотя вам нужно зарегистрировать хук , чтобы получить то, что вы хотите в отношении обратного вызова. Возможно, вам потребуется использовать перехватчик обратного вызова CBTProc , который вызывается всякий раз, когда:

активирует, создает, уничтожает, минимизирует, максимизирует, перемещает или изменяет размер окна; перед выполнением системной команды; перед удалением события мыши или клавиатуры из очереди системных сообщений; перед установкой фокуса клавиатуры; или перед синхронизацией с системной очередью сообщений

Обратите внимание, однако, что я не верю, что такие хуки работают в окнах консоли, потому что они являются доменом ядра, а не Win32.

Существуют ли хорошо документированные API-интерфейсы Windows (и работающие в соответствии с их спецификациями), позволяющие это сделать?

Да. Вы можете использовать функции GetTopWindow и GetNextWindow , чтобы получить все дескрипторы окон на рабочем столе в правильном Z-порядке.

Легко ли регистрировать обратный вызов каждый раз при изменении окна? (если его размер был изменен, перемещен, перенесен на задний / передний план или появилось новое окно, и т. д.)

См. первый ответ:)

Какие будут ошибки?

См. первый ответ :)

Дополнительный вопрос: представьте, что вам нужно написать крошечный.exe записывает имена / положение / размер окон во временный файл каждый раз, когда происходит изменение окна на экране, как долго такая программа будет примерно на выбранном вами языке и сколько времени вам потребуется для ее написания?

Несколько сотен строки C и пару часов. Хотя мне пришлось бы использовать какую-то форму опроса - я никогда раньше не делал хуков. Если бы мне понадобились крючки, это заняло бы немного больше времени.

7
ответ дан 26 November 2019 в 23:09
поделиться

Я помню, что в 2006 году в составе sysinternals была утилита WinObj, которая, возможно, делала то, что вы хотите. Часть этих утилит была предоставлена с исходным кодом автором (Марком Руссиновичем).

С тех пор его компания была куплена Microsoft, поэтому я не знаю, доступны ли еще исходники.

Также стоит проверить следующее:

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

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

1
ответ дан 26 November 2019 в 23:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: