Основы программирования Windows

Windows поддерживает два типа приложений: основанные на графическом интерфейсе (graphical user interface, GUI) и консольные (console user interface, CUI).
Приложения первого типа создают окна, имеют меню, взаимодействуют с пользователем через диалоговые окна. Почти все стандартные программы Windows являются GUI-приложениями.
Приложения консольного типа работают в текстовом режиме.

Во всех Windows-приложениях должна быть входная функция. Существует четыре такие функции:

1
2
3
4
5
6
7
int WINAPI WinMain( HINSTANCE hinstExe, HINSTANCE,PSTR pszCmdLine, int nCmdShow);
 
int WINAPT wWinMain( HINSTANCE hinstExe, HINSTANCE,PWSTR pszCmdLine, int nCmdShow);
 
int __cdecl main( int argc, char *argv[], char *envp[]);
 
int _cdecl wmain( int argc, wchar_t *argv[], wchar_t *envp[]);

GUI-приложение, работающее с ANSI-символами и строками используют WinMain

GUI-приложение, работающее с Unicode-символами и строками используют wWinMain

CUI-приложение, работающее с ANSI-символами и строками используют main

CUI-приложение, работающее с Unicode-символами и строками используют wmain

В отличие от традиционного программирования на основе линейных алгоритмов, программы для Windows строятся по принципам событийно-управляемого программирования, при котором поведение компонента системы определяется набором внешних событий и реакций компонента на них. Такими компонентами в Windows являются окна. С каждым окном в Windows связана определенная функция обработки событий. События для окон называются сообщениями. Сообщение относится к тому или иному типу, идентифицируемому определенным кодом (32-битным целым числом), и сопровождается парой 32-битных параметров WPARAM и LPARAM, интерпретация которых зависит от типа сообщения. В заголовочном файле windows.h для кодов сообщений определены константы с интуитивно понятными именами:
#define WM_CREATE 0x0001 сообщение о создании окна
#define WM_DESTROY 0x0002 сообщение об уничтожении окна
#define WM_SIZE 0x0005 сообщение об изменении размеров окна
#define WM_COMMAND 0x0111 сообщение от команды меню или управляющего элемента

Таким образом, задача любого приложения — создать главное окно и сообщить Windows функцию обработки событий для этого окна.

Для стандартных управляющих элементов (библиотека Common Controls Library — COMCTL32.DLL) в Windows имеются предопределенные обработчики событий, которые при наступлении событий сообщают информацию окну, содержащему этот управляющий элемент. Стандартная библиотека Common Dialog Box Library (COMDLG32.DLL) содержит несколько готовых диалоговых окон с обработчиками: диалоги выбора файла, настроек печати, выбора шрифта, выбора цвета и др.

Программа для Win32 обычно состоит из следующих блоков:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include
 
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR pszCmdLine, int nCmdShow)
{
  Блок инициализации:
  создание класса главного окна,
  создание главного окна,
  загрузка ресурсов и т.п.
 
  Цикл обработки событий:
  MSG msg;
  while (GetMessage(&msg,(HWND)NULL,0,0))
  {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
  }
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  Обработка сообщений главного окна
  switch (msg)
  {
    case WM_CREATE:
    ...
    return 0;
    case WM_COMMAND:
    ...
    return 0;
    case WM_DESTROY:
    ...
    PostQuitMessage(0);
    return 0;
    ...
  }
  return DefWindowProc(hWnd,message,wParam,lParam);
}

Каждое окно принадлежит определенному классу окон. Обычно каждое приложение создает для главного окна программы свой класс. Если приложению требуются дополнительные нестандартные окна, оно регистрирует другие классы.
Стандартные диалоги и управляющие элементы принадлежат к предопределенным классам окон, для них не надо регистрировать новые классы.

Чтобы определить новый класс окон, надо заполнить структуру WNDCLASSEX, содержащую следующие поля:
UINT cbSize — размер структуры
UINT style — стиль класса окон
WNDPROC lpfnWndProc — процедура обработки событий окна
int cbClsExtra — размер дополнительной памяти в системной структуре класса для данных пользователя
int cbWndExtra — размер дополнительной памяти в системной структуре окна для данных пользователя
HINSTANCE hInstance — дескриптор модуля (экземпляра программы) в котором реализована процедура обработки
HICON hIcon — дескриптор иконки окна
HCURSOR hCursor — дескриптор курсора мыши для окна
HBRUSH hbrBackground — дескриптор кисти для закрашивания фона окна
LPCSTR lpszMenuName — имя ресурса, содержащего меню окна
LPCSTR lpszClassName — имя класса
HICON hIconSm — дескриптор иконки

Класс регистрируется при помощи функции:

1
ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcx)

При успешном завершении функция возвращает целочисленный код, соответствующий строке-имени класса в общесистемной таблице строк (такой код называется атомом). При ошибке возвращается 0.

Для создания окна вызывается функция:

1
2
3
4
5
6
7
8
9
10
11
12
HWND WINAPI CreateWindow(
  LPCSTR lpClassName, //имя класса
  LPCSTR lpWindowName, //имя окна (заголовок)
  DWORD dwStyle, //стиль (поведение) окна
  int x, //горизонтальная позиция окна на экране
  int y, //вертикальная позиция окна на экране
  int nWidth, //ширина окна
  int nHeight, //высота окна
  HWND hWndParent, //дескриптор родительского окна
  HMENU hMenu, //дескриптор меню
  HANDLE hInstance, //дескриптор экземпляра программы
  LPVOID lpParam )

Вместо параметров x, y, nWindth, nHeight допустимо передавать константу CW_USEDEFAULT, позволяющую операционной системе задать эти числа по ее усмотрению.

Интерпретация кода стиля определяется классом окна. Стиль определяет не только оформление окна, но и его поведение. Общие для всех классов константы стилей (при необходимости объединяются операцией побитовое ИЛИ):
WS_DISABLED — при создании окно заблокировано (не может получать реакцию от пользователя)
WS_VISIBLE — при создании окно сразу же отображается (не надо вызывать ShowWindow)
WS_CAPTION — у окна есть строка заголовка
WS_SYSMENU — у окна есть системное меню
WS_MAXIMIZEBOX — у окна есть кнопка разворачивания
WS_MINIMIZEBOX — у окна есть кнопка сворачивания
WS_SIZEBOX или WS_THICKFRAME — у окна есть рамка изменения размеров
WS_BORDER — у окна есть рамка (не подразумевает изменение размеров)
WS_HSCROLL или WS_VSCROLL — у окна есть горизонтальная или вертикальная прокрутка
WS_OVERLAPPED или WS_TILED — «перекрываемое» окно — обычное окно с рамкой и строкой заголовка
WS_POPUP — «всплывающее» окно
WS_OVERLAPPEDWINDOW — «перекрываемое» окно с системным меню, кнопками сворачивания/разворачивания, рамкой изменения размеров, короче, типичный стиль для главного окна приложения.

Во время выполнения функции CreateWindow процедуре обработки событий окна посылается сообщение WM_CREATE. При успешном выполнении функции возвращается дескриптор созданного окна, при неудаче — NULL.
После создания окна его нужно отобразить, если только оно не создано со стилем WS_VISIBLE:

1
BOOL ShowWindow( HWND hWnd,int nCmdShow)

Второй параметр этой функции — код состояния отображения окна. В качестве этого кода можно взять значение четвертого параметра, с которым была запущена функция WinMain. Другие возможные значения этого параметра:
SW_SHOW — отобразить и активировать окно
SW_HIDE — скрыть окно
SW_MAXIMIZE — развернуть окно на весь экран
SW_RESTORE — активировать окно и отобразить его в размерах по умолчанию
SW_MINIMIZE — свернуть окно

Если перед вызовом этой функции окно было видимым, функция возвращает TRUE, если же окно было скрыто — FALSE.
Функция UpdateWindow непосредственно вызывает процедуру обработки событий указанного окна с сообщением WM_PAINT (минуя очередь сообщений приложения):

1
BOOL UpdateWindow(HWND hWnd)

Windows использует два способа доставки сообщений процедуре обработки событий окна:
— непосредственный вызов процедуры обработки событий (внеочередные или неоткладываемые сообщения — nonqueued messages);
— помещение сообщения в связанный с данным приложением буфер типа FIFO, называемый очередью сообщений — message queue (откладываемые сообщения — queued messages).

К внеочередным сообщениям относятся те сообщения, которые непосредственно влияют на окно, например, сообщение активации окна WM_ACTIVATE и т.п. Кроме того, вне очереди сообщений обрабатываются сообщения, сгенерированные различными вызовами Win32 API, такими как SetWindowPos, UpdateWindow, SendMessage, SendDlgItemMessage.
К откладываемым сообщениям относятся сообщения, связанные с реакцией пользователя: нажатие клавиш на клавиатуре, движение мышки и клики.

Чтобы извлечь сообщение из очереди, программа вызывает функцию

1
2
3
4
5
6
BOOL WINAPI GetMessage(
  MSG *lpmsg, //сюда попадает сообщение со всякими параметрами
  HWND hw, //извлекать только сообщения для указанного окна
  UINT wMsgFilterMin, //фильтр сообщений (нам не надо - ставим 0)
  UINT wMsgFilterMax //фильтр сообщений (нам не надо - ставим 0)
)

Эта функция возвращает FALSE, если получено сообщение WM_QUIT, и TRUE в противном случае. Очевидно, что условием продолжения цикла обработки событий является результат этой функции. Если приложение хочет завершить свою работу, оно посылает само себе сообщение WM_QUIT при помощи функции

1
void WINAPI PostQuitMessage(int nExitCode)

Ее параметр — статус выхода приложения. Обычно эта функция вызывается в ответ на сообщение об уничтожении окна WM_DESTROY.

После извлечения сообщения из очереди следует вызвать функцию TranslateMessage, переводящую сообщения от нажатых клавиш в удобоваримый вид, а затем DispatchMessage, которая определяет предназначенное этому сообщению окно и вызывает соответствующую процедуру обработки событий.

1
2
BOOL WINAPI TranslateMessage(const MSG *lpmsg)
LONG WINAPI DispatchMessage(const MSG *lpmsg)

Результат возврата соответствует значению, которое вернула процедура обработки событий (обычно никому не нужен).
Процедура обработки сообщений окна должна быть объявлена по следующему прототипу:

1
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

Значения параметров: hWnd — дескриптор окна, которому предназначено сообщение, message — код сообщения, wParam и lParam — 32-битные параметры сообщения, интерпретация которых зависит от кода сообщения. Зачастую старший/младший байт или старшее/младшее слово параметров сообщения несут независимый смысл,тогда удобно использовать определенные в windows.h макросы:

1
2
3
4
#define LOBYTE(w) ((BYTE) (w))
#define HIBYTE(w) ((BYTE) (((WORD) (w) >> 8) & 0xFF))
#define LOWORD(l) ((WORD) (l))
#define HIWORD(l) ((WORD) (((DWORD) (l) >> 16) & 0xFFFF))

Например, сообщение WM_COMMAND посылается окну в трех случаях:
— пользователь выбрал какую-либо команду меню;
— пользователь нажал «горячую» клавишу (accelerator);
— в дочернем окне произошло определенное событие.

При этом параметры сообщения интерпретируются следующим образом. Старшее слово параметра WPARAM содержит: 0 в первом случае, 1 во втором случае и код события в третьем случае. Младшее слово WPARAM содержит целочисленный идентификатор пункта меню, «горячей» клавиши или дочернего управляющего элемента. Параметр LPARAM в первых двух случаях содержит NULL, а в третьем случае — дескриптор окна управляющего элемента.

Процедура обработки событий должна вернуть определенное 32-битное значение, интерпретация которого также зависит от типа сообщения. В большинстве случаев, если сообщение успешно обработано, процедура возвращает значение 0.
Процедура обработки событий не должна игнорировать сообщения. Если процедура не обрабатывает какое-то сообщение, она должна вернуть его системе для обработки по умолчанию. Для этого вызывается функция: DefWindowProc(hWnd, message, wParam, lParam);

1
LRESULT WINAPI DefWindowProc(HWND hWnd, UINT message,WPARAM wParam, LPARAM lParam)

Оставить комментарий


Примечание - Вы можете использовать эти HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>