Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Hello, World!
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
 
 22:50 Geo
 
 
Во Флориде и в Королевстве сейчас  23:04[Войти] | [Зарегистрироваться]

Мечты вуайериста III

Дмитрий Богданов
дата публикации 14-11-2003 13:33

Мечты вуайериста III

Лирическое отступление или два года спустя (вполне можно пропустить)

Не ожидал, что мои графоманские экзерсисы вызовут неподдельный интерес у читающих и пишущих. К вящему моему сожалению проект работы с чужими окнами был надежно заброшен мной уже давно. Но материал был рассчитан на четыре части, а описано было только две. Сразу оговорюсь. Текст программы по здравому размышлению я не приводил и не привожу по целому ряду причин:

  1. Написано все было для Дельфи 3, но некоторые системные библиотеки не имели нужного описания (например, некоторые библиотеки тот же common controls interface unit пришлось брать из 5) и были чуть исправлены мной, вспомнить, что и где правилось, предусмотреть к чему приведет изменение этих модулей, я просто не могу. Хотя у меня вроде как работает.
  2. Программа перегружена огромным количеством интерфейсного материала (кнопочки и прочь и прочь) разобраться какие компоненты и чьи я использовал тоже занятие долгое и муторное, а как все это будет работать без интерфейсных компонент, не знаю.
  3. Программы структурирована a la Турбо Паскаль (ну пишу я так) комментарии редки и малоинформативны для всех кроме меня. Это при том, что общей объем кода составляет что-то около 4000 строк без вспомогательных юнитов. Поверьте мне на слово разбираться гораздо проще по доведенным до ума статьям, чем по таким программам.
  4. И наконец программа так и не была закончена и многие заготовки вообще неизвестно что делают и для чего задумывались. Да и передавать столь сырой текст, считаю просто не этичным.

Честное слово. Если бы выложив программу, я кому-то помог, а не погрузил бы в бездну дополнительных сложностей я бы так и сделал с самого начала. Более того, если программа будет доведена до какого-нибудь внятного финала я убедительно попрошу разместить ее исходники рядом со статьями.

Если мои объяснения вас не убедили, покорнейше прошу прощения.

А вот тут можно поставить слово "Начало".

Итак, мы разобрались с тем, что такое чужие окна. Как с ними работать и так далее. Это конечно интересно, но лично меня (да я думаю и еще многих, включая истинных вуайеристов) интересует не чужие окна как таковые, а то, что в них. Этот раздел посвящен как раз получению оконных элементов, коими являются кнопки, мемо, списки и прочие излишества. Оконные элементы так же называются дочерними окнами.

Общие слова.

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

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

Как, зная описатель окна верхнего уровня, получить все его оконные элементы ?

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

Функция FindWindowEx
Синтаксис:
function FindWindowEx(hndParent,hndChild:HWnd; ClassName,WindowName:LpctStr): HWnd;
Описание:
Находит дочернее окно принадлежащие окну с описателем hndParent с совпадающими ClassName и WindowName.
Параметры:
  • HndParent: Описатель родительского окна верхнего уровня
  • HndChild: Описатель дочернего окна с которого начинается поиск
  • ClassName: Имя класса окна (заканчивающееся пустым символом, 0 - если все классы).
  • WindowName: Текстовый заголовок окна или 0, если все окна.
Возвращаемое значение:
Описатель окна; 0 - если такого окна нет.


Простейшее получение списка элементов окна:

Procedure GetSubChild(wd:HWnD); // Передаем  в процедуру описатель окна верхнего уровня
Var Cw:HWnd;			 // Описываем еще один описатель
Begin
List1.Items.Clear;		      // Очистим список 
If WD=0 then Exit;	  	      // Если родительское окно не определено то уходим
Cw := FindWindowEx(Wd, 0, nil, nil); // Находим первый элемент произвольного класса
 while (Cw <> 0) do		     // Есть еще что искать ?
    begin
       ListBox1.Items.Add(IntToStr(Cw)); 	        // Добавим описатель в виде текста в список
       Application.ProcessMessages;                 // Дадим поработать другим
       Cw := FindWindowEx(Wd, Cw, nil, nil);       // Ищем следующие дочернее окно
     End;
End;

Итак, это сработало, но уж очень криво. В зависимости от того, с каким окном вы работали. Результатом может быть от одного найденного элемента до всех найденных элементов. В этом есть маленькая хитрость в работе с дочерними окнами. Они сами могут стать родительскими для оконных элементов. Например, на вашей форме лежит панель (TPanel) на которой, в свою очередь располагаются кнопки. В таком случае дочерним окном для формы будет являться именно панель. А кнопок приведенная выше процедура просто не найдет. Вот как все оказывается просто.

Модифицируем нашу программу, учитывая данную специфику. Для этого сделаем вызов процедуры рекурсивным

Рекурсивное получение списка элементов окна:

Procedure GetSubChild(wd:HWnD); // Передаем  в процедуру описатель окна верхнего уровня
Var Cw:HWnd;			 // Описываем еще один описатель
Begin
// Очищать список в процедуре нельзя !!!
If WD=0 then Exit;	  	      // Если родительское окно не определено то уходим
Cw := FindWindowEx(Wd, 0, nil, nil); // Находим первый элемент произвольного класса
 while (Cw <> 0) do		     // Есть еще что искать ?
    begin
       ListBox1.Items.Add(IntToStr(Cw)); 	        // Добавим описатель в виде текста в список
       Application.ProcessMessages;                         // Дадим поработать другим
       GetSubChild(Cw);			         //Вызываем себя, но родительское окно уже Cw
       Cw := FindWindowEx(Wd, Cw, nil, nil);       // Ищем следующие дочернее окно
     End;
End;

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

И как всегда существует более изящный способ получения списка оконных элементов

Функция EnumChildWindows
Синтаксис:
function EnumChildWindows(hndParent: HWnd; EnumFunc: TFarProc, lParam: Longint): Bool;
Описание:
Перечисляет все дочерние окна , передавая функции обратного вызова ( т.е объявленной как stdcall функция) описатель окна и lParam. Перечисление заканчивается, если функция обратного вызова возвращает нуль или если перечислены все окна.
Параметры:
  • HndParent: Описатель окна верхнего уровня для которого ищутся элементы
  • EnumFunc: Адpес экземпляpа пpоцедуpы функции обpатного вызова.
  • lParam: Значение, пеpеданное функции обpатного вызова.
Возвращаемое значение:
Не нуль, если пеpечислены все окна; 0 - в пpотивном случае
И опять необходима дополнительная функция для получения списка.

Правильное получение списка элементов окна:

function EnumProc (WD: HWnd; Param: LongInt): Boolean; stdcall;
Begin
List1.Items.Add(IntToStr(WD)); //Запихнули в список описатель
EnumProc:=True;
End;

procedure GetSubChild;
Begin
List1.Items.Clear;			//Очистили список
EnumChildWindows (Wd,@EnumProc, 0);       //Вызвали основную "вспомогательную" процедуру
End;

Все как обычно… классы, названия и т.п.

Вот и получен список оконных элементов для любого окна. Вернее самого списка мы так и не видим. Видим просто список описателей. Но мы уже продвинуты. Мы знаем что описатель - это все для оконного элемента. И что делать с ним, мы тоже знаем. Можем получить класс (все та же старая добрая функция GetClassName), можем узнать текст (GetWindowText). Только текстом будут совершено разные вещи. Для кнопки - название, а для большинства элементов пустая строка. Определение этих параметров все так же советую помещать непосредственно в функцию определения окна:

Получение информации об элементах окна

function EnumProc (WD: HWnd; Param: LongInt): Boolean; stdcall;
Var Nm:Array[0..255] of Char; // буфер для имени 
Cs: Array[0..255] of Char; // буфер для класса 
Begin 
GetWindowText(Wd,Nm,255); // считываем текст заголовка окна 
GetClassName(Wd,Cs,255); // считываем название класса окна 
List1.Items.Add(String(Nm)+'/'+String(Cs));  //Запихнули в список название и класс
EnumProc:=True;
End;

procedure GetSubChild;
Begin
List1.Items.Clear;			//Очистили список
EnumChildWindows (Wd,@EnumProc, 0);       //Вызвали основную "вспомогательную" процедуру
End;

Можно поэкспериментировать с определением стилей для оконных элементов, используя те же функции, которые мы использовали для определения стилей у окон верхнего уровня.

Очень полезными могут оказаться функции определяющие видимость/доступность оконного элемента (IsWindowVisible / IsWindowEnabled)

А вот то, чего не было у окон верхнего уровня, так это получения описателя родительского окна по описанию дочернего.

Функция GetParent
Синтаксис:
function IsChild(WndParent,WndChild: HWnd): Bool;
Описание:
Опpеделяет, является ли окно дочерним.
Параметры:
  • WndParent: Идентификатор окна претендующего на "отцовство".
  • WndChild: Идентификатор дочернего окна.
Возвращаемое значение:
Не нуль, если окно максимизировано; 0 - если нет.

И, наконец, несколько слов о классах.

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

Вот примерный список некоторых стандартных классов

'LISTBOX',     'COMBOBOX',    'MEMO',       'MAINMENU',
'EDIT',        'SCROLLBAR',   'BUTTON',     'LISTVIEW',
'STATIC',      'TREEVIEW',    'HEADER',     'TOOLBAR',
'STATUSBAR',   'TRACKBAR',    'UPDOWN',     'PROGRESS',
'TABCONTROL'   'RICHEDIT',    'POPUPMENU',  'CHECKBOX',
'LABEL',       'GAUGE' 

Кроме того, зачастую классы указывают на то, что имеют отношение к тому или иному стандартному классу, например класс ComboboxEx32 скорее всего имеет некоторое отношение к Combobox.

Все это достаточно важно, потому что методы работы и свойства оконных элементов зависят от типа классов.

ИТОГО

В дополнение к списку окон мы научились получать список оконных элементов. Увидели что во многом информация, получаемая для окон верхнего уровня, может быть получена и для оконных элементов. Методы работы и функции, описанные в первой части, в большинстве случаев применимы и для оконных элементов. Можете попробовать скопировать оконный элемент в Bmp, используя нашу старую функцию,… это будет работать.

Список функций
  1. FindWindowEx
  2. EnumChildWindows
  3. GetParent
  4. IsChild
Список текстов
  1. Простейшее получение списка элементов окна
  2. Рекурсивное получение списка элементов окна
  3. Правильное получение списка элементов окна
  4. Получение информации об элементах окна

Дмитрий Богданов,
Специально для Королевства Delphi






Смотрите также материалы по темам:
[Окна, оконные сообщения] [Работа с контролами чужого приложения]

 Обсуждение материала [ 12-01-2004 23:23 ] 4 сообщения
  
Время на сайте: GMT минус 5 часов

Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.

Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

 
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.

Яндекс цитирования