Hlavní
Hlavní strana
Seznam článků
Nejčtenější články
Progres e-mailem
Visual C++ FAQ

Seriály
COM
ISAPI

banner1.gif (2545 bytes)

Nenechte si ujít
Neobdélníková okna
Tisk bez Preview
MFC a DLL
Logo v MDI ploše
Kouzla s kombo-boxem
Výjimky v C++

banner.gif (3305 bytes)

Hook - monitorování zpráv II. Jan Odvárko
12.11.1999
[Hlavní stránka]  |  [Rubrika]  |  [Download]

...pokračování a dokončení článku z předchozí části.

4. Monitorování zpráv od myši
V následujícím příkladu použijeme mechanismu hookování pro monitorování všech zpráv od myši. Připomeňme jen, že reagováním v okénkové proceduře, odchytáváme tyto zprávy pouze tehdy, nachází-li se myš nad příslušným oknem. To samozřejmě nemusí v některých případech postačovat. Protože budeme vytvářet globální hook, musíme monitorovací proceduru umístit do DLL knihovny. Tato knihovna se pak bude automaticky nahrávat do dalších procesů.

4.1 DLL knihovna
V této DLL knihovně vytvoříme dvě globální proměnné. První z nich je theInstance, která bude obsahovat handle DLL knihovny a druhá ghMouseHook, která bude obsahovat handle hookovací procedury. Jejich definice je následující.

HINSTANCE theInstance = NULL;
HHOOK ghMouseHook = NULL;

První dvě funkce, které implementujeme jsou HookMouse a UnhookMouse. Jako vždy se nejdříve podíváme na jejich zdrojový kód.

BOOL HookMouse()
{
 ghMouseHook = ::SetWindowsHookEx(WH_MOUSE, (HOOKPROC) MouseHookCallback,
    theInstance, 0);
  return (ghMouseHook != NULL);
}

BOOL UnhookMouse()
{
  return UnhookWindowsHookEx(ghMouseHook);
}

Funkce HookMouse zajišťuje instalaci hookovací procedury a inicializuje globální proměnnou ghMouseHook. Funkce UnhookMouse tuto proceduru jednoduše odinstaluje. Obě dvě funkce musí být z DLL knihovny exportovány. Export těchto funkcí zajistíme hlavičkovým souborem, který bude společný  pro DLL knihovnu i pro aplikaci (tzn. musíme jej vložit do DLL i do EXE). Jeho obsah je následující.

__declspec(dllexport) BOOL HookMouse();
__declspec(dllexport) BOOL UnhookMouse();

Poslední funkcí v knihovně je samotná monitorovací procedura.

LRESULT CALLBACK MouseHookCallback( int nCode, WPARAM wParam,
  LPARAM lParam )
{
  if (nCode < 0)
    return CallNextHookEx(ghMouseHook, nCode, wParam, lParam);

  if (wParam == WM_MOUSEMOVE || wParam == WM_NCMOUSEMOVE)
  {
    LPMOUSEHOOKSTRUCT mhs = (LPMOUSEHOOKSTRUCT) lParam;

    CWnd* poWnd = CWnd::FindWindow(NULL, "MouseHook");
    if (poWnd != NULL)
    {
      poWnd->PostMessage((UINT) wParam, 0,
        MAKELPARAM(mhs->pt.x, mhs->pt.y));
    }
  }
  return CallNextHookEx(ghMouseHook, nCode, wParam, lParam);
}

V prvním parametru nCode obdrží funkce kód, který specifikuje způsob zpracování zprávy. Pokud je tento parametr nastaven na hodnotu HC_ACTION nebo HC_NOREMOVE je jisté, že v parametrech wParam a lParam jsou další informace. Hodnota HC_NOREMOVE dále říká, že zpráva nebude vyjmuta z fronty (aplikace volala PeekMessage s příznakem PM_NOREMOVE). Pokud je parametr menší než 0 musíme funkci okamžitě ukončit voláním CallNextHookEx.V parametru wParam obdrží tato metoda kód zprávy od myši a v parametru lParam ukazatel na strukturu MOUSEHOOKSTRUCT, která obsahuje další informace (např. souřadnice myši). Následující zdrojový kód ukazuje členské proměnné této struktury.

V případě, že byla odchycena zpráva WM_MOUSEMOVE, nebo WM_NCMOUSEMOVE pokusíme se pomocí metody FindWindow vyhledat okno s aplikací a zaslat mu zprávu o pohybu myši. Tato metoda ve svém druhém parametru očekává jméno okna.

4.2 Aplikace
Nyní vytvoříme aplikaci, která bude přijímat zprávy od hookovací procedury a bude zobrazovat aktuální polohu myši. Pro náš příklad zvolíme jednoduchý model dialog-based aplikace. V okamžiku vytvoření dialogu (v reakci na zprávu WM_CREATE) nainstalujeme hook voláním exportované funkce HookMouse a při zavírání dialogu (v reakci na WM_DESTROY), tzn. při ukončování aplikace, zavoláme druhou exportovanou funkci UnhookMouse a proceduru odinstalujeme.

int CMouseHookDlgAPP::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
  if (CDialog::OnCreate(lpCreateStruct) == -1)
    return -1;
  
  if (!HookMouse())
    return -1;

  return 0;
}

void CMouseHookDlgAPP
::OnDestroy() 
{
  UnhookMouse();
  CDialog::OnDestroy();
}

Poslední reakce bude na zprávy WM_MOUSEMOVE a WM_NCMOUSEMOVE, ve kterých budeme nastavovat statický text v dialogu tak, aby zobrazoval aktuální souřadnice. Podívejme se na zdrojový kód těchto funkcí.

void CMouseHookDlgAPP::OnMouseMove(UINT nFlags, CPoint point) 
{
  m_sMousePosition.Format("Pozice myši x:%d, y:%d", point.x, point.y);
  UpdateData(FALSE);
  CDialog::OnMouseMove(nFlags, point);
}

void CMouseHookDlgAPP::OnNcMouseMove(UINT nHitTest, CPoint point) 
{
  m_sMousePosition.Format("Pozice myši x:%d, y:%d", point.x, point.y);
  UpdateData(FALSE);
  CDialog::OnNcMouseMove(nHitTest, point);
}

Proměnná m_sMousePosition je typu CString a je "namapovaná" na statický text v dialogové šabloně.

jo_11111999_mousehook_obr1.gif (1294 bytes)

 


Podobné články: MFC a DLL, díl 1.,

<<Předchozí
Hook - monitorování zpráv I.
Článek je zařazen do seriálu  

Kdo Otázka nebo připomínka

Prohlížení příspěvků nebo nový příspěvek

O firmě... Kontakt ;