Операционная система Windows 95 для программиста

       

Обработка 32-разрядных сообщений


В приложениях Win16 параметр lParam часто использовался для передачи сразу двух значений, соответственно, через младшее и старшее слово. Для удобства выделения этих значений предназначались специальные макрокоманды LOWORD и HIWORD .

Например, для сообщения WM_COMMAND в младшем слове параметра lParam передавался 16-разрядный идентификатор дочернего окна hWnd (органа управления, пославшего это сообщение), в старшем - 16-разрядный код извещения wCmd. Через параметр wParam передавался 16-разрядный идентификатор органа управления wId (рис. 1.14).

Рис. 1.14. Формат параметров wParam и lParam для сообщения WM_COMMAND в приложениях Win16

В приложениях Win32 идентификатор окна hWnd стал 32-разрядным, поэтому его никак нельзя разместить в старшем слове параметра lParam. Теперь приходится отводить для идентификатора окна все разряды параметра lParam.

А что делать с кодом извещения wCmd, который оказался "выселен" из хорошо обжитого им параметра lParam?

Его пришлось перенести в старшее слово параметра wParam, удвоившего свою разрядность (рис. 1.15).

Рис. 1.15. Формат параметров wParam и lParam для сообщения WM_COMMAND в приложениях Win32

Таким образом, идентификатор окна остался на месте, а код извещения "переехал" в старшее слово параметра wParam. Аналогичным образом изменился формат и других сообщений.

Приведем два фрагмента обработчика сообщения WM_COMMAND, первый из которых используется в приложениях Win16, а второй - в приложениях Win32.

Итак, первый фрагмент.

case WM_COMMAND: { wId = wParam; hWnd = LOWORD(lParam); nCmd = HIWORD(lParam); ... }



Приложения Win32 должны разбирать сообщение WM_COMMAND на составные части по-другому:

case WM_COMMAND: { wId = LOWORD(wParam); hWnd = (HWND)(UINT)lParam; nCmd = HIWORD(wParam); ... }

В файле windowsx.h определены макрокоманды разборки сообщений (message crackers), которые позволяют "извлечь" из сообщений отдельные параметры.

Приведем для примера определения макрокоманд разборки сообщения WM_COMMAND из файла windowsx.h:


#define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp) #define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp) #define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp) #define GET_WM_COMMAND_MPS(id, hwnd, cmd) \ (WPARAM)MAKELONG(id, cmd), (LONG)(hwnd)

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

Предположим, нам надо организовать обработку сообщений WM_CREATE и WM_LBUTTONDOWN . Мы готовим две функции с именами WndProc_OnCreate и WndProc_OnLButtonDown, которые будут заниматься обработкой этих сообщений:

BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct); void WndProc_OnLButtonDown(HWND hWnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);

Имена функций не играют никакой роли, однако Microsoft рекомендует составлять их из префикса имени функции окна (например, WndProc) с добавлением строки _On и названия сообщения, в котором удален префикс WM_.

Затем в функции окна мы используем макрокоманду HANDLE_MSG , указывая ей в качестве первого параметра идентификатор окна, в качестве второго - номер сообщения и, наконец, в качестве третьего - имя функции, которая будет обрабатывать сообщение:

LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { HANDLE_MSG(hWnd, WM_CREATE, WndProc_OnCreate); HANDLE_MSG(hWnd, WM_LBUTTONDOWN, WndProc_OnLButtonDown); default: return(DefWindowProc(hWnd, msg, wParam, lParam)); } }

Теперь оператор switch будет выглядеть компактнее, так как для обработки каждого сообщения в него добавляется только одна строка.

Следует, однако, заметить, что для работы с макрокомандой HANDLE_MSG вы должны использовать в качестве имен для последних двух параметров функции WndProc имена wParam и lParam (только эти имена).

Как выглядит функция обработчика сообщения, вызываемая макрокомандой HANDLE_MSG?

Так же, как и обычная функция, за одним исключением - она должна оканчиваться вызовом макрокоманды FORWARD_<имя сообщения> в операторе return (даже если функция имеет тип void):

void WndProc_OnLButtonDown(HWND hWnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) { ... return FORWARD_WM_LBUTTONDOWN(hWnd, fDoubleClick, x, y, keyFlags, DefWindowProc); }

Но при обработке сообщения WM_CREATE вы должны в случае успешной инициализации данных окна вернуть значение TRUE, иначе окно так и не будет создано:

BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct) { ... return TRUE; }

Вы можете создать перечисленные выше макрокоманды и для обработки собственных сообщений, взяв за основу определения из файла windowsx.h.

В этой книге мы приведем несколько примеров, демонстрирующих применение макрокоманд разборки сообщений. Для отключения предупреждающего сообщения о том, что функция типа void возвращает управление при помощи оператора return, перед определением функции обработчика сообщения добавляем следующую строку:

#pragma warning(disable: 4098)


Содержание раздела