- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Delphi. Трюки и эффекты - Валерий Борисок
Шрифт:
Интервал:
Закладка:
Возвращаясь к теме расположения ловушки зададимся вопросом: почему именно DLL? Чем плохо расположение ловушки в ЕХЕ-модуле приложения? Самое время вспомнить о том, что каждый процесс в Windows выполняется в своем собственном адресном пространстве. Поэтому адрес функции в исполняемом файле одного процесса вполне может быть адресом структуры данных где-то внутри другого процесса (рис. 10.1).
Рис. 10.1. Пример адресного пространства разных процессов
В отличие от ЕХЕ-файлов, файлы библиотек легко проецируются в адресное пространство использующего их процесса. Разместив функцию ловушки в DLL и указав дескриптор модуля этой DLL, мы предоставляем системе полную информацию для того, чтобы она смогла:
• спроецировать библиотеку с ловушкой в адресное пространство исследуемого процесса;
• однозначно определить положение (адрес) функции-ловушки в адресном пространстве исследуемого процесса.
Описанные выше манипуляции с DLL проиллюстрированы на рис. 10.2 (Процесс 2 на рисунке – процесс, в который внедряется ловушка).
Рис. 10.2. Загрузка DLL с ловушкой в адресное пространство исследуемого процессаТеперь нет никаких препятствий в вызове функции-ловушки при наблюдении за другим процессом.
...Примечание
В каждой библиотеке реализуется функция DIIMain, вызываемая (упрощенно) при загрузке/выгрузке библиотеки. Жаль только, что при описанном способе подгрузки DLL эта функция не вызывается. Это приводит к усложнению кодаловушки, в чем вы сможете вскоре убедиться.
10.2. Программа «Оконный шпион»
Перейдем, наконец, к практической части главы: рассмотрим создание программы, позволяющей составлять список (а точнее, дерево) всех окон, просматривать и изменять их свойства, а также осуществлять перехват сообщений выбранного окна (недаром мы столько времени потратили на рассмотрение ловушек Windows).
Несмотря на свое «противозаконное» название, рассматриваемая программа может весьма пригодиться при отладке приложений, а отнюдь непри их взломе и шпионаже (хотя многое зависит от добросовестности лица, использующего программу). В частности, с помощью этой программы была найдена ошибка, на долгое время закравшаяся в один из примеров гл. 2: из-за неправильной установки стилей при ручном создании главного окна программы не удавалось добиться правильной перерисовки элемента управления «рамка».
Составление списка открытых окон
Список (а точнее, дерево) окон, открытых в момент запуска программы, показан на рис. 10.3.
Рис. 10.3. Дерево открытых окон
Форма, показанная на рис. 10.3, имеет имя f rmMain. Элемент управления TreeView имеет имя tree. Часть программы, отвечающая за построение дерева, относительно проста. Она использует вскользь рассмотренный в гл.2 механизм перечисления окон. Составление дерева окон начинается с процедуры LoadWindowsTree, которая и запускает перечисление окон верхнего уровня, то есть окон, родителем которых формально является окно Рабочего стола (листинг 10.1).
...Листинг 10.1. Начало составления дерева окон
procedure TfrmMain.LoadWindowsTree();
var
desktop: TTreeNode;
//enInfo: TEnumInfo;
begin
tree.Items.Clear;
//Добавление узла для Рабочего стола
desktop := tree.Items.Add(tree.Items.GetFirstNode, 'Рабочий
стол');
//Перечисление окон
enInfo.tree := tree;
enInfo.parent := desktop;
EnumWindows(Addr(NewWindow), Integer(Addr(enInfo)));
end;
Сразу следует привести объявление структуры, интенсивно используемой (далее это будет видно) при составлении дерева:
...Type
TEnumInfo = Record
tree: TTreeView; //Компонент TreeView
parent: TTreeNode; //Элемент дерева, соответствующий
//текущему окну, дочерние
//окна которого перечисляются
end;
При нахождении каждого нового окна вызывается функция NewWindow (ее адрес передан в API-функцию EnumWindows). Функция NewWindow (листинг 10.2) решает две задачи. Во-первых, она добавляет в дерево элемент, соответствующий найденному окну. Во-вторых, запускает поиск дочерних окон относительно найденного окна, что позволяет перечислить все окна (от главной формы приложения до кнопок, надписей и т. д.).
...Листинг 10.2.
Добавление в дерево информации об окне и поиск дочерних окон
function NewWindow(wnd: HWND; param: LPARAM):BOOL; stdcall;
var
wndNode, parentNode: TTreeNode;
begin
wndNode := AddWindowToTree(wnd); //Добавление информации об
окне в дерево
//Перечисление дочерних окон
parentNode := enInfo.parent;
enInfo.parent := wndNode;
EnumChildWindows(wnd, Addr(NewWindow), param);
enInfo.parent := parentNode;
//Продолжать перечисление (после перечисления
//всех дочерних окон)
NewWindow := True;
end;
Используемая в листинге 10.3 функция AddWindowToTree добавляет элемент, соответствующий найденному окну, в дерево (определяет текст заголовка окна и имя оконного класса):
...Листинг 10.3.
Добавление элемента, соответствующего окну, в дерево
function AddWindowToTree(wnd: HWND): TTreeNode;
var
caption, classname: String;
text: String;
node: TTreeNode;
begin
//Получение текста окна
SetLength(caption, SendMessage(wnd, WM_GETTEXTLENGTH, 0, 0) + 1);
SetLength(caption, SendMessage(wnd, WM_GETTEXT, Length(caption),
Integer(PAnsiChar(caption))));
//Имя класса окна
SetLength(classname, 1024);
SetLength(classname, GetClassName(wnd, PAnsiChar(classname),
100));
//Формирование текста для элемента и добавление его в дерево
text := '"' + caption + '" ' + classname;
node := enInfo.tree.Items.AddChild( enInfo.parent, text );
node.Data := Pointer(wnd); //Не забываем запомнить
//дексриптор окна
AddWindowToTree := node;
end;
Вот, собственно, и все, что требуется для построения полного дерева окон, показанного на рис. 10.3.
Получение информации об окне
Следующей функцией «оконного шпиона» является определение более-менее полной информации об окне, выбранном в дереве. Форма с информацией о выделенном в дереве окне (в данном случае это пресловутая кнопка Пуск) показана на рис. 10.4.
Рис. 10.4. Форма свойств окна
Начинается все с того, что по команде меню Правка → Свойства вызывается метод ShowWindowProp созданного при запуске программы объекта f rmWindowProp. Этот метод принимает в качестве параметра дескриптор окна, информацию о котором нужно отобразить (дескриптор сохраняется в поле Data каждого элемента при построении дерева) (листинг 10.4).
...Листинг 10.4.
Подготовка формы свойств выбранного окна
procedure TfrmWindowProp.ShowWindowProp(window: HWND);
begin
wnd := window;
LoadWindowInfo();
ShowModal(); //Не забываем показать сами себя
end;
Переменная wnd, в которой сохраняется переданный BShowWindowProp дескриптор окна, является членом класса Tf rmWindowProp. Она нужна для того, чтобы другие методы формы Tf rmWindowProp могли получать доступ к дескриптору окна.
Определение заголовка, имени класса, идентификатора окна, а также области экрана, занимаемой окном, осуществляется в процедуре LoadWindowInf о (листинг 10.5).
...Листинг 10.5.
Определение общей информации об окне
procedure TfrmWindowProp.LoadWindowInfo();
var
rect: TRect;
buffer: String;
begin
//Сбор сведений об окне
//..имя класса
SetLength(buffer, 1024);
SetLength(buffer, GetClassName(wnd, PAnsiChar(buffer), 1024));
txtClassName.Text := buffer;
//..имя (заголовок) окна
SetLength(buffer, SendMessage(wnd, WM_GETTEXTLENGTH, 0, 0) + 1);
SendMessage(wnd, WM_GETTEXT, Length(buffer),
Integer(PAnsiChar(buffer)));
txtWindowName.Text := buffer;
//..идентификатор (или дескриптор меню) окна
txtId.Text := IntToStr(GetWindowLong(wnd, GWL_ID));
//..оконный прямоугольник
GetWindowRect(wnd, rect);
txtWindowRect.Text :=
'(' + IntToStr(rect.Left) + ',' + IntToStr(rect.Top) + ')' +
' – ' +
'(' + IntToStr(rect.Right) + ',' + IntToStr(rect.Bottom) + ') ' +
IntToStr(rect.Right–rect.Left) + 'x' + IntToStr(rect.Bottom –
rect.Top);
//Определение стиля окна
LoadWindowStyle();
LoadWindowExStyle();
end;
Если вы внимательно просмотрели листинг 10.5, то могли заметить вызовы двух процедур в двух последних строках кода. Процедура LoadWindowStyle заполняет списки используемых и доступных оконных стилей (см. рис. 10.4), а процедура LoadWindowExStyle соответственно заполняет списки используемых и доступных дополнительных (или расширенных) стилей окна.
Реализация процедуры LoadWindowStyle приводится в листинге 10.6
...Листинг 10.6.
Заполнение списков оконных стилей
procedure TfrmWindowProp.LoadWindowStyle();
var
i: Integer;
style: DWORD;
begin
style := GetWindowLong(wnd, GWL_STYLE);
lstStyle.Clear();
lstAvailStyle.Clear();
//Выделение из 32-битного значения составляющих стиля окна
for i := 0 to 17 do
if styles[i].value and style <> 0 then
begin
//Стиль используется
lstStyle.Items.Add(styles[i].name);
styles[i].used := True;
end
else
begin
//Стиль не используется
lstAvailStyle.Items.Add(styles[i].name);
styles[i].used := False;
end;
end;
Вместо громоздкой проверки наличия в значении, возвращенном API-функцией GetWindowLong, битов каждого возможного стиля при помощи, например, case здесь используется глобальный массив styles структур Styleinf о. Объявление типа структуры (записи) Styleinf о выглядит следующим образом:
...type
StyleInfo = record
value: DWORD; //Код стиля
name: String; //Текстовое обозначение стиля
used: Boolean; //Служебное поле
end;
Каждый элемент массива styles хранит информацию об определенном оконном стиле. Объявление этого массива, так же, как структуры Stylelnfo и прочих рассмотренных в этом разделе типов данных, находится в модуле WindowData, расположенном на диске в папке с номером главы.

