Ассемблер под Windows №28

Хуки в Windows


Доброго времени суток, уважаемые подписчики. Сегодня познакомимся с так называемыми хуками (это не ругательство, а русская итерпритация слова hook=крючок) и обсудим их использование в нашем проекте.


Существует много ситуаций, когда какие-нибудь сообщения окна нужно обрабатывать незамедлительно, а так как пришедшие на процедуру окна сообщения обрабатываются поочерёдно, то обработка важного сообщения может затянуться надолго. Выходом может создание двух потоков (вернее тредов=thread, но поток понятнее звучит), один из которых обрабатывает важные сообщения, другой - все остальные. Но часто хуки могут стать идеальным решением. Хуки позволяют перехватывать некоторые сообщения при их посылке (а не получении), что позволяет быстрее обработать нужные сообщения. Хуки устанавливаются функцией SetWindowsHookEx, которая имеет следующие параметры:

  • Тип хука
  • адрес хук-процедуры
  • handle процесса, создающего хук
  • Индекс треда на который ставиться хук
Первый параметр может принимать следующие значения:
WH_CALLWNDPROC    - Перехватывает ВСЕ сообщения ДО того как их получает процедура окна
WH_CALLWNDPROCRET - Перехватывает ВСЕ сообщения ПОСЛЕ того как их обработала процедура окна
WH_CBT            - Перехватывает сообщения связанные с изменениями окна
WH_DEBUG          - Перехватывает ВСЕ сообщения прежде чем они попадают к хук-процедурам
WH_KEYBOARD       - Перехватывает "клавиатурные" сообщения, такие как нажатие клавиши
WH_MOUSE          - Перехватывает сообщения мышки
WH_MSGFILTER      - Перехватывает сообщение посланые диалогом, MessageBox-ом, меню или ScrollBar-ом
WH_SHELL          - Перехватывает сообщения оболочки (то есть Windows), такие как изменение текущего языка ввода текста
В нашем проекте я собираюсь использовать WM_MOUSE и WM_KEYBOARD. Именно процедура перехвата сообщений клавиатуры находиться в файле keyboard.asm нашего проекта. Давайте разберёмся, как же это работает, на примере нашего проекта:
AsmGL.asm (лишь интересующая нас часть, полный файл см. в выпуске №26):
... _TEXT SEGMENT public USE32 'code'

_AsmGLWindow@40 proc
  ...
_AsmGLWindow@40 endp

_AsmGLResizeScene@8 proc
  ...
_AsmGLReSizeScene@8 endp

_start@12 proc
  ...
_start@12 endp

RegisterAsmGLClass proc
  ...
RegisterAsmGLClass endp

AsmGLWndProc proc
  push ebp
  mov ebp,esp
  cmp dword ptr [ebp+0ch],WM_CREATE
  je create_proc
  run GetWindowLong, dword ptr [ebp+08h], 0
  pop ebp
  test eax,eax
  jz not_yet
  jmp eax
not_yet:
  jmp DefWindowProcW
create_proc:
  run GetCurrentThreadId, ebx
  run SetWindowsHookExW, WH_KEYBOARD, offset HotKeys, ebx, eax
  run SetWindowLong, dword ptr [ebp+08h], GWL_USERDATA, eax   mov ebx,[ebp+14h]
  mov ebx,[ebx]
  run SetWindowLong, dword ptr [ebp+08h], 0, ebx
  mov eax,ebx
  pop ebx
  pop ebp
  jmp eax
AsmGLWndProc endp

InitGL proc
  ...
InitGL endp

KillGLWindow proc
  ...
KillGLWindow endp

;Другие функции, которые будем рассматривать позже
include HotKeys.asm
include Draw.asm

;Инициализированные данные
ClearDepth dq 1.0f
...
HotKeys.asm:
HotKeys proc
  push ebp
  mov ebp,esp
  pusha
  null ebx
  mov esi, [ebp+0Ch]
  run CallNextHookEx, hHook, dword ptr [ebp+08h], esi, dword ptr [ebp+10h]
  mov eax,esi
  mov edi, offset Keys
  mov ecx,(offset Kproc)-(offset Keys)
  repne scasb
  jne EndHookProc_1
  mov eax,offset Keys
  sub edi,eax
  jmp dword ptr Kproc[edi*4-4]
escape_k:
  mov ExitFlag,1
EndHookProc_1:
  popa
  null eax
  pop ebp
  ret 12
XXX_k:
  ...
  jmp short EndHookProc_1

Keys  db VK_ESCAPE
      db VK_XXX

Kproc dd offset escape_k
      dd offset XXX_k

HotKeys endp
К сожалению, это процедура не закончена, так как я ещё точно не знаю какие клавиши должны быть использованы, XXX означает любую клавишу. Рассмотрим, как же она работает! Она получает три параметра, тип операции, код виртуальной клавиши, информацию о нажатии клавиши. Так как хук-функция обязана заботиться о том, чтоб следующая хук-процедура тоже получила это сообщение, первым делом вызываем CallNextHookEx. После чего проверяем не нужная ли нам клавиша нажата следующим способом:
- Зансим указатель на массив нужных нам клавиш в edi
- в ecx помещаем количество клавиш в массиве
- и смотрим не совпадает ли хоть одна из них с полученной
- если совпала, то используем индекс найденной клавиши в качестве адреса процедуры


На сегодня это всё. В следующем уроке рассмотрим все типы хук-процедур. Если есть какие вопросы, пишите. Пишите на Dark_Lord@RusFAQ.ru или Dark_Lord@land.ru.

Сайт управляется системой uCoz