Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [GWL_WNDPROC] Подмена оконной процедуры. Фильтрация сис.сообщений окну... 
V
    Опции темы
MuForum
  Дата 26.11.2007, 03:30 (ссылка) |  (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 427
Регистрация: 13.6.2007
Где: Молдова, Кишинев

Репутация: нет
Всего: 4



Доброе время суток!
В связи с тем, что сам долго не мог решить и разобраться казалось бы в элементарной вещи, решил создать гид на тему: 'Как фильтровать сообщения окну? | Как подменить оконную процедуру?'


# Вопрос: Как можно фильтровать системные сообщения, которые отправляются какому-либо окну?
# Ответ: Существует несколько способов:
  1.  Это объявить глобальный хук 'WH_GETMESSAGE' и уже при помощи него фильтровать.
  2.  Подменить 'оригинальную оконную процедуру' и уже через вашу 'оконную процедуру' принимать все сообщения, фильтровать и отправлять дальше. (Рекомендую)

# Вопрос: А как можно реализовать подмену оконной процедуры?
# Ответ: Необходимо объявить глобальный хук на перехват клавиатуры и уже при каком-либо событие делать что-либо.


# Вопрос: А какого типа глобальный хук необходимо объявить для перехвата клавиатуры: 'WH_KEYBOARD' или 'WH_KEYBOARD_LL' ?
# Ответ: Необходимо использовать только 'WH_KEYBOARD'.
  •  'WH_KEYBOARD' - Обрабатывает в контексте потока того процесса, где была нажата клавиша.
  •  'WH_KEYBOARD_LL' - Обрабатывает в контексте процесса установившего хук, и поэтому не подменяется 'Оконная процедура'.

# Вопрос: А можно реализовать подмену 'Оконной процедуры' в программе?
# Ответ: Нет, подобные вещи можно реализовывать только с хуком, который лежит в '.dll'. Надо писать на 'native' языке: 'C++', 'Delphi' и т.д. (т.е. '.NET' тут не подойдёт.)


# Первый шаг:
Код

// Создаём глобальную переменную для объявления глобального хука.
HHOOK KeyboardHook;
......
......
// Объявление глобального хука на клавиатуру.
try{ KeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, hInstance, 0); } catch(...) {;}
......
......
// Удаление глобального хука.
UnhookWindowsHookEx(KeyboardHook);
......
......

Цитата(SetWindowsHookEx)



  •  WH_KEYBOARD - Тип хука.

  •  KeyboardProc - Имя процедуры, которая будет вызываться до всех процедур для обработки сообщений от клавиатуры.

  •  hInstance - Указатель на 'INSTANCE' приложения или '.dll', которое содержит данную процедуру, если стоит 'NULL', то процедура находится в текущем приложении и будет активно пока активно данное приложение или '.dll'.

  •  0 - указывает в цепочку какого приложения следует вставлять процедуру перехвата, если стоит 'NULL' или '0', процедура перехвата будет выполняться для любого приложения запущенного в системе(Другими словами для любого активного потока). 





# Второй шаг:
Код

// Объявляем глобальные переменные.
HWND hWnd;
static LRESULT OldWindowProc = NULL;
static LRESULT NewWindowProc = NULL;
......
......
// Функция обработки всех событий от клавиатуры.
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{    
    bool bDown = lParam & (1<<30); // Если кнопка была нажата. (Другими словами событие: 'WM_KEYUP')

    if((bDown) && (HC_ACTION == nCode))
    {
        if(wParam >= 0x7A && wParam <= 0x7B) // Если нажатая кнопка содержит код в заданном интервале, то происходят следующие действия. (Код кнопок смотри ниже)
        {
            if(wParam == VK_F11) // Если была нажата кнопка 'F11'.
            {
                hWnd = FindWindow(NULL, "TEST"); // Ищем в системе окно с заголовком 'TEST', и присваеваем результат глобальной переменной.
                OldWindowProc = SetWindowLong(hWnd, GWL_WNDPROC, (long)WindowProc); // Задаём новый адрес 'оконной процедуры' и присваеваем старый адрес уже 'оконной процедуры' глобальной переменной.
            }
            if(wParam == VK_F12) // Если была нажата кнопка 'F12'.
            {
                SetWindowLong(hWnd, GWL_WNDPROC, (long)OldWindowProc); // Задаём нашему окну изначальный адрес 'оконной процедуры', т.е. все сообщения от системы уже будут направлятся напрямую окну, а не через нашу 'оконную процедуру'.
            }
        }
    }
LRESULT RetVal = CallNextHookEx(KeyboardHook, nCode, wParam, lParam); // Вызываем слудующее системное сообщение из очереди для обработки.
return RetVal; // Возвращаем результат.
}
......
......
// Функция обработки новой подмененной 'оконной процедуры'.
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg) // Делаем выборку параметра 'uMsg'.
    {
        case WM_DESTROY: UnhookWindowsHookEx(KeyboardHook); break; // Если наше окно было разрушено, но удаляем глобальный хук.
        case WM_CLOSE: UnhookWindowsHookEx(KeyboardHook); break; // Если окно было закрыто, то удаляем глобальный хук.
        case WM_ACTIVATE: // Если окно было активировано...
        case WM_KILLFOCUS: // Если был убран фокус с окна...
            return DefWindowProc(hWnd, uMsg, wParam, lParam); // ..., то все остальные сообщения будет обрабатывать оконная процедура по умолчанию - defwindowproc();
        break;
        default: break; // Если не одно из перечисленных событий не соответствует событию, которое произошло, то выходим из выборки.
    }
    return CallWindowProc((WNDPROC)NewWindowProc, hWnd, uMsg, wParam, lParam); // Вызываем слудующее системное сообщение из очереди для обработки.
}



# Коды клавиш/кнопок:
Код

F1  - '0x70' или 'VK_F1'
F2  - '0x71' или 'VK_F2'
F3  - '0x72' или 'VK_F3'
F4  - '0x73' или 'VK_F4'
F5  - '0x74' или 'VK_F5'
F6  - '0x75' или 'VK_F6'
F7  - '0x76' или 'VK_F7'
F8  - '0x77' или 'VK_F8'
F9  - '0x78' или 'VK_F9'
F10 - '0x79' или 'VK_F10'
F11 - '0x7A' или 'VK_F11'
F12 - '0x7B' или 'VK_F12'
//--------------------------------------------------
Space(пробел) - '0x20' или 'VK_SPACE'
BackSpace     - '0x8' или 'VK_BACK'
Tab           - '0x9' или 'VK_TAB'
Enter         - '0x0D' или 'VK_RETURN'
Shift         - '0x10' или 'VK_SHIFT'
Ctrl          - '0x11' или 'VK_CONTROL'
Alt           - '0x12' или 'VK_MENU'
CapsLock      - '0x14' или 'VK_CAPITAL'
Esc           - '0x1B' или 'VK_ESCAPE'
Insert        - '0x2D' или 'VK_INSERT'
PageUp        - '0x21' или 'VK_PRIOR'
PageDown      - '0x22' или 'VK_NEXT'
End           - '0x23' или 'VK_END'
Home          - '0x24' или 'VK_HOME'
//--------------------------------------------------
Стрелка влева  - '0x25' или 'VK_LEFT'
Стрелка вверх  - '0x26' или 'VK_UP'
Стрелка вправо - '0x27' или 'VK_RIGHT'
Стрелка вниз   - '0x28' или 'VK_DOWN'
//--------------------------------------------------
PrintScreen     - '0x2C' или 'VK_SNAPSHOT'
Scrooll Lock    - '0x91' или 'VK_SCROLL'
Pause           - '0x13' или 'VK_PAUSE'
NumLock         - '0x90' или 'VK_NUMLOCK'
Windows(Левая)  - '0x5B' или 'VK_LWIN'
Windows(Правая) - '0X5C' или 'VK_RWIN'
//--------------------------------------------------
0 - '0x30' или '0'
1 - '0x31' или '1'
2 - '0x32' или '2'
3 - '0x33' или '3'
4 - '0x34' или '4'
5 - '0x35' или '5'
6 - '0x36' или '6'
7 - '0x37' или '7'
8 - '0x38' или '8'
9 - '0x39' или '9'
//--------------------------------------------------
A - '0x41' или 'A'
B - '0x42' или 'B'
C - '0x43' или 'C'
D - '0x44' или 'D'
E - '0x45' или 'E'
F - '0x46' или 'F'
G - '0x47' или 'G'
H - '0x48' или 'H'
I - '0x49' или 'I'
J - '0x4A' или 'J'
K - '0x4B' или 'K'
L - '0x4C' или 'L'
M - '0x4D' или 'M'
N - '0x4E' или 'N'
O - '0x4F' или 'O'
P - '0x50' или 'P'
Q - '0x51' или 'Q'
R - '0x52' или 'R'
S - '0x53' или 'S'
T - '0x54' или 'T'
U - '0x55' или 'U'
V - '0x56' или 'V'
W - '0x57' или 'W'
X - '0x58' или 'X'
Y - '0x59' или 'Y'
Z - '0x5A' или 'Z'
//--------------------------------------------------


P.S. -> Если необходимо узнать коды других клавиш, то наберите в поиске вот такую фразу: 'Коды клавиш'.



# Названия событий:
Код

WM_DESTROY - 
WM_CLOSE - 
WM_ACTIVATE - 
WM_KILLFOCUS - 
WM_SETFOCUS - 
WM_ACTIVATEAPP - 
WM_MOUSEMOVE - 
WM_MOUSELEAVE - 
WM_SETCURSOR - 
WM_NCACTIVATE - 
WM_SIZE - 



# Благодарность: 'stab' и '586' в помощи написания данной статьи.

Это сообщение отредактировал(а) MuForum - 31.3.2008, 17:01


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли)
PM MAIL WWW ICQ Skype MSN   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0432 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.