Bajar el ejemplo aquí.
"Un proceso es una aplicación en ejecución que consiste en un espacio de direcciones privado, código, datos, y otros recursos del sistema operativo, tales como archivos, tuberías, y objetos de sincronización que son visibles al proceso."
Cómo puedes ver, un proceso "se apropia" de algunos objetos: el espacio de direcciones, el módulo ejecutante o los módulos, y cualquier cosa que el módulo ejecutante pueda crear o abrir. Al menos, un proceso debe consistir en un módulo ejecutable, un espacio de direcciones privado y un hilo. Todo proceso debe tener por lo menos un hilo.
¿Qué es un hilo? Un hilo es realmente una cola o flujo de ejecución. Cuando Windows crea un proceso, crea sólo un hilo para el proceso. Este hilo generalmente inicia la ejecución desde la primera instrucción en el módulo. Si el proceso luego necesita más hilos, puede crearlos explícitamente.
Cuando Windows recibe la orden de crear un proceso, crea un espacio de direcciones privado para el proceso y luego proyecta el archivo ejecutable en la memoria de ese proceso. Después de eso crea el hilo primario del proceso.
Bajo Win32, puedes crear procesos desde tus programas llamando a la función CreateProcess. CreateProcess tiene la siguiente sintaxis:
CreateProcess
proto lpApplicationName:DWORD,\
lpCommandLine:DWORD,\
lpProcessAttributes:DWORD,\
lpThreadAttributes:DWORD,\
bInheritHandles:DWORD,\
dwCreationFlags:DWORD,\
lpEnvironment:DWORD,\
lpCurrentDirectory:DWORD,\
lpStartupInfo:DWORD,\
lpProcessInformation:DWORD
No te alarmes por el número de parámetros. Podemos ignorar muchos de ellos.
lpApplicationName --> El nombre del archivo ejecutable, con o sin ubicación, que quieres ejecutar. Si este parámetro es nulo, debes proveer el nombre del archivo ejecutable en el parámetro lpCommandLine
lpCommandLine --> Los argumentos en la línea de órdenes del programa que quieres ejecutar. Nota que si lpApplicationName es NULL, este parámetro debe contener también el nombre del archivo ejecutable. Como este: "notepad.exe readme.txt"
lpProcessAttributes ylpthreadAttributes --> Especifican los atributos de seguridad para el proceso y el hilo primario. Si son NULLs, son usados los atributos de seguridad por defecto.
bInheritHandles --> Una bandera que especifica si quieres que el nuevo proceso herede todos los manejadores abiertos de tu proceso.
dwCreationFlags --> Algunas banderas que determinan la conducta del proceso que quieres crear, tales como, ¿quieres que el proceso sea cerrado pero inmediatamente suspendido para que puedas examinarlo o modificarlo antes de que corra? También puedes indicar la clase de prioridad del(os ) hilo(s) en el nuevo proceso. Esta clase de prioridad es usada para determinar el plan de prioridades de los hilos dentro del proceso. Normalmente usamos la bandera NORMAL_PRIORITY_CLASS.
lpEnvironment --> Puntero a un bloque del entorno que contiene algunas cadenas del entorno para el nuevo proceso. Si este parámetro es NULL, el nuevo proceso hereda el bloque de entorno del proceso padre.
lpCurrentDirectory --> Puntero que especifica el volumen o disco duro y el directorio para el proceso hijo. NULL si quieres que el proceso hijo herede el del padre.
lpStartupInfo --> Apunta a una estructura STARTUPINFO que especifica como la ventana principal del nuevo proceso debería aparecer. la estructura STARTUPINFO contienen muchos miembros que especifican la apariencia de la ventana principal del proceso hijo. Si no quieres nada especial, puedes llenar la estructura STARTUPINFO con los valores del proceso padre llamando a la función GetStartupInfo.
lpProcessInformation --> Apunta a la estructura PROCESS_INFORMATION que recibe información sobre la identificación del nuevo proceso. La estructura PROCESS_INFORMATION tiene los siguientes miembros:
PROCESS_INFORMATION
STRUCT
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
El manejador del proceso y su ID son dos cosas diferentes. Un ID de proceso es un identificador único para el proceso en el sistema. Un manejador de proceso es un valor que regresa Windows para usar en otras funciones API relacionadas con el proceso. Un manejador de proceso no puede ser usado para identificar un proceso, ya que no es único.
Después de llamar a CreateProcess, se crea un nuevo proceso y la llamada a CreateProcess regresa de inmediato. Puedes chequear si el nuevo proceso todavía está activo llamando a la función GetExitCodeProcess que tiene la siguiente sintaxis:
GetExitCodeProcess proto hProcess:DWORD, lpExitCode:DWORD
Si esta llamada tiene éxito, lpExitCode contiene el status de terminación del proceso en cuestión. Si el valor en lpExitCode es igual a STILL_ACTIVE, entonces ese proceso todavía está corriendo.
Puedes forzar la terminación de un proceso llamando a la función TerminateProcess. Tiene la siguiente sintaxis:
TerminateProcess proto hProcess:DWORD, uExitCode:DWORD
Puedes especificar
el código de salida que desees para el proceso, cualquier valor que te
guste. TerminateProcess no es una manera limpia de terminar un proceso ya que
ninguna dll enganchada al proceso será notificada que el proceso ha terminado.
.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_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 ? ; contiene el estatus del código de salida de la
llamada a
;
GetExitCodeProcessl.
.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
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 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
LOCAL startInfo:STARTUPINFO
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==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 uMsg==WM_COMMAND
mov eax,wParam
.if lParam==0
.if ax==IDM_CREATE_PROCESS
.if processInfo.hProcess!=0
invoke CloseHandle,processInfo.hProcess
mov processInfo.hProcess,0
.endif
invoke GetStartupInfo,ADDR startInfo
invoke CreateProcess,ADDR programname,NULL,NULL,NULL,FALSE,\
NORMAL_PRIORITY_CLASS,\
NULL,NULL,ADDR startInfo,ADDR processInfo
invoke CloseHandle,processInfo.hThread
.elseif ax==IDM_TERMINATE
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if ExitCode==STILL_ACTIVE
invoke TerminateProcess,processInfo.hProcess,0
.endif
invoke CloseHandle,processInfo.hProcess
mov processInfo.hProcess,0
.else
invoke DestroyWindow,hWnd
.endif
.endif
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc
endp
end
start
.ELSEIF uMsg==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
¿Por qué queremos procesar este mensaje? porque queremos preparar los elementos en el menú emergente antes de que el usuario pueda verlos. En nuestro ejemplo, si el nuevo proceso aún no ha comenzado, queremos habilitar el elemento "start process" y difuminar [gray out] el elemento "terminate process". Hacemos la inversión si el nuevo proceso ya está activo.
Primero chequeamos si el nuevo proceso todavía está activo llamando a la función GetExitCodeProcess con el manejador de proceso llenado por la función CreateProcess. Si GetExitCodeProcess regresa FALSE, significa que el proceso no ha comenzado todavía así que difuminamos el elemento de menú "terminate process". Si GetExitCodeProcess regresa TRUE, sabemos que ha sido iniciado un nuevo proceso, pero tenemos que chequear luego si todavía está corriendo. Así que comparamos el valor en ExitCode al valor STILL_ACTIVE, si son iguales, el proceso todavía está corriendo: debemos difuminar el elemento de menú "start process" ya que no queremos iniciar varios procesos concurrentes.
.if ax==IDM_CREATE_PROCESS
.if processInfo.hProcess!=0
invoke CloseHandle,processInfo.hProcess
mov processInfo.hProcess,0
.endif
invoke GetStartupInfo,ADDR startInfo
invoke CreateProcess,ADDR programname,NULL,NULL,NULL,FALSE,\
NORMAL_PRIORITY_CLASS,\
NULL,NULL,ADDR startInfo,ADDR processInfo
invoke CloseHandle,processInfo.hThread
Cuando el usuario
selecciona el elemento de menú "start process", primero chequeamos si
el miembro hProcess de la estrcutura PROCESS_INFORMATION ya está cerrado.
Si es la primera vez, el valor de hProcess siempre será cero ya que definimos
la estructura PROCESS_INFORMATION en la sección .data. Si el valor del
miembro hProcess no es 0, significa que el proceso hijo ha terminado pero no
hemos cerrado su manejador de proceso todavía. Así que este es
el momento de hacerlo.
Si llamamos a la función GetStartupInfo llenaremos la estructura startupinfo que pasaremos a la función CreateProcess. Después de que llamamos a la función CreateProcess para comenzar el nuevo proceso. Nota que no hemos chequeado el valor regersado por CreateProcess ya que haría más complejo el ejemplo. En la vida real, deberías chequear el valor regresado por CreateProcess. Inmediatamente después de CreateProcess, cerramos el manejador de hilo primario regresado en la estructura processInfo. Cerrar el manejador no significa que hemos terminado el hilo, sólo siginifica que no queremos usar el manejador para referirse al hilo de nuestro programa. Si no lo cerramos, causará carencia de recursos.
.elseif ax==IDM_TERMINATE
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if ExitCode==STILL_ACTIVE
invoke TerminateProcess,processInfo.hProcess,0
.endif
invoke CloseHandle,processInfo.hProcess
mov processInfo.hProcess,0
Cuando el
usuario selecciona el elemento de menú "terminate process", chequeamos
si el nuevo proceso ya está activo llamando a la función GetExitCodeProcess.
Si todavía está activo, llamamos la función TerminateProcess
para matar el proceso. También cerramos el manejador del proceso hijo
ya que no lo necesitamos más.
[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