Documente online.
Zona de administrare documente. Fisierele tale
Am uitat parola x Creaza cont nou
 HomeExploreaza
upload
Upload




Subclasarea

windows


Subclasarea

Subclasarea este o tehnica ce permite unei aplicatii sa intercepteze mesaje destinate pentru o alta fereastra.

Subclasarea este o cale efectiva de a schimba sau extinde comportarea unei ferestre fara a redezvolta fereastra.



Subclasarea claselor controalelor window implicite (controale buton, list box, combo box, controale statice, scroll bar) constituie o metoda preferata pentru a obtine functionalitatea controlului si a modifica comportarea sa. De exemplu, intr-un control EDIT ce accepta linii multiple (control plasat intr-o caseta de dialog, ce contine si un buton <OK> ce are tasta Enter atasata implicit), apasarea tastei Enter va duce la terminarea dialogului (se trimite mesajul BN_CLICKED pentru butonul <OK>). Pentru a schimba functionalitatea controlului EDIT astfel incit la apasarea tastei Enter sa se insereze un carriage return si line feed in control, va trebui sa subclasam acest control; sa interceptam mesajul inainte de a ajunge la procedura fereastra a dialogului.

Bazele subclasarii

Primul pas in crearea unei ferestre este completarea unei structuri WNDCLASS(EX) si apoi sa inregistram aceasta clasa apelind RegisterClass(Ex). O data membru a acestei structuri contine adresa procedurii fereastra. Cind este creata fereastra, SO ia adresa procedurii fereastra si o copie in structura de informatii a ferestrei. Cind se trimite un mesaj la fereastra, SO apeleaza procedura fereastra corecta (vezi structura MSG, aceasta contine HWND-ul ferestrei).

A subclasa o fereastra, inseamna a inlocui vechea procedura fereastra cu una noua.

Cind o aplicatie subclaseaza o fereastra, aceasta poate face urmatoarele actiuni cu mesajul:

sa 'paseze' mesajul procedurii originale a fereastrei;

sa modifice mesajul si sa-l paseze procedurii 545g69f originale a ferestrei;

sa nu paseze mesajul procedurii originale a ferestrei.

Aplicatia poate procesa mesajul inainte, dupa, sau inainte si dupa pasarea mesajului procedurii originale a ferestrei.

Tipuri de subclasare

Exista doua tipuri de subclasari: instance subclassing (subclasarea instantei) si global subclassing (subclasare globala).

Instance subclassing este subclasarea unei structuri individuale de informatii a ferestrei. In acest caz numai mesajele unei instante particulare a ferestrei sunt trimise la noua procedura fereastra.

Subclasarea globala insemana inlocuirea adresei procedurii fereastra in structura WNDCLASS(EX) a clasei fereastra. Toate ferestrele create dupa aceea din aceasta structura au adresa procedurii fereastra substituita. Sunt afectate numai ferestrele create dupa ce a fost realizata subclasarea globala.

Reguli pentru subclasare Win32

Doua reguli se aplica pentru subclasare (instance si global):

Subclasarea este permisa numai in interiorul unui proces.

O aplicatie nu poate subclasa o fereastra sau o clasa ce apartine la un alt proces.

Functii folosite SetWindowLong si SetClassLong. A se vedea de asemenea si functiile GetWindowLong(), GetClassLong().

Modalitati de a realiza subclasarea

Atita timp cit avem definita o functie in spatiul de adrese al unui proces, putem subclasa orice in acel proces. Aceasta functie trebuie sa stie sa trateze mesajele ce ne intereseaza.

Metoda 1

Cea mai usoara cale este de a adauga numele unei biblioteci de legaturi dinamice (DLL) la urmatoarea cheie din registri:

HKEY_LOCAL_MACHINESoftwareMicrosoftWindows NT CurrentVersionWindowsAPPINIT_DLLS

Aceasta cheie permite SO Windows sa adauge acest DLL fiecarui proces din sistem. DLL-ul trebuie 'trezit' intr-un fel dupa fiecare eveniment pe care DLL-ul ar dori sa-l subclaseze.

'A hook' WH_CBT face in mod normal acest lucru. DLL-ul poate fi 'trezit' pentru evenimentul HCBT_CREATEWND, apoi subclaseaza fereastra dorita. (vezi exemplul CTL3D).

hook = un punct in mecanismul de manipulare a mesajelor din Windows unde o aplicatie poate instala o subrutina pentru a monitoriza mesajul.

hook chain = o lista de pointeri la proceduri hook asociate cu un hook. Cind apare un mesaj ce este monitorizat de hook, Windows apeleaza mai intai prima procedura din lista.

hook procedure = o functie callback definita de aplicatie a carei adresa a fost instalata intr-un lant hook.

Vezi si articolul Win32 Hooks de Kyle Marsh
Microsoft Developer Network Technology Group

Created: July 29, 1993

Metoda 2

O alta modaliate de a realiza subclasarea consta in a folosi 'a systemwide hook'.

Cind 'a systemwide hook' este apelat din contextul unui alt proces, systemul incarca DLL-ul, ce contine 'hook', in proces. Aceasta inseamna ca DLL-ul va intercepta mesajele, si va trata numai o parte a acestora, returnind obligatoriu celelalte mesaje catre aplicatie.

Metoda 3

Aceasta metoda adauga codul de subclasare in alt proces si este foarte complicata.

Aceasta implica folosirea functiilor, OpenProcess, WriteProcessMemory si CreateRemoteThread pentru a injecta cod in alt proces. Metoda nu este recomandata. Se recomanda folosirea OLE-uri.

Detalii de implementare a subclasarii

Procesul de subclasare poate sa nu utilizeze adresa originala a procedurii fereastra in mod direct.

Singura modalitate de a utiliza adresa procedurii fereastra returnata de SetWindowLong sau SetClassLong este de a o folosi ca un parametru intr-un apel al functiei CallWindowProc.

Instance Subclassing

Functia SetWindowLong este folosita pentru a subclasa o instanta a ferestrei. Aplicatia trebuie sa aiba adresa functiei ce va realiza subclasarea, cea care va fi folosita in locul procedurii fereastra, aceasta primeste mesajele si le poate trece mai departe la procedura fereastra originala printr-un apel al functiei CallWindowProc(). Daca aceasta functie se gaseste intr-un DLL, aceasta trebuie exportata in aplicatie sau in fisierul de definitie al DLL-ului. In cadrul functiei ce realizeaza subclasarea, un rol important il are mesajul WM_GETDLGCODE (vezi mai jos).

Etapele realizarii subcalsarii in acest caz sunt:

se apeleaza functia SetWindowLong() al carei prototip este:

LONG SetWindowLong( HWND hWnd // handle-rul ferestrei

int nIndex // offset valorii ce va fi setata

LONG dwNewLong // noua valoare );

In acest caz nIndex = GWL_WNDPROC, dwNewLong = adresa noii proceduri fereastra.

Valoarea returnata constituie adresa originala a procedurii fereastra. Aceasta trebuie memorata pentru a avea posibilitatea sa o repunem printr-un nou apel al acestei functii.

Aplicatia trece mesajul catre procedura originala a ferestrei printr-un apel al functiei CallWindowProc(), de asemenea vor fi pasati hwnd, Message, wParam si lParam folositi in mesajul Windows.

LRESULT CallWindowProc(

WNDPROC lpPrevWndFunc // pointer la procedura fereastra

HWND hWnd // handle la fereastra

UINT Msg // mesajul

WPARAM wParam // primul parametru al mesajului

LPARAM lParam // al doilea parametru al mesajului);

Exemplu de cod pentru subclasarea unui control EDIT:

// Functia ce va realiza subclasarea, va intercepta mesajul

LONG FAR PASCAL SubClassFunc(HWND hWnd,WORD Message,WORD wParam,

LONG lParam);

FARPROC lpfnOldWndProc;

HWND hEditWnd;

// Cream un control de editare si il subclasam

hEditWnd = CreateWindow('EDIT', 'EDIT Test',

WS_CHILD | WS_VISIBLE | WS_BORDER ,

0, 0, 50, 50,

hWndMain,

NULL,

hInst,

NULL);

// Acum subclasam fereastra ce a fost creata

// Observati conversia asupra rezultatului returnat de SetWindowLong

lpfnOldWndProc = (FARPROC)SetWindowLong(hEditWnd,

GWL_WNDPROC, (DWORD) SubClassFunc);

// Revenim la starea initiala (stergem subclasarea)

//

SetWindowLong(hEditWnd, GWL_WNDPROC, (DWORD) lpfnOldWndProc);

// Exemplu de cod in functia ce realizeaza subclasarea

LONG FAR PASCAL SubClassFunc( HWND hWnd,

WORD Message,

WORD wParam,

LONG lParam)

WM_GETDLGCODE

Mesajul WM_GETDLGCODE este trimis procedurii fereastra asociata cu un control. Implicit, sistemul trateaza toate intrarile de la tastatura realizate in cadrul controlului; sistemul interpreteaza anumite anumite tipuri de intrari de la tasttatura drept chei de navigare in cadrul casetei de dialog. Pentru a evita comportarea implicita, controlul poate raspunde mesajului WM_GETDLGCODE pentru a indica tipurile de intrari pe care doreste sa le proceseze.

WM_GETDLGCODE

wParam;    // not used

pMsg = (LPMSG) lParam; // pointer la o structura MSG

Parametri

pMsg

Valoarea lui lParam este NULL daca sistemul executa o cerere, sau lParam este un pointer la o structura MSG

Valori returnate

Vaoarea returnata (una din cele de mai jos) indica ce tip de intrare proceseaza aplicatia.

Valoare

Descriere

DLGC_BUTTON

Buton.

DLGC_DEFPUSHBUTTON

Buton push implicit.

DLGC_HASSETSEL

Mesaje EM_SETSEL

DLGC_RADIOBUTTON

Buton radio.

DLGC_STATIC

Control static.

DLGC_UNDEFPUSHBUTTON

Buton push neimplicit.

DLGC_WANTALLKEYS

Toate intrarile de la tastatura.

DLGC_WANTARROWS

Chei de directionare.

DLGC_WANTCHARS

Mesaje WM_CHAR

DLGC_WANTMESSAGE

Toate intrarile de la tastatura (aplicatia paseaza acest mesaj in structura MSG la control).

DLGC_WANTTAB

Tasta TAB.

Functia DefWindowProc returneaza zero.

In MFC trebuie suprascrisa functia CWnd::OnGetDlgCode al carei prototip este (vezi MSDN):

afx_msg UINT OnGetDlgCode( );

Observatie: Cind o aplicatie subcalaseaza ferestre subclasate, subclasarile trebuiesc sterse in ordinea inversa in care au fost facute.In MFC subclasarea se face la un singur nivel.

Aplicatiile ce subclaseaza ferestre ar trebui sa memoreze datele necesare pentru o instanta a ferestrei subcalsate in lista de proprietati a ferestrei.

Functiile implicate sunt: SetProp, LocallAlloc, GlobalAlloc, GetProp, RemoveProp, LocalFree, GlobalFree.

Subclasarea globala

Subclasarea globala este asemanatoare cu subclasarea instantei ferestrei.

In acest caz functiile implicate sunt: SetClassLong, CallWindowProc.

Si in acest caz trebuie pastrat pointerul la adresa originala a procedurii fereastra pentru a-l putea repune la un nou apel al functiei SetClassLong.

In MSDN prototipul pentru SetClassLong este:

DWORD SetClassLong( HWND hWnd // handle la fereastra

int nIndex // indexul valorii de schimbat

LONG dwNewLong // valoarea noua);

Pentru mai multe detalii consultati MSDN.

Exemplu de cod ce subclaseaza global un control EDIT.

// Functia ce realizeaza subclasarea

LONG FAR PASCAL SubClassFunc(HWND hWnd,WORD Message,WORD wParam,

LONG lParam);

FARPROC lpfnOldClassWndProc;

HWND hEditWnd;

// Cream un control de editare si il subclasam.

// Controlul nu este vizibil.

hEditWnd = CreateWindow('EDIT', 'EDIT Test',

WS_CHILD,

0, 0, 50, 50,

hWndMain,

NULL,

hInst,

NULL);

// Observati conversia facuta

lpfnOldClassWndProc =

(FARPROC)SetClassLong(hEditWnd, GCL_WNDPROC,

(DWORD)SubClassFunc);

// Stergem subclasarea

SetClassLong(hEditWnd, GWL_WNDPROC, (DWORD) lpfnOldClassWndProc);

DestroyWindow(hEditWnd);

Subclasarea Claselor Control Window cu MFC

Subclasarea controalelor fereastra cu MFC are putine lucruri in comun cu subclasarea controalelor folosind Microsoft Win32® API.

Din cauza naturii functiilor virtuale in clasele C++, inlocuirea unei functii handler pentru o clasa de baza cu una personalizata se realizeaza in mod automat. Din cauza ca C++ inlocuieste functiile membru virtuale cu functii membru din clasa derivata, 'overriding' ce functia handler a mesajului este apelata de harta de mesaje din MFC este facuta automat.

Etapele de realizare sunt:

Cream clasa si o derivam din clasa pe care dorim sa o subclasam.

Pentru fiecare mesaj pe care dorim sa-l procesam, cream o functie membru cu exact acelasi nume si parametri ca pentru functia ce exista in clasa parinte. Indicarea subclasarii poate fi facuta in functia ce trateaza mesajul WM_INITDIALOG (in cazul casetelor de dialog) sau intr-o functie folosita la initializarea ferestrei, dar inainte ca fereastra sa fie afisata.

Cind dorim sa fie utilizata functionalitatea clasei parinte, apelam functia corespunzatoare din clasa parinte (folosind sintaxa ParentClassName::FunctionName).

Returnam valoarea valoarea functiei membru din clasa parinte (bine-nteles, putem totdeauna returna propria noastra valoare daca nu apelam functia membru din clasa parinte).

Exemplu se gaseste in clasa CAutoListCtrl din Virtual Office Systems, Inc. Web site.

Superclasarea

Superclasarea (cunoscuta si sub numele de clonare clase) creaza o noua clasa fereastra. Noua clasa fereastra foloseste procedura fereastra din clasa existenta pentru a da noii clase functionalitatea clasei existente. Superclasa este bazata pe existenta altor clase fereastra, cunoscute ca clase de baza. In mod obisnuit o clasa de baza este o clasa control furnizata de SO Windows, dar poate fi orice clasa fereastra cunoscuta in sistem.

Observatie: Controlul scroll bar nu trebuie superclasat pentru ca Windows il foloseste numele clasei pentru a produce comportarea corecta pentru aceasta fereastra.

Superclasa are propria procedura fereastra, procedura superclasei, care poate executa acelasi actiuni ca si procedura clasei de baza.

Procedura superclasei poate executa aceleasi tipuri de actiuni ca in cazul subclasarii:

a)      sa 'paseze' mesajul procedurii originale a fereastrei;

b)      sa modifice mesajul si sa-l paseze procedurii 545g69f originale a ferestrei;

c)      sa nu paseze mesajul procedurii originale a ferestrei.

Pentru anumite mesaje legate de crearea ferestrei (de ex. WM_NCCREATE, WM_CREATE), procedura superclasei trebuie sa paseze acest mesaj procedurii ferestrei originale.

Functiile implicate in supercalsare sunt: GetClassInfoEx(), CallWindowProc().

BOOL GetClassInfoEx(

HINSTANCE hinst // handle la instanta aplicatiei

LPCTSTR lpszClass // adresa numelui clasei

LPWNDCLASSEX lpwcx    // adresa structurii WNDCLASSEX

);

Parametri

hinst = handle la instanta aplicatiei ce a creat aceasta clasa. Pentru a regasi informatia definita de sistem (cum ar fi butoane sau list box-uri), acest parametru trebuie pus NULL.

lpszClass = pointer la un sir de caractere ce contine numele clasei, nume folosit in functia RegisterClassEx().

Valori returnate

In al treilea parametru se returneaza indormatiile despre clasa in cazul cind functia se executa cu succes (valoarea returnata diferita de zero).

Daca clasa de baza are un meniu, aplicatia ce superclaseaza clasa de baza trebuie sa furnizeze un nou meniu cu acelasi ID ca cel din clasa de baza. Daca superclasa intentioneaza sa proceseze mesajul WM_COMMAND si sa nu-l paseze la procedura clasei de baza, meniul nu trebuie sa aiba ID-ul corespunzator.

GetClassInfo nu returneaza cimpurile lpszMenuName, lpszClassName, sau hInstance din structura WNDCLASSEX.

Ultimul cimp ce trebuie setat in structura WNDCLASSEX a superclasei este lpfnWndProc.    GetClassInfo completeaza acest cimp cu adresa procedurii originale a acestei ferestre.

Aplicatia trebuie sa salveze aceasta adresa pentru a o putea folosi intr-un viitor apel al functiei CallWindowProc(). Dupa aceasta aplicatia trebuie sa seteze acest cimp cu noua adresa a procedurii fereastra. De asemenea aplicatia poate modifica oricare din cimpurile structurii WNDCLASSEX.

Dupa ce structura WNDCLASSEX a fost completat, aplicatia apeleaza functia RegisterClass(Ex) pentru a inregistra noua clasa fereastra. Din acest moment se pot crea noi ferestre folosind aceasta clasa.

Mesaje Window definite de utilizator

Aceste mesaje incep la valoarea definita de WM_USER in windef.h si ajung pina la 0x7FFF.

Etape:

#define WM_DBINIT_COMPLETE (WM_USER + 100)

Adaugam o functie membru in .h cu urmatorul prototip:

LRESULT CMainFrame::OnDBInitComplete(WPARAM wParam, LPARAM lParam)

Modificam harta de mesaje:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

//}AFX_MSG_MAP

ON_MESSAGE(WM_DBINIT_COMPLETE, OnDBInitComplete)

END_MESSAGE_MAP()

Adaugam functia in .cpp si scriem codul

Codul trebuie sa se execute cit mai rapid, pentru ca in acest timp interfata aplicatiei cu utilizatorul nu mai este activa (vezi functia SendMessage()).


Document Info


Accesari: 1124
Apreciat: hand-up

Comenteaza documentul:

Nu esti inregistrat
Trebuie sa fii utilizator inregistrat pentru a putea comenta


Creaza cont nou

A fost util?

Daca documentul a fost util si crezi ca merita
sa adaugi un link catre el la tine in site


in pagina web a site-ului tau.




eCoduri.com - coduri postale, contabile, CAEN sau bancare

Politica de confidentialitate | Termenii si conditii de utilizare




Copyright © Contact (SCRIGROUP Int. 2024 )