Рихтер Дж., Назар К. - Windows via C C++. Программирование на языке Visual C++ - 2009
.pdf876 Часть VI. Приложения
/* void Cls_OnCommand(HWND hWnd, int Id, HWND hWndCtl, UINT codeNotify); */
#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)dParam), \ (UINT)HIWORD(wParam)), OL)
#deflne FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \ (void)(fn)((hwnd), WM_COMMAND, \ MAKEWPARAM((UINT)(id),(UINT)(codeNotify)), \ (LPARAM)(HWND)(hwndCtl))
Первая строка—комментарий, показывающий прототип функции, которую вы должны написать. Следующая строка — уже рассмотренный нами макрос HANDLE_WM_, а последняя содержит предописатель сообщения (message forwarder). Допустим, при обработке сообщения WMCOMMAND вы хотите вызвать оконную процедуру, используемую по умолчанию. Это выглядело бы так.
void Cls_OnCommand (HWND hWnd, int id, HWND hWndCtl, UINT codeNotify) {
//выполняем обычную обработку
//обработка по умолчанию
FORWARD_WM_COMMAND(hWnd, id, hwndCtl, codeNotify, DefWindowProc);
}
Макросы FORWARD_WM_ принимают распакованные параметры сообщения и воссоздают их эквиваленты wParam и lParam, после чего вызывают указанную вами функцию. В приведенном примере это DefWindowProc, но так же легко можно использовать SendMessage или PostMessage. Фактически, чтобы отправить (синхронно или асинхронно) сообщение какому-то окну в системе, можно применить макрос FORWARD_WM_ — это поможет скомбинировать отдельные параметры сообщения.
Макросы для дочерних элементов управления
Эти макросы упрощают посылку сообщений дочерним элементам управления. Они очень похожи на макросы FORWARD_WM_. Имя каждого из них начинается с типа управляющего элемента, которому передается сообщение, затем идут знак подчеркивания и имя сообщения. Например, чтобы послать сообщение LB_ GETCOUNT окну списка, задействуйте такой макрос из файла WindowsX.h:
#define ListBox_GetCount(hwndCtl) \ ((int)(DWORD)SNDMSG((hwndCtl), LB_GETCOUNT, 0, 0L))
Позвольте сделать несколько замечаний по этому макросу. Во-первых, у него только один параметр (hwndCtl) — описатель окна списка. Так как сообщение LB_GETCOUNT игнорирует параметры wParam и lParam, вам вообще нет нужды беспокоиться о них. Макрос, как вы уже видели, автоматичес-
Приложение Б. Распаковщики сообщений, макросы для дочерних элементов управления и
API-макросы.docx 877
ки передаст нули. Во-вторых, тип значения, возвращаемого SendMessage, преобразуется в int, в связи с чем не нужно самому преобразовывать тип.
Что мне не нравится в этих макросах, так это необходимость передавать им описатель окна элемента управления. Чаще всего элементы управления, которым вы посылаете сообщения, являются дочерними окнами диалогового окна. Из-за этого придется все время вызывать GetDlgItem примерно так:
int n = ListBox_GetCount(GetDlgItem(hDlg, ID_LISTBOX));
Этот код выполняется ничуть не медленнее, чем код с использованием SendDlgItemMessage, но объем программы увеличивается из-за дополнительных вызовов GetDlgItem. Если надо послать несколько сообщений одному и тому же элементу управления, вы, возможно, захотите обратиться к GetDlgItem лишь раз, сохранить описатель дочернего окна, а затем вызвать все необходимые макросы:
HWND hWndCtl = GetDlgItem(hDlg, ID_LISTBOX); int n = ListBox_GetCount(hWndCtl);
ListBox_AddString(hWndCtl, TEXT("Another string"));
…
Если вы пишете код именно так, приложение заработает быстрее, поскольку не будет повторных вызовов GetDlgItem. Эта функция вообще-то выполняется довольно медленно, если в диалоговом окне много элементов управления, а искомый элемент находится где-то в конце Z-цепочки.
API-макросы
Они упрощают выполнение некоторых распространенных операций — например, создание нового шрифта, выбор его в контекст устройства и сохранение описателя исходного шрифта. Необходимый для этого код выглядит как-то вроде:
HFONT hFontOrig = (HFONT) SelectObject(hDC, (HGDIOBJ) hFontNew);
Этот оператор требует два преобразования типов, чтобы избежать предупреждений при компиляции. Как раз для этого и предназначен один из макросов, определенных в файле WindowsX.h:
#define SelectFont(hdc, hfont) \
((HFONT) SelectObject( (hdc), (HGDIOBJ) (HFONT) ((hfont)))
При его использовании строка кода в программе станет такой:
HFONT hFontOrig = SelectFont(hDC, hFontNew);
Этот код читать гораздо легче, и он меньше подвержен ошибкам.
В файле WindowsX.h есть еще несколько API-макросов, помогающих в реализации распространенных операций. Ознакомьтесь с ними самостоятельно и чаще их используйте.