· 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 Прокручивается окно вертикально.
Например, для того чтобы свернуть окно достаточно написать:
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; // буфер для сообщения об ошибке…// при возникновении ошибки ее код нужно преобразовать в понятный пользователю текст с помощью функции FormatMessageFormatMessage( 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… программно заставить сохранить по указанному заранее пути. Попробуйте создать свою кнопку в чужом приложении.
Тест содержит 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. Материалы форума сайта “Мастера Делфи” http://www.delphimaster.ru/
3. Материалы форума сайта “Королевсво Делфи” http://www.delphikingdom.com/
4. В.В. Фаронов. Delphi 4. Учебный курс. 1999.