Мечты вуайериста - чужие окнаDelphi , Программа и Интерфейс , Приложения чужиеМечты вуайериста - чужие окнаДля чего это? Нет, конечно, никакого отношения это статья к привычным извращениям не имеет, просто рассказывает, как можно подглядывать в чужие окна. Судя по тому шквалу вопросов, которыми завалены форумы, вопрос изучения чужих окон интересует многих. Каюсь, здесь я оказался в большинстве. Движимый любопытством я попытался разобраться в том, как же все-таки заглянуть в чужое окно. И написал некую прогр аммку, которая все это умеет делать. Ну, почти все. Попутно пришлось найти ответы на многие вопросы, которые, как мне кажется, интересуют не только меня. Программа написана на Delphi 3 для Windows 98. И, возможно, в более поздних версиях Delphi появились дополнительные возможности. Чтобы не засорять место бесконечными объяснениями интерфейсной части полный исходный текст программы приводить не буду, постараюсь изложить по пунктам, как она работает. Тест будет избыточным с большим количеством ненужных примеров, например, нахождение в ерхних окон приводиться в двух вариантах, оба рабочие, но один из которых работает с определенными трудностями. Зачем это делается??? Просто программа писалась для определенных задач, кои могут не совпадать с Вашими. Основная цель объяснить, как работать с чужими окнами при помощи функциями API, а какие примеры и для чего применять решать Вам. Для кого это? Для всех, кто хочет научиться работать с WINAPI. Для тех, кто программирует в Delphi, хотя почти все сказанное тут может быть использовано и в других языках, тем и хороши функции API. По мере использования приводятся краткие описания функций API. Эта публикация подразумевает достаточно низкий уровень знания Дельфи и АПИ, но какие-то базовые знания все-таки необходимы. С другой стороны, никакой Америки здесь не открывается, просто приводятся примеры работы с чужими окнами. Для подключения функций API необходимо включить в описание используемых модулей Uses ShellAPI; Как получить список всех окон запущенных в системе. Первое что нас интересует так это получение списка окон, запущенных в системе. Прошу не путать с процессами, это совсем другая песня. Коротко говоря, у одного процесса может быть несколько окон, но бывают процессы, у которых окон вообще нет, тогда как люб ое окно должно принадлежать какому-либо процессу. Но здесь и сейчас мы говорим только об окнах. Попробуем найти так называемые окна верхнего уровня, или, попросту говоря главные окна приложений. Найти окно в системе - означает получить его описатель (дескриптор). По этому описателю окно идентифицируется единственным возможным способом. Идентификатор окна, он же дескриптор он же описатель окна это просто число, зная которое можно получить доступ к каждому конкретному окну в системе. Для нахождения окон запущенных в системе существует целый ряд функций WinAPI (в дальнейшем просто API). Функция FindWindow Синтаксис:
Описание: Находит родительское окно верхнего уровня с совпадающими ClassName и WindowName. Не осуществляет поиск дочерних окон. Параметры: ClassName: Имя класса окна (заканчивающееся пустым символом, 0 - если все классы).WindowName: Текстовый заголовок окна или 0, если все окна. Возвращаемое значение: Описатель окна; 0 - если такого окна нет. Итак, функция FindWindow находит все окна верхнего уровня по названию класса и заголовку окна. Если Ваша задача определить запущено ли определенное окно (с известными именем класса и заголовком) в настоящий момент, можно использовать
Но, зачастую требуется определить все окна, или окна, для которых не известен класс и/или заголовок. Для решения нашей задачи, также можно использовать функцию FindWindow Но посмотрим, что еще у нас есть из функций работы с окнами. Функция GetNextWindow Синтаксис:
Описание: Считывает из Wnd следующее или предыдущее окно. В случае окна верхнего уровня ищется следующее окно верхнего уровня, а в случае дочернего окна ищется следующее дочернее окно. параметры:
Wnd: идентификатор окна. Функция GetNextWindow находит все окна текущего уровня (если задано окно верхнего уровня, - то ищет окно верхнего уровня, если дочернее окно - то список дочерних) Осталось определить, как найти исходный описатель окна, от которого будем плясать (параметр WND функции) Можно попробовать начать поиски с верхнего окна системы. Его можно определить при помощи следующей функции API: Функция: GetForegroundWindow Синтаксис:
Описание: Показывает верхнее окно системы. Параметры: нет. Возвращаемое значение: Идентификатор окна. А можно при помощи все той же функции FindWindow и все-таки для определения окон верхнего уровня, на мой взгляд, предпочтительней использовать функцию FindWindow. Давайте попробуем описать первый вариант функции, которая составляет список всех окон верхнего уровня системы, пусть у нас есть на форме некий ListBox1:TlistBox, будем помещать в него найденные окна. И процедура поиска окон будет выглядеть тогда следующим образом:
Работает??? Работает, но как-то не совсем так, как хотелось, ряд окон не отображается (например, системные окна, такие как System Tray), возможно некое зацикливание программы в некоторых случаях. Просто потому, что для этих целей существует совсем другой способ. Функция EnumWindows Синтаксис:
Описание: Пеpечисляет все pодительские окна на экpане, пеpедавая функции обpатного вызова ( т.е объявленная как stdcall функция) описатель окна и lParam. Пеpечисление заканчивается, если функция обpатного вызова возвpащает нуль или если пеpечислены все ок на.
Параметры:
EnumFunc: Адpес экземпляpа пpоцедуpы функции обpатного вызова. Вот эта функция прям-таки и просится, чтобы перечислить все окна в системе. Для этого нам потребуется вспомогательная функция (хотя конечно она то и будет основной) И так:
И получается проще. В дальнейшем все изменения будут идти относительно текста 2, хотя все это будет справедливо и для текста 1. Как получить общую информацию об окнах верхнего уровня. Итак, мы научились получать список описателей для всех окон в системе. Но почему-то это не особенно радует. Действительно взирать на список чисел, которые представляют собой описатели окон грустно. И вообще интересует совсем другая информация об окнах, нежли просто список описателей. Давайте разбираться, что же можно вытащить из окна верхнего уровня. Для начала получим информацию о классе окна и заголовке окна: Функция GetClassName Синтаксис:
Описание: Считывает имя класса окна. Параметры:
Wnd: Идентификатор окна. Функция GetWindowText Синтаксис:
Описание: Копиpует в Str заголовок окна или текст оpгана упpавления. Параметры:
Wnd: Идентификатор окна или оpгана упpавления. Описатели окна мы уже имеем, так что самое время получить имя класса и заголовок. Изменим полученную функцию EnumProc следующим образом:
Конечно, красоты ради, стоило бы сначала определить необходимый размер буфера, но в подавляющем большинстве случаев вполне хватает 255 символов. Для желающих поразвлечься самостоятельно предлагаю определить размер заголовка помощи следующих функции: Функция GetWindowTextLength Синтаксис:
Описание: Считывает длину заголовка окна или текста оpгана упpавления. Параметры:
Wnd: Идентификатор окна. Вот теперь мы видим какие окна верхнего уровня у нас загружены в системе, и даже можем понемногу разбираться какие окна к чему относятся. Но появляются разные странности. Во-первых количество окон в системе оказывается больше чем то, что мы видим. Во-вторых появляются окна вообще с непонятными классами и/или названиями или вообще без них. Спешу Вас успокоить, список содержит ВСЕ окна которые есть в системе, включая скрытые, системные (например ProgMan не что иное как рабочий стол). В том числе и Вашу программу. Встает вопрос, как бы убрать собственную программу из списка ? Для этого коротенько намекну, что описатель, который мы так долго и муторно получали, на самом деле, совпадает с Handle, который есть у любой формы. Чтобы исключить свою программу из списка достаточно просто поставить проверку В тексте 3:
Для пущей красоты можно сделать переключатель, который отвечает за то, будет ли в список добавляться Ваша программа. Если у Вас не одно окно, а несколько, то нужно проверять все окна. Что из общих параметров можно узнать еще об окне ??? Ну например можно узнать состояние окна, то есть : Функция IsIconic Синтаксис:
Описание: Опpеделяет, является ли окно пиктогpаммой (минимизиpованным). Параметры:
Wnd: Идентификатор окна. Функция IsWindow Синтаксис:
Описание: Опpеделяет, является ли окно допустимым существующим окном. Параметры:
Wnd: Идентификатор окна. Функция IsWindowEnabled Синтаксис:
Описание: Опpеделяет, является ли окно pазpешенным для ввода с мыши и с клавиатуpы. Параметры:
Wnd: Идентификатор окна. Функция IsWindowVisible Синтаксис:
Описание: Опpеделяет, сделано ли окно видимым функцией ShowWindow. Параметры: Wnd: Идентификатор окна. Возвращаемое значение: Не нуль, если окно существует на экpане (даже если полностью закpыто); 0 - если нет. Функция IsZoomed Синтаксис:
Описание: Опpеделяет, является ли окно максимизиpованным. Параметры: Wnd: Идентификатор окна. Возвращаемое значение: Не нуль, если окно максимизиpовано; 0 - если нет. Простой пример использования этих функций:
Работа с остальными функциями этой группы проводиться таким же образом, Вы получаете значение типа boolean, и что-то где-то отображаете. Кроме того, можно так же предусмотреть возможность отображать только окна определенного вида. Например, только видимые. Для этого достаточно вставить вместо строки
Впрочем, это уже на Ваш вкус, что отображать и как. Что еще можно узнать об окнах верхнего уровня ? Конечно, на этом информация об окнах не исчерпывается, еще очень и очень многое можно узнать об окне, зная его описатель. Я приведу вкратце некоторые из наиболее интересных, на мой взгляд: Все примеры, как бы являются функциями, которые можно вставлять в EnumProc например, и вызывать из нее передавая необходимые параметры. Получение данных о расположении окна: Процедура GetWindowRect Синтаксис:
Описание: Считывает в ARect pазмеpности огpаничивающего пpямоугольника окна (в кооpдинатах экpана). Параметры:
Wnd: Идентификатор окна. Функция просто возвращает полный размер окна (с заголовком, меню и т.д.) в глобальных экранных координатах. Чтобы пояснить работу напишем функцию которая возвращает область окна в виде Trect. Ничего сложного в этой функции нет, просто как пояснение к использованию:
Пpоцедуpа GetClientRect Синтаксис:
Описание: Считывает кооpдинаты пользователя окна. Параметры:
Wnd: Идентификатор окна. Функция возвращает размер рабочей области окна (уже без заголовка, меню и т.д.) в глобальных экранных координатах. Укажем еще на одну функцию API необходимую для весьма полезной процедуры: Функция GetWindowDC Синтаксис:
Описание: Считывает контекст дисплея, обычно используемый для pаскpаски в окне областей, не являющихся областями пользователя. Параметры:
Wnd: Идентификатор окна. Функция возвращает контекст устройства, грубо говоря, то где это окно рисуется. А теперь реализуем пару своих функций, которые возвращают текущее окно в виде картинки BMP: Скопировать все окно в BMP
и функция, которая копирует только клиентскую часть окна в BMP
Видно, что эти функции отличаются только определением области окна, которое будет скопировано. Сложностей с пониманием работы этих функций быть не должно, получили область копирования по описателю, вычислили размеры области копирования, получили контекст устройства, и скопировали. Кстати сказать, для того, чтобы скопировать весь экран или часть экрана можно использовать подобные функции. Единственное, что в таком случае придется поменять так это контекст устройства. Контекст устройства всего экрана 0. Ну и вместо того, чтобы получа ть область окна, нужно будет явно передавать координаты области, которую необходимо скопировать. Очень много информации об окне можно получить при помощи следующей функции: Функция GetWindowLong Синтаксис:
Описание: Считывает инфоpмацию об окне или о значениях дополнительного байта окна. Паpаметpы:
Wnd: Идентификатоp окна. Наиболее интересной информацией, на мой взгляд, является стиль окна и экземпляр приложения. Как пользоваться подобной функцией ?? Например получаем экземпляр приложения:
Похожим образом получается любая информация, только в качестве второго параметра Вы передаете тот флаг, который Вам необходим. Для интереса, можете посмотреть еще описание функции GetWindowWord она сходна с функцией GetWindowLong, но возможно получение не сколько других параметров окна. Еще ряд параметров можно вытащить используя функцию: Функция GetClassLong Синтаксис:
Описание: Считывает из стpуктуpы окна TWndClass со смещением Index длинное значение. Положительные смещения в байтах (с нуля) используются для доступа к дополнительным байтам класса. Паpаметpы:
Wnd: Идентификатоp окна. Возвpащаемое значение: Считанное значение. Надо сказать, что, к сожалению, далеко не все данные, возвращаемые этой функцией верны. Скорее всего она возвращает сведения только о тех классах окон которые корректно зарегистрированы в системе, хотя возможно, что здесь я ошибаюсь. Теперь попробуем применить полученные сведения на практике. Ниже приводится текст позволяющий извлекать иконки из приложений, которые запущены в настоящий момент (как было сказано выше, к сожалению, работает не для всех окон).
Как видно, процедура не такая уж и сложная. Для полноты информации можно еще извлечь идентификатор нити, к которой относиться окно. Функция GetWindowThreadProcessId Синтаксис:
Описание: Возвращает идентификатор процесса к которому принадлежит данное окно Параметры:
Wnd: Идентификатор окна. Как использовать данную функцию ??
Эта функция хороша тем, что для всех окон одного приложения этот идентификатор будут един, если они запущены внутри одной нити (что зачастую и делается). То есть Вы можете разбить окна по нитям и /или по процессам, к которым они относятся. А так же Вы мож ете определять, какие окна данного приложения в настоящий момент доступны, видны, свернуты и т.д. Итоги Итак, мы получили список всех окон верхнего уровня, запущенных в системе и огромное количество информации об окнах верхнего уровня, практически все, что может понадобиться:
Описатель окна The article discusses how to use Windows API functions to retrieve information about windows and their properties. It provides examples of using these functions to get the following information * Window hand Комментарии и вопросыПолучайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта. :: Главная :: Приложения чужие ::
|
|||||||||||||||||||||||||||||||||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |