Быстрое написание программ на WinAPI
Все программисты делятся на две группы – oldschool и новую волну. Сыны старой школы помнят историю о 640 килобайтах, помнят о тысяче игр на одной дискете… Новая волна, чаще всего, даже не знает устройство компьютера, но так же считается – программистами. Использование IDE изменило представление о программистах. Посмотрим, что же может дать отказ от визуального программирования. В этой статье я опишу один из способов быстрого написания приложений с использованием функций WinAPI.
Вступление или «Кому это нужно?»
Вы можете задаться вопросом, зачем же насиловать свой мозг, если давным-давно изобретена VCL, MFC и прочие прелести визуального программирования? Для ответа на этот вопрос давайте посмотрим на плюсы и минусы визуального и низкоуровневого* программирования.
* Комментарий автора.
Здесь под низкоуровневым программированием я имею в виду программирование без использования графических компонентов — использование функций WinAPI напрямую для создания окон, работы с графикой и т.д.
Итак, рассмотрим плюсы визуального программирования:
быстрое написание программ (достаточно накидать кнопок на форму и написать их процедуры);
удобство использования (это удобнее, чем описывать каждый шаг на низком уровне, не нужно заботиться о памяти).
И минусы:
огромный размер приложений — «пустое» приложение на Delphi «весит» ~300 кб;
из-за огромного количества надстроек быстродействием приходится пренебречь, особенно в плане графики на Canvas.
И в противоположность, рассмотрим плюсы низкоуровневого программирования на WinAPI:
малый размер конечных файлов (согласитесь, что между 30 кб и 300 кб есть большая разница);
быстродействие на достаточно высоком уровне (быстрее получится только, если писать целиком на ассемблере – то еще удовольствие).
И минусы:
нет визуализации (труднее представить, что создать, что уничтожить, что где писать);
для создания обычного окна потребуется примерно 50 строк кода (создать и зарегистрировать само приложение, создать окно, заботиться о всех параметрах);
необходимо помнить о необходимости следить за использованием памяти — освобождением, взятием. Здесь обычным *.Free не обойдешься.
Но, если мы представим, что избавились о минусах программирования на WinAPI, чаша весов склонится в сторону низкоуровневого программирования. Так как же нам от них избавиться? Итак, взглянем в сторону фреймворков, которые это позволяют. За всю мою практику программирования на Delphi сталкивался с таким только единожды** – APIx 2 (Visual WinAPI). Но данное средство разработки не предполагает активное использование графики, только создание окон и кнопок. Поэтому я решил создать такую библиотеку, которая позволит не только быстро создавать окна, но и активно использовать графику.
Не хвастаясь особо, сообщу, что мне это удалось. И через три недели разработки GRAY FUR был готов.
** Комментарий автора.
Не сомневаюсь, что существуют и другие, но они остались вне моего поля зрения. Хотя я допускаю, что никто просто не думал о таком — все привыкли к визуальному программированию.
WTF… или что это даст?
Mon ami, это же элементарно: не нужно заботиться о расходе и приходе памяти, размышлениям о бренности окон. Да, мы по прежнему не имеем дела с визуальностью, но, согласитесь, что намного удобнее вызвать одну процедуру, чем записывать пару десятков с многочисленными параметрами. Так, например отрисовать текстуру на экране можно так:
Var
Loc : HDC;
TNum : Integer;
Begin
Loc := CreateCompatibleDC(DC);
SelectObject(Loc, Bitmap);
BitBlt(DC,
X, Y,
Width,
Height,
Loc,
0, 0,
SRCCOPY);
DeleteDC(Loc);
End;
А можно и так:
Draw(Form1, Num, X, Y, FALSE);
BufferDraw;
Причем, если мы не подумаем о том, как создать двойную буферизацию в первом случае изображение будет мерцать при отрисовке. Во втором случае все это уже встроено в систему.
Panic button
Рассмотрим написание Panic button с использованием нашей системы. Для того, кто еще не читал моей статьи о создании Panic Button на WinAPI [1] поясню, что эта кнопка на экране будет сворачивать все окна по нажатию на нее.
Итак, скачаем *** FrameWork и посмотрим, как же это делается. По привычке, я буду делать это на Lazarus, но вы так же можете использовать Delphi, используя пакет для разработки под Delphi.
*** Комментарий автора.
Все ссылки представлены в конце статьи.
Для начала создадим то, что кнопка должна делать:
Procedure HideAll(Handle : HWND); // Эту процедуру будем использовать по клику левой кнопки мыши
Begin
Keybd_event(VK_LWIN,0,0,0); // Эмулируем нажатие клавиши Win
Keybd_event(VK_D ,0,0,0); // Эмулируем нажатие клавиши D
Keybd_event(VK_D ,0,KEYEVENTF_KEYUP,0); // Отпустим D - все окна свернутся
Keybd_event(VK_LWIN,0,KEYEVENTF_KEYUP,0); // Отпустим Win.
End;
Так же сделаем процедуру закрытия приложения:
Procedure KillMe(Handle : HWND); // Процедура жестокого убийства
Begin
DestroyTimer(ID); // Удалим таймер, созданием которого мы еще займемся
DestroyApplication; // Уничтожим приложение
End;
И для полного счастья сделаем так, чтобы кнопка всегда была наверху:
Procedure OnTop;
Begin
SetformOnTop(Form1, TRUE); // Установим её всегда сверху.
End;
Да, и еще создадим функцию для вычисления вертикальной позиции:
Function CalculateYp : Integer;
Var
R : Rect;
H : Handle;
W : Integer;
PH : Integer;
Begin
W := GetSystemMetrics(SM_CYSCREEN); // Получаем вертикальное разрешение
ZeroMemory(@R, SizeOf(R));
H := FindWindow('Shell_TrayWnd', Nil); // Найдем окно панели задач
GetWindowRect(H, R); // Его размеры
PH := R.Bottom - R.Top; // Вычислим высоту
Result := W - PH - Form1.Height; // И получим искомое
End;
Рассмотрим само тело программы:
program Project1;
{$mode delphi}{$H+} // Директивы для Lazarus
Uses
Windows, // Подключим Windows
Scow; // Подключим модуль-связку проекта
Var
Form1 : TForm; // Наше главное окно. Тип описан в Scow
ID : Integer; // ID таймера
// Здесь находятся процедуры, описанные выше
begin
CreateApplication; // Создаем приложение
SetApplicationReaction1(HN_LBUTTONDOWN, HideAll); // Назначим событие по левому клику
SetApplicationReaction1(HN_RBUTTONDOWN, KillMe); // Назначим событие по правому клику
CreateForm(Form1, FALSE); // Создадим форму FALSE - не показывать на панели задач
ShowForm(Form1, TRUE); // Покажем ее на экране
ResizeForm(Form1, 64, 64); // Назначим размеры
MoveForm(Form1, 0, CalculateYp); // И положение
LoadTexture(Form1, 'Button.bmp', 'Button'); // Загрузим текстуру в хранилище****
Draw(Form1, 'Button', 0, 0, FALSE); // Нарисуем текстуру на буфере
BufferDraw(Form1); // И выведем его на экран
ID := CreateTimer(1000, OnTop); // Создадим таймер для вызова процедуры OnTop
CollectMessages; // И организуем цикл сбора сообщений для корректной работы приложения
end. // That's all, folks!
**** Комментарий автора.
Все подробности управления графикой смотрите в документации к проекту.
Да, и это все, как и говорится в последней строке программы. Попробуйте поискать многочисленные работы с памятью и прочими непристойностями — их просто нет. Таким образом, мы избавились от главного минуса программ на WinAPI – скорости и сложности написания. И получили плюсы – размер проекта на Delphi всего ~20 кБ по сравнению с ~300 и 39 кБ в Lazarus по сравнению с ~900 кБ. Так же не пострадало и быстродействие – прямые работы с памятью в операциях с графикой и прямой вызов WinAPI функций в проекте.
Вместо заключения
Итак, использование фреймворка дало свои плюсы. Быстрота написания (на это у меня ушло не более 3-х минут), малый размер и быстродействие – все это в одном флаконе. Так же, так как практически все функции имеют понятные названия и параметры то его можно запросто использовать для обучения основам управления программой на WinAPI. В общем, я надеюсь, что он, повторяя путь развития паскаля, перейдет в массы.
|