(всеми означают, действительно повторно отмечают с соответствующей технологией: Я не знаю, которые они :)
Я, вероятно, приеду позже с более подробными вопросами об определенных деталях, но на данный момент я пытаюсь схватить "большое изображение": я ищу способ перечислить "реальные видимые окна" в 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 во временный файл каждый раз на экране существует изменение окна, какой длины такая программа была бы приблизительно на предпочтительном языке и сколько времени необходимо будет записать это?
(еще раз я пытаюсь заставить "большое изображение" понимать то, что работает здесь),
Для перечисления окон верхнего уровня следует использовать 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 для следующего и предыдущего значений и проверить, что они согласованы и являются действительными дескрипторами окна.
можно ли это сделать?
Да, хотя вам нужно зарегистрировать хук , чтобы получить то, что вы хотите в отношении обратного вызова. Возможно, вам потребуется использовать перехватчик обратного вызова CBTProc , который вызывается всякий раз, когда:
активирует, создает, уничтожает, минимизирует, максимизирует, перемещает или изменяет размер окна; перед выполнением системной команды; перед удалением события мыши или клавиатуры из очереди системных сообщений; перед установкой фокуса клавиатуры; или перед синхронизацией с системной очередью сообщений
Обратите внимание, однако, что я не верю, что такие хуки работают в окнах консоли, потому что они являются доменом ядра, а не Win32.
Существуют ли хорошо документированные API-интерфейсы Windows (и работающие в соответствии с их спецификациями), позволяющие это сделать?
Да. Вы можете использовать функции GetTopWindow и GetNextWindow , чтобы получить все дескрипторы окон на рабочем столе в правильном Z-порядке.
Легко ли регистрировать обратный вызов каждый раз при изменении окна? (если его размер был изменен, перемещен, перенесен на задний / передний план или появилось новое окно, и т. д.)
См. первый ответ:)
Какие будут ошибки?
См. первый ответ :)
Дополнительный вопрос: представьте, что вам нужно написать крошечный.exe записывает имена / положение / размер окон во временный файл каждый раз, когда происходит изменение окна на экране, как долго такая программа будет примерно на выбранном вами языке и сколько времени вам потребуется для ее написания?
Несколько сотен строки C и пару часов. Хотя мне пришлось бы использовать какую-то форму опроса - я никогда раньше не делал хуков. Если бы мне понадобились крючки, это заняло бы немного больше времени.
Я помню, что в 2006 году в составе sysinternals была утилита WinObj, которая, возможно, делала то, что вы хотите. Часть этих утилит была предоставлена с исходным кодом автором (Марком Руссиновичем).
С тех пор его компания была куплена Microsoft, поэтому я не знаю, доступны ли еще исходники.
Также стоит проверить следующее:
http://msdn.microsoft.com/en-us/library/aa264396(VS.60).aspx