Чтение онлайн

ЖАНРЫ

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

Для приложений WinAPI реализация цикла обработки сообщений может выглядеть таким образом:

...

while (GetMessage(&msg, NULL, 0, 0)) {

 if ((WM_KEYDOWN == pMsg->message) && (VK_RETURN == pMsg->wParam)) {

OnEnterPressed; // вызов диспетчера нажатия Enter

continue; // запрет дальнейшей обработки

 }

 // стандартная обработка сообщения

 TranslateMessage(&msg);

 DispatchMessage(&msg);

}

...

В

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

Редкий вариант, но вдруг вам понравится…

ПРИМЕЧАНИЕ

Поскольку этот вариант является существенным только для модальных диалогов, в которых, для того чтобы добраться до цикла сообщений, необходимо применить то (сабклассинг окна диалога) или иное (постановка локального хука) ухищрение, и поскольку сказанное совершенно не относится к 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-программ

Поделиться с друзьями: