CreateProcess

来源:互联网 发布:第二代民族政策 知乎 编辑:程序博客网 时间:2024/05/13 20:57
一个线程调用CreateProcess时,系统装创建一个进程内核对象,其初始使用计数为1。
进程内核对象不是进程本身,而是操作系统用来管理这个进程的一个小型数据结构-----可以把进程内核对象想象成由进程统计信息构成的一个小型数据结构。
然后,系统为新进程创建一个虚拟地址空间,并将可执行文件(和所有的DLL)的代码及数据加载到进程的地址空间。
然后,系统为新进程的主线程创建一个线程内核对象(其使用计数为1)。和进程内核对象一样,线程内核对象也是一个小型数据结构,操作系统用它来管理这个线程。
这个主线程一开始就会执行C/C++运行时的启动例程,它是由链接器高为应用程序入口的,最终会调用应该程序WinMain,wWinMain,main,wmain函数。如果系统成功创建了新进程和主线程
,CreateProcess将返回TRUE。

CreateProcess详细参数的讨论
函数原型:
BOOL CreateProcess(PCTSTR pszApplicationName,PTSTR pszCommandLine,PSECURITY_ATTRIBUTES        pszProcess,PSECURITY_ATTRIBUTES pszThread,
                    BOOL bInheritHandles,DWORD fdwCreate,PVOID pvEnvironment,PCTSTR pszCurDir,PSTARTUPINFO psiStartInfo,PPROCESS_INFORMATION ppiProcInfo);

pszApplicationName
:指定新进程要使用的可执行文件的名称,可以传入NULL,也可以传入想要运行的可执行文件的名称。
pszCommandLine的类型是PTSTR,期望我们传入的是一个非 常量字符串指针 ,因为在内部,CreateProcess实际是会对pszCommandLine进行修改,传入PTSTR的,是把数据放入了可读可写的区域。
                如果直接传入字符串,是会放入到只读区域,这样就会发生访问违规。
解决这个问题的最佳办法是在调用CreateProcess前,把常量字符串放到一个临时缓冲区,如下:
TCHAR szPath[]=TEXT("WordPad ReadMe.txt");
CreateProcess(TEXT("C:\\Windows\\System32\\Notepad.exe"),szPath,...);
(解释一下PTSTR:P代表指针、T是一个宏,可以说是表示宽字节吧、STR是字符串的意思;PCTSTR比PTSTR多了一个C,C代表的是const常量)
pszProcess是进程对象安全性。
pszThread是线程对象安全性。
hInheriHandles子进程是否从父进程处继承了句柄。

    typedef struct _SECURITY_ATTRIBUTES {
  DWORD nLength; //结构体大小,可用sizeof取得
  LPVOID lpSecurityDescriptor; //安全描述符
  BOOL bInheritHandle;//安全描述的对象能否被新创建的进程继承
  } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;
结构体中关键的是第三个,决定了该对象是否可以被继承。

进程A调用CreateProcess(设置pszProcess结构中bInheritHandle=TRUE、设置pszThread结构中hInheritHandle=FALSE)来创建进程B,则进程A可以操纵进程B的进程对象和线程对象。
进程A调用CreateProcess(pszProcess和pszThread结构体都传入NULL,bInheritHandle设置TRUE)创建进程C,此时进程C将继承A中的所有可继承的句柄,包括进程B的进程对象,
但是不包括线程对象,这样就可以看出pszProcess和pszThread中hInheritHandle的作用了。

写一个实例:

#include <windows.h>int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow){    //定义几个对象    STARTUPINFO si={sizeof(si)};    SECURITY_ATTRIBUTES saProcess,saThread;    PROCESS_INFORMATION piProcessB,piProcessC;    TCHAR szPath[MAX_PATH];    //设置saProcess为可继承    saProcess.nLength=sizeof(saProcess);    saProcess.lpSecurityDescriptor=NULL;    saProcess.bInheritHandle=TRUE;    //设置saThread为不可继承    saThread.nLength=sizeof(saThread);    saThread.lpSecurityDescriptor=NULL;    saThread.bInheritHandle=FALSE;    //////////////////////////////////////////////////////////    //下面代码进程C可以继承进程A,可以继承进程B的进程对象,不可以继承进程B的线程对象。    //////////////////////////////////////////////////////////    _tcscpy_s(szPath,_countof(szPath),TEXT("ProcessB"));    CreateProcess(NULL,szPath,&saProcess,&saThread,FALSE,0,NULL,NULL,&si,&piProcess);        _tcscpy_s(szPath,_countof(szPath),TEXT("ProcessC"));    CreateProcess(NULL,szPath,NULL,NULL,TRUE,0,NULL,NULL,&si,&piProcessC);    return 0;}

fdwCreate参数标识了影响新进程的创建方式的标志,多个标志可以按位或来使用,还可以指定进程优先级,具体的就msdn吧。
pvEnvironment参数指向一块内存,包含新进程要使用的环境字符串,多数传入NULL。
pszCurDir父进程设置子进程的当前驱动器和目录。
psiStartInfo一般创建新进程时使用,记得要清0,其实情况,下次再说,太复杂了。
ppiProcInfo用来接收新进程的识别信息。