Download the example here.
"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.
BOOL CreateProcess(
LPCTSTR lpApplicationName,
// pointer to name of executable module
LPTSTR lpCommandLine,
// pointer to command line string
LPSECURITY_ATTRIBUTES lpProcessAttributes,
// pointer to process security attributes
LPSECURITY_ATTRIBUTES lpThreadAttributes,
// pointer to thread security attributes
BOOL bInheritHandles,
// handle inheritance flag
DWORD dwCreationFlags,
// creation flags
LPVOID lpEnvironment,
// pointer to new environment block
LPCTSTR lpCurrentDirectory,
// pointer to current directory name
LPSTARTUPINFO lpStartupInfo,
// pointer to STARTUPINFO
LPPROCESS_INFORMATION lpProcessInformation
// pointer to PROCESS_INFORMATION
);
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 CREATE_NEW_CONSOLE and NORMAL_PRIORITY_CLASS flags.
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 STRUCTProcess 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 ? ; handle to the child process
hThread HANDLE ? ; handle to the primary thread of the child process
dwProcessId DWORD ? ; ID of the child process
dwThreadId DWORD ? ; ID of the primary thread of the child process
PROCESS_INFORMATION ENDS
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:
BOOL GetExitCodeProcess(
HANDLE hProcess,
// handle to the process
LPDWORD lpExitCode //
address to receive termination status
);
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:
BOOL TerminateProcess(
HANDLE hProcess,
// handle to the process
UINT uExitCode
// exit code for the process
);
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.
include windows.inc
includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
.const
IDM_CREATE_PROCESS equ 1
IDM_TERMINATE equ 2
IDM_EXIT equ 3
.data
ClassName db "Win32ASMProcessClass",0
AppName db "Win32 ASM Process Example",0
MenuName db "FirstMenu",0
processInfo PROCESS_INFORMATION <>
programname db "msgbox.exe",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hMenu HANDLE ?
ExitCode DWORD ?
; contains the process exitcode status from GetExitCodeProcess call.
.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
LOCAL hwnd:HWND
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
LOCAL startInfo:STARTUPINFO
mov eax,uMsg
.IF eax==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF eax==WM_INITMENUPOPUP
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if eax==TRUE
.if ExitCode==STILL_ACTIVE
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_GRAYED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
.ELSEIF eax==WM_COMMAND
mov eax,wParam
.if lParam==0
.if ax==IDM_CREATE_PROCESS
invoke GetStartupInfo,ADDR startInfo
invoke CreateProcess,ADDR programname,NULL,NULL,NULL,FALSE,\
NORMAL_PRIORITY_CLASS,\
NULL,NULL,ADDR startInfo,ADDR processInfo
.elseif ax==IDM_TERMINATE
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if ExitCode==STILL_ACTIVE
invoke TerminateProcess,processInfo.hProcess,0
.endif
.else
invoke DestroyWindow,hWnd
.endif
.endif
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
.ELSEIF eax==WM_INITMENUPOPUP
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if eax==TRUE
.if ExitCode==STILL_ACTIVE
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_GRAYED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
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==IDM_CREATE_PROCESS
invoke GetStartupInfo,ADDR startInfo
invoke CreateProcess,ADDR programname,NULL,NULL,NULL,FALSE,\
NORMAL_PRIORITY_CLASS,\
NULL,NULL,ADDR startInfo,ADDR processInfo
When the user selects "start process" menu item, 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.
.elseif ax==IDM_TERMINATE
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if ExitCode==STILL_ACTIVE
invoke TerminateProcess,processInfo.hProcess,0
.endif
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.