На этом шаге мы приведем общую структуру Windows-программы.
Теперь обратимся к структуре всей программы. Как мы уже отмечали, мы будем рассматривать классическую структуру программы под Windows. В такой программе имеется главное окно, а следовательно, и процедура главного окна. В целом, в коде программы можно выделить следующие разделы:
Конечно, в программе могут быть и другие разделы, но данные разделы образуют основной скелет программы. Разберем эти разделы по порядку.
Регистрация класса окон осуществляется с помощью функции RegisterClassA, единственным параметром которой является указатель на структуру WNDCLASS, содержащую информацию об окне.
На основе зарегистрированного класса с помощью функции CreateWindowExA (или CreateWindowA) можно создать экземпляр окна. Как можно заметить, это весьма напоминает объектную модель программирования.
Вот как выглядит этот цикл на языке C:
while (GetMessage (&msg,NULL,0,0)) { //Разрешить использование клавиатуры //путем трансляции сообщений о виртуальных клавишах //в сообщения об алфавитно-цифровых клавишах. TranslateMessage(&msg); //Вернуть управление Windows и передать сообщение дальше //процедуре окна. DispatchMessage(&msg) ; }
Функция GetMessage() "отлавливает" очередное сообщение из ряда сообщений данного приложения и помещает его в структуру msg.
Что касается функции TranslateMessage, то ее компетенция касается сообщений WM_KEYDOWN и WM_KEYUP, которые транслируются в WM_CHAR и WM_DEDCHAR, а также WM_SYSKEYDOWN и WM_SYSKEYUP, преобразующиеся в WM_SYSCHAR и WM_SYSDEADCHAR. Смысл трансляции заключается не в замене, а в отправке дополнительных сообщений. Так, например, при нажатии и отпускании алфавитно-цифровой клавиши в окно сначала придет сообщение WM_KEYDOWN, затем WM_KEYUP, а затем уже WM_CHAR.
Как можно видеть, выход из цикла ожиданий имеет место только в том случае, если функция GetMessage возвращает 0. Это происходит только при получении сообщения о выходе (сообщение WM_QUIT). Таким образом, цикл ожидания играет двоякую роль: определенным образом преобразуются сообщения, предназначенные для какого-либо окна, и ожидается сообщение о выходе из программы.
Вот прототип функции окна на языке C:
LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
Оставив в стороне тип возвращаемого функцией значения, обратите внимание на передаваемые параметры. Вот смысл этих параметров:
Все четыре параметра, как вы, наверное, уже догадались, имеют тип DWORD.
А теперь рассмотрим "скелет" этой функции на языке ассемблера.
WNDPROC PROC PUSH EBP MOV EBP,ESP ;Теперь EBP указывает на вершину стека. PUSH EBX PUSH ESI PUSH EDI PUSH DWORD PTR [EBP+14H]; LPARAM (lParam) PUSH DWORD PTR [EBP+10H]; WPARAM (wParam) PUSH DWORD PTR [EBP+OCH]; MES (message) PUSH DWORD PTR [EBP+08H]; HWND (hwnd) CALL DefWindowProcA@16 POP EDI POP ESI POP EBX POP EBP RET 16 WNDPROC ENDP
Прокомментируем приведенный фрагмент.
RET 16 - выход с освобождением стека от четырех параметров (16 = 4 х 4).
Доступ к параметрам осуществляется через регистр ЕВР:
Функция DefWindowProc вызывается для тех сообщений, которые не обрабатываются в функции окна. В данном примере, как вы понимаете, никакие из сообщений, приходящих в функцию окна, не обрабатываются.
На следующем шаге мы приведем пример простой программы для Windows.