Рассылка закрыта
При закрытии подписчики были переданы в рассылку "О карьере и профессиональном развитии IT-специалистов" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
← Декабрь 2005 → | ||||||
1
|
2
|
3
|
4
|
|||
---|---|---|---|---|---|---|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
15
|
16
|
17
|
18
|
|
19
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
27
|
28
|
29
|
30
|
31
|
Статистика
-4 за неделю
Программирование для начинающих и не только
Информационный Канал Subscribe.Ru |
Чистый WinAPI
Время от времени в разных форумах посвященных Delphi возникают вопросы об уменьшении размера готовых приложений. И очень часто в ответах мелькает фраза: <Используй WinAPI>. Но для человека, который начал изучение программирования с Delphi с его джентельментским набором под названием VCL, бывает очеть трудно перестроится на логику WinAPI.
О чем реч
Как видно из названия ОС Windows все елементы ее графического интерфейса, будь то осонная форма, кнопка, панель или другие элементы представляются в виде окон. Сейчас же мы попытаемся вместе разобраться с возможностями WinAPI на примере создания небольшой оконой формы и организации взаимодействия с пользователем и системой.
Итак.
Для начала следует сказать, что мы здесь не будем использовать все Forms,Buttons,StdCtrls - модули созданные Borland для упрощения жизни программистов. Мы полечем как всегда через окно, и будем использовать только модули Windows, в котором объявлены все необходимые функции и модуль Messages, в котором объявлены константы сообщений системы необходимые для организации реакции элементов на те или иные события.
Из модуля Windows мы в основном будем оспользовать функцию CreateWindow, которая имеет следующий вид:
Эта функция принимает такие параметры:function CreateWindow(lpClassName: PChar; lpWindowName: PChar; dwStyle: DWORD; X, Y, nWidth, nHeight: Integer; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND;
- LpClassName - указатель на зарегистрированное имя класса. Это имя может быть как зарегистрированным новым именем класса, так и уже имеющемся в системе классом. Так среди уже зарегистрированных имен классов можно увидеть:BUTTON,COMBOBOX,EDIT,LISTBOX,MDICLIENT,SCROLLBAR,STATIC.
- LpWindowName - указатель на название окна
- DwStyle - флаги задающие стиль окна. Их значения приведены в табл.1
- x, y, nWidth, nHeight - координаты окна
- hWndParent - идентификатор родительского окна.
- HMenu - идентификатор меню.
- HInstance - идентификатор приложения.
- LParam - указатель на дополнительные данные для создания окна.
- Возвращаемое значение - если создание окна прошло удачно, то функция возвращает его идентификатор, если же окно по каким либо причинам не было созданно, то возвращает 0.
function RegisterClass(const lpWndClass: TWndClass): ATOM; stdcall;
где- lpWndClass - структура описывающая все особенности поведения окон созданных при помощи этого класса.
- Результат функции - тип ATOM по сути тот же тип Word. Если выполнение функции прошло удачно, то возвражает идентификатор класса, и значение NULL (т.е. 0) в противном случае.
style: UINT; | Значение задающее стиль окна. Возможные значения поданы в табл.2 |
lpfnWndProc: TFNWndProc; | Указатель на процедуру-обработчик событий возникающих для данного элемента |
cbClsExtra: Integer; | Задает размер екстра-памяти выделяемой при создании оконного класса.В нашем случае - 0 |
cbWndExtra: Integer; | Задает размер екстра-памяти выделяемой при создании нового экземпляра окна. В нашем случае - 0 |
hInstance: HINST; | Идентификатор нашего приложения |
hIcon: HICON; | Идентификатор иконки. |
hCursor: HCURSOR; | Идентификатор курсора. |
hbrBackground: HBRUSH; | Идентификатор класса фоновой заливки |
lpszMenuName: PAnsiChar; | Указатель на название ресурса-меню в ресурсах приложения |
lpszClassName: PAnsiChar; | Указатель на название регистрируемого класса |
В этой структуре нам следует обратить внимание на параметр lpfnWndProc так как именно суда записывается указатель на функцию-обработчик событий, который выглядит следующим образом:
function (hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
здесь
- hwnd - идентификатор окна
- Msg - сообщение переданное окну
- lParam,wParam - дополнительная информация зависящая от переданного сообщения
- Возвращаемое значение - результат выполнения функции и зависит от переданного сообщения
Подготовительные работы
Для того, чтоб иметь возможность вдоволь насладится нашим, созданным в ручную, окном, мы сперва должны зарегистрировать соответствующий класс. Для этого нам подадобится в первую очередь заполнить структуру WndClass следующим образом:
Далее посредством вызова функции Windows.RegisterClass мы регистрируем наш класс под названием WinAPITestForm:ZeroMemory(@WndClass,SizeOf(WndClass)); WndClass.style:=CS_HREDRAW or CS_VREDRAW; WndClass.lpfnWndProc:=@DefWindowProc; WndClass.hInstance:=Sysinit.hInstance; WndClass.hIcon:=0; WndClass.hCursor:=0; WndClass.hbrBackground:=COLOR_WINDOW; WndClass.lpszClassName:='WinAPITestForm';
Windows.RegisterClass(WndClass);
Теперь мы уже можем приступить к созданию самого окна:После этого в реальном приложении необходимо проверить правильно ли созданно окно, и вывести информацию об ошибке при негативном ответе и сделать <аварийный> выход из программы. Но здесь мы этого делать не будем по причине тривиальности этого кода.Wnd:=CreateWindow('WinAPITestForm','Test Form', WS_BORDER or WS_CAPTION or WS_SYSMENU or WS_VISIBLE, 100,100,300,300,0,0,hInstance,@CSTR);
Далее нам необходимо реализовать цикл обработки сообщений. Без этого цыкла наше приложение просто не сможет жить долго. При запуске оно будет сразу же закрываться.
Тело цыкла выглядит следующим обратом:
Вот так вот простенько и реализовываем обработку сообщений. Здесь главную роль играет функция GetMessage прототип еоторой объявлен следующим образом:while GetMessage(Msg,0,0,0) do begin TranslateMessage(Msg); DispatchMessage(Msg); end;
Здесьfunction GetMessage(var lpMsg: TMsg; hWnd: HWND; wMsgFilterMin, wMsgFilterMax: UINT): BOOL; stdcall;
- lpMsg - адрес структуры с сообщением и дополнительными параметрами
- hWnd - идентификатор окна для которого идет обработка сообщений wMsgFilterMin
- wMsgFilterMax - флаги фильтрации сообщений
- Результат - 0 если возникло сообщение WM_QUIT, тогда реализуется выход из приложения. Или же ненулевое значение для других сообщений. При возникновении ошибки результат функции равен -1
Все. Конец приложения. Полний текст приложения можно увидеть в листинге.1, а результат работы приложения на рис.1Windows.UnregisterClass('WinAPITestForm',hInstance); Halt(Msg.wParam);

Обработка сообщений
Но в таком виде (пустая форма), наше приложение никому не нужно, и кроме как занимания места на ґкране оно ничего не делает. К стати оно даже не может нормально завершится, поскольку функция DefWindowProc, которая была объявлена в качестве обработчика сообщений нашей формы не реализуе посылку сообщения WM_QUIT. Можете проверить нажав на Ctrl+Alt+Del. Для того чтоб сдеталь нашу форму более живой нам потребуется реализовать свой собственный обработчик сообщений. Для этого еще раз вспомним объявление,
функции-обработчика сообщения:
function (hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
И постараемся добавить до функции DefWindowProc дополнительные возможности. Для этого мы сначала объявим следующую функцию:
function MyWindowProc(Wnd:Hwnd;Msg:UINT;lParam:LPARAM;wParam:WPARAM):LRESULT;stdcall;
И не забываем, не забываем об stdcall иначе у нас как минимум ничего не получится. Далее в теле этой функции мы можем обрабатывать все необходимые сообщения. Первым делом что мы сделаем - это будет реализация нормального закрытия нашего приложения:
Теперь все что нам остается сделать, это перенаправить обработку сообщений из DefWindowProc на наш обработчик при объявлении параметорв класса. (просто заменим ссылку WndClass.lpfnWndProc на MyWindowProc). И откомпилировать приложение.Result:=0; case Msg of WM_DESTROY:PostQuitMessage(0); else Result:=DefWindowProc(Wnd,Msg,lParam,WParam); end;
Другие окна
Итак, теперь мы уже знаем как <открывать> окна без помоши VCL, но конечно одними окнами сыт не будеш, и глаз уже интуитивно ищет чтоб такое нажать. Для этого эстественно предназначены конпки, которые мы и создадим на следующем этапе.
И спешу вас обрадовать, что нам больше не придется ничего регистрировать и писать лишние обработчики. Для создания конпки достаточно только одной строки:
Wnd1:=CreateWindow('BUTTON','Button1',BS_PUSHBUTTON or WS_VISIBLE or WS_CHILD,110,110,150,40,Wnd,0,hInstance,@CSTR);
Да и то большинство элементов которой Вам уже знакомы. Так здесь мы создаем элемент оконного класса

Операции кнопками созданными в таком виде тоже осуществляются путем посыла и обработки сообщений. Так к примеру для изменения названия кнопки следует применить такой подход:
SendMessage(Wnd1,WM_SETTEXT,0,LPARAM(PChar('Testing')));
Т.е. послать конпке сообщение об изменении текста и в качестве параметра lParam передать текст нового нозвания конпки.
Так же можно и прочитать название конпки, только вместо WM_SETTEXT передать сообщение WM_GETTEXT и предоставить ссылку на переменную в которую можно поместить результат.
И на последок мы нсколько изменим наш обработчик сообщений и покажем как можно обрабатывать сообщения мыши. Для этого мы впишем в функцию MyWindowProc реакцию на сообщение WM_LBUTTONDOWN, которая будет изменять текст нашей кнопки. После всех изменений наш обработчик выглядит следуюшим образом:
И после компиляции и запуска приложения мы жмем на область формы и получаем результат показанный на рис.3, при условии что в S было записано значениеfunction MyWindowProc( Wnd:Hwnd; Msg:UINT; lParam:LPARAM; wParam:WPARAM): LRESULT; stdcall; begin Result:=0; case Msg of WM_LBUTTONDOWN:SendMessage(Wnd1,WM_SETTEXT,0,Integer(S)); WM_DESTROY:PostQuitMessage(0) else Result:=DefWindowProc(Wnd,Msg,lParam,WParam); end; end;

Для чего все это надо
Действительно, для чего нам осваивать WinAPI если можно намного быстрее сообразить все это на VCL. Да, конечно если вы так скажете, то будете правы, вот только тепер создайте такую же форму с кнопкой с использовнием VCL и откомпилируйте ее. Так, а теперь посмотрите на размеры файлов. У меня получилось 300К а при использовании WinAPI только 15К т.е. в 20 раз меньше. Здесь также можно возразить чот мол это не страшно, ведь сегодня мы и не такими размерами файлов балуемся, но во первых не у все есть доступ к таким большим размерам да и с и-нета закачивать 15К намного быстрее и экономнее чем 300К. А если еще предположить с точки зрения быстродействия, что системе надо перемалывать все эти 300К то сразу становиться ясно, как необходимо писать приложения требовательные к времени выполнения.
Таблица.1 Описание некоторых флагов dwStyles функции CreateWindow | |
---|---|
WS_BORDER | Задает наличие границы. |
WS_CAPTION | Создание окна, с названием и титульной областью свехру |
WS_CHILD, WS_CHILDWINDOW | Создает дочернее окно. Нельзя использовать вместе с WS_POPUP |
WS_CLIPCHILDREN | Вырезает из главной области отрисовки те области что используются дочерними окнами. |
WS_DISABLED | Создает окно первоначально находящееся в отключенном виде. |
WS_DLGFRAME | Создает окно с фиксированными границами и стилем используемым для диалогов |
WS_GROUP | Задает первое окно из семейства сгрупированных компонентов. Все следующие создаваемые окна будут принадлежать той же групе, пока не будет созданн следующий компонент с этим флагом, который задаст начало другой групе. |
WS_HSCROLL | Создает компонент, который имеет окно горизонтальной прокрутки |
WS_ICONIC | Созданное окно первоначально находится в свернутом виде. То же что и WS_MINIMIZE |
WS_MINIMIZEBOX | Создает окно, которое имеет кнопочку минимизации. |
WS_MAXIMIZE | Созданное окно первоначально раскрыто на весь экран |
WS_MAXIMIZEBOX | Создает окно с кнопочкой максимизации |
WS_POPUP | Создает всплывающее pop-up окно |
WS_POPUPWINDOW | Создает окно со свойствами WS_POPUP, WS_BORDER, WS_SYSMENU |
WS_SIZEBOX | Создает окно размеры которого можно менять. |
WS_SYSMENU | Создает окно которое содержит системное меню e.g. Восстановить, Свернуть, Максимизироать, Закрыть. |
WS_THICKFRAME | То же что и WS_SIZEBOX |
WS_VISILE | Созданное окно сразу стает видимым |
WS_VSCROLL | Создает окно с вертикальной линейкой прокрутки |
Флаги специфические для класса BUTTON | |
BS_3STATE | Создает кнопку, такую же как и CheckBox, но с дополнительным состоянием Grayed. |
BS_AUTO3STATE | То же что и BS_3STATE только при нажатии состояние кнопки цыклически меняется Checked -> Unchecked -> Grayed. |
BS_AUTOCHECKBOX | Создает кнопку такую же как и Checkbox, состояние которой меняется цыклически Checked -> Unchecked |
BS_AUTORADIOBUTTON | Создает оуно такое же как и RadioButton. При нажатии система автоматически выставляет ее состояние в Checked а всех других аналогичных компонентов в той же групе в Unchecked |
BS_CHECKBOX | Создает стандартный Checkbox |
BS_DEFPUSHBUTTON | Создает кнопку со свойством Default. (Дополнительное черное обрамление). Которая реагирует на нажатие Enter даже ели на ней нет фокуса |
BS_GRUOPBOX | Сознает окно GroupBox |
Таблица.2 Описание флагов style структуры WNDCLASS | |
---|---|
CS_BYTEALIGNCLIENT | Выстраивает клиентскую часть окна на границу байта, что позволяет достичь большей производительности при отрисовке |
CS_BYTEALIGNWINDOW | То же что и CS_BYTEALIGNCLIENT, только увеличивает производительность при перемежении окна |
CS_CLASSDC | Создает контекст устройства, которые разделяется между всема наследнками этого класса |
CS_DBLCLKS | Разрешает обработку сообщений о двойном щелчке мыши |
CS_GLOBALCLASS | Разрешает создание окон с независимыми идентификаторами приложений, если этот флаг не указан, то значение hInstance при создании окна должно быть таким же как и при регистрации класса RegisterClass. |
CS_HREDRAW | Перерисовывает окно при его перемещении по горизонтали |
CS_VREDRAW | Перерисовывает окно при его перемещении по вертикали |
CS_NOCLOSE | Убирает команду закрыть из системного меню окна |
CS_OWNDC | Создает уникальный контекст устройства для каждого вновь создаваемого окна |
Subscribe.Ru
Поддержка подписчиков Другие рассылки этой тематики Другие рассылки этого автора |
Подписан адрес:
Код этой рассылки: comp.soft.prog.programmershelp Архив рассылки |
Отписаться
Вспомнить пароль |
В избранное | ||