Tutorial 16: Event Object
From UIC
Tutorial 16: Event Object
Contents |
| Tutorial 16: Event Object | |
|---|---|
| Author: | Iczelion |
| Email: | Translate: -NeuRaL_NoiSE |
| Website: | Mirror |
| Date: | 17/01/2009 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | Formattazione Wiki: Antelox |
Introduzione
Impareremo cos'è un event object e come usarlo in un programma in multithreading.
Tools
Preliminari
Nel tutorial precedente, ho dimostrato come i thread comunicano tra di loro con un messaggio di windows personalizzato. Non ho parlato di altri due metodi: le variabili globali e gli event objects. Li utilizzeremo entrambi in questo tutorial. Un event object e' come un interruttore: ha solo due stati, ON o OFF. Quando un event object e' accesso (ON), e' in stato "segnalato". Quando e' spento (OFF), e' instato "non-segnalato". Voi create un event object e inserite uno spezzone di codice nei thread interessati per controllare lo stato dell'event object. Se l'event object e' in stato "non-segnalato", i threads che lo aspettano saranno "addormentati". Quando i threads sono in stato di attesa, consumano poco CPU time. Creerete un event object chiamando la funzione CreateEvent che ha la seguente sintassi:
LPSECURITY_ATTRIBUTES lpEventAttributes, // indirizzo degli attributi di sicurezza
BOOL bManualReset, // flag per l'evento di reset manuale
BOOL bInitialState, // flag per lo stato iniziale
LPCTSTR lpName // indirizzo del nome dell'event object
);
lpEventAttribute --> Se specificate il valore NULL, l'event object e' creato con il descrittore di sicurezza predefinito.
bManualReset --> Se volete che Windows resetti automaticamente l'event object in stato "non-segnalato" dopo la chiamata a WaitForSingleObject, dovete specificare FALSE in questo parametro. Altrimenti, dovete resettare manualmente l'event object con la chiamata a ResetEvent.
bInitialState --> Se volete che l'event object venga creato in stato "segnalato", specificate TRUE come parametro o altrimenti l'event object sara' creato in stato "non-segnalato".
lpName --> Puntatore ad una stringa ASCIIZ che contiene il nome dell'event object. Questo nome e' usato quando volete chiamare OpenEvent.
Se la chiamata ha successo, restituisce l'handle del nuovo event object, altrimenti restituisce NULL. Potete modificare lo stato di un event object con due funzioni API: SetEvent e ResetEvent. La funzione SetEvent mette l'event object in stato "segnalato". ResetEvent fa il contrario. Quando un event object viene creato, dovete inserire la chiamata a WaitForSingleObject nel thread che deve controllare lo stato dell'event object. WaitForSingleObject ha la seguente sintassi:
HANDLE hObject, // handle dell'object da aspettare
DWORD dwTimeout // intervallo di time-out in millisecondi
);
hObject --> L'handle di uno dei synchronization objects. L'event object e' un tipo di synchronization object.
dwTimeout --> Specifica il tempo in millisecondi che questa funzione aspettera' per vedere se l'object e' in stato "segnalato". Se il tempo specificato e' passato e l'event object e' ancora in stato "non-segnalato", WaitForSingleObject ritorna al caller. Se volete aspettare l'object per un tempo indefinito, dovete specificare il valore INFINITE in questo parametro.
Essay
L'esempio che segue mostra una finestra che aspetta che l'utente selezioni un comando dal menu. Se l'utente sceglie "run thread", il thread comincia la savage calculation. Quando ha finito, viene mostrata una message box che informa l'utente che il lavoro e' stato completato. Mentre il thread e' in esecuzione, l'utente puo' scegliere "stop thread" per fermarlo.
includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
.const
IDM_START_THREAD equ 1
IDM_STOP_THREAD equ 2
IDM_EXIT equ 3
WM_FINISH equ WM_USER+100h
.data
ClassName db "Win32ASMEventClass",0
AppName db "Win32 ASM Event Example",0
MenuName db "FirstMenu",0
SuccessString db "The calculation is completed!",0
StopString db "The thread is stopped",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwnd HANDLE ?
hMenu HANDLE ?
ThreadID DWORD ?
ExitCode DWORD ?
hEventStart HANDLE ?
EventStop BOOL FALSE
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,OFFSET MenuName
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,0
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,\
ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,300,200,NULL,NULL,\
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
invoke GetMenu,hwnd
mov hMenu,eax
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
mov eax,uMsg
.IF eax==WM_CREATE
invoke CreateEvent,NULL,FALSE,FALSE,NULL
mov hEventStart,eax
mov eax,OFFSET ThreadProc
invoke CreateThread,NULL,NULL,eax,\
NULL,NORMAL_PRIORITY_CLASS,\
ADDR ThreadID
invoke CloseHandle,eax
.ELSEIF eax==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF eax==WM_COMMAND
mov eax,wParam
.if lParam==0
.if ax==IDM_START_THREAD
invoke SetEvent,hEventStart
invoke EnableMenuItem,hMenu,IDM_START_THREAD,MF_GRAYED
invoke EnableMenuItem,hMenu,IDM_STOP_THREAD,MF_ENABLED
.elseif ax==IDM_STOP_THREAD
mov EventStop,TRUE
invoke EnableMenuItem,hMenu,IDM_START_THREAD,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_STOP_THREAD,MF_GRAYED
.else
invoke DestroyWindow,hWnd
.endif
.endif
.ELSEIF eax==WM_FINISH
invoke MessageBox,NULL,ADDR SuccessString,ADDR AppName,MB_OK
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
ThreadProc PROC USES ecx Param:DWORD
invoke WaitForSingleObject,hEventStart,INFINITE
mov ecx,600000000
.WHILE ecx!=0
.if EventStop!=TRUE
add eax,eax
dec ecx
.else
invoke MessageBox,hwnd,ADDR StopString,ADDR AppName,MB_OK
mov EventStop,FALSE
jmp ThreadProc
.endif
.ENDW
invoke PostMessage,hwnd,WM_FINISH,NULL,NULL
invoke EnableMenuItem,hMenu,IDM_START_THREAD,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_STOP_THREAD,MF_GRAYED
jmp ThreadProc
ret
ThreadProc ENDP
end start
Analisi
In quest'esempio, dimostro un altra tecnica di thread.
invoke CreateEvent,NULL,FALSE,FALSE,NULL
mov hEventStart,eax
mov eax,OFFSET ThreadProc
invoke CreateThread,NULL,NULL,eax,\
NULL,NORMAL_PRIORITY_CLASS,\
ADDR ThreadID
invoke CloseHandle,eax
Potete vedere che creo l'event object e il thread durante l'elaborazione del messaggio WM_CREATE. Creo l'event object in stato "non-segnalato" con reset automatico. Una volta creato l'event object, creo il thread. Comunque il thread non parte immediatamente perche' attende che l'event object sia in stato "segnalato" con il codice seguente:
invoke WaitForSingleObject,hEventStart,INFINITE
mov ecx,600000000
La prima linea della thread procedure e' la chiamata a WaitForSingleObject. Essa aspetta indefinitamente per lo stato "segnalato" dell'event object prima di ritornare. Cio' significa che nonostante noi creiamo il thread, lo mettiamo in stato di inattivita'. Quando l'utente sceglie il comando "run thread" dal menu, mettiamo l'event object in stato "segnalato" cosi':
invoke SetEvent,hEventStart
La chiamata a SetEvent mette l'event object in stato "segnalato", che a sua volta fa si che la chiamata a WaitForSingleObject nella thread procedure ritorni e quindi che il thread cominci ad essere eseguito. Quando l'utente seleziona il comando "stop thread", noi settiamo il valore della variabile globale "EventStop" a TRUE.
add eax,eax
dec ecx
.else
invoke MessageBox,hwnd,ADDR StopString,ADDR AppName,MB_OK
mov EventStop,FALSE
jmp ThreadProc
.endif
Cio' blocca il thread e salta di nuovo alla chiamata a WaitForSingleObject. Notate che non dobbiamo resettare manualmente l'event object in stato "non-segnalato", poiche' abbiamo specificato il parametro bManualReset della chiamata a CreateEvent come FALSE.
Disclaimer
I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.
Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.