"A process is an executing application that consists of a private virtual address space, code, data, and other operating system resources, such as files, pipes, and synchronization objects that are visible to the process."As you can see from the definition above, a process "owns" several objects: the address space, the executing module(s), and anything that the executing modules create or open. At the minimum, a process must consist of an executing module, a private address space and a thread. Every process must have at least one thread. What's a thread? A thread is actually an execution queue. When Windows first creates a process, it creates only one thread per process. This thread usually starts execution from the first instruction in the module. If the process later needs more threads, it can explicitly create them.
CreateProcess
proto lpApplicationName:DWORD,\
lpCommandLine:DWORD,\
lpProcessAttributes:DWORD,\
lpThreadAttributes:DWORD,\
bInheritHandles:DWORD,\
dwCreationFlags:DWORD,\
lpEnvironment:DWORD,\
lpCurrentDirectory:DWORD,\
lpStartupInfo:DWORD,\
lpProcessInformation:DWORD
Don't be alarmed by the number of parameters. We can ignore most of them.
lpApplicationName
--> The name of the executable file with or without pathname that you want
to execute. If this parameter is null, you must provide the name of the
executable file in the lpCommandLine parameter.
lpCommandLine
--> The command line arguments to the program you want to execute. Note
that if the lpApplicationName is NULL, this parameter must contain the
name of the executable file too. Like this: "notepad.exe readme.txt"
lpProcessAttributes
and lpthreadAttributes --> Specify the security attributes for the process
and the primary thread. If they're NULLs, the default security attributes
are used.
bInheritHandles
--> A flag that specify if you want the new process to inherit all opened
handles from your process.
dwCreationFlags
--> Several flags that determine the behavior of the process you want to
created, such as, do you want to process to be created but immediately
suspended so that you can examine or modify it before it runs? You can
also specify the priority class of the thread(s) in the new process. This
priority class is used to determine the scheduling priority of the threads
within the process. Normally we use NORMAL_PRIORITY_CLASS flag.
lpEnvironment
--> A pointer to the environment block that contains several environment
strings for the new process. If this parameter is NULL, the new process
inherits the environment block from the parent process.
lpCurrentDirectory
--> A pointer to the string that specifies the current drive and directory
for the child process. NULL if you want the child process to inherit
from the parent process.
lpStartupInfo
--> Points to a STARTUPINFO structure that specifies how the main window
for the new process should appear. The STARTUPINFO structure contains many
members that specifies the appearance of the main window of the child process.
If you don't want anything special, you can fill the STARTUPINFO structure
with the values from the parent process by calling GetStartupInfo function.
lpProcessInformation
--> Points to a PROCESS_INFORMATION structure that receives identification
information about the new process. The PROCESS_INFORMATION structure
has the following members:
PROCESS_INFORMATION:Process handle and process ID are two different things. A process ID is a unique identifier for the process in the system. A process handle is a value returned by Windows for use with other process-related API functions. A process handle cannot be used to identify a process since it's not unique.
hProcess: ? ; handle to the child process
hThread! ? ; handle to the primary thread of the child process
dwProcessId: ? ; ID of the child process
dwThreadId: ? ; ID of the primary thread of the child process
After the CreateProcess call, a new process is created and the CreateProcess call return immediately. You can check if the new process is still active by calling GetExitCodeProcess function which has the following syntax:
GetExitCodeProcess proto hProcess:DWORD, lpExitCode:DWORD
If this call is successful, lpExitCode contains the termination status of the process in question. If the value in lpExitCode is equal to STILL_ACTIVE, then that process is still running.
You can forcibly terminate a process by calling TerminateProcess function. It has the following syntax:
TerminateProcess proto hProcess:DWORD, uExitCode:DWORD
You
can specify the desired exit code for the process, any value you like.
TerminateProcess is not a clean way to terminate a process since any dll
attached to the process will not be notified that the process was terminated.
;
Equates:
[M00_Menu
2000
M00_Process 2001
M00_Create_Process 2002
M00_Terminate_Process
2003 M00_Exit 2004]
_____________________________________________________________________________________
;
Data:
[WindowHandle:
0 ExitCode: 0 MenuHandle: 0
ClassName:
'Win32ASMProcessClass' 0 AppName: 'Win32 ASM Process 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 #10]
____________________________________________________________________________________________
____________________________________________________________________________________________
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
.ELSEIF D@Message = &WM_INITMENUPOPUP
call 'KERNEL32.GetExitCodeProcess' D§PI_hProcess ExitCode
..If eax = &TRUE
If D§ExitCode = &STILL_ACTIVE
call 'User32.EnableMenuItem' D§MenuHandle M00_Create_Process
&MF_GRAYED
call 'User32.EnableMenuItem' D§MenuHandle M00_Terminate_Process
&MF_ENABLED
Else
call 'User32.EnableMenuItem' D§MenuHandle M00_Create_Process
&MF_ENABLED
call 'User32.EnableMenuItem' D§MenuHandle M00_Terminate_Process
&MF_GRAYED
End_If
..Else
call 'User32.EnableMenuItem' D§MenuHandle M00_Create_Process
&MF_ENABLED
call 'User32.EnableMenuItem' D§MenuHandle M00_Terminate_Process
&MF_GRAYED
..End_If
.Else_If D@Message = &WM_COMMAND
mov eax D@wParam
..if D@lParam = 0
...If ax = M00_Create_Process
If D§PI_hProcess ne 0
call 'KERNEL32.CloseHandle' D§PI_hProcess | mov D§PI_hProcess
0
Endif
call 'KERNEL32.GetStartupInfoA' STARTUPINFO
call 'KERNEL32.CreateProcessA' ProgramName &NULL &NULL &NULL
&FALSE,
&NORMAL_PRIORITY_CLASS,
&NULL &NULL STARTUPINFO PROCESS_INFORMATION
call 'KERNEL32.CloseHandle' D§PI_hThread
...Else_If ax = M00_Terminate_Process
call 'KERNEL32.GetExitCodeProcess' D§PI_hProcess ExitCode
If D§ExitCode = &STILL_ACTIVE
call 'KERNEL32.TerminateProcess' D§PI_hProcess 0
Endif
call 'KERNEL32.CloseHandle' D§PI_hProcess
mov D§PI_hProcess 0
...Else
call 'User32.DestroyWindow' D@Adressee
...End_If
..endif
.Else
popad
call 'User32.DefWindowProcA' D@Adressee D@Message D@wParam D@lParam
Exit
.End_If
popad | mov eax &FALSE
EndP
.ELSEIF D@Message = &WM_INITMENUPOPUP
call 'KERNEL32.GetExitCodeProcess' D§PI_hProcess ExitCode
..If eax = &TRUE
If D§ExitCode = &STILL_ACTIVE
call 'User32.EnableMenuItem' D§MenuHandle M00_Create_Process
&MF_GRAYED
call 'User32.EnableMenuItem' D§MenuHandle M00_Terminate_Process
&MF_ENABLED
Else
call 'User32.EnableMenuItem' D§MenuHandle M00_Create_Process
&MF_ENABLED
call 'User32.EnableMenuItem' D§MenuHandle M00_Terminate_Process
&MF_GRAYED
End_If
..Else
call 'User32.EnableMenuItem' D§MenuHandle M00_Create_Process
&MF_ENABLED
call 'User32.EnableMenuItem' D§MenuHandle M00_Terminate_Process
&MF_GRAYED
..End_If
Why
do we want to process this message? Because we want to prepare the menu
items in the popup menu before the user can see them. In our example, if
the new process is not started yet, we want to enable the "start process"
and gray out the "terminate process" menu items. We do the reverse if the
new process is already active.
We
first check if the new process is still running by calling GetExitCodeProcess
function with the process handle that was filled in by CreateProcess function.
If GetExitCodeProcess returns FALSE, it means the process is not started
yet so we gray out the "terminate process" menu item. If GetExitCodeProcess
returns TRUE, we know that a new process has been started, but we have
to check further if it is still running. So we compare the value in ExitCode
to the value STILL_ACTIVE, if they're equal, the process is still
running: we must gray out the "start process" menu item since we don't
want to start several concurrent processes.
...If ax = M00_Create_Process
If D§PI_hProcess ne 0
call 'KERNEL32.CloseHandle' D§PI_hProcess | mov D§PI_hProcess
0
Endif
call 'KERNEL32.GetStartupInfoA' STARTUPINFO
call 'KERNEL32.CreateProcessA' ProgramName &NULL &NULL &NULL
&FALSE,
&NORMAL_PRIORITY_CLASS,
&NULL &NULL STARTUPINFO PROCESS_INFORMATION
call 'KERNEL32.CloseHandle' D§PI_hThread
When
the user selects "start process" menu item, we first check if hProcess
member of PROCESS_INFORMATION structure is already closed. If this is the
first time, the value of hProcess will always be zero since we define PROCESS_INFORMATION
structure in .data section. If the value of hProcess member is not 0, it
means the child process has exited but we haven't closed its process handle
yet. So this is the time to do it.
We
call GetStartupInfo function to fill in the startupinfo structure that
we will pass to CreateProcess function. After that we call CreateProcess
function to start the new process. Note that I haven't checked the return
value of CreateProcess because it will make the example more complex. In
real life, you should check the return value of CreateProcess. Immediately
after CreateProcess, we close the primary thread handle returned in processInfo
structure. Closing the handle doesn't mean we terminate the thread, only
that we don't want to use the handle to refer to the thread from our program.
If we don't close it, it will cause a resource leak.
...Else_If ax = M00_Terminate_Process
call 'KERNEL32.GetExitCodeProcess' D§PI_hProcess ExitCode
If D§ExitCode = &STILL_ACTIVE
call 'KERNEL32.TerminateProcess' D§PI_hProcess 0
Endif
call 'KERNEL32.CloseHandle' D§PI_hProcess
mov D§PI_hProcess 0
When
the user selects "terminate process" menu item, we check if the new process
is still active by calling GetExitCodeProcess function. If it's still active,
we call TerminateProcess function to kill the process. Also we close the
child process handle since we have no need for it anymore.