Delphirus - Прогулка по окнам Windows
[/] Все о delphi Delphirus - прграммирование на delphi Навигация Главная Статьи Базы данных Графика Защита Интернет Система Тексты Мультимедиа Файлы Формы и окна Другое Советы Базы данных Графика Интернет Мультимедиа Система Тексты Файлы Файлы Исходники Компоненты Инфо Поиск по сайту Обратная связь Самое популярное Аккаунт Карта сайта Реклама Размещение статей - CLX.ru Прогулка по окнам Windows "); // --> Всё или почти всё (хотя я не возьмусь сказать, что именно составляет исключение) в Windows имеет свой хэндл (Handle). Интересен перевод системой Сократ термина «Handle» — «Ручка», на нормальном техническом русском это будет дескриптор (определитель, идентификатор, описатель). Таким образом, handle — некий уникальный идентификатор любого ресурса Windows. Каждое окно имеет свой собственный дескриптор. Иерархия окон в системе представлена таким образом: каждое окно имеет список подчинённых окон. Список может быть пустым, в случае, если стиль окна не предусматривает хранения подчинённых элементов. каждое окно имеет окно-владельца. Дескриптор окна-владельца будет нулевым (пустым), если окно имеет верхний уровень вложенности, например, главное окно программы. для каждого окна можно получить слудующее и предыдущее, в его уровне вложенности, окно. Мы имеем древовидную структуру с возможностью навигации по дереву, как вверх и вниз по уровню вложенности, так и горизонтально. Горизонтальная навигация возможна исключительно по окнам, имеющим то же окно-владелец. Рассмотрим простенькую схемку: Для «Окна 3» — владелец «Окно 1», окна своего уровня — «Окно 3 …Окно N», и соответсвующие по рисунку, дочерние окна — «Окно N+1 … N+M». При этом, непосредственно получить идентификаторы других окон, используя идетификатор исходного окна невозможно. Перейдём к иструментарию Windows API, позволяющему реализовать сказаное выше. Оконные функции WinAPI, используемые в данном проекте. function GetWindow(hWnd: HWND; uCmd: UINT): HWND; Функция возвращает дескриптор окна, с заданным положением в иерархии окон относительно заданного окна. hWnd — дескриптор исходного окна. uCmd — направление связи, т.е. вверх, вниз или по горизонтали. Значения переменной uCmd: GW_CHILD — Возвращает дескриптор дочернего (подчинённого) окна, находящегося в верхней позиции Z-упорядочивания. В случае, если окно не имеет дочерних окон, возвращается 0. GW_HWNDFIRST — Возвращает дескриптор окна, находящегося в верхней позиции Z-упорядочивания того же уровня, что и исходное окно. GW_HWNDLAST — Возвращает дескриптор окна, находящегося в нижней позиции Z-упорядочивания того же уровня, что и исходное окно. GW_HWNDNEXT — Возвращает дескриптор окна, находящегося в следующей позиции Z-упорядочивания того же уровня, что и исходное окно. GW_HWNDPREV — Возвращает дескриптор окна, находящегося в предыдущей позиции Z-упорядочивания того же уровня, что и исходное окно. GW_OWNER — Возвращает дескриптор окна владельца исходного окна. Если окно имеет нулевой уровень вложенности, возвращается 0. О Z-упорядочивании: самое «верхнее» окно на экране имеет нулевую позицию, следующее, перекрываемое им окно - первую позицию, и так далее до самого «нижней» части экрана. Таким образом реализуется понятие трёхмерности, хотя в одной умной книжке я читал, что многооконная среда условно имеет 2.5-мерность (2.5D). С помощью этой функции мы можем получить список всех окон системы несложной рекурсивной прогулкой по дереву (задача 1-го курса ВУЗа «Обход дерева»). Нам понадобятся ещё несколько функций WinAPI: function GetWindowText(hWnd: HWND; lpString: PChar; nMaxCount: Integer): Integer; Функция получает текст окна по его идентификатору и возвращает считанную длину строки текста окна. hWnd - идентификатор окна. lpString - текст окна в переменной PChar. Переменную необходимо создать заранее. nMaxCount - длина строки lpString. function GetClassName(hWnd: HWND; lpClassName: PChar; nMaxCount: Integer): Integer; hWnd - идентификатор окна. lpClassName - имя класса окна в переменной PChar. Переменную необходимо создать заранее. nMaxCount - длина строки lpClassName. function GetMenu(hWnd: HWND): HMENU; Функция возвращает идентификатор меню по переданному идентификатору окна. Перейдём к непосредственному построению программы. Построение программы. Запустим Delphi и создадим новое приложение в меню File->New Application. Не будем отвлекаться на навороченный интерфейс, не сомневаюсь, что большинство делает это легко, как «два байта переслать» ;). Построим что-нибудь а-ля "Проводник". Обзовём главную форму fmMain, а главный модуль - Main.pas. Разместим на форме компоненты как показано на рисунке: Слева на форме находится компонент Tree:TTreeView, а клиентскую часть занимает компонент List:TListView. Добавим в форму fmMain процедуру заполнения дерева FillTree следующего содержания: // процедура заполнения дереваprocedure TfmMain.FillTree;var h,h1:THandle; Buffer:PChar; // рекурсивная процедура заполнения дереваprocedure RegisterWindow(hWnd:THandle;ParentTreeItem:TTreeNode);var Node:PNode; // данные окна TreeNode:TTreeNode; // узел дерева h:THandle; // хэндл окна, промежуточная переменнаяbegin // получение и сохранение информации об окне // создание переменной информации обокне New(Node); // присвоение дескриптора Node^.Handle:=hWnd; // получение текста окна GetWindowText(hWnd,Buffer,256); Node^.Text:=Trim(StrPas(Buffer)); // получение класса окна GetClassName(hWnd,Buffer,255); Node^.CName:=Trim(StrPas(Buffer)); // получение дескриптора меню окна Node^.Menu:=GetMenu(hWnd); // размещение в дереве TreeNode:=Tree.Items.AddChild(ParentTreeItem,''); // присвоение отображаемого текстового значения if Node^.Text<>'' then TreeNode.Text:=Node^.Text else if Node^.CName<>'' then TreeNode.Text:=Node^.CName else TreeNode.Text:=IntToStr(Node^.Handle); // сохранение ссылки на информацию об окне в соответствующем узле дерева TreeNode.Data:=Node; // Рекурсивные вызовы // получение поддчинённых элементов h:=GetWindow(hWnd,gw_Child); if h<>0 then RegisterWindow(h,TreeNode); // получение элеметов того же уровня h:=GetWindow(hWnd,gw_hWndNext); if h<>0 then RegisterWindow(h,ParentTreeItem);end;begin // сообщение в строке статуса Status.SimpleText:='Обновление информации об окнах ...'; Application.ProcessMessages; // выключение отображения изменений дерева Tree.Items.BeginUpdate; // очистка дерева Tree.Items.Clear; // создание буфера для работы с PChar Buffer:=StrAlloc(256); // Получаем хэндл текущего окна h1:=Handle; repeat // получаем хэндл окна-владельца h:=GetWindow(h1,GW_OWNER); // если не окно верхнего уровня, то ищем дальше if h<>0 then begin h1:=h; end; until h=0; // находим первое верхнее окно h:=GetWindow(h1,GW_HWNDFIRST); // запуск рекурсии RegisterWindow(h,nil); // задание выделенного элемента дерева Tree.Selected:=Tree.Items[0]; // включение отображения изменений дерева Tree.Items.EndUpdate; // удаление буфера для работы с PChar StrDispose(Buffer); // сообщение в строке статуса Status.SimpleText:='Готово.';end; Теперь попробуем в ней разобраться (смотри по тексту процедуры). Status — класс TStatus Bar. Сообщим в строке статуса, что мы обновляем информацию. Выключим отображение обновления дерева для того, чтобы ничего в процессе обновления у нас на экране не дёргалось. Очистим дерево и создадим переменную Buffer, в которую будем записывать строковые результаты выполнения функций WinAPI. Следующий этап - добраться до самого верхнего и самого первого окна системы. Мы вызываем функцию GetWindow с параметром GW_OWNER — получение окна-владельца, начиная с главного окна программы. Получив окно, не имеющее владельца, находим для этого окна окно с нулевым Z-порядком, вызвав функцию GetWindow с параметром GW_HWNDFIRST — получение первого окна в данном уровне вложенности. Теперь мы можем начать обход дерева окон, начиная с самого первого по порядку возрастания вложенности и Z-порядка, вызвав рекурсивную процедуру RegisterWindow. Как известно, у класса TTreeNode — узла дерева — есть поле Data:Pointer. В это поле можно записывать любые ссылки на данные, которые требуется ассоциировать с узлом дерева. Создадим структуру данных для хранения информации об окне. // тип для хранения информации об окнеTNode=record Handle:THandle; // хэндл окна Text:string[255]; // текст окна CName:string[255]; // имя класса Menu:HMenu; // хендл менюend;PNode=^TNode; // указатель на структуру При нахождении очередного окна будем создавать динамическую переменную типа PNode и её значение записывать в поле TTreeNode.Data. Итак, мы знаем «первое верхнее» окно. Передадим его в процедуру RegisterWindow. Также в эту процедуру передаётся ссылка на узел дерева, к которому добавляются узлы подчинёных окон. В первом случае вызова рекурсии, эта ссылка равна nil. Следующие действия просты до безобразия (процедура RegisterWindow): создать переменную описания окна; получить по заданному идентификатору описанными ранее функциями WinAPI текст, имя класса и идентификатор меню, и записать эти значения в переменную окна; создать узел дерева и присвоить ему перменную окна, задав владельца узла и присвоив ему текстовое значение; получить идентификатор дочернего окна, и если идентификатор не равен 0, рекурсивно его обработать, передав в RegisterWindow полученные параметры. При этом, в процедуру передаётся идентификатор полученного дочернего окна и только что созданный узел дерева; получить идентификатор следующего за текущим окна того же уровня вложенности. И если он не равен 0, передать в RegisterWindow полученный идентификатор и внешний параметр ParentTreeItem. При этом узлы дерева будут добавляться на том же уровне, что и текущий узел. Если мы вызовем процедуру FillTree в событии FormCreate, то дерево автоматически заполнится при запуске программы. Создадим действие acRefresh:TAction и свяжем его с кнопкой обновления, расположенной на форме. В обработке запуска действия напишем такой код: // действие "обновить"procedure TfmMain.acRefreshExecute(Sender: TObject);begin // заполнение дерева FillTree;end; Теперь мы можем принудительно обновлять список. Перейдём к отображению всей собранной информации об окне в компоненте List:TListView. Обработаем событие TTreeView.OnChange так: // событие изменения выделенного элемента дереваprocedure TfmMain.TreeChange(Sender: TObject; Node: TTreeNode);// добавление в List строкиprocedure AddItem(Name,Value:String);var Item:TListItem;begin Item:=List.Items.Add(); Item.Caption:=Name; Item.SubItems.Add(Value);end;begin // выключение обновления List.Items.BeginUpdate; // очистка List.Items.Clear; // добавление элементов if (Node<>nil) and (Node.Data<>nil) then begin AddItem('Текст',TNode(Node.Data^).Text); AddItem('Класс',TNode(Node.Data^).CName); AddItem('Дескриптор окна',IntToStr(TNode(Node.Data^).Handle)); AddItem('Дескриптор меню',IntToStr(TNode(Node.Data^).Menu)); end; // включение обновления List.Items.EndUpdate;end; На выделение соответсвующего элемента дерева (Node:TTreeNode), добавляем в компонент List:TListView строки со значениями всех полей записи PNode^. Всё! Мы имеем информацию о всех окнах и используя идентификатор окна можем получить доступ к ОЧЕНЬ БОЛЬШОМУ КОЛИЧЕСТВУ параметров окна через WinAPI И зачем всё это нужно? Проиллюстрируем четырьмя примерами: Спрятать ненужное (читаем, надоевшее) окно. Например, окно системы баннерных показов. Делается так: ShowWindow(TNode(Tree.Selected.Data^).Handle,sw_Hide). Правда эффективного скрытия этого окна нужно работать с собщениями cерии ABM_*, но это другая история. Показать упрятанное окно. Обратное действие: ShowWindow(TNode(Tree.Selected.Data^).Handle,sw_Show). Например, слетела панель с кнопкой "Пуск". Все значки в системном трее пропали. Показать окно не представляет проблемы. Разрешить запрещенный элемент управления: EnableWindow(TNode(Tree.Selected.Data^).Handle,True). Для чего это нужно, не будем даже и говорить. Убить окно: PostMessage(TNode(Tree.Selected.Data^).Handle,wm_Close,0,0). Объяснение — см. пункт 3. Источник www.delphi.aiq.ru Разместил 10/02/2004 от rolcom ( Прочитано: ) Связанные ссылки · Больше про Формы и окна · Новость от rolcom Самая читаемая статья: Формы и окна: Окна - такие разные:круглые, треугольные, звездообразные... Рейтинг статьи Средняя оценка: 4 Ответов: 4 Пожалуйста, проголосуйте за эту статью: опции Напечатать текущую страницу Отправить статью другу tramadol order - hydrochloride tramadol - радиолюбителям - tramadol used - tramadol ultram - cheap tramadol - hcl tramadol Page generation 0.297 seconds