Поскольку этот вариант является существенным только для модальных диалогов, в которых, для того чтобы добраться до цикла сообщений, необходимо применить то (сабклассинг окна диалога) или иное (постановка локального хука) ухищрение, и поскольку сказанное совершенно не относится к MFC, где модальные диалоги "от системы" практически не применяются, то мы рассмотрим только WinAPI-вариант.
…локальный хук?
Условимся заранее, что теорию применения хуков вы получите из любых других источников (например, из статьи Kyle Marsh Хуки в Win32или Dr. Joseph M. Newcomer Хуки и DLLна нашем сайте). Там же вы познакомитесь и с их разновидностями. Мы же продолжим решать нашу задачу – перехват нажатия Enter в модальном диалоге.
Итак, в качестве необходимого теоретического минимума заметим, что механизм "крюков" (hook – англ., крюк) позволяет приложению зарегистрировать некий обработчик, который система будет вызывать в ответ на события, происходящие в ее недрах, с целью оповещения пользовательского кода об этих событиях. Локальный хук вызывается только для событий, относящихся к процессу, поставившему хук, что практически никак не ухудшает общую производительность системы вцелом. И потому именно этот механизм подходит нам для наших целей.
Нам необходимо поставить хук типа , который позволяет проводить мониторинг событий в диалогах (в том числе и MessageBox), меню и полосах прокрутки. Код логически распадается на относительно стандартную часть, имеющую сходное строение для хуков любого типа, и специфическую часть, которая будет выполнять для нас полезную работу. Стандартный код может выглядеть следующим образом:
LRESULT DlgBoxMsgFilter(UINT code, WPARAM wParam, LPARAM lParam);
HHOOK g_hHook = NULL;
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam) {
LRESULT res = 0;
// служебная обработка
if (0 > code) return CallNextHookEx(WH_MSGFILTER, code, wParam, lParam);
// вызов пользовательской процедуры "полезного действия"
res = DlgBoxMsgFilter(code, wParam, lParam);
if (res > -1) return res;
return CallNextHookEx(WH_MSGFILTER, code, wParam, lParam);
}
BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG:
// постановка хука...
g_hHook = SetWindowsHookEx(WH_MSGFILTER, HookProc,
GetModuleHandle(NULL), GetCurrentThreadId());
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDCANCEL:
if (BN_CLICKED == HIWORD(wParam)) {
// ... и его снятие
if (g_hHook) UnhookWindowsHookEx(h_hHook);
EndDialog(hDlg, 0);
}
break;
}
break;
}
return 0;
}
Теперь обратимся к процедуре. Легко заметить, что она выполняет практически те же действия, что и из ОСНОВНОГО ВАРИАНТА, а именно – обнаружение нажатия Enter и переход на следующий контрол, имеющий стиль. Поскольку нас интересуют только события диалогов (а не меню, и не скроллбаров), то и фильтровать мы будем только коды типа.
LRESULT DlgBoxMsgFilter(UINT code, WPARAM wParam, LPARAM lParam) {
LPMSG pMsg = (LPMSG)lParam;
HWND hEdit1 = GetDlgItem(g_hDlg, IDC_EDIT1), hEdit2 = GetDlgItem(g_hDlg, IDC_EDIT2);
switch (code) {
case MSGF_DIALOGBOX:
{
// следим за нажатиями в обоих эдитбоксах
if (hEdit1 != pMsg->hwnd && hEdit2 != pMsg->hwnd) return -1;
switch (pMsg->message) {
case WM_KEYDOWN:
if (VK_RETURN == pMsg->wParam) {
// нажат Enter, сообщим об этом родительскому окну (диалогу)
SendMessage(g_hDlg, pMsg->message, pMsg->wParam, pMsg->lParam);
// перейдем к следующему TABSTOP-контролу диалога
SetFocus(GetNextDlgTabItem(g_hDlg, pMsg->hwnd, FALSE));
return TRUE;
}
break;
}
}
break;
}
return –1;
}
На этом, собственно, мы и остановимся. Насколько понятно/удобно/оправдано пользоваться этим методом – судить вам.
ПРИМЕЧАНИЕ
В демонстрационном проектевы найдете подпроект HkEdDlg, в котором продемонстрирована приведенная методика. Там же, кстати, вы сможете найти и пример реализации глобального (системного) хука, но это, как говорится, уже совсем другая история…
Это все на сегодня. Пока!
Алекс Jenter jenter@rsdn.ru Duisburg, 2001. Публикуемые в рассылке материалы принадлежат сайту RSDN.
Программирование на Visual C++
Выпуск №64 от 17 февраля 2002 г.
Здравствуйте, уважаемые подписчики!
СТАТЬЯ
Заметка о производительности многопоточных Win32-программ
Автор: Роман Хациев
Тестовое приложение – 835 B
"Живые объекты"
Довольно давно я прочитал статью, автор которой объединил две концепции – многозадачность и объектно-ориентированное программирование. В результате получились так называемые "живые объекты". Идея крайне проста – при инициализации объекта создается отдельный поток и объект в нем живет своей жизнью, а создатель объекта по мере необходимости получает информацию о состоянии объекта из его свойств. Код для такого объекта на C++ выглядит примерно так:
Читать дальше