CreateThread
proto lpThreadAttributes:DWORD,\
dwStackSize:DWORD,\
lpStartAddress:DWORD,\
lpParameter:DWORD,\
dwCreationFlags:DWORD,\
lpThreadId:DWORD
CreateThread
function looks a lot like CreateProcess.
lpThreadAttributes
--> You can use NULL if you want the thread to have default security descriptor.
dwStackSize
--> specify the stack size of the thread.
If you want the thread to have the same stack size as the primary thread,
use NULL as this parameter.
lpStartAddress-->
Address of the thread function.It's the function that will perform the
work of the thread. This function MUST receive one and only one 32-bit
parameter and return a 32-bit value.
lpParameter
--> The parameter you want to pass to the thread function.
dwCreationFlags
--> 0 means the thread runs immediately after it's created. The opposite
is CREATE_SUSPENDED flag.
lpThreadId
--> CreateThread function will fill the thread
ID of the newly created thread at this address.
If
CreateThread call is sucessful, it returns the handle of the newly created
thread. Otherwise, it returns NULL.
The
thread function runs as soon as CreateThread call is success ful unless
you specify CREATE_SUSPENDED flag in dwCreationFlags. In that case, the
thread is suspended until ResumeThread function is called.
When
the thread function returns with ret instruction, Windows calls ExitThread
function for the thread function implicitly. You can call ExitThread function
with in your thread function yourself but there' s little point in doing
so.
You
can retrieve the exit code of a thread by calling GetExitCodeThread function.
If
you want to terminate a thread from other thread, you can call TerminateThread
function. But you should use this function under extreme circumstance since
this function terminates the thread immediately without giving the thread
any chance to clean up after itself.
Now
let's move to the communication methods between threads.
There
are three of them:
[WM_MYCUSTOMMSG &WM_USER+0100]
Windows
will not use any value from WM_USER upward for its own messages so you
can use the value WM_USER and above as your own custom message value.
If
one of the thread is a user interface thread and the other is a worker
one, you cannot use this method as two-way communication since a worker
thread doesn't have its own window so it doesn't have a message queue.
You can use the following scheme:
User interface Thread ------> global variable(s)----> Worker thread
Worker Thread ------> custom window message(s) ----> User interface
Thread
In
fact, we will use this method in our example.
The
last communication method is an event object. You can view an event object
as a kind of flag. If the event object is in "unsignalled" state, the thread
is dormant or sleeping, in this state, the thread doesn't receive CPU time
slice. When the event object is in "signalled" state,Windows "wakes up"
the thread and it starts performing the assigned task.
___________________________________________________________________________________
;
Equates:
[M00_Menu
2000
M00_Process 2001
M00_Create_Thread 2002
M00_Exit
2003]
[WM_FINISH 0500] ; [&WM_USER+0100] not possible actually (&WM_USER = 0400)
_____________________________________________________________________________________
;
Data:
[WindowHandle:
0 ExitCode: 0 MenuHandle: 0 ThreadID: 0
ClassName:
'Win32ASMThreadClass' 0 AppName: 'Win32 ASM MultiThreading
Example' 0
programname:
'msgbox.exe' 0]
[PROCESS_INFORMATION:
PI_hProcess: 0 PI_hThread: 0
PI_dwProcessId: 0 PI_dwThreadId: 0]
[STARTUPINFO:
SI_cb: 0
SI_lpReserved: 0 SI_lpDesktop: 0
SI_lpTitle: 0 SI_dwX: 0
SI_dwY: 0
SI_dwXSize: 0 SI_dwYSize:
0 SI_dwXCountChars:
0
SI_dwYCountChars: 0 SI_dwFillAttribute: 0 SI_dwFlags:
0
SI_wShowWindow: W§ 0 SI_cbReserved2: W§ 0 SI_lpReserved2:
D§ 0
SI_hStdInput: 0 SI_hStdOutput: 0
SI_hStdError: 0]
______________________________________________________________________________________
; Window Class Structure:
[WindowClassEx:
wc_Size: len wc_style:
&CS_HREDRAW+&CS_VREDRAW WndProc: MainWindowProc
wc_ClsExtra: 0 wc_WndExtra: 0
hInstance: 0
wc_hIcon: 0
wc_hCursor: 0
wc_hbrBackground: 6
wc_MenuName: M00_Menu wc_ClassName: ClassName
wc_hIconSm: 0]
[FirstMessage: 0 #7]
____________________________________________________________________________________________
____________________________________________________________________________________________
Main:
call 'Kernel32.GetModuleHandleA' &NULL | mov D§hInstance
eax
call 'User32.LoadIconA' 0 &IDI_WINLOGO | mov D§wc_hIcon
eax D§wc_hIconSm eax
call 'User32.LoadCursorA' 0 &IDC_ARROW | mov D§wc_hCursor
eax
call 'User32.RegisterClassExA' WindowClassEX
call 'User32.CreateWindowExA' &NULL ClassName AppName,
&WS_OVERLAPPEDWINDOW,
&CW_USEDEFAULT &CW_USEDEFAULT 300 200,
&NULL &NULL D§hInstance &NULL
mov D§WindowHandle eax
call 'User32.ShowWindow' D§WindowHandle &SW_SHOWNORMAL
call 'User32.UpdateWindow' D§WindowHandle
call 'User32.GetMenu' D§WindowHandle
mov D§MenuHandle eax
L1:
call 'User32.GetMessageA' FirstMessage 0 0 0 | cmp eax 0 | je L9>
call 'User32.TranslateMessage' FirstMessage
call 'User32.DispatchMessageA' FirstMessage
jmp L1<
L9:
call 'Kernel32.ExitProcess' 0
__________________________________________________________________________________
Proc
MainWindowProc:
Arguments @Adressee, @Message, @wParam, @lParam
pushad
.If D@Message = &WM_DESTROY
call 'User32.PostQuitMessage' &NULL
.Else_If D@Message = &WM_COMMAND
mov eax D@wParam
..If D@lParam = 0
...If ax = M00_Create_Thread
call 'Kernel32.CreateThread' &NULL &NULL ThreadProc,
&NULL &NORMAL_PRIORITY_CLASS,
ThreadID
call 'Kernel32.CloseHandle' eax
...Else
call 'User32.DestroyWindow' D@Adressee
...End_If
..End_If
.Else_If D@Message = WM_FINISH
call 'User32.MessageBoxA' &NULL AppName AppName &MB_OK
.Else
popad
call 'User32.DefWindowProcA' D@Adressee D@Message D@wParam D@lParam
Exit
.End_If
popad | mov eax &FALSE
EndP
ThreadProc:
mov ecx 300000000
L1:
add eax eax | dec ecx | jnz L1<
call 'User32.SendMessageA' D§WindowHandle WM_FINISH &NULL &NULL
ret
...If ax = M00_Create_Thread
call 'Kernel32.CreateThread' &NULL &NULL ThreadProc,
&NULL &NORMAL_PRIORITY_CLASS,
ThreadID
call 'Kernel32.CloseHandle' eax
The
above function creates a thread that will run a procedure named ThreadProc
concurrently with the primary thread. After the successful call, CreateThread
returns immediately and ThreadProc begins to run. Since we do not use thread
handle, we should close it else there'll be some leakage of memory. Note
that closing the thread handle doesn't terminate the thread. Its only effect
is that we cannot use the thread handle anymore.
ThreadProc:
mov ecx 300000000
L1:
add eax eax | dec ecx | jnz L1<
call 'User32.SendMessageA' D§WindowHandle WM_FINISH &NULL &NULL
ret
As you can see, ThreadProc performs a savage calculation which takes quite a while to finish and when it finishs it posts a WM_FINISH message to the main window. WM_FINISH is our custom message defined like this: