Download the example here.
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.
.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
includelib
\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
HANDLE ?
.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
start
.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 doesn't run immediately 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
.endif
This
stops the thread and jumps to the WaitForSingleObject call again. Note
that we don't have to manually reset the event object into nonsignalled
state because we specify the bManualReset parameter of the CreateEvent
call as FALSE.