Федеральное государственное образовательное учреждение Высшего профессионального образования «Южный федеральный университет» Авакян Леон Александрович «использование win api функций в среде делфи» (учебно-методическое пособие)

3.2. Приемы управления сторонними приложениями

Очень часто возникают ситуации, когда необходимо заставить некоторое стороннее приложение, исходный код которого недоступен и не экспортирует собственного API, выполнять некоторые действия. Одним из примеров является нажатие 500 раз на кнопку “Отмена” при установки ПО с некачественного диска. В другом примере, необходимо провести рутинную операцию по сглаживанию кривой, которая включает в себя команд – загрузить файл, построить график, выполнить сглаживание, экспортировать результат… Гораздо удобнее один раз нажать на кнопку и проделать эти операции автоматически. В этом разделе будет рассказано, каким образом можно подавать команды на различные управляющие элементы приложений.

В качестве примера, рассмотрим управление приложением, написанным на чистом API в предыдущей части “Создание …”.

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

function FindWindow(ClassName, WindowName: PChar): HWnd;
где ClassName - имя класса окна (заканчивающееся пустым символом, nil - если все классы), WindowName - текстовый заголовок окна или nil, если все окна.

Функция возвращает 0, если окно не найдено, либо, в случае успеха, дескриптор окна.

Таким образом, для получения дескриптора необходимо указать имя класса окна и его заголовок. Если они неизвестны, то можно было бы запустить процедуру поиска с использованием функции EnumWindows, которая будет рассмотрена позже.

В нашем случае, зная заголовок и класс окна, можно обойтись следующим кодом:

program program_1;

{$APPTYPE CONSOLE}

uses Windows, SysUtils;

const

sClassName = 'myWindow';

var

handle: HWND;

begin

handle := FindWindow(sClassName, nil);

if handle = 0 then

Writeln('The window not found!')

else

Writeln('*> handle = ', handle);

writeln('press enter');

readln;

end.

В данном случае нет необходимости указывать заголовок окна – оно однозначно определяется классом.

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

Функция

Описание

Параметры

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

GetClassName

Считывает имя класса окна.

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

ClassName: Буфеp для приема имени класса.

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

Фактическое число скопированных символов;

0 - если ошибка

GetWindowText

Копиpует в Str заголовок окна или текст органа управления

Wnd: Идентификатор окна или органа управления.

Str: Буфер, принимающий строку.

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

Фактическое число скопированных байт или 0, если текст отсутствует

GetWindowTextLength

Считывает длину заголовка окна или текста органа управления.

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

Длина заголовка окна в символах

IsIconic

Определяет, является ли окно пиктограммой (минимизированным).

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

Не нуль, если минимизировано; 0 - если нет

IsWindow

Определяет, является ли окно допустимым существующим окном.

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

Не нуль, если окно достоверно; 0 - если нет.

IsWindowEnabled

Определяет, является ли окно разрешенным для ввода с мыши и с клавиатуры

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

Не нуль, если окно разрешено; 0 - если нет.

IsWindowVisible

Определяет, сделано ли окно видимым функцией ShowWindow.

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

Не нуль, если окно существует на экране (даже если полностью закрыто); 0 - если нет

IsZoomed

Определяет, является ли окно максимизированным.

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

Не нуль, если окно максимизировано; 0 - если нет

GetWindowRect

Считывает в ARect размерности ограничивающего прямоугольника окна (в координатах экрана).

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

Rect: Пpинимающая стpуктуpа TRect.

Не используется

GetClientRect

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

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

Rect: Структура TRect для приема координат пользователя.

Не используется

GetWindowLong

Считывает информацию об окне или о значениях дополнительного байта окна

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

Index: Смещение в байтах или одна из следующих констант:

GWL_EXSTYLE GWL_STYLE GWL_WNDPROC GWL_HINSTANCE GWL_HWNDPARENT GWL_ID

GWL_USERDATA

Информация, характерная для окна

GetClassLong

Считывает из структуры окна TWndClass со смещением Index длинное значение. Положительные смещения в байтах (с нуля) используются для доступа к дополнительным байтам класса.

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

Index: Смещение в байтах или константа

GCL_WNDPROC возвращает адрес стандартной процедуры окна

Считанное значение

GetWindowThreadProcessId

Возвращает идентификатор процесса к которому принадлежит данное окно. Как правило, одинаков для всех окон приложения.

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

lpdwProcessId : 32битное значение идентификатора процесса

Идентификатор потока

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

function EnumProc(h: HWND; param: longint): boolean; stdcall;

var wnd_class, wnd_name: pchar; // буферы для класса и заголовка окна

begin

GetMem(wnd_name, 256); // резервируемпамять

GetMem(wnd_class, 256);

GetWindowText(h, wnd_name, 256);

GetClassName(h, wnd_class, 256);

writeln(k,') ',h,' "',wnd_name,'" {',wnd_class,'}');

inc(k); // k – глобальная переменная-счетчик

result := true;

FreeMem(wnd_name); // освобождаемпамять

FreeMem(wnd_class);

result := true; // продолжаемперебиратьокна

end;

адрес которой будет передан API функции EnumWindows:

begin

...

k := 1;

EnumWindows( @EnumProc, 0 );

...

end.

Результат работы консольного приложения (отрывок):

221) 66248 "SysFader" {SysFader}

222) 66106 "┬ёяы√тр■∙хх ьхэ■ ёхЄш" {ATL:701331A0}

223) 65860 "" {SynTrackCursorWindowClass}

224) 65812 "" {SynTrackCursorWindowClass}

225) 65788 "CL RC Engine3 Dummy Winidow" {CL RC Engine3 Dummy Winidow}

226) 65770 "" {tooltips_class32}

227) 131134 "CiceroUIWndFrame" {CiceroUIWndFrame}

228) 196642 "TF_FloatingLangBar_WndTitle" {CiceroUIWndFrame}

229) 66212 "" {tooltips_class32}

230) 131408 "╤яшёюъ с√ёЄЁющ тёЄртъш" {#32770}

231) 590728 "" {ComboLBox}

232) 393944 "" {WMDMNotificationWindowClass}

233) 131900 "DDE Server Window" {OleDdeWndClass}

234) 525194 "" {WMPMessenger}

Практически любые манипуляции с окнами и элементами управления выполняются путем отправки сообщений с помощью функции SendMessage и PostMessage. Отличие между этими функциями заключается в том, что функция SendMessage ожидает, пока адресат не обработает сообщение, в то время как PostMessage просто добавляет сообщение в очередь.

LRESULT SendMessage/PostMessage(

HWND hWnd, // дескрипторокна-адресата

UINT Msg, // посылаемое сообщение

WPARAM wParam, // первый параметр сообщения

LPARAM lParam // второй параметр сообщения

);

Например, рассмотренная выше функция GetWindowText эквивалентна посылке сообщения WM_GETTEXT.

Довольно часто используется сообщение WM_SYSCOMMAND, которое, позволяет выполнять различные операции в зависимости от значения параметра wParam:

  • 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_TASKLISTYLE="Выполняет или инициирует Windows Task Manager.

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

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

SendMessage(handle, WM_SYSCOMMAND, SC_MINIMIZE, nil);

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

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

EnumChildWindows(handle, @EnumProc, 0);

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

1) 918740 "&Click here" {Button}

2) 853116 "Hello" {Edit}

3) 1180824 "Memo1" {Edit}

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

function FindWindowEx(hndParent, hndChild :HWnd; ClassName, WindowName :LpctStr): HWnd;

где HndParent - дескриптор родительского окна верхнего уровня, HndChild - дескриптор дочернего окна с которого начинается поиск, ClassName - имя класса окна (заканчивающееся пустым символом, nil - если все классы), WindowName - текстовый заголовок окна или nil, если все окна. Функция возвращает дескриптор найденного окна либо нуль, если окно не найдено.

Получим дескриптор кнопки:

h_butt := FindWindowEx( handle, 0, 'BUTTON', '&Click here');

if h_butt = 0 then Writeln('The button not found!')

else Writeln(' handle of the button is ', h_butt);

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

var id_butt: integer;

id_butt := GetDlgCtrlID(h_butt);

И убедимся, что этот идентификатор совпадает с заданным нами в предыдущей части (id_button=100). Согласно справки MSDN по сообщению BN_CLICKED, нижнее слово параметра wParam, который имеет тип LongWord или двойного слова (одно слово – 16 бит), должно содержать идентификатор, а верхнее – номер сообщения BN_CLICKED. Параметр lParam содержит дескриптор элемента управления – кнопки. То есть, необходимо отправить следующее сообщение:

SendMessage(handle, WM_COMMAND, MakeWParam(id_butt, BN_CLICKED), h_butt);

где функция MakeWParam собирает двойное слово из двух слов.

Для того, чтобы записать текст в строковой редактор можно использовать сообщение WM_SETTEXT. Участок кода, выполняющий поиск edit’а и меняющий его текст выглядит следующим образом:

var pCh: pChar;

...

h_edit := FindWindowEx( handle, 0, 'EDIT', 'Hello');

if h_edit = 0 then

Writeln('The edit not found!')

else begin

Writeln(' handle of the edit is ', h_edit);

pCh := 'текст, вставленный из другой программы';

SendMessage(h_edit, WM_SETTEXT, 0, integer(pCh));

end;

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

h_menu := GetMenu(Handle); //получили дескриптор главного меню окна.

if h_menu <> 0 then begin

h_menu := GetSubMenu(h_menu,0);//получили дескриптор первого пункта главного меню (0 -первый пункт)

//получим идентификатор 3 пункта подменю меню (черты в меню - это также пункты)

id_menu := GetMenuItemID(h_menu, 2);

if id_menu <> 0 then

//запускаемпунктменю. Именно PostMessage, SendMessage - неработает.

PostMessage(handle, WM_COMMAND, id_menu, 0);

end;

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

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

// следующая функция является макросом, не переведенным с С++ в поставке Delphi

function MAKELANGID(sPrimaryLanguage : Word;

sSubLanguage : Word) : Word;

begin

result := (sSubLanguage shl 10) or

sPrimaryLanguage;

end;

var pCh: pChar; // буфер для сообщения об ошибке

// при возникновении ошибки ее код нужно преобразовать в понятный пользователю текст с помощью функции FormatMessage

FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER OR FORMAT_MESSAGE_FROM_SYSTEM,

nil, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) {Default language},pCh, 0, nil);

// показываемошибкупользователю:

MessageBox( 0, pCh, 'Last error', MB_OK or MB_ICONINFORMATION );

Проектное задание

Написать программу, которая будет пытаться двигать главное окно компилятора Delphi, вызывать пункты меню сохранить (Save all) и запустить (Run). При вызове пункте меню Save as… программно заставить сохранить по указанному заранее пути. Попробуйте создать свою кнопку в чужом приложении.

Тест рубежного контроля №3

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

1. Утилита WinSight позволяет

1)

Следить за окнами и сообщения, приходящим к ним

2)

Следить за окнами и изменять их свойства

3)

Изменять сообщения, приходящие окнам и менять класс окон

4)

Только определить класс и заголовок окна

2. Режим поиска Follow focus позволяет

1)

Искать окна

2)

Отслеживать сообщения

3)

Искать окна и отслеживать нужные сообщения

4)

Не используется в 32 разрядных операционных системах

3. Для управления окном необходимо получить его

1)

Экранные координаты (Rect)

2)

Графический дескриптор (HDC)

3)

Оконный дескриптор (HWND)

4)

Класс окна, зарегистрированный в системе

4. Для программного нажатия на кнопку необходимо знать

1)

Дескриптор кнопки

2)

Акселератор (id) кнопки

3)

Дескриптор и акселератор

4)

Дескриптор кнопки, ее акселератор и дескриптор окна

5. Перебор всех главных окон в системе рекомендуется осуществлять функциями:

1)

EnumWindows

2)

FindWindow, GetNextWindow

3)

EnumChildWindow

4)

FindWindowEx

Бланк ответов

1

2

3

4

1)

2)

3)

4)

5)

Критерии оценки

4 и более правильных ответов – отлично

3 правильных ответа – хорошо

2 правильных ответа – удовлетворительно

1 и менее правильных ответов - неудовлетворительно

Список литературы

  1. MSDN, July 2006

  2. Материалы форума сайта “Мастера Делфи” /

  3. Материалы форума сайта “Королевсво Делфи” /

  4. В.В. Фаронов. Delphi 4. Учебный курс. 1999.

  1. Каталог конкурентоспособных предприятий краснодарского края (1)

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

    Документ
    Буровое и нефтепромысловое оборудование, циркуляционные системы, башни сотовой связи, блоки к циркуляционным системам, емкости до 60м3, поддоны стеновых панелей для панельного домостроения,
  3. Каталог конкурентоспособных предприятий краснодарского края (3)

    Документ
    Омская, Курганинская, Челябинская, Сведрловская, Курская, Белгородская, Воронежская, Волгоградская, Ростовская области, Республики Адыгея, Башкортостан,
  4. М. П. Горчакова-Сибирская (отв ред., Спбгиэу), д-р философ наук, проф (2)

    Документ
    д-р пед. наук, проф. М. П. Горчакова-Сибирская (отв. ред., СПбГИЭУ), д-р философ. наук, проф. Е. А. Гусева (зам. отв. ред. СПбГИЭУ), канд. филолог. наук, Е.
  5. М. П. Горчакова-Сибирская (отв ред., Спбгиэу), д-р философ наук, проф (1)

    Документ
    д-р пед. наук, проф. М. П. Горчакова-Сибирская (отв. ред., СПбГИЭУ), д-р философ. наук, проф. Е. А. Гусева (зам. отв. ред. СПбГИЭУ), канд. пед. наук М.
  6. Департамент внешнеэкономических и межрегиональных связей Костромской области

    Документ
    В целях развития двустороннего межрегионального сотрудничества и расширения взаимовыгодных поставок потребительских товаров и продукции производственно технического назначения департамент внешнеэкономических и межрегиональных связей
  7. Каталог конкурентноспособных предприятий кубани (1)

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

    Документ
    Производство прочего подъемно - транспортного оборудования (домкратные установки для подъема подвижного состава,гидравлический инструмент для ремонта и текущего содержания пути и др.
  9. Выпускаемые товары и услуги

    Документ
    Производство изделий медицинского, технического и бытового назначения на основе натурального латекса (перчатки анатомические, хирургические, технические,

Другие похожие документы..