Мечты вуайериста — чужие окна 2

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Теперь, попробуем менять, что-то в чужих окнах. И вообще попробуем сделать с ними то же, что мы делаем со своими окнами. Сразу скажу, что тема эта неисчерпаема. Ей можно посвятить не одно скромное обозрение, а детальное многотомное издание. Я не ставлю св оей задачей.

Несколько предварительных сурьезных слов.

Вынужден сказать, что многое изложенное ниже может привести к неприятным последствиям. Например, к тому, что программа или система будет зависать. Поэтому будем считать, что читатель находиться в трезвом уме и здравой памяти и не будет совершать необдуман ные действия. Прежде чем убить или закрыть чужое окно, подумайте, а зачем это окно вообще висит. Помните, что если окна висят в системе значит это кому то нужно ?! (почти Маяковский). Ну а теперь немного попугав для проформы перейдем к делу.

Содержание:

Несколько предварительных сурьезных слов.

Режимы отображение окон верхнего уровня.

Системное меню и кнопки заголовка.

Некоторые дополнительные возможности.

Итоги

Итак…

Режимы отображение окон верхнего уровня.

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

Функция SetForegroundWindow

Синтаксис:

function SetForeGroundWindow(Wd: Hwnd):Boolean;

Описание: Показывает верхние окно системы.

Параметры:

Wnd: Идентификатор окна.

Возвращаемое значение: True- если функция отработала, False- при ошибке.

Процедура BringWindowToTop

Синтаксис:

procedure BringWindowToTop(Wnd: HWnd);

Описание: Активизирует и перемещает Wnd в вершину стека перекрывающихся окон.

параметры:

Wnd: Всплывающее или дочернее окно.

Возвращаемое значение: Нет

Теперь попробуем проделать с неким окном, имеющим идентификатор окна HD:HWnd некие стандартные действия:

1) Свернуть данное окно;

2) Развернуть данное окно;

3) Закрыть данное окно.

Все данные действия могут быть проделаны с окном при помощи стандартной функции SendMessage или PostMessage, с различными параметрами:

1) SendMessage(HD,WM_SYSCOMMAND,SC_MINIMIZE,0);

2) SendMessage(HD,WM_SYSCOMMAND,SC_MAXIMIZE,0);

3) SendMessage(HD,WM_SYSCOMMAND,SC_CLOSE,0);

Существуют и другие константы, для сообщений вида WM_SYSCOMMAND:

SC_CLOSE Закрывает окно.

SC_CONTEXTHELP Изменяет курсор на вопросительный знак.

SC_DEFAULT Выбирает элемент по умолчанию; эмулирует двойное нажатие на Системное меню.

SC_HOTKEY Инициирует окно, связанное с текущим — указанной комбинацией горячих клавиш.

SC_HSCROLL Прокручивается горизонтально окно.

SC_KEYMENU Открывает Системное меню как результат нажатия клавиши.

SC_MAXIMIZE (или SC_ZOOM) Разворачивает окно.

SC_MINIMIZE (или SC_ICON) Сворачивает окно.

SC_MONITORPOWER Устанавливает состояние дисплея.

SC_MOUSEMENU Открывает Системное меню как результат щелчка мыши.

SC_MOVE Перемещает окно.

SC_NEXTWINDOW Переходит к следующему окну.

SC_PREVWINDOW переходит к предыдущему окну.

SC_RESTORE Восстанавливает окно к его нормальной позиции и размеру.

SC_SCREENSAVE Запускает стандартный скринсейвер.

SC_SIZE Задает размеры окно.

SC_TASKLIST Выполняет или инициирует Windows Task Manager.

SC_VSCROLL Прокручивается окно вертикально.

Первый параметр — описатель искомого окна, второй сообщение (в нашем случае WM_SYSCOMMAND) третий одна из констант приведенных выше, четвертый параметр — координаты (x- младшее слово y — старшее).

Можно, так же, показать или скрыть окно, используя функцию API:

Процедура ShowWindow

Синтаксис:

function ShowWindow(Wnd: HWnd; CmdShow: Integer);

Описание: отображает или прячет окно образом, указанным параметром CmdShow.

параметры:

Wnd: Всплывающее или дочернее окно.

CmdShow — одна из констант:

SW_HIDE

SW_MAXIMIZE

SW_MINIMIZE

SW_RESTORE

SW_SHOW

SW_SHOWDEFAULT

SW_SHOWMAXIMIZED

SW_SHOWMINIMIZED

SW_SHOWMINNOACTIVE

SW_SHOWNA

SW_SHOWNOACTIVATE

SW_SHOWNORMAL

Возвращаемое значение: Не нуль, если окно было ранее видимым; нуль — если оно было ранее спрятанным.

Константы позволяют скрыть/показать окно с различными типами (распахнутым, свернутым, неактивным и пр.)

Давайте теперь попробуем решить ряд наиболее часто встречающихся проблем:

1) Как свернуть все окна системы ??? (как свернуть все окна системы кроме окна программы)

// Любимая наша процедура.

{Для того чтобы использовать данный пример необходимо наличие кнопки Button1.}

function EnumMiniProc (Wd: HWnd; Param: LongInt): Boolean; stdcall; // Обязательно stdcall !!!

Begin

If WdForm1.Handle then // если это не наша программа

If IsWindowVisible(WD) then // если окно видимо

If not IsIconic(WD) then // если окно не свернуто

If isWindow(WD) then // и вообще это — окно.

ShowWindow(WD, SW_MINIMIZE); // свернем его.

EnumProc := TRUE; // продолжаем перебирать все окна системы.

end;

procedure TForm1.Button1Click(Sender: : TObject); // допустим, закрываем по нажатию на клавишу

begin

EnumWindows (@EnumMiniProc, 0); // отрабатываем сворачивание окон.

end;

Для того чтобы окно программы тоже сворачивалось достаточно убрать строку If WdForm1.Handle then в EnumMiniProc

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

Еще один пример, который бывает зачастую нужен:

2) Как закрыть (или постоянно закрывать) окна, например содержащие в заголовке подстроку «Реклама»

Закрыть все окна, содержащие определенную подстроку в заголовке.

Const

ReclamaName : String = ‘Реклама’ ; // строка, по которой мы узнаем, что это — реклама.

TimeInterval : Integer = 500; // Интервал, с которым будем проверять наличие окон

{Для того чтобы использовать данный пример необходимо наличие таймера Timer1.}

// Любимая наша процедура

function EnumCloseProc (Wd: HWnd; Param: LongInt): Boolean; stdcall; // Обязательно stdcall !!!

Var

Nm:Array[0..255] of Char; // буфер для имени

zName:String;

Begin

GetWindowText(Wd,Nm,255); // считываем текст заголовка окна

ZName:=AnsiUpperCase(String(Nm)); // преобразуем к верхнему регистру т.е РЕКЛАМА

If Pos(ReclamaName,zName)0 then SendMessage(WD,WM_SYSCOMMAND,SC_CLOSE,0);

EnumProc := TRUE; // продолжаем перебирать все окна системы.

end;

procedure Tform1.Timer1Timer(Sender: TObject); // будем проверять по таймеру…

begin

Timer1.Interval:= TimeInterval; // установим время до следующего вызова

EnumWindows (@EnumCloseProc, 0); // отрабатываем закрытие окон.

end;

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

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

Системное меню и кнопки заголовка.

Системное меню, отображает обычно ряд доступных стандартных функций применимых к окнам.

Обычно к таким функциям относятся следующие команды (применительно к локализованным Windows, в англоязычных названия будут другие, есть подозрения, что английские J):

Восстановить — восстанавливает размер окна.

Переместить — перемещает окно.

Размер — позволяет изменить размер окна.

Свернуть — сворачивает окно до иконки (минимизирует).

Развернуть — разворачивает окна до максимально возможного размера

Закрыть — закрывает окно.

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

Ряд команд имеет кнопку, расположенную в правой части заголовка. Обычно таких кнопок три: свернуть, восстановить, закрыть. Иногда добавляется кнопка помощь.

Зачем манипулировать доступными командами системного окна ??? Ну, например, есть окошко, у которого кнопка закрыть — недоступна, а в системном меню пункта закрыть нет, да и на Alt F4 она не откликается. А убрать программку ужас как хочется.

Процедура GetSystemMenu

Синтаксис:

function GetSystemMenu(Wnd: HWnd; Revert: Bool): HMenu;

Описание: Считывает системное меню окна для копирования и модификации.

параметры:

Wnd: Всплывающее или дочернее окно.

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

Возвращаемое значение: идентификатор системного меню;

0 — если Revert отлична от нуля и системное меню не модифицировано.

Для начала надо получить идентификатор системного меню. При помощи приведенной выше функции.

Далее попробуем определить, что именно содержится в системном меню (надо сказать, что приведенные ниже функции API справедливы для любых меню, а не только системных, но об этом несколько позже):

Процедура GetMenuString

Синтаксис:

function GetMenuString(Menu: HMenu; IDItem: Word; Str: PChar;

MaxCount: Integer; Flag: Word): Integer;

Описание: копирует метку элемента меню в Str. параметры:

Menu: идентификатор меню.

IDItem: идентификатор элемента меню.

Str: принимающий буфер.

MaxCount: размер буфера.

Flag: Одна из констант меню

mf_ByPosition — определять пункт меню по порядковому номеру

mf_ByCommand — определять пункт меню по выполняемой команде.

Возвращаемое значение: Количество реально скопированных байт.

Как видно из описания функции возможно два варианта определения списка по номеру или по выполняемой команде.

Если Flag = mf_ByCommand тогда в качестве IDItem передаются стандартные команды (см. константы в WM_SYSCOMMAND. Предыдущий раздел).

Например

I:=GetMenuString (hMenu, SC_CLOSE, Mn,255,mfByCommand);

Возвращает название пункта системного меню, отвечающего за закрытие окна. I=0 указывает, что такого пункта в системном меню нет.

Если Flag = mf_ByPosition тогда в качестве IDItem передается порядковый номер искомого пункта меню, начиная с 0

Например

I:=GetMenuString (hMenu, 0, Mn,255,mfByPosition);

Возвращает название самого первого по порядку пункта системного меню (обычно это восстановить). I=0 указывает, что такого пункта в системном меню нет. ИМХО первый вариант более пригоден для получения списка строк системного меню, в то время как второй — д ля определения присутствует ли данная команда в системном меню.

Количество элементов меню можно получить при помощи функции

Процедура GetMenuItemCount

Синтаксис:

function GetMenuItemCount(Menu: HMenu): Word;

Описание: определяет число меню и элементов меню верхнего уровня в указанном меню.

параметры:

Menu: идентификатор меню.

Возвращаемое значение: В случае успешного завершения возвращается число элементов меню; 0 — в противном случае.

Вот как приблизительно может выглядеть функция, которая определяет системное меню окна:

Получение списка системного меню окна.

ListBox1 : TlistBox; // Полученный список запихиваем сюда

… …

Procedure GetSysMenuItem (Wd:HWND); // Передаем идентификатор окна.

Var

I,K,Q:Word;

hMenuHandle : HMENU;

Nm:Array[0..255] of Char;

Begin

ListBox1.Clear; // Очистим список перед использованием.

hMenuHandle:=GetSystemMenu(Wd, FALSE); // Получим идентификатор

if (hMenuHandle = 0) then Exit; // Если такого меню нет, то выходим

Q:=GetMenuItemCount(hMenuHandle); // Определяем количество пунктов меню.

For k:=0 to Q-1 do

Begin

i:=GetMenuString(hMenuHandle,k,Nm,255,MF_BYPOSITION); // Считываем название

ListBox1.Items.Add(String(Nm)); // Добавляем в список.

End;

End;

Итак, мы получили список пунктов системного меню. Пустые строки, скорее всего, означают разделители. Так же используются акселераторы (

Добавить комментарий