Чтение онлайн

на главную - закладки

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

 WndPID: Cardinal;

begin

 Result := True;

 // Здесь отсеиваются окна, которые не принадлежат

 // выбранному процессу

 GetWindowThreadProcessID(Wnd, @WndPID);

 if WndPID = PIDNeeded then

 begin

TextLen := GetWindowTextLength(Wnd);

SetLength(Text, TextLen);

if TextLen > 0 then GetWindowText(Wnd, PChar(Text), TextLen + 1);

if TextLen > 100 then Text := Copy(Text, 1, 100) + '...';

GetClassName(Wnd, ClassName, ClassNameLen);

ClassName[ClassNameLen - 1] := #0;

if Text = '' then NodeName := 'Без
названия (' + ClassName + ')'

else NodeName := Text + ' (' + ClassName + ')';

NodeName := '$' + IntToHex(Wnd, 8) + ' ' + NodeName;

Node := ProcessesInfoForm.TreeWindows.Items.AddChild(nil, NodeName);

Node.Data := Pointer(Wnd);

EnumChildWindows(Wnd, @EnumWindowsProc, LParam(Node));

 end;

end;

procedure TProcessesInfoForm.FillWindowList(PID: Cardinal);

begin

 if PID = 0 then Exit;

 EnumWindows(@EnumTopWindowsProc, PID);

end;

В отличие от примера

EnumWnd
из разд. 1.2.1 здесь для функций
EnumWindows
и
EnumChildWindows
предусмотрены разные процедуры обратного вызова. Связано это с тем, что окна верхнего уровня необходимо фильтровать по принадлежности к выбранному процессу, и параметр функции обратного вызова служит для передачи PID этого процесса. А их дочерние окна фильтровать по процессам не обязательно (мы предполагаем, что если некоторое окно верхнего уровня принадлежит данному процессу, то и все его дочерние окна также принадлежат этому процессу), зато нужно передавать указатель на элемент дерева, соответствующий родительскому окну, чтобы процедура знала, где размещать новый элемент. Таким образом, смысл параметра меняется, поэтому требуется новая процедура обратного вызова. (В принципе, можно было бы проверять, есть ли у найденного окна родитель, и в зависимости от этого трактовать параметр так или иначе, используя приведение типов. Но сильно усложняет код, поэтому в учебном примере мы не будем использовать такой способ.)

Примечание

Как уже было сказано ранее, мы полагаем, что если некоторое окно верхнего уровня принадлежит данному процессу, то и все его дочерние окна также принадлежат этому процессу. В общем случае это неверно: функция

CreateWindow(Ex)
позволяет при создании нового окна использовать в качестве родительского окно другого процесса. Поэтому наш код ошибочно отнесет подобные окна к тому процессу, к которому относятся их родители, а не к тому, который их реально создал. Здесь мы пренебрегаем такой возможностью, потому что для ее учета не нужны дополнительные знания API, необходимо просто запрограммировать более сложный алгоритм отсева. В учебном примере, посвященном API, реализация такого алгоритма была бы неоправданным усложнением. но в реальных программах эту возможность следует учесть.

Для получения названия окна в приведенном коде используется функция

GetWindowText
. Эта функция безопасна при работе с зависшими приложениями, поскольку она гарантирует, что вызвавшее ее приложение не зависнет само, пытаясь получить ответ от зависшего приложения. Но
GetWindowText
не всегда может получить названия элементов управления, расположенных в окнах чужих приложений (точнее, в MSDN написано, что она вообще не может получать названия элементов управления в чужих окнах, но практика показывает, что нередко
GetWindowText
все же делает это). Существует альтернативный способ получения названия окна — отправка ему сообщения
WM_GETTEXT
. При этом ограничений на работу
с чужими элементами управления нет, но и гарантии, что из-за отсутствия ответа от чужого приложения программа не зависнет, тоже нет.

Использование

WM_GETTEXT
показано в другой части программы — при заполнении списка параметров окна, отображающегося в правом нижнем углу формы. Чтобы программа не зависала, вместо
SendMessage
для отправки
WM_GETTEXT
применяется
SendMessageTimeout
. Код получения имени показан в листинге 1.44.

Листинг 1.44. Получение заголовков "чужих" окон

if SendMessageTimeout(Wnd, WM_GETTEXTLENGTH, 0, 0,

 SMTO_NORMAL or SMTO_ABORTIFHUNG, 5000, TextLen) = 0 then

begin

 LastError := GetLastError;

 if LastError = 0 then Text := 'Приложение не отвечает'

 else

Text:= 'Ошибка при получении длины заголовка: ' + IntToStr(LastError);

end

else

begin

 SetLength(Text, TextLen);

 if TextLen > 0 then

if SendMessageTimeout(Wnd, WM_GETTEXT, TextLen + 1, LParam(Text),

SMTO_NORMAL or SMTO_ABORTIFHUNG, 5000, TextLen) = 0 then

begin

LastError := GetLastError;

if LastError = 0 then Text := 'Приложение не отвечает'

else Text := 'Ошибка при получении заголовка:' + IntToStr(LastError);

end;

end;

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

EDIT
,
COMBOBOX
и т.п.

Вообще, наследования оконных классов в Windows нет. Но существует один нехитрый прием, который позволяет имитировать наследование. Оконная процедура обычно не обрабатывает все сообщения, а передает часть их в одну из стандартных оконных процедур (

DefWindowProc
,
DefFrameProc
и т.п.). Программа может с помощью функции
GetClassInfo
узнать адрес оконной процедуры, назначенной стандартному классу, и использовать ее вместо стандартной оконной процедуры. Так как большая часть свойств окна определяется тем, как и какие сообщения оно обрабатывает, использование оконной процедуры другого класса позволяет почти полностью унаследовать свойства этого класса. (В VCL для наследования оконных классов существует метод
TWinControl.CreateSubClass
.) Функция
RealGetWindowClass
позволяет узнать имя класса-предка, если такой имеется. Соответствующая часть кода примера приведена в листинге 1.45.

Листинг 1.45. Получение реального класса окна

GetClassName(Wnd, ClassName, ClassNameLen);

ClassName[ClassNameLen - 1] := #0;

ListParams.Items[2].SubItems[0] := ClassName;

RealGetWindowClass(Wnd, ClassName, ClassNameLen);

ClassName[ClassNameLen - 1] := #0;

ListParams.Items[3].SubItems[0] := ClassName;
 

У окна, если оно имеет стиль

WS_CHILD
, должно быть родительское окно. Если такого стиля нет, то окно располагается непосредственно на рабочем столе. Кроме того, такое окно может (но не обязано) иметь владельца. Получить дескриптор родительского окна можно с помощью функции
GetParent
. Владельца — с помощью функции
GetWindow
с параметром
GW_OWNER
.

Поделиться:
Популярные книги

Долгий путь домой

Русич Антон
Вселенная EVE Online
Фантастика:
космическая фантастика
попаданцы
6.20
рейтинг книги
Долгий путь домой

Убивать чтобы жить 6

Бор Жорж
6. УЧЖ
Фантастика:
боевая фантастика
космическая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 6

Возвышение Меркурия. Книга 3

Кронос Александр
3. Меркурий
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 3

Фиктивная жена

Шагаева Наталья
1. Братья Вертинские
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Фиктивная жена

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

Барон Дубов 4

Карелин Сергей Витальевич
4. Его Дубейшество
Фантастика:
юмористическое фэнтези
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Барон Дубов 4

Лекарь для захватчика

Романова Елена
Фантастика:
попаданцы
историческое фэнтези
фэнтези
5.00
рейтинг книги
Лекарь для захватчика

Идеальный мир для Лекаря 24

Сапфир Олег
24. Лекарь
Фантастика:
городское фэнтези
попаданцы
5.00
рейтинг книги
Идеальный мир для Лекаря 24

Ваше Сиятельство 9

Моури Эрли
9. Ваше Сиятельство
Фантастика:
боевая фантастика
попаданцы
стимпанк
аниме
фэнтези
5.00
рейтинг книги
Ваше Сиятельство 9

Господин следователь

Шалашов Евгений Васильевич
1. Господин следователь
Детективы:
исторические детективы
5.00
рейтинг книги
Господин следователь

Академия проклятий. Книги 1 - 7

Звездная Елена
Академия Проклятий
Фантастика:
фэнтези
8.98
рейтинг книги
Академия проклятий. Книги 1 - 7

Полковник Гуров. Компиляция (сборник)

Макеев Алексей Викторович
Полковник Гуров
Детективы:
криминальные детективы
шпионские детективы
полицейские детективы
боевики
крутой детектив
5.00
рейтинг книги
Полковник Гуров. Компиляция (сборник)

Первый среди равных. Книга V

Бор Жорж
5. Первый среди Равных
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Первый среди равных. Книга V

Землянка для двух нагов

Софи Ирен
Фантастика:
космическая фантастика
5.00
рейтинг книги
Землянка для двух нагов