Такие программы жрут память, как термиты и
занимают, своим жирным телом, лишнее дисковое
пространство. Как правило, MFC/VCL аналоги
"весят" в десять - двадцать раз больше, чем
программы написанные на чистом API. А Visual
Basic (да простит меня бог за это
словосочетание) с его msvbvmXX.dll? Да и
системных ресурсов расходуется значительно
больше (в несколько раз). Бедные пользователи,
отказывая себе в пиве, копят ассигнации на
покупку нового железа. Разве не жалко -
бедненьких? Не только же программерам пиво пить?
Есть еще один положительный момент в API
кодинге, программист становится ближе к
операционной системе. Соответственно - лучше ее
понимает и контролирует. Да и просто - это очень
увлекательное занятие. Повторюсь, все
вышесказанное относится именно к маленьким,
простеньким программкам, в больших проектах все
обстоит совершенно иначе.
Надеюсь, убедил. Поехали.
Мы рассмотрим создание простенького оконного
интерфейса с минимальной функциональностью. Это
будет простое окошко с двумя полями ввода и
двумя кнопочками. При нажатии на кнопку "Copy",
текст из первого поля ввода будет скопирован во
второе. При нажатии на кнопку "Close", программа
завершит свою работу. В дальнейшем оно может
послужить шаблоном для написания других, более
сложных, приложений. Будем общаться на языке
C/C++, хотя и Delphi не обидим. Общий принцип
один и тот же, различается только синтаксис.
Чтобы работать с системными сообщениями и
API-функциями, необходимо к своему проекту
подключить заголовочные файлы; в C/C++ это
windows.h, в Delphi это модули windows и
messages.
Любая программа в ОС Windows состоит из трех
основных частей: главной функции, цикла
обработки сообщений и оконной функции, которая
обрабатывает все сообщения, посылаемые окну.
Наша программа начинает выполняться с функции
WinMain(). Это и есть главная функция.
Функция WinMain() выполняет, обычно,
следующие задачи:
- Определяет класс окна. Не путать с классом
ООП.
- Регистрирует данный класс в системе.
- Создает главное окно приложения и другие
элементы управления.
- Отображает окно на экране.
- Запускает цикл обработки сообщений.
- Объявляется она вот каким образом:
int APIENTRY WinMain(HINSTANCE
hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, int nCmdShow) Разберемся
с параметрами:
- hInstance - дескриптор текущего экземпляра
приложения.
- hPrevInstance - дескриптор предыдущего
экземпляра приложения, если оно запущено.
- lpCmdLine - указатель на строку, содержащую
параметры передаваемые программе при запуске.
- nCmdShow - константа определяющая способ
отображения окна. (Смотри константы SW_).
В Delphi мы не увидим такой картины, в этой
среде разработки главная функция скрывается от
программиста компилятором. Хотя, несомненно, она
присутствует в конечном коде. Для регистрации
класса окна, необходимо заполнить поля структуры
типа WNDCLASS (в Delphi TWNDCLASS). У
нас, для этого, объявлена переменная
wcl.
- wcl.hInstance = hInstance;
- Дескриптор текущего экземпляра приложения,
переменная hInstance инициализируется функцией
WinMain(). В Delphi инициализируется неявным
образом.
- wcl.lpszClassName = szWinName;
- Имя класса. Строковую переменную szWinName
мы создали и инициализировали предварительно.
- wcl.lpfnWndProc = WindowFunc;
- Указатель на оконную функцию.
- wcl.style = 0;
- Константа, задающая стиль окна. Для этого
используется флаги CS_, я просто обнулил. Можно
задавать комбинацию флагов с помощью битовой
операции "или".
- wcl.hIcon = LoadIcon(NULL, IDI_ASTERISK);
- Дескриптор иконки приложения, возвращаемый
функцией LoadIcon(). Я загрузил стандартную
иконку. Смотри константы IDI_.
- wcl.hCursor = LoadCursor(NULL,IDC_ARROW);
- Дескриптор курсора приложения, возвращаемый
функцией LoadCursor(). Я загрузил стандартную
стрелочку. Смотри константы IDC_.
- wcl.lpszMenuName = NULL;
- Указатель на строку, задающую имя ресурса
меню для данного оконного класса. Нет меню, нет
и указателя.
- wcl.cbClsExtra = 0;
- Зарезервированное поле. Обнуляем.
- wcl.cbWndExtra = 0;
- Зарезервированное поле. Обнуляем.
- wcl.hbrBackground = (HBRUSH)COLOR_WINDOW;
- Цвет окошка. Константа COLOR_WINDOW
приводится к типу HBRUSH (в Delphi приводить не
нужно). Также, с помощью функции
GetStockObject(), можно задать цвет кисти окна
или фоновый рисунок.
Теперь, смело,
регистрируем класс окна.
RegisterClass(&wcl);
В качестве параметра функции
RegisterClass передается указатель на
структуру wcl.
Следующей строкой мы
создаем наше окно.
hMainWnd = CreateWindow(szWinName,
"Простое окно на
API.", WS_OVERLAPPEDWINDOW ^
WS_THICKFRAME ^ S_MAXIMIZEBOX, CW_USEDEFAULT,
CW_USEDEFAULT, 300, 170, HWND_DESKTOP, NULL,
hInstance, NULL);
- Первый параметр - имя класса окна.
- Второй параметр - Заголовок окна.
- Третий параметр - стиль окна. Из
стандартного WS_OVERLAPPEDWINDOW, с помощью
операции xor, я изъял возможность
масштабирования окна и отключил кнопку
максимизации.
- Четвертый и пятый - положение окна от
левого, верхнего угла экрана. У меня
CW_USEDEFAULT, при этом значении система
выбирает положение окна автоматически.
- Шестой и седьмой параметры - ширина и высота
окна, соответственно.
- Восьмой параметр - окно владелец. У главного
окна, владелец - рабочий стол (0). У элементов
управления - главное окно.
- Девятый - указатель на дескриптор меню. Нет
меню, нет и указателя.
- Десятый параметр - Дескриптор текущего
экземпляра приложения.
- Одиннадцатый - Используется при создании
приложений с MDI-интерфейсом. Нам не
нужен.
Функция возвращает дескриптор созданного
окна, который заносится в переменную hMainWnd.
Дескриптор окна - уникальный номер в
системе, по которому идентифицируется окно или
элемент управления.
Далее мы создадим необходимые элементы
управления. Все элементы управления - те же
окна, просто они имеют другое имя класса. Классы
элементов управления регистрировать не нужно,
они уже предопределены в системе. Кнопка - класс
button. Поле ввода - класс
edit. Надпись - класс ststic.
Существует множество классов, которые
соответствуют стандартным элементам управления.
Контролы создаем с помощью, знакомой нам,
функции CreateWindow()
и незнакомой
CreateWindowEx().
CreateWindowEx() позволяет создать окно
с расширенным стилем. Мы используем ее для
создания полей ввода. В этой функции добавлен
первый параметр, который и задает этот самый
расширенный стиль, остальные параметры как у
CreateWindow(). Элементы управления
являются дочерними окнами, их владелец главное
окно.
Создавая контролы, в параметрах функции
необходимо указать дескриптор главного окна, а
также стиль окна WS_CHILD. Внешним видом и
функциональностью элементов управления можно
манипулировать с помощью флагов: WS_, ES_, BS_,
SS_, объединяя их битовой операцией "или".
Создавая контролы, мы инициализируем
соответствующие переменные их дескрипторами,
которые возвращают функции CreateWindow() и
CreateWindowEx(). Эти дескрипторы понадобятся
нам для дальнейшей работы с элементами
управления. Отображаем, созданное нами, окно на
экране и перерисовываем его.
ShowWindow(hMainWnd,
nCmdShow); UpdateWindow(hMainWnd); //
Создаем цикл обработки
сообщений while(GetMessage(&msg, NULL, 0,
0)){
TranslateMessage(&msg);
DispatchMessage(&msg); }
Функция GetMessage выбирает очередное
сообщение из очереди сообщений приложения и
отправляет его окну.
- Первый параметр - структура типа MSG (в
Delphi типа TMSG)
- Второй параметр - дескриптор окна, которому
предназначено сообщение. Если NULL или 0, то все
окна приложения.
- Третий и четвертый - позволяют задать
диапазон принимаемых сообщений. Если 0, то все
сообщения, адресованные окну.
- GetMessage
- - возвращает FALSE при появлении сообщения
WM_QUIT, в этом случае происходит выход из цикла
и приложение завершает работу.
- TranslateMessage
- - переводит виртуальные коды клавиш в
клавиатурные сообщения.
- DispatchMessage
- - отправляет сообщение оконной функции, для
обработки.
Оконная функция обеспечивает функциональность
программы, путем обработки системных сообщений.
Оконная функция является CALLBACK - функцией,
т.е. вызывается операционной системой в ответ на
поступившее, новое сообщение. Оконная функция
объявлена таким образом:
LRESULT CALLBACK WindowFunc(HWND
hMainWnd, UINT iMsg, WPARAM wParam, LPARAM
lParam)
- HMainWnd - дескриптор главного окна.
- iMsg - номер сообщения. Смотри константы
WM_.
- lParam и wParam - параметры сообщения.
При появлении сообщения, мы можем сравнить
параметр iMsg с одной из констант WM_ и
запрограммировать соответствующую реакцию
программы.
Например: при нажатии левой кнопки
мыши, когда указатель мыши находится над
клиентской областью окна, возникает событие
WM_LBUTTONDOWN. Вызывается оконная функция, в
параметр iMsg заносится значение константы
WM_LBUTTONDOWN, мы можем проверить условие и
запрограммировать нужную нам реакцию программы.
Внутри оконной функции расположен оператор
выбора, который и выполняет вышеописанную
задачу. В операторе выбора обязательно должен
быть организован обработчик по умолчанию,
который реализуется функцией
DefWindowProc(hMainWnd, iMsg, wParam,
lParam);
Если этого не сделать, наша программа
издохнет так и не ожив. Множество сообщений,
обрабатывается самой системой, такие как:
изменение размеров окна,
сворачивание/разворачивание окна, вызов
системного меню etc. Для этого и служит
DefWindowProc().
При работе с оконными элементами управления,
окну владельцу посылается сообщение WM_COMMAND,
при этом lParam содержит дескриптор элемента
управления, а старший байт параметра wParam -
идентификатор события, вызванного в элементе
управления. Например: при нажатии на кнопку -
BN_CLICKED. Смотри константы
BN_, WM_. Закрыть прогу мы
можем использовав функцию
PostQuitMessage(0). Эта функция
посылает окну сообщение WM_QUIT.
Несколько слов о том, как писать такие
программы на Delphi. Создаем новый проект,
запускаем Project Manager, удаляем Unit1 вместе
с формой. Жмем Ctrl + F12 и открываем файл
проекта. Удаляем из uses модуль forms, добавляем
туда windows и messages. Удаляем все между begin
и end. Заготовка готова. Можно кодить. Писать
программы на чистом API невозможно без справки,
которая всегда должна быть под рукой. Будь ты
самим Гейтсом - все не запомнить. Рекомендую:
Скачать пример: createwnd.zip (архив
содержит файлы windows.cpp и windows.dpr). Вот и
все. Удачи. |