Rozdział XXIV - Podpięcia do systemu Windows


Na tej lekcji dowiemy się o podpinaniu się do systemu Windows (Windows hooks), które jest bardzo potężnym narzędziem. Przy jego pomocy możesz zaglądać do wnętrza innych procesów, a czasami nawet zmieniać sposób ich działania.

 

 

Kod źródłowy możesz pobrać {z tego archiwum}.

 

Teoria

Podpięcia do Windows można uważać za jedną z najpotężniejszych cech tego systemu. Dzięki nim możesz przechwycić zdarzenia, które wystąpią albo w twoim własnym procesie, albo w innych procesach. "Podpięcie" oznacza nakazanie systemowi Windows wywołania pewnej funkcji filtrującej, zwanej procedurą podpięcia (hook procedure) za każdym razem, gdy pojawi się interesujące nas zdarzenie. Istnieją dwa rodzaje podpięć: lokalne i odległe.

Gdy instalujesz podpięcia, pamiętaj, iż wpływają one na wydajność systemu. Podpięcia ogólnosystemowe są tutaj najbardziej zniesławione. Ponieważ WSZYSTKIE zdarzenia będą przechodziły poprzez twoją funkcję filtrującą, to twój system może zauważalnie zwolnić. Zatem jeśli używasz podpięcie ogólnosystemowe, powinieneś robić to inteligentnie i rozłączyć się natychmiast, gdy przestanie ci to być potrzebne. Również masz większą szansę zablokowania innych procesów, ponieważ wtrącasz się w ich pracę i jeśli twoja funkcja filtrująca pracuje nieprawidłowo, to może puścić inne procesy w niepamięć. Pamiętaj: władza oznacza odpowiedzialność.

Zanim będziesz mógł wykorzystać efektywnie podpięcia, musisz poznać sposób ich działania. Gdy tworzysz podpięcie, system Windows buduje w pamięci strukturę danych zawierającą informację o danym podpięciu i dodaje ją do listy istniejących podpięć. Nowe podpięcie dodawane jest przed starymi. Gdy następuje jakieś zdarzenie, a zainstalowałeś lokalne podpięcie, to w twoim procesie zostaje wywołana funkcja filtrująca, zatem jest to operacja bezpośrednia. Lecz jeśli zainstalowałeś odległe podpięcie, to system musi wstrzyknąć kod procedury podpięcia w przestrzeń adresową innego procesu. A system może to wykonać tylko wtedy, gdy funkcja ta znajduje się w bibliotece DLL. Stąd, jeśli chcesz użyć odległego podpięcia, twoja procedura musi znaleźć się w bibliotece DLL. Istnieją dwa odstępstwa od tej reguły: podpięcia do nagrywania i odtwarzania dziennika systemu Procedury podpięć dla tych dwóch przypadków muszą znajdować się w wątkach, które je zainstalowały. Powodem jest to, iż oba podpięcia mają do czynienia z przechwytywaniem niskopoziomowych zdarzeń pochodzących od sprzętu. Zdarzenia wejściowe muszą być nagrywane i odtwarzane w tej samej kolejności, w której wystąpiły. Gdyby kod tych podpięć znajdował się w bibliotece DLL, to zdarzenia wejściowe rozproszyłyby się po kilku wątkach i nie moglibyśmy odgadnąć ich kolejności. Stąd rozwiązaniem jest umieszczenie ich procedur w pojedynczym wątku, tj. wątku, który zainstalował te podpięcia.

Istnieje 14 typów podpięć:

Teraz, gdy poznaliśmy już nieco teorii, możemy przejść do sposobów instalowania i odinstalowywania podpięć.

Aby zainstalować podpięcie, wywołujesz funkcję SetWindowsHookEx o następującej składni:

 

SetWindowsHookEx PROTO HookType:  DWORD,\
                       pHookProc: DWORD,\
                       hInstance: DWORD,\
                       ThreadID:  DWORD

Jeśli wywołanie się powiedzie, zwraca w rejestrze eax uchwyt podpięcia. Jeśli nie, zwracana jest wartość NULL. Musisz zachować ten uchwyt do późniejszego usunięcia podpięcia.

Podpięcie możesz odinstalować wywołując funkcję UnhookWindowsHookEx, która akceptuje tylko jeden parametr - uchwyt podpięcia do odinstalowania. Jeśli wywołanie się powiedzie, to zwraca niezerową wartość w rejestrze eax. W przeciwnym razie zwraca NULL.

Teraz, gdy znasz sposoby instalowania i usuwania podpięć, możemy zbadać procedurę podpięcia.

Procedura ta zostanie wywołana za każdym razem, gdy wystąpi zdarzenie powiązane z zainstalowanym typem podpięcia. Na przykład, jeśli zainstalowałeś podpięcie WH_MOUSE, to przy wystąpieniu zdarzenia myszki zostanie wywołana twoja procedura. Bez względu na typ zainstalowanego podpięcia jego procedura zawsze posiada następujący prototyp:

HookProc PROTO nCode:DWORD, wParam:DWORD, lParam:DWORD

HookProc jest właściwie szablonem nazwy funkcji. Możesz funkcję tę nazwać w dowolny sposób, o ile zachowasz zgodność z powyższym prototypem. Interpretacja parametrów nCode, wParam i lParam zależy od typu zainstalowanego podpięcia. Również odnosi się to do wartości zwrotnej z procedury podpięcia. Na przykład:

 

WH_CALLWNDPROC
nCode może mieć jedynie wartość HC_ACTION, która oznacza wysłanie wiadomości do okna.
wParam zawiera wysyłaną wiadomość
lParam wskazuje strukturę CWPSTRUCT
wartość
zwrotna
nie używana, zwracaj zero

 

WH_MOUSE
nCode może mieć wartość HC_ACTION lub HC_NOREMOVE
wParam zawiera wiadomość myszki
lParam wskazuje strukturę MOUSEHOOKSTRUCT
wartość
zwrotna
zero, jeśli wiadomość powinna być obsłużona i jeden, jeśli wiadomość należy porzucić.

 

Zawsze skonsultuj się z plikiem pomocy dla biblioteki API Win32 odnośnie szczegółowych znaczeń poszczególnych parametrów oraz wartości zwrotnej w procedurze podpięcia, którą planujesz zainstalować.

Istnieje mały haczyk odnośnie procedury podpięcia. Pamiętaj, iż podpięcia tworzą połączoną ze sobą listę, w której ostatnio zainstalowane podpięcie znajduje się na samym początku. Gdy wystąpi zdarzenie, system Windows wywoła jedynie pierwsze podpięcie na liście. Od twojej procedury zależy, czy wywoła ona następne podpięcie na liście. Możesz zdecydować się nie wywoływać go, lecz lepiej upewnij się, co robisz. W większości przypadków dobrą praktyką jest wywoływanie następnej procedury, aby inne podpięcia mogły również spojrzeć na to zdarzenie. Następne podpięcie możesz wywołać za pomocą funkcji CallNextHookEx o następującym prototypie:

 

CallNextHookEx PROTO hHook:DWORD, nCode:DWORD, wParam:DWORD, lParam:DWORD

Istotna uwaga na temat odległych podpięć: procedura podpięcia musi znajdować się w bibliotece DLL, która zostanie odwzorowana w inne procesy. Gdy system Windows odwzorowuje bibliotekę DLL w przestrzeń adresową innych procesów, nie przenosi sekcji danych do tych procesów. W skrócie, wszystkie procesy dzielą pojedynczą kopię kodu, lecz każdy z nich posiada prywatną kopię sekcji danych biblioteki DLL! Może to być wielką niespodzianką dla niezorientowanych. Możesz sądzić, iż jeśli wpiszesz wartość do zmiennej w sekcji danych biblioteki DLL, to wartość ta będzie dzielona przez wszystkie procesy, które załadują tę bibliotekę DLL w swoją przestrzeń adresową. A to po prostu nieprawda. W normalnych warunkach zachowanie takie jest pożądane, ponieważ dostarcza iluzji posiadania przez każdy proces własnej kopii biblioteki DLL. - ale nie, gdy rozważamy podpięcie systemu Windows. Chcemy, aby biblioteka pozostawała identyczna we wszystkich procesach, łącznie z jej danymi. Rozwiązanie: musisz zaznaczyć sekcję danych jako współdzieloną. Możesz tego dokonać określając atrybut sekcji w przełączniku konsolidatora. Dla MASM'a powinieneś użyć przełącznika:

 

/SECTION:<nazwa sekcji>, S

 

Nazwą zainicjowanej sekcji danych jest .data, a sekcji niezainicjowanej jest .bss. Na przykład, jeśli chcesz dokonać asemblacji biblioteki DLL zawierającej procedurę podpięcia z wspólną dla procesów sekcją danych niezainicjowanych, musisz użyć następującego wiersza polecenia:

 

link /section:.bss,S /DLL /SUBSYSTEM:WINDOWS ...

 

Atrybut S oznacza tę sekcję jako współdzieloną (shared).

Przykład

Występują dwa moduły: jeden jest programem głównym, który obsłuży graficzny interfejs użytkownika, a drugi jest biblioteką DLL instalującą o usuwającą doczepienie.

Plik programu głównego MOUSEHOOK.ASM

 

.386

.MODEL FLAT, STDCALL

OPTION CASEMAP:NONE

INCLUDE    \masm32\include\windows.inc
INCLUDE    \masm32\include\user32.inc
INCLUDE    \masm32\include\kernel32.inc
INCLUDE    HookDLL.inc
INCLUDELIB HookDLL.lib
INCLUDELIB \masm32\lib\user32.lib
INCLUDELIB \masm32\lib\kernel32.lib

DlgFunc PROTO :DWORD, :DWORD, :DWORD, :DWORD

.CONST

IDD_MAINDLG   EQU  101
IDC_CLASSNAME EQU 1000
IDC_HANDLE    EQU 1001
IDC_WNDPROC   EQU 1002
IDC_HOOK      EQU 1004
IDC_EXIT      EQU 1005
WM_MOUSEHOOK  EQU WM_USER+6

.DATA

HookFlag   DD FALSE
HookText   DB "&Podepnij", 0
UnhookText DB "&Odepnij", 0
template   DB "%lx", 0

.DATA?

hInstance DD ?
hHook     DD ?

.CODE

start:
    INVOKE GetModuleHandle, NULL
    mov    hInstance, eax
    INVOKE DialogBoxParam, hInstance, IDD_MAINDLG, NULL, ADDR DlgFunc, NULL
    INVOKE ExitProcess, NULL

DlgFunc PROC hDlg:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

LOCAL hLib:         DWORD
LOCAL buffer[128]:  BYTE
LOCAL buffer1[128]: BYTE
LOCAL rect:         RECT

    .IF uMsg==WM_CLOSE
        .IF HookFlag==TRUE
            INVOKE UninstallHook
        .ENDIF
        INVOKE EndDialog, hDlg, NULL
    .ELSEIF uMsg==WM_INITDIALOG
        INVOKE GetWindowRect, hDlg, ADDR rect
        INVOKE SetWindowPos, hDlg, HWND_TOPMOST,\
                             rect.left, rect.top,\
                             rect.right, rect.bottom, SWP_SHOWWINDOW
    .ELSEIF uMsg==WM_MOUSEHOOK
        INVOKE GetDlgItemText, hDlg, IDC_HANDLE, ADDR buffer1, 128
        INVOKE wsprintf, ADDR buffer, ADDR template, wParam
        INVOKE lstrcmpi, ADDR buffer, ADDR buffer1
        .IF eax!=0
            INVOKE SetDlgItemText, hDlg, IDC_HANDLE, ADDR buffer
        .ENDIF
        INVOKE GetDlgItemText, hDlg, IDC_CLASSNAME, ADDR buffer1, 128
        INVOKE GetClassName, wParam, ADDR buffer, 128
        INVOKE lstrcmpi, ADDR buffer, ADDR buffer1
        .IF eax!=0
            INVOKE SetDlgItemText, hDlg, IDC_CLASSNAME, ADDR buffer
        .ENDIF
        INVOKE GetDlgItemText, hDlg, IDC_WNDPROC, ADDR buffer1, 128
        INVOKE GetClassLong, wParam, GCL_WNDPROC
        INVOKE wsprintf, ADDR buffer, ADDR template, eax
        INVOKE lstrcmpi, ADDR buffer, ADDR buffer1
        .IF eax!=0
            INVOKE SetDlgItemText, hDlg, IDC_WNDPROC, ADDR buffer
        .ENDIF
    .ELSEIF uMsg==WM_COMMAND
        .IF lParam!=0
            mov ax, WORD PTR wParam
            mov dx, WORD PTR wParam + 2
            .IF dx==BN_CLICKED
                .IF ax==IDC_EXIT
                    INVOKE SendMessage, hDlg, WM_CLOSE, 0, 0
                .ELSE
                    .IF HookFlag==FALSE
                        INVOKE InstallHook, hDlg
                        .IF eax!=NULL
                            mov    HookFlag, TRUE
                            INVOKE SetDlgItemText, hDlg, IDC_HOOK, ADDR UnhookText
                        .ENDIF
                    .ELSE
                        INVOKE UninstallHook
                        INVOKE SetDlgItemText, hDlg, IDC_HOOK, ADDR HookText
                        mov    HookFlag, FALSE
                        INVOKE SetDlgItemText, hDlg, IDC_CLASSNAME, NULL
                        INVOKE SetDlgItemText, hDlg, IDC_HANDLE, NULL
                        INVOKE SetDlgItemText, hDlg, IDC_WNDPROC, NULL
                    .ENDIF
                .ENDIF
            .ENDIF
        .ENDIF
    .ELSE
        mov eax, FALSE
        ret
    .ENDIF
    mov eax, TRUE
    ret

DlgFunc ENDP

END start

 

Plik zasobów MOUSEHOOK.RC:

 

#define IDD_MAINDLG           101
#define DS_MODALFRAME        0x80
#define ES_AUTOHSCROLL       0x80
#define IDC_CLASSNAME        1000
#define IDC_HANDLE           1001
#define IDC_WNDPROC          1002
#define IDC_HOOK             1004
#define IDC_EXIT             1005
#define ES_READONLY         0x800
#define IDC_STATIC             -1
#define DS_MODALFRAME        0x80
#define WS_POPUP       0x80000000
#define WS_CAPTION       0xC00000
#define WS_SYSMENU        0x80000
#define ES_AUTOHSCROLL       0x80
#define ES_READONLY         0x800

IDD_MAINDLG DIALOG 0, 0, 226, 79
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Podpięcie do Myszki"
FONT 8,  "MS Sans Serif"
{
    GROUPBOX      "Informacje o oknie", IDC_STATIC, 7, 7, 213, 67
    LTEXT         "Nazwa klasy:", IDC_STATIC, 13, 22, 57, 8, 0
    EDITTEXT      IDC_CLASSNAME, 75, 21, 139, 12, ES_AUTOHSCROLL | ES_READONLY
    LTEXT         "Uchwyt:", IDC_STATIC, 13, 36, 58, 8, 0
    EDITTEXT      IDC_HANDLE, 75, 37, 77, 12, ES_AUTOHSCROLL | ES_READONLY
    LTEXT         "Procedura okna:", IDC_STATIC, 13, 52, 57, 8, 0
    EDITTEXT      IDC_WNDPROC, 75, 52, 77, 12, ES_AUTOHSCROLL | ES_READONLY
    DEFPUSHBUTTON "&Podepnij", IDC_HOOK, 163, 35, 50, 14
    PUSHBUTTON    "&Koniec", IDC_EXIT, 163, 50, 50, 14
}

 

To jest kod źródłowy biblioteki DLL - plik HOOKDLL.ASM:

 

.386

.MODEL FLAT, STDCALL

OPTION CASEMAP:NONE

INCLUDE    \masm32\include\windows.inc
INCLUDE    \masm32\include\kernel32.inc
INCLUDE    \masm32\include\user32.inc
INCLUDELIB \masm32\lib\kernel32.lib
INCLUDELIB \masm32\lib\user32.lib

.CONST

WM_MOUSEHOOK EQU WM_USER+6

.DATA

hInstance DD 0

.DATA?

hHook DD ?
hWnd     DD ?

.CODE

DllEntry PROC hInst:HINSTANCE,  reason:DWORD,  reserved1:DWORD

    push hInst
    pop  hInstance
    mov  eax, TRUE
    ret

DllEntry ENDP

MouseProc PROC nCode:DWORD, wParam:DWORD, lParam:DWORD

    INVOKE CallNextHookEx, hHook, nCode, wParam, lParam
    mov    edx, lParam

ASSUME edx:PTR MOUSEHOOKSTRUCT

    INVOKE WindowFromPoint, [edx].pt.x, [edx].pt.y
    INVOKE PostMessage, hWnd, WM_MOUSEHOOK, eax, 0

ASSUME edx:NOTHING

    xor eax, eax
    ret

MouseProc ENDP

InstallHook PROC hwnd:DWORD

    push   hwnd
    pop    hWnd
    INVOKE SetWindowsHookEx, WH_MOUSE, ADDR MouseProc, hInstance, NULL
    mov    hHook, eax
    ret 

InstallHook ENDP

UninstallHook PROC

    INVOKE UnhookWindowsHookEx, hHook
    ret

UninstallHook ENDP

END DllEntry

 

Plik HOOKDLL.DEF

 

LIBRARY HookDLL
EXPORTS 
    MouseProc
    InstallHook
    UninstallHook

 

Plik MAKEFILE dla biblioteki HookDLL. Jeśli asembler ml.exe i konsolidator link.exe nie znajdują się w systemowej ścieżce dostępu, to w pliku MAKEFILE należy określić odpowiednie ścieżki dostępu (również do bibliotek).

 

NAME=HookDLL
$(NAME).dll: $(NAME).obj
    Link /SECTION:.bss,S /DLL /DEF:$(NAME).def /SUBSYSTEM:WINDOWS /LIBPATH:c:\masm\lib $(NAME).obj
$(NAME).obj: $(NAME).asm
    ml /c /coff /Cp $(NAME).asm
 
 

Uwaga: jeśli korzystasz z pakietu RadASM (tak jak tłumacz), to utwórz projekt biblioteki DLL, a następnie w polu Link wprowadź poniższy tekst:

7,O,$B\LINK.EXE /SECTION:.bss|S /SUBSYSTEM:WINDOWS /RELEASE /DLL /DEF:$6 /LIBPATH:"$L",3

Chodzi tutaj głównie o wysłanie do konsolidatora przełącznika /SECTION:.bss,S. Jednakże jeśli dopiszesz ten przełącznik do treści pola Link, to interpreter poleceń środowiska RadASM źle zinterpretuje przecinek przed S - należy zamiast przecinka koniecznie wpisać znak |, który pełni właśnie rolę przecinka wysyłanego w wierszu polecenia do konsolidatora.

 

Analiza

Przykład wyświetli okno dialogowe z trzema kontrolkami edycyjnymi, które będą wypełniane nazwą klasy, uchwytem okna oraz adresem procedury okna związanymi z oknem pod kursorem myszki. W oknie dialogowym znajdują się dwa przyciski, Podepnij oraz Koniec. Gdy klikniesz przycisk Podepnij, program dokona doczepienia do danych pochodzących od myszki i tekst na przycisku zostanie zmieniony na Odepnij. Gdy przesuwasz kursor myszki ponad jakimś oknem, w głównym oknie przykładu wyświetlane są odpowiednie informacje. Gdy klikniesz przycisk Odepnij, program usunie doczepienie myszki.

 

 

Główny program stosuje okno dialogowe w charakterze swojego okna głównego. Definiuje on prywatną wiadomość WM_MOUSEHOOK, która będzie wykorzystywana pomiędzy programem głównym a biblioteką DLL. Gdy główny program otrzyma tę wiadomość, wParam będzie zawierało uchwyt okna, nad którym znajduje się kursor myszki. Oczywiście można to zrobić w sposób dowolny. Ja zdecydowałem się na wykorzystanie wParam do przekazywania uchwytu dla prostoty rozwiązania. Ty możesz wybrać swą własną metodę wymiany danych pomiędzy programem głównym a tą biblioteką DLL.

 

    .IF HookFlag==FALSE
        INVOKE InstallHook, hDlg
        .IF eax!=NULL
            mov    HookFlag, TRUE
            INVOKE SetDlgItemText, hDlg, IDC_HOOK, ADDR UnhookText
        .ENDIF

 

Program stosuje znacznik HookFlag do monitorowania stanu podpięcia. Ma on wartość FALSE, gdy podpięcie nie jest zainstalowane, a TRUE, gdy jest.

Gdy użytkownik kliknie przycisk Podepnij, program sprawdza, czy podpięcie jest już zainstalowane. Jeśli nie jest, to wywołuje funkcję InstallHook w bibliotece DLL, aby je zainstalować. Zwróć uwagę, iż jako parametr tej funkcji przekazujemy uchwyt głównego okna dialogowego, aby biblioteka DLL mogła przesyłać wiadomości WM_MOUSEHOOK do właściwego okna, tj. do naszego własnego.

Gdy program jest ładowany, wraz z nim zostaje również załadowana biblioteka DLL podpięcia. Właściwie biblioteki DLL są ładowane natychmiast po umieszczeniu programu w pamięci. Przed pierwszą instrukcja w programie wywoływana jest funkcja wejściowa biblioteki DLL. Zatem gdy program rozpocznie swoją pracę, biblioteki DLL są zainicjowane. W funkcji wejściowej biblioteki DLL podpięcia umieszczamy następujący kod:

 

DllEntry PROC hInst:HINSTANCE,  reason:DWORD,  reserved1:DWORD

    push hInst
    pop  hInstance
    mov  eax, TRUE
    ret

DllEntry ENDP

 

Kod ten po prostu zachowuje uchwyt egzemplarza samej biblioteki DLL w globalnej zmiennej o nazwie hInstance do użytku wewnątrz funkcji InstallHook.

 

InstallHook PROC hwnd:DWORD

    push   hwnd
    pop    hWnd
    INVOKE SetWindowsHookEx, WH_MOUSE, ADDR MouseProc, hInstance, NULL
    mov    hHook, eax
    ret 

InstallHook ENDP

 

Funkcja InstallHook jest sama w sobie bardzo prosta. Zachowuje ona przekazany jej jako parametr uchwyt okna w zmiennej globalnej o nazwie hWnd dla przyszłego użytku. Następnie wywołuje SetWindowsHookEx, aby zainstalować podpięcie do myszki. Wartość zwrotna z tego wywołania jest umieszczana w zmiennej globalnej o nazwie hHook do użycia przez funkcję UnhookWindowsHookEx.

Po wywołaniu SetWindowsHookEx podpięcie do myszki już działa. Gdy wystąpi w systemie jakieś zdarzenie myszki, zostanie wywołana procedura MouseProc (twoja procedura podpięcia).

 

MouseProc PROC nCode:DWORD, wParam:DWORD, lParam:DWORD

    INVOKE CallNextHookEx, hHook, nCode, wParam, lParam
    mov    edx, lParam

ASSUME edx:PTR MOUSEHOOKSTRUCT

    INVOKE WindowFromPoint, [edx].pt.x, [edx].pt.y
    INVOKE PostMessage, hWnd, WM_MOUSEHOOK, eax, 0

ASSUME edx:NOTHING

    xor eax, eax
    ret

MouseProc ENDP

 

Pierwszą rzeczą jest wywołanie CallNextHookEx, aby dać szansę przetworzenia zdarzenia myszki innym podpięciom. Następnie wywołuje funkcję WindowFromPoint, aby pobrać uchwyt okna zajmującego określone współrzędne na ekranie. Zauważ, iż korzystamy tutaj z podstruktury POINT wewnątrz struktury MOUSEHOOKSTRUCT wskazywanej przez lParam jako bieżących współrzędnych myszki. I dalej wysyłamy ten uchwyt okna do programu głównego poprzez funkcję PostMessage z wiadomością WM_MOUSEHOOK. Musisz pamiętać, iż nie powinieneś używać wewnątrz procedury podpięcia funkcji SendMessage, ponieważ może ona doprowadzić do zakleszczenia. Zalecane jest użycie PostMessage. Strukturę MOUSEHOOKSTRUCT definiujemy poniżej:

 

MOUSEHOOKSTRUCT STRUCT DWORD 
    pt           POINT <> 
    hwnd         DWORD ? 
    wHitTestCode DWORD ? 
    dwExtraInfo  DWORD ? 
MOUSEHOOKSTRUCT ENDS

Gdy główne okno otrzyma wiadomość WM_MOUSEHOOK, użyje uchwytu okna z parametru wParam do pobrania informacji o tym oknie.

 

    .ELSEIF uMsg==WM_MOUSEHOOK
        INVOKE GetDlgItemText, hDlg, IDC_HANDLE, ADDR buffer1, 128
        INVOKE wsprintf, ADDR buffer, ADDR template, wParam
        INVOKE lstrcmpi, ADDR buffer, ADDR buffer1
        .IF eax!=0
            INVOKE SetDlgItemText, hDlg, IDC_HANDLE, ADDR buffer
        .ENDIF
        INVOKE GetDlgItemText, hDlg, IDC_CLASSNAME, ADDR buffer1, 128
        INVOKE GetClassName, wParam, ADDR buffer, 128
        INVOKE lstrcmpi, ADDR buffer, ADDR buffer1
        .IF eax!=0
            INVOKE SetDlgItemText, hDlg, IDC_CLASSNAME, ADDR buffer
        .ENDIF
        INVOKE GetDlgItemText, hDlg, IDC_WNDPROC, ADDR buffer1, 128
        INVOKE GetClassLong, wParam, GCL_WNDPROC
        INVOKE wsprintf, ADDR buffer, ADDR template, eax
        INVOKE lstrcmpi, ADDR buffer, ADDR buffer1
        .IF eax!=0
            INVOKE SetDlgItemText, hDlg, IDC_WNDPROC, ADDR buffer
        .ENDIF

 

Aby uniknąć migotania, sprawdzamy tekst znajdujący się już w kontrolkach edycyjnych i tekst do wprowadzenia do nich. Jeśli teksty są identyczne, opuszczamy operację uaktualnienia zawartości kontrolki edycyjnej.

Nazwę klasy otrzymamy wywołując GetClassName, a adres procedury okna wywołując GetClassLong z wartością GCL_WNDPROC, a następnie formatujemy je i umieszczamy w odpowiednich kontrolkach edycyjnych.

 

    INVOKE UninstallHook
    INVOKE SetDlgItemText, hDlg, IDC_HOOK, ADDR HookText
    mov    HookFlag, FALSE
    INVOKE SetDlgItemText, hDlg, IDC_CLASSNAME, NULL
    INVOKE SetDlgItemText, hDlg, IDC_HANDLE, NULL
    INVOKE SetDlgItemText, hDlg, IDC_WNDPROC, NULL

 

Gdy użytkownik kliknie przycisk Odepnij, program wywołuje funkcję UninstallHook w bibliotece DLL. UninstallHook po prostu wywołuje UnhookWindowsHookEx. Po tej operacji zmienia tekst przycisku z powrotem na Podepnij, a HookFlag na FALSE i wymazuje zawartość kontrolek edycyjnych.

 

Autorem kursu jest Iczelion. Kurs programowania Windows znalazł się na serwerze I LO w Tarnowie za pisemną zgodą autora.
Tłumaczenie z języka angielskiego, opracowanie HTML i konwersję przykładów programów wykonał mgr Jerzy Wałaszek.



List do administratora Serwisu Edukacyjnego Nauczycieli I LO

Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz  ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

 

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień szeroko opisywanych w podręcznikach.



   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2017 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.