WIN32汇编语言教程:第13章 进程控制 · 13.2 执行可执行文件(3)
invoke RtlZeroMemory,addr @stOF,sizeof @stOF
mov @stOF.lStructSize,sizeof @stOF
push hWinMain
pop @stOF.hwndOwner
mov @stOF.lpstrFilter,offset szFileExt
mov @stOF.lpstrFile,offset szFileName
mov @stOF.nMaxFile,MAX_PATH
mov @stOF.Flags,OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST
invoke GetOpenFileName,addr @stOF
.if eax
invoke SetDlgItemText,hWnd,IDC_FILE,addr szFileName
.endif
;********************************************************************
.elseif ax == IDC_FILE
invoke GetWindowTextLength,lParam
mov ebx,eax
invoke GetDlgItem,hWnd,IDOK
invoke EnableWindow,eax,ebx
.endif
;********************************************************************
.elseif eax == WM_CLOSE
invoke EndDialog,hWnd,NULL
;********************************************************************
.elseif eax == WM_INITDIALOG
push hWnd
pop hWinMain
invoke SendDlgItemMessage,hWnd,IDC_FILE,\
EM_LIMITTEXT,MAX_PATH,0
invoke SendDlgItemMessage,hWnd,IDC_CMDLINE,\
EM_LIMITTEXT,MAX_PATH,0
;********************************************************************
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
_ProcDlgMain endp
;####################################################################
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,eax,DLG_MAIN,NULL,\
offset _ProcDlgMain,NULL
invoke ExitProcess,NULL
;####################################################################
end start
当按下“浏览”按钮(IDC_BROWSE)的时候,程序在WM_COMMAND消息中显示一个“打开文件”通用对话框并让用户选择可执行文件。
当按下IDOK按钮的时候,如果有进程在执行中(hProcess不为0),表示现在按下的是“终止”按钮,这时程序调用TerminateProcess函数强制结束进程;如果没有进程在执行,表示按下的是“执行”按钮,程序创建一个新线程_ProcExec子程序,在这个子程序中完成创建新进程和等待它结束的工作。
函数CreateProcess在子进程创建以后是马上返回的,但是程序需要等待子进程结束,为了在等待的过程中主线程还能够处理对话框消息,所以程序在这里使用一个新的线程来完成创建和等待子进程的工作。
在线程函数_ProcExec中,程序灰化“文件名”输入框、“命令行”输入框和“浏览”按钮,并将文件名和命令行参数获取到缓冲区szFileName和szCmdLine中,接下来调用CreateProcess函数创建进程。
1. 创建进程
创建进程需要为新进程窗口的外观指定一些属性,就像使用Shell调用方式执行文件时的dwCmdShow参数一样,这些属性通过一个STARTUPINFO结构来指定:
STARTUPINFO STRUCT
cb DWORD ? ;结构的长度
lpReserved DWORD ? ;保留字段
lpDesktop DWORD ? ;NT下使用,指定桌面名称
lpTitle DWORD ? ;控制台程序使用,指定控制台窗口标题
dwX DWORD ? ;当新进程使用CW_USEDEFAULT参数创建
dwY DWORD ? ;窗口的时候将使用这些位置和大小属性
dwXSize DWORD ?
dwYSize DWORD ?
dwXCountChars DWORD ? ;控制台程序使用,指定控制台窗口行数
dwYCountChars DWORD ?
dwFillAttribute DWORD ? ;控制台程序使用,指定控制台窗口背景色
dwFlags DWORD ? ;标志
wShowWindow WORD ? ;窗口的显示方式
cbReserved2 WORD ?
lpReserved2 DWORD ?
hStdInput DWORD ? ;控制台程序使用:几个标准句柄
hStdOutput DWORD ?
hStdError DWORD ?
STARTUPINFO ENDS
在需要定制新进程的窗口的时候,才需要手工填写STARTUPINFO结构(比如需要将控制台程序的输入和输出重新定位时,可以改写hStdInput和hStdOutput字段),在大部分情况下,并不需要新进程的窗口有什么特殊之处,这时只要使用GetStartupInfo获取当前进程的STARTUPINFO并使用它的默认值就可以了:
.data?
stStartUp STARTUPINFO <?>
.code
invoke GetStartupInfo,addr stStartUp
获取STARTUPINFO结构以后,就可以把它用在创建进程的函数CreateProcess中:
invoke CreateProcess,lpApplicationName,lpCommandLine,\
lpProcessAttributes,lpThreadAttributes,bInheritHandles,\
dwCreationFlags,lpEnvironment,lpCurrentDirectory,\
lpStartupInfo,lpProcessInformation
函数的各个参数定义如下。
● lpApplicationName——指向一个以0结尾的字符串,用来指定可执行文件名,如果这个参数指定为NULL,那么文件名可以在lpCommandLine参数指定的命令行参数中包括。
● lpCommandLine—指向一个以0结尾的字符串,用来指定命令行参数,如果lpApplicationName参数为NULL,那么命令行字符串的第一个组成部分用来指定可执行文件名;如果两个参数都不为空,那么lpApplicationName用做文件名,lpCommandLine用做命令行参数。
● lpProcessAttributes——指向一个SECURITY_ATTRIBUTES结构,用来指定新进程的安全属性,如果进程句柄不需要被其他子进程继承,可以在这里使用NULL。
● lpThreadAttributes——指向一个SECURITY_ATTRIBUTES结构,用来指定新进程的安全属性,如果进程句柄不需要被其他线程继承,可以在这里使用NULL。
● bInheritHandles——指定当前进程的句柄是否可以被新进程继承,如果指定TRUE,那么可以继承,一般在这里使用FALSE。
● dwCreationFlags——创建标志,指定新进程的优先级以及其他标志,这个参数类似于CreateThread函数中的同名参数,它可以是一些标志的组合,下面列出了一些常用的标志:
■ CREATE_NEW_CONSOLE——如果新进程是控制台程序,那么为它新建一个控制台窗口,而不是使用父进程的控制台窗口。
■ CREATE_SUSPENDED—新建进程的主线程一开始处于挂起状态,需要以后用 ResumeThread函数来恢复它的执行。
■ DEBUG_PROCESS和DEBUG_ONLY_THIS_PROCESS——调试进程,相关内容在13.3一节的进程调试中会有详细介绍,如果同时指定DEBUG_ONLY_THIS_PROCESS标志,那么被调试的进程仅是被创建的子进程,否则子进程创建的“孙进程”也在被调试之列。
■ HIGH_PRIORITY_CLASS,IDLE_PRIORITY_CLASS,NORMAL_PRIORITY_CLASS和REALTIME_PRIORITY_CLASS——用来指定新进程的优先级。
● lpEnvironment——指向新进程的环境变量块,如果这个参数指定为NULL,表示让Windows拷贝当前进程的环境块当做子进程的环境块,如果程序需要将修改过的环境块传递给子进程,可以设置这个参数。
● lpCurrentDirectory——指向一个路径字符串,用来指定子进程的当前驱动器和当前目录,如果指定为NULL,子进程将引用父进程的当前路径。
● lpStartupInfo——指向前面介绍的STARTUPINFO结构。
● lpProcessInformation——指向一个PROCESS_INFORMATION结构,这个结构用来供函数返回新建进程的相关信息。
如果函数执行成功,返回值是非0值,否则函数返回0。新建进程的句柄在哪里呢?这些句柄就在lpProcessInformation参数指向的PROCESS_INFORMATION结构中。结构定义为:
上页:第13章 进程控制 · 13.2 执行可执行文件(2) 下页:第13章 进程控制 · 13.2 执行可执行文件(4)