Bajar el ejemplo aquí.
En el tutorial anterior, demostré como se comunican los hilos usando un mensaje de ventana custom. I left out otros dos métodos: variable global y objeto evento. Usaremos los dos en este tutorial.
Un objeto evento es como un conmutador [switch]: tiene dos estados: activado [on] o inactivado [off]. Cuando un objeto es activado [turned on], está en estado "señalado". Cuando es desactivado [turned off], está en estado "no-señalado". Creas un evento y pones en un recorte de código en los hilos releventes para ver el estado del objeto evento. Si el objeto evento está en el estado no señalado, los hilos que esperan serán puestos a dormir [asleep]. Cuando los hilos están en estado de espera, consumen algo de tiempo del CPU.
Creas un objeto evento llamando a la función CreateEvent que tiene la siguiente sintaxis:
CreateEvent
proto lpEventAttributes:DWORD,\
bManualReset:DWORD,\
bInitialState:DWORD,\
lpName:DWORD
lpEventAttribute-->
Si especificas un valor NULL, el objeto evento es creado con el descriptor de
seguridad por defecto.
bManualReset-->
Si quieres que Windows automáticamente restablezca el objeto evento a
estado no señalado después de llamara WaitForSingleObject, debes
especificar FALSE en este parámetro. Sino debes restablecer manualmente
el objeto evento con la llamada a ResetEvent.
bInitialState-->
Si quieres que el objeto evento sea creado en el estado señalado, especifica
TRUE como este parámetro sino el objeto evento será creado en
estado no señalado.
lpName
--> Puntero a una cadena ASCIIZ que es el nombre
de un objeto evento. Este nombre es usado cuando quieres llamar a OpenEvent.
Si la llamada tiene éxito, regresa el manejador al objeto evento creado sino regresa NULL.
Puedes modificar
el estado de un objeto evento con dos llamadas a la API: SetEvent y ResetEvent.
La función SetEvent pone el objeto evento en estado señalado.
ResetEvent lo pone en el estado inverso.
Cuando se crea
un objeto, debes poner la llamada a WaitForSingleObject en el hilo que espera
por el estado de un objeto evento. WaitForSingleObject tiene la siguiente sintaxis:
WaitForSingleObject proto hObject:DWORD, dwTimeout:DWORD
hObject
--> Un manejador a uno de los objetos de sincronización. El objeto evento
es uno de los objetos de sincronización.
dwTimeout
--> especificar el tiempo en milisegundos que
esta función esperará para ser el objeto señalado. Si el
tiempo especificado ha pasado y el evento objeto todavía no está
en estado señalado, WaitForSingleObject regresa a la instrucción
que le llamó. Si quieres esperar por el objeto indefinidamente, debes
especificar el valor INFINITE como valor de este parámetro.
.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
Puedes ver que creo un objeto evento durante el proceso del mensaje WM_CREATE. Creo el objeto evento en estado no señalado con restableci iento automático. Después de que es creado el objeto evento, creo el hilo. Sin embargo, el hilo no corre de inmediato, porque espera que el objeto evento esté en el estado señalado según el código siguiente:
ThreadProc
PROC USES ecx Param:DWORD
invoke WaitForSingleObject,hEventStart,INFINITE
mov ecx,600000000
La primera linea del procedimiento de hilo es la llamada a WaitForSingleObject. Espera infinitamente por el estado señalado del objeto evento antes de que retorne. Esto significa que incluso cuando el hilo es creado, lo ponemos en estado durmiente.
Cuando el usuario selecciona la orden "run thread" del menú, ponemos el evento en estado señalado siguiendo este código:
.if ax==IDM_START_THREAD
invoke SetEvent,hEventStart
La llamada a SetEvent pone el evento en estado señalado lo cual hace que la llamada a WaitForSingleObject en el procedimiento de hilo regrese y el hilo comience a correr. Cuando el usuario selecciona la orden [command] "stop thread", ponemos el valor de la variable global "EventStop" en 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
Esto detiene
el hilo y salta de nuevo a la llamada a WaitForSingleObject. Nota que no tienes
que restablecer manualmente el objeto evento en estado no señalado porque
especificamos el parámetro bManualReset de la llamada a CreateEvent como
FALSE.
[Iczelion's Win32 Assembly HomePage]
n u M I T_o r's Programming Page
Este tutorial, original de Iczelion, ha sido traducido por: n u M I T_o r