TUTORIAL 16: Event Object
We will Learn What An Event Object Is And How To Use IT I Multithreaded Program.
Download The Example Here.
Theory: From the previous tutorial, I demonstrated how threads communicate with a custom window message I left out two other methods:.. Global variable and event object We will use both of them in this tutorial.
An event object is like a switch: it has only two states:. On or off When an event object is turned on, it's in the "signalled" state When it is turned off, it's in the "nonsignalled" state You create.. an event object and put in a code snippet in the relevant threads to watch for the state of the event object. If the event object is in the nonsignalled state, the threads that wait for it will be asleep.When the threads are in wait state . They consume Little CPU Time.
You create An Event Object by Calling CreateEvent Function Which Has The Following Syntax:
CreateEvent Proto Lpeventattributes: DWORD, / BMANUALRESET: DWORD, / BINITIALSTATE: DWORD, / LPNAME: DWORD
lpEventAttribute -> If you specify NULL value, the event object is created with default security descriptor bManualReset -.> If you want Windows to automatically reset the event object to nonsignalled state after WaitForSingleObject call, you must specify FALSE as this parameter Else. you must manually reset the event object with the call to ResetEvent bInitialState -.> If you want the event object to be created in the signalled state, specify TRUE as this parameter else the event object will be created in the nonsignalled state lpName. - -> Pointer to an ASCIIZ string that is the name of the event object This name is used when you want to call OpenEvent.If the call is successful, it returns the handle to the newly created event object else it returns NULL you can.. modify the state of an event object with two API calls:... SetEvent and ResetEvent SetEvent function sets the event object into signalled state ResetEvent does the reverse When the event object is created, you must put THE CALL TO WAITFORSINGLEOBJECT in The Thread That Wants To Watch for the State of The Event Object. WaitforsingleObject Has The Following Syntax:
WaitforsingleObject Proto Hobject: DWORD, DWTIMEOUT: DWORD
hObject -.> A handle to one of the synchronization object Event object is a type of synchronization object dwTimeout -..> specify the time in milliseconds that this function will wait for the object to be in signalled state If the specified time has PaSSED and The Event Object Is Still in Nonsignalled State, WaitforsingleObject Returns The The Caller. If You Want To Wait For the Object Indefinitely, You Must Specify The Value Infinite as this parameter.
Example: The example below displays a window waiting for the user to select a command from the menu If the user selects "run thread", the thread starts the savage calculation When it's finished, a message box appears informing the user that the job.. is done During the time that the thread is running, the user can select "stop thread" to stop the thread..386 .model flat, stdcall option casemap:. none WinMain proto: DWORD,: DWORD,: DWORD,: DWORD include /masm32/include/windows.inc include /masm32/include/user32.inc include /masm32/include/kernel32.inc includelib /masm32/lib/user32.lib includeelib /masm32/lib/kernel32.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 EventStop BOOL FALSE
.DATA? Hinstance Hinstance? CommandLine LPSTR? HWND HANDLE? HMENU HANDLE? Threadid DWORD? EXITCODE DWORD? HEVENTSTART HANDE?
. Code Start: Invoke GetModuleHandle, Null Mov Hinstance, Eax Invoke Getcommandline Mov Commandline, Eax Invoke Winmain, Hinstance, Null, CommandLine, SW_SHOWDEFAULT INVOKE EXITPROCESS, EAX
WinMain proc hInst: HINSTANCE, hPrevInst: HINSTANCE, CmdLine: LPSTR, CmdShow: DWORD 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 hInst 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, eax 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 .IF uMsg == WM_CREATE invoke CreateEvent, NULL, FALSE, FALSE, NULL mov hEventStart, eax mov eax, OFFSET ThreadProc invoke CreateThread, NULL, NULL, eax , / NULL, 0, / ADDR ThreadID invoke CloseHandle, eax .ELSEIF uMsg == WM_DESTROY invoke PostQuitMessage, NULL .ELSEIF uMsg == 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 uMsg == 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 startAnalysis: In this example, I demonstrate another Thread Technique.
.IF uMsg == WM_CREATE invoke CreateEvent, NULL, FALSE, FALSE, NULL mov hEventStart, eax mov eax, OFFSET ThreadProc invoke CreateThread, NULL, NULL, eax, / NULL, 0, / ADDR ThreadID invoke CloseHandle, eax
You can see that I create the event object and the thread during the processing of WM_CREATE message. I create the event object in the nonsignalled state with automatic reset. After the event object is created, I create the thread. However the thread does not Run Immedierately Because It Waits for the Event Object To BE in The Signalled State As The Code Below:
ThreadProc Proc Uses ECX Param: DWORD INVOKE WAITFORSINGLEOBJECT, HEVENTSTART, INFINITE MOV ECX, 600000000
The first line of the thread procedure is the call to WaitForSingleObject. It waits infinitely for the signalled state of the event object before it returns. This means that even when the thread is created, we put it into a dormant state. When the user selects "Run Thread" Command from The Menu, We set the Event Object INTO SIGNALLED State As Below: .if AX == idm_start_thread invoke setevent, HEVENTSTART
The call to SetEvent turns the event object into the signalled state which in turn makes the WaitForSingleObject call in the thread procedure return and the thread starts running. When the user selects "stop thread" command, we set the value of the global variable "EventStop "to true.
. IF EventStop == False Add Eax, EAX DEC ECX .ELSE INVOKE Messagebox, Hwnd, Addr Stopstring, Addr Appname, MB_OK MOV EventStop, False Jmp ThreadProc .endproc.
This stops the thread and jumps to the WaitForSingleObject call again. Note that we do not have to manually reset the event object into nonsignalled state because we specify the bManualReset parameter of the CreateEvent call as FALSE.