Maeștri de delphi, cârlige - aspecte ale implementării

Cârlige - aspecte ale implementării.

Vreau doar să fac câteva rezervări: în viitor, va merge doar despre Windows pe 32 de biți și capcane globale, pentru că în timpul programării apar mai multe erori; toate exemplele vor fi date pe Delphi, pentru că exemple și descrieri pentru iubitorii de C ++ este suficient.

O altă narațiune presupune că cititorul este familiarizat cu principiile de bază ale colaborării cu DLL-ul și cel puțin în general conturează mecanismul de scriere a acestora.

Ce se întâmplă în sistem când "setăm" o capcană și ceea ce este în general - o capcană.

Un cârlig este un mecanism Windows care permite interceptarea evenimentelor destinate unei aplicații înainte ca aceste evenimente să ajungă la această aplicație.

Filtrele funcționale sunt funcții care primesc notificări despre un eveniment care a apărut dintr-o capcană.

În funcție de tipul de capcană, funcțiile de filtrare pot modifica evenimentele, le pot anula sau pot reacționa pur și simplu la ele. Astfel, atunci când spunem "setați capcana", înțelegem procesul de atașare a funcției de filtrare la tipul de capcană pe care l-am ales. Deci, când folosim funcția SetWindowsHookEx în programul nostru, atașăm funcția de filtrare, pointerul la care trecem al doilea parametru, de exemplu:
SetWindowsHookEx (WH_SHELL, @ ShellHook.Hinstance, 0); în acest caz, ShellHook este funcția de filtrare. Mai târziu, sub expresia "setați capcana", înțelegem atașarea unei funcții de filtrare la o capcană.

Ce se întâmplă după ce am stabilit o capcană globală. Înțelegerea paragrafului următor este cheia pentru a înțelege mecanismul capcanelor Windows, aflat în DLL. Dacă nu o înțelegi, du-te înapoi și citiți-o din nou și așa mai departe până când totul devine clar.

Mesajul că mesajul a ajuns la n-1 cârlig (cârlig n-1) ar trebui să fie îngrijit de programator. În acest stadiu apar adesea greșeli.

Pentru a apela următoarea capcana în lanțul de capcane utilizate în funcție pentru Windows CallNextHookEx, primul parametru este un mâner pentru capcana curentă, se obține o funcție SetWindowsHookEx. Acum, atenția: am setat capcana în Process1, adică SetWindowsHookEx funcția efectuată în DLL, localizat în AP Process1 (vezi. Figura 1) și, în consecință, mânerul returnat de SetWindowsHookEx capcana instalat apartine date DLL rezidente în AP Process1. Să Process2 eveniment are loc la care capcana set apoi Dll din primul proces proiectat pe AP Process2, un Process2 de date DLL inițializat și apoi din nou că Process2 variabilă, în care „mincinoase“ descriptor set capcane Process1, va fi egală cu 0. Procedura de filtrare funcțională 2, care a îndeplinit, va trebui să transmită mesajul mai departe de-a lungul lanțului de capcane, adică CallNextHookEx efectua o funcție, primul parametru care trebuie să fie actuale capcane descriptori, dar nici un DLL în aceste date descriptor situat în Process2 (variabilă care ar trebui să conțină ea cuprinde zero). „Cum să fie într-un astfel de caz. De unde știm ocupa o capcană stabilită în alt proces, în cazul în care procesele de ei înșiși nu știu nimic despre unul pe altul?“ - întrebi. La această întrebare voi răspunde mai târziu, dar acum, să trecem în revistă tipurile de capcane de suprafață, deși informații despre tipurile de complet specificate în SDK.

După cum știm deja, cârligul este setat utilizând funcția API Win32 SetWindowsHookEx ():

funcția SetWindowsHookEx (idHook: integer; lpfn: TFNHookProc; hmod: HINST; dwThreadID: DWORD): HHOOK; stdcall;
idHook. descrie tipul de capcană instalat. Acest parametru poate lua una dintre următoarele valori:

Filtrul pentru aplicația shell. Funcția de filtrare a capcanelor este apelată atunci când ferestrele de nivel superior sunt create și distruse sau atunci când aplicația shell trebuie să devină activă.

Valoarea fiecărui parametru al funcției de filtrare a capcanei variază în funcție de tipul de capcană stabilit. Pentru explicații mai detaliate ale valorilor parametrilor, consultați Ajutorul API pentru Win32.

hmod. Acest parametru trebuie să aibă valoarea hInstance în fișierele EXE sau DLL care conțin o capcană a filtrelor funcționale (amintesc că aceasta este o funcție de retur). Dacă vorbim de capcane globale, atunci acest parametru poate accepta doar un descriptor DLL, din care este setată o capcană. Motivul este evident - fișierul EXE nu poate fi mapat la AP al altui proces, în timp ce fișierele DLL sunt create special pentru acest lucru. Subliniez această circumstanță încă o dată: capcanele globale pot fi localizate numai în DLL, dar nu în fișierele EXE.

dwThreadID. Acest parametru identifică firul cu care va fi conectat capcana. Vorbim despre capcane globale, deci acest parametru va fi întotdeauna 0, ceea ce înseamnă că capcana va fi conectată la toate firele din sistem.

Valoarea returnată: funcția SetWindowsHookEx returnează descriptorul cârligului instalat, acest descriptor ar trebui să fie pus la dispoziția tuturor instanțelor DLL afișate. Cum să faceți acest lucru, vă spun după un mic exemplu, arătând în practică necesitatea de a păstra mânerul capcanei pentru a putea apela capcana anterioară în lanț.

Notă. Când instalați două capcane de diferite tipuri, sistemul va crea două lanțuri de capcane. Ie fiecare tip de capcană are propriul său lanț. Prin urmare, atunci când instalați cârligele WH_MOUSE și WH_KEYBOARD, ambele capcane vor fi în lanțuri diferite și, în consecință, vor fi procesate independent una de cealaltă.

Pentru a elimina funcția de filtrare din coadă, trebuie să apelați funcția UnhookWindowsHookEx. Această funcție acceptă descriptorul de cârlig obținut de funcția SetWindowsHookEx. Dacă ștergerea a eșuat, funcția readuce zero, altfel valoarea nu este zero. În viitor, sub expresia "scoateți capcana", înțelegem îndepărtarea funcției de filtrare.

Acum, că știți cum să configurați o capcană și cum să o trageți, să analizăm câteva exemple care vor da o reprezentare vizuală a izolării proceselor AP și vor indica una dintre cele mai frecvente erori.

Cred că acum, după ce ați înțeles codurile sursă ale bibliotecilor din primul exemplu, v-ați dat seama cum să nu scrieți DLL-uri, din care ați stabilit capcane globale. Imaginați-vă că un utilizator folosește programul dvs., care implică cârlig la nivel mondial, executați un alt program, care stabilesc, de asemenea, același tip de capcana pe care a ta, dar instalați-l în coada de așteptare, în acest caz, în cazul în care acesta din urmă, al doilea program va fi scrise incorect - programul dvs. se va opri din cauza căci în capcana dvs. nu va fi trimis un mesaj din fața dvs. Acesta este un exemplu al modului în care o lucrare subordonată a unui programator poate strica o lucrare perfect executată a altui programator.

Acum câteva cuvinte despre implementarea software-ului tuturor celor de mai sus.

Creează un obiect de afișare a fișierelor. Această funcție returnează un mâner obiectului de afișare a fișierelor.

Această funcție închide fișierul afișat în memorie și eliberează descriptorul acesteia. Dacă funcția este reușită, funcția returnează o valoare nenulă și 0 în caz de eșec.

Pentru informații detaliate despre parametrii funcțiilor descrise mai sus, vă rugăm să consultați SDK-ul, precum și să înțelegeți exemplul, care va fi discutat mai jos.

Notă. primul parametru al funcției CreateFileMapping () trebuie să fie descriptorul de fișier pe care urmează să-l afișăm. pentru că vom afișa datele din fișierul de paginare, apoi ar trebui să trecem valoarea $ FFFFFFFF sau DWORD (-1), care corespunde aceleiași valori; ci pentru că se apropie epoca sistemelor pe 64 de biți, merită folosită valoarea INVALID_HANDLE_VALUE, care va fi de $ FFFFFFFFFFFFFFFFF în sistemul de 64 de biți, respectiv. Pentru cei care au trecut de la versiunile anterioare Delphi la cele mai vechi (de exemplu, cu Delphi2 la Delphi4), aceștia s-au confruntat cu astfel de probleme în programele lor.
Deoarece vom crea un obiect de afișare a fișierului numit, ultimul parametru al funcției CreateFileMapping () este numele obiectului care va folosi mai târziu alte procese pentru a face referire la aceeași regiune de memorie. Trebuie menționat faptul că obiectul creat în acest mod trebuie să aibă o dimensiune fixă, adică Nu se poate schimba în cursul programului.

Acum avem toate cunoștințele necesare pentru a examina al doilea exemplu. Deschideți directorul Example2 și urmați aceiași pași ca în primul exemplu, după ce studiați cu atenție codul sursă. După ce executați ambele aplicații și setați funcția două dintre ele filtru de același tip, încercați să faceți clic dreapta pe oricare dintre ferestrele și veți vedea că îndeplinesc acum ambele capcane set, indiferent care dintre ferestre era un click de mouse (adică, indiferent de instanța DLL care este apelată din funcția CallNextHookEx ()). Astfel, atunci când orice aplicație va afișa la AP DLL sale, care este funcția de filtru, DLL acest caz, va avea acces la datele sunt mapate în memorie de la Process1 sau Process2, în funcție de DLL. Cred că, după astfel de explicații detaliate, totul ar trebui să fie clar.

Îi mulțumesc lui Yuri Zotov pentru sprijin.

Arhiva cu exemple la articol: example.zip

Lista literaturii utilizate:

  1. Setul de dezvoltare software Microsoft Win32.
  2. Steve Teixeira și Xavier Pacheco, "Ghidul dezvoltatorului Delphi5: Volumul 1. Metode și tehnologii de bază".
  3. Kyle Marsh, "Hooks in Win32" (în original).
  4. Dr. Joseph M. Newcomer, "Hooks and DLLs" (în original).

Institutul de Inginerie Electrică din Moscova (Universitatea Tehnică)
Facultatea de Centrale Nucleare
27/2/02