Download the example here.
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, //
address of security attributes
BOOL bManualReset,
// flag for manual-reset event
BOOL bInitialState,
// flag for initial state
LPCTSTR lpName
// address of event-object name
);
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:
DWORD WaitForSingleObject(
HANDLE hObject,
// handle of object to wait for
DWORD dwTimeout
// time-out interval in milliseconds
);
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.
include windows.inc
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
.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
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 indefinitely 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.