关于一些进程的概念就不说了。。。
一创建进程GreateProcess
(1).当一个进程被创建时:
①.系统为进程创建一个内核对象,并将这个对象的计数设置为1,进程对象只是一个比较小的数据结构,可以通过进程句柄来引用
②.系统为进程创建一个虚拟地址空间,并将可执行文件装载到这个地址空间中,系统同时处理可执行文件的导入表,将导入表中所有dll文件装入.
每个dll被装入的时候,dll入口函数被执行,如果入口函数返回初始化失败信息的话 ,进程的初始化失败.
可执行文件的每个dll都被看作单独的模块,都被分配了一个实例句柄(实例句柄在数值上等于模块装入到地址空间中的线性地址)
③.系统为进程建立一个主线程,主线程将从可执行文件的的入口地址开始执行
④.对于进程来说,每一个进程对应一个进程句柄和一个进程ID
(2).和创建进程有关的一些结构
①STARTUPINFO
typedef struct _STARTUPINFO {
DWORD cb; ;结构的长度
LPTSTR lpReserved; ;保留字段
LPTSTR lpDesktop; ;NT下使用,指定桌面名称
LPTSTR lpTitle; ;控制台使用指定控制台窗口标题
DWORD dwX; ;当新进程使用CW_USEDEFAULT参数创建
DWORD dwY; ;窗口的时候将使用这些位置和大小属性
WORD dwXSize;
ORD dwYSize;
DWORD dwXCountChars; ;控制台程序使用,指定控制台窗口行数
DWORD dwYCountChars; ;
DWORD dwFillAttribute; ;控制台程序使用,指定控制台窗口背景色
DWORD dwFlags; ;标志
WORD wShowWindow; ;窗口的显示方式
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput; ;控制台程序使用:几个标准句柄
ANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO,
*LPSTARTUPINFO;
在需要指定新进程的窗口时,才需要手动填写STARTUPINFO结构(比如需要控制台程序的输入输出重定位时候,可以改写hStdInput和hStdOutput字段)
在大多数情况下,并不需要新进程的窗口有什么特殊之处,这时只需要使用GetStartupInfo获取当前进程的STARTUPINFO结构并使用他就可以了
invoke GetStartupInfo,addr stStartupInfo
②.PROCESS_INFOMATION
typedef struct _PROCESS_INFORMATION
{
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId; 主线程句柄
PROCESS_INFORMATION,
*LPPROCESS_INFORMATION;
(3).CreateProcess
BOOL WINAPI CreateProcess(
__in_opt LPCTSTR lpApplicationName,
__inout_opt LPTSTR lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCTSTR lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);
①lpApplicationName
指向一个以0结尾的字符串,指明可执行文件名,如果这个参数为NULL,那么文件名可以在老婆CommandLine参数指定的命令行参数中包含
②lpCommandLine
用来指定命令行参数,如果 lpApplicationName为NULL,那么命令行参数的第一个组成部分用来指定可执行文件名;
如果2个参数都为空,那么lpApplicationName为文件名,lpCommandLine作为命令行参数
③lpProcessAtrributes
指向一个SECURITY_ATTRIBUTES结构,用来指定新进程的安全属性,如果进程句柄不需要被其他子进程继承,可以在这里使用NULL
④lpThreadAtrributes
指向一个SECURITY_ATTRIBUTES结构,用来指定新进程的安全属性,如果进程句柄不需要被其他线程继承,可以在这里使用NULL
⑤bInheritHandles
指定当前进程句柄是否可以被新进程继承,如果指定为TRUE,那么可以继承,一般在这里使用FALSE
⑥dwCreationFlags
创建标志,指定新进程的优先级以及其他标志,这个参数类似于CreateThread函数中的同名参数它可以是一些标志的组合,下面列举一些常用的标志
CREATE_NEW_CONSOLE 如果新进程是控制台程序,那么为他新建一个控制台窗口,而不是使用父进程的窗口
CREATE_SUSPENED 新建进程的主线程一开始处于挂起状态需要以后用ResumeThread函数来恢复它的执行
DEBUG_PROCESS ;调试有关
DEBUG_ONLY_THIS_PROCESS
HIGH_PRIORITY_CLASS ;指定新进程的优先级
NORMAL_PRIORITY_CLASS
REALTIME_PRIORIY_CLASS
⑦lpEnvironment
指向新进程的环境变量块,如果这个参数指定为NULL,表示让Windows拷贝当前进程的环境块当做子进程的环境块,如果程序需要将修改过的环境块传给子进程,可以设置这个参数
⑧lpCurrentDirectory
指向一个字符路径,用来指定子进程的当前驱动器和当前目录,如果指定为NULL,子进程将引用父进程的当前路径
⑨后面2个参数分别指向前面介绍的2个结构体
---------------------------------------------------------------------------------------------------------------------------------------------------
二.结束进程
(1)ExitProcess dwExitCode
ExitProcess只能用来结束当前进程,不能用来结束其他进程,包括当前进程创建的子进程
(2)TerminateProcess hProcess,dwExitCode
这个函数不推荐使用,一般仅在很极端的条件下使用,(如任务管理器用来结束响应的进程)
因为目标进程无条件结束,没有机会进行扫尾工作,同时目标进程使用的dll文件也不会收到结束通知,所以极有可能 造成数据丢失
当前进程被结束时,系统将做如下工作
①进程创建或打开的所有对象句柄被关闭
②进程的所有线程被终止
③进程和进程中所有的线程状态被改为置位状态,以便让WaitForSingleObject函数正常的检测
④进程对象中的退出码字段从STILL_ACTIVE被改为指定的退出码
(3)要检测一个进程的退出码可以使用
GetExitCodeProcess hProcess,lpExitCode
如果函数执行成功返回退出码到lpExitCode
如果失败返回STILL_ACTIVE到lpExitCode
通过检测一个子进程的退出码是否为STILL_ACTIVE,就可以得知子进程是否已经结束,但如果需要在父进程中等待子进程结束时,就没有必要不停的检测退出码
可以使用WaitForSingleObject hProcess,dwMilliseconds
dwMilliseconds指定为INFINITE就可以了,表示子进程结束前函数不会返回
当一个进程被结束时,并不影响它所创建的子进程,进程对象也不会马上从内存中删除,因为可能其他进程还需要通过进程句柄检测进程状态,直到使用CloseHandle函数将进程句柄关闭以后,
进程对象才是真正的被删除了,所以当不在使用进程句柄的时候,不要忘记关闭PROCESS_INFORMATION中的进程句柄 和主线程句柄