![CreateProcess函数详细使用说明_第1页](http://file3.renrendoc.com/fileroot_temp3/2022-1/11/6f3cc272-459a-4301-9ee7-25e22e93f839/6f3cc272-459a-4301-9ee7-25e22e93f8391.gif)
![CreateProcess函数详细使用说明_第2页](http://file3.renrendoc.com/fileroot_temp3/2022-1/11/6f3cc272-459a-4301-9ee7-25e22e93f839/6f3cc272-459a-4301-9ee7-25e22e93f8392.gif)
![CreateProcess函数详细使用说明_第3页](http://file3.renrendoc.com/fileroot_temp3/2022-1/11/6f3cc272-459a-4301-9ee7-25e22e93f839/6f3cc272-459a-4301-9ee7-25e22e93f8393.gif)
![CreateProcess函数详细使用说明_第4页](http://file3.renrendoc.com/fileroot_temp3/2022-1/11/6f3cc272-459a-4301-9ee7-25e22e93f839/6f3cc272-459a-4301-9ee7-25e22e93f8394.gif)
![CreateProcess函数详细使用说明_第5页](http://file3.renrendoc.com/fileroot_temp3/2022-1/11/6f3cc272-459a-4301-9ee7-25e22e93f839/6f3cc272-459a-4301-9ee7-25e22e93f8395.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、CreateProcess函数详细使用说明函数原型BOOL CreateProcess(LPCTSTR lpApplicationName,LPTSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes。LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCTSTR lpCurrentDirectory,LPSTARTUPINFO lpStartupInfo,LPPROCE
2、SS_INFORMATION lpProcessInformation);CreateProcess函数用于创建进程:1. BOOL CreateProcess(2. PCTSTR pszApplicationName,3. PTSTR pszCommandLine,4. PSECURITY_ATTRIBUTES psaProcess,5. PSECURITY_ATTRIBUTES psaThread,6. BOOL bInheritHandles,7. DWORD fdwCreate,8. PVOID pvEnvironment,9. PCTSTR pszCurDir,10. PSTARTU
3、PINFO psiStartInfo,11. PPROCESS_INFORMATION ppiProcInfo);线程调用CreateProcess时,系统会创建一个进程内核对象,将其引用计数初始化为1(进程内核对象并不是进程本身,它只是操作系统用来管理进程的数据结构,其中包含了进程的一些统计信息)。然后系统为新进程开辟虚拟地址空间,并将可执行文件的代码和数据以及所需的DLL装载到该地址空间中。接着系统为进程主线程创建线程内核对象,并将其引用计数初始为1(同进程一样,线程内核对象也不是线程本身,而且操作系统用来管理线程的数据结构)。主线程将链接器设置的入口点函数作为C/C+运行时启动函数调用,
4、这些启动函数最终又调用代码中的入口点函数如WinMain、wWinMain、main和 wmain。当操作系统成功创建了新的进程和主线程后,CreateProcess返回TRUE。以上是CreateProcess的简要介绍,下面我们来详细讨论它的参数。pszApplicationName和pszCommandLinepszApplicationName和pszCommandLine分别表示进程使用的可执行文件名和向其传递的命令行字符串,我们先来看看 pszCommandLine参数。注意pszCommandLine是PTSTR,这意味着你必须为其传递指向非常量字符串的地址。 CreatePro
5、cess内部会更改向其传递的命令行字符串,但在CreateProcess返回之前,它会将该字符串恢复原样。这一点是非常重要的,因为如果你向CreateProcess传递的命令行字符串位于进程的只读存储区,就会发生Access Violation错误。比如,下面的代码执行时会触发Access Violation,因为微软的C/C+编译器会把常量字符串放入只读存储区(注意早期的微软C/C+编译器会将常量字符串放在可读写存储区,因此下面的代码在旧的编译环境下不会出错):1. STARTUPINFO si = sizeof(si) ;2. PROCESS_INFORMATION pi;3. Creat
6、eProcess(NULL, TEXT("NOTEPAD"), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);解决这个问题的方法很简单,将命令行字符串复制到临时缓冲区既可,如下所示:1. STARTUPINFO si = sizeof(si) ; 2. PROCESS_INFORMATION pi; 3. TCHAR szCommandLine = TEXT("NOTEPAD"); 4. CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0
7、, NULL, NULL, &si, &pi);微软在其C+编译器选项中提供了/GF开关,/GF打开时,程序中所有用到的常量字符串将只维护单一副本,且位于只读存储部分。在调用 CreateProcess时,开发人员应该打开/GF开关并使用缓冲区。我们希望微软在未来版本的Windows中会改进CreateProcess,使其接受常量字符串作为命令行参数,并在其内部分配/释放临时缓冲区而不是让API调用者来做。另外,假如你使用常量ANSI字符串作为 CreateProcess参数,并不会发生Access Violation错误,我们在前面的章节已经提到过,许多WinAPI函数的AN
8、SI版本会将ANSI参数转换为UNIDOE编码后调用其 Unicode版本,CreateProcess会把ANSI字符串转换为Unicode编码后放在临时缓冲区,并调用Unicode版的 CreateProcess,因此不会触发Access Violation。pszCommandLine参数指定了 CreateProcess创建新进程所需的完整命令行。当CreateProcess解析该参数时,它会检查命令行参数中的第一个标记,并将其作为进程要执行的可执行文件名,如果该文件名没有指定后缀,函数将把它当作exe文件。CreateProcess会按下面的顺序查找该文件:1. 包含当前进程可执行文件
9、的目录2. 当前进程的当前目录3. Windows系统目录,既GetSystemDirectory返回的目录4. Windows目录5. PATH环境变量列出的目录当然,如果文件名包含了完整路径,系统将会在该路径中查找文件而不会再做上面的搜索。如果系统找到了可执行文件,它会创建一个新的进程并把可执行文件的代码和数据映射到进程的地址空间,然后调用CRT启动函数(linker选项卡中的入口点函数),接着CRT启动函数检查命令行参数,过滤掉其中的可执行文件部分,并把剩下字符串的地址作为pszCmdLine传给wWinMain/WinMain。以上情形都是在pszApplicationName为NUL
10、L时发生的。 pszApplicationName指定了进程要执行的可执行文件的名称,假如没有指定文件后缀,系统并不会做任何处理。 pszApplicationName不包含完整路径时,CreateProcess只从当前目录中查找可执行文件,查找失败时函数失败并返回 FALSE。即使指定了pszApplicationName,CreateProcess仍然会将pszCommandLine参数作为新进程的命令行。比如下面的代码:1. / Make sure that the path is in a read/write section of memory. 2. TCHAR szPath =
11、TEXT("WORDPAD README.TXT"); 3. / Spawn the new process. 4. CreateProcess(TEXT("C:WINDOWSSYSTEM32NOTEPAD.EXE"),szPath,.); 执行上面代码时,系统会打开notepad.exe(记事本),但它的命令行却是WORDPAD README.TXT(WORDPAD是写字板),这看上去非常奇怪,但CreateProcess就是这样工作的。这种 pszApplicationName提供的特性被用来支持Windows的POSIX子系统。psaProcess
12、, psaThread和bInheritHandles创建新进程时,系统会创建一个进程内核对象和一个线程内核对象(用于进程的主线程),和其它内核对象一样,创建者(在这儿是父进程)必须指定其安全属性。psaProcess和psaThread分别指定了新进程的进程内核对象和线程内核对象的安全属性。将其设为NULL时,系统为对应的内核对象指定默认的安全属性。你可以创建SECURITY_ATTRIBUTES类型的变量,设置其中各个域的值然后将变量地址传递给psaProcess或 psaThread,以应用指定的安全属性。正如在第3章讨论内核对象时谈到的,当你想要控制新的进内核对象的句柄能否被父进程以后
13、创建的子进程继承时,你应该设置SECURITY_ATTRIBUTES变量的bInheritHandle域的值。下面的Inherit.cpp展示了内核对象句柄继承。假设执行该代码的进程为A,它调用CreateProcess创建了进程B,接着又创建了子进程C。注意调用CreateProcess时A使用的psaProcess、psaThread和bInheritHandles参数,代码注释很详细的描述了这些参数的作用:1. /* 2. Module name: Inherit.cpp 3. Notices: Copyright (c) 2008 Jeffrey Richter & Chris
14、tophe Nasarre 4. */ 5. #include <Windows.h> 6. int WINAPI _tWinMain (HINSTANCE hInstanceExe, HINSTANCE, 7. PTSTR pszCmdLine, int nCmdShow) 8. / Prepare a STARTUPINFO structure for spawning processes. 9. STARTUPINFO si = sizeof(si) ; 10. SECURITY_ATTRIBUTES saProcess, saThread; 11. PROCESS_INFO
15、RMATION piProcessB, piProcessC; 12. TCHAR szPathMAX_PATH; 13. / Prepare to spawn Process B from Process A. 14. / The handle identifying the new process 15. / object should be inheritable. 16. saProcess.nLength = sizeof(saProcess); 17. saProcess.lpSecurityDescriptor = NULL; 18. saProcess.bInheritHand
16、le = TRUE; 19. / The handle identifying the new thread 20. / object should NOT be inheritable. 21. saThread.nLength = sizeof(saThread); 22. saThread.lpSecurityDescriptor = NULL; 23. saThread.bInheritHandle = FALSE; / Spawn Process B.24. _tcscpy_s(szPath, _countof(szPath), TEXT("ProcessB");
17、 25. CreateProcess(NULL, szPath, &saProcess, &saThread, 26. FALSE, 0, NULL, NULL, &si, &piProcessB); 27. / The pi structure contains two handles 28. / relative to Process A: 29. / hProcess, which identifies Process B's process 30. / object and is inheritable;and hThread,which ide
18、ntifies31. / Process B's primary thread object and is NOT inheritable.32. / Prepare to spawn Process C from Process A. 33. / Since NULL is passed for the psaProcess and psaThread 34. / parameters, the handles to Process C's process and 35. / primary thread objects default to "noninherit
19、able." 36. / If Process A were to spawn another process, this new 37. /process would NOT inherit handles to Process C's process38. / and thread objects. 39. / Because TRUE is passed for the bInheritHandles parameter,40. / Process C will inherit the handle that identifies Process41. / B'
20、s process object but will not inherit a handle to 42. / Process B's primary thread object. 43. _tcscpy_s(szPath, _countof(szPath), TEXT("ProcessC"); 44. CreateProcess(NULL, szPath, NULL, NULL, 45. TRUE, 0, NULL, NULL, &si, &piProcessC); 46. return(0); 47. fdwCreatefdwCreate参数用来
21、控制进程被创建时的行为,下面列出了它可能的取值:·DEBUG_PROCESS:父进程将调试子进程及子进程创建的所有进程,指定该参数后,在子进程或子进程创建的任意进程中发生特定事件时系统将通知父进程·DEBUG_ONLY_THIS_PROCESS:父进程将调试子进程,指定该参数后,在子进程中发生特定事件时系统将通知父进程·CREATE_SUSPENDED:进程创建后其主线程暂不执行。此时父进程可以在子进程运行之前更改子进程地址空间中的数据、更改子进程主线程优先级、将子进程添加到作业中等。父进程完成其更改后,可以调用ResumeThread函数恢复子进程主线程运行
22、183;DETACHED_PROCESS:系统将阻止CUI程序向其父进程的CUI窗口写入其输出。当父进程为CUI进程时,创建的CUI子进程默认使用父进程的CUI窗口(如cmd.exe程序)。指定该参数后,新进程在需要输出到窗口时必须调用AllocConsole创建CUI窗口·CREATE_NEW_CONSOLE:系统自动为新进程创建一个CUI窗口,该标志不能与DETACHED_PROCESS同时使用·CREATE_NO_WINDOW:系统不为新进程创建CUI窗口,使用该标志可以创建不含窗口的CUI程序·CREATE_NEW_PROCESS_GROUP:新进程将作为
23、一个新的进程组的根进程,新的进程组将包含以根进程为祖先的所有进程。用户在进程组中的某个进程CUI窗口中按下Ctrl+C或Ctrl+B时,系统将通知进程组中的所有进程这一事件·CREATE_DEFAULT_ERROR_MODE:子进程不继承父进程的任何错误标志·CREATE_SEPARATE_WOW_VDM:仅用于16位Windows程序,不译·CREATE_SHARED_WOW_VDM:仅用于16位Windows程序,不译·CREATE_UNICODE_ENVIRONMENT:子进程的环境块为Unicode字符串。进程的环境块默认只包含ANSI字符串
24、183;CREATE_FORCEDOS:强制系统运行内嵌在16位OS/2系统中的MS-DOS程序·CREATE_BREAKAWAY_FROM_JOB:当父进程属于某个作业时,新建的子进程将不再与该作业关联·EXTENDED_STARTUPINFO_PRESENT:传递给CreateProcess函数的psiStartInfo参数是STARTUPINFOEX类型的变量fdwCreate参数也可以用于设置新进程的优先级。但你不必这样做,对大多数应用你也不应该这样做系统会为新进程分配默认优先级。表4-5列出了可能的优先级常量:这些常量决定了进程中的线程在CPU中调度的优先级,我们
25、在188页的“优先级概述”中会讨论该问题。pvEnvironment 参数pvEnvironment指向一块内存区域,其中包含新进程用到的环境字符串。大多数情况下,你可以为其传递NULL,此时新进程将继承父进程的环境字符串。pszCurDir参数pszCurDir允许父进程设置子进程的当前驱动器和目录。如果该参数为NULL,子进程将使用父进程的当前驱动器和目录作为其当前驱动器和目录。如果pszCurDir非空,则其必须指向一个包含驱动器标识的以0结尾的路径字符串。psiStartInfopsiStartInfo是指向STARTUPINFO或STARTUPINFOEX变量的提针:1. typed
26、ef struct _STARTUPINFO 2. DWORD cb; 3. PSTR lpReserved; 4. PSTR lpDesktop; 5. PSTR lpTitle; 6. DWORD dwX; 7. DWORD dwY; 8. DWORD dwXSize; 9. DWORD dwYSize; 10. DWORD dwXCountChars; 11. DWORD dwYCountChars; 12. DWORD dwFillAttribute; 13. DWORD dwFlags; 14. WORD wShowWindow; 15. WORD cbReserved2; 16.
27、PBYTE lpReserved2; 17. HANDLE hStdInput; 18. HANDLE hStdOutput; 19. HANDLE hStdError; 20. STARTUPINFO, *LPSTARTUPINFO; 21. 22. typedef struct _STARTUPINFOEX 23. STARTUPINFO StartupInfo; 24. struct _PROC_THREAD_ATTRIBUTE_LIST *lpAttributeList; 25. STARTUPINFOEX, *LPSTARTUPINFOEX; Windows创建新进程时会使用STAR
28、TUPINFO(EX)的成员变量,大多数情况下可以使用这些变量的默认值,此时你应该该将其cb域设置为结构的大小,并将其余域清0,如下:1. STARTUPINFO si = sizeof(si) ; 2. CreateProcess(., &si, .); 许多开发人员常常会忘记执行上述操作,如果你没有清空其内容,STARTUPINFO(EX)的内容会是调用线程堆栈上的一些数据。将这些垃圾数据传递给CreateProcess可能导致无法预料的结果,为了让CreateProcess正常工作,你必须将STARTUPINFO(EX)中没有用到的域清0。表4-6列出了STARTUPINFO(E
29、X)结构的成员,注意有些成员只在GUI应用中生效,而有些则只在CUI应用中生效:现在我们来讨论dwFlags成员。dwFlags包含一组标志用来指示如何创建子进程,其中大多数标志只是告诉CreateProcess是否使用STARTUPINFO结构中的某个成员,表4-7列出了dwFlags的可取值:现在我们来讨论dwFlags成员。dwFlags包含一组标志用来指示如何创建子进程,其中大多数标志只是告诉CreateProcess是否使用STARTUPINFO结构中的某个成员,表4-7列出了dwFlags的可取值:另外两个标志 STARTF_FORCEONFEEDBACK和STARTF_FORCE
30、OFFFEEDBACK可以控制在创建子进程时如何显示鼠标指针。由于 Windows支持抢先式多任务调度,因此你可以在创建子程并等待子进程初始化时,执行另外的程序。如果你指定了 STARTF_FORCEONFEEDBACK,Windows会在新进程初始化时将鼠标光标指针更改为“后台运行”,如下图: 这个标志意味着系统后台正在处理某些任务(在这里是创建并初始化子进程),但你依然可以继续使用系统。当你指定了STARTF_FORCEOFFFEEDBACK标志时,CreateProcess不会更改鼠标指针样式。如果指定了STARTF_FORCEONFEEDBACK,且子进程在CreateProcess调
31、用后2秒内执行了GUI调用,CreateProcess会等待子进程显示窗口。如果该GUI调用后5秒之内还没有窗口显示,CreateProcess会将鼠标指针恢复原状,否则继续等待5秒,如果在这5秒之内子进程调用了GetMessage函数,CreateProcess会认为子进程已经完成初始化并将鼠标指针复位。STARTUPINFO的wShowWindow变量将传递给wWinMain/WinMain的最后一个参数nCmdShow,它的取值是 ShowWindow函数接受的参数值之一,通常被指定为SW_SHOWNORMAL、SW_SHOWMINNOACTIVE或 SW_SHOWDEFAULT。在结束
32、本节之前,我们来看看STARTUPINFOEX结构。通过使用同时兼容STARTUPINFOEX和STARTUPINFO结构的参数psiStartInfo,微软在保持CreateProcess签名的同时提高了其扩展性。下面是STARTUPINFOEX结构的定义:1. typedef struct _STARTUPINFOEXA 2. STARTUPINFOA StartupInfo; 3. struct _PROC_THREAD_ATTRIBUTE_LIST *lpAttributeList; 4. STARTUPINFOEXA, *LPSTARTUPINFOEXA; 5. typedef st
33、ruct _STARTUPINFOEXW 6. STARTUPINFOW StartupInfo; 7. struct _PROC_THREAD_ATTRIBUTE_LIST *lpAttributeList; 8. STARTUPINFOEXW, *LPSTARTUPINFOEXW; lpAttributeList(属性链表)是_PROC_THREAD_ATTRIBUTE_LIST结构的链表,其中每个结构包含一个key/value对,目前,_PROC_THREAD_ATTRIBUTE_LIST中key的取值只能是下面两种:· PROC_THREAD_ATTRIBUTE_HANDLE
34、_LIST:告诉 CreateProcess指定的句柄可被子进程继承,当然该句柄必须是可继承的(其继承标志位为1),且无需将CreateProcess的 bInheritHandles参数设置为TRUE。使用该标志可以指定子进程继承可继承句柄的子集而不是全部。这对于需要在不同的安全环境中创建子进程的进程而言非常重要,在这种情况下,由于安全原因,某些子进程可能不应该继承全部的可继承句柄。· PROC_THREAD_ATTRIBUTE_PARENT_PROCESS:指定一个进程句柄,指定的进程(包括其可继承句柄、亲缘性、优先级等等)会替代调用CreateProcess的当前进程,成为子进
35、程的父进程。如果当前进程在调用CreateProcess时指定了DEBUG_PROCESS或DEBUG_ONLY_THIS_PROCESS,重新指定父进程并不影响原父进程调试过程,在子进程中发生的特定事件仍然会报告给原父进程。属性链表的内容是不透明的,因此我们需要一些函数来创建空的属性链表。创建属性链表需要以下几个步骤,首先,为其分配存储空间,然后向其中添加键值对。函数InitializeProcThreadAttributeList用来创建新的属性链表并为其分配存储空间:1. BOOL InitializeProcThreadAttributeList( 2. PPROC_THREAD_AT
36、TRIBUTE_LIST pAttributeList, 3. DWORD dwAttributeCount, 4. DWORD dwFlags, 5. PSIZE_T pSize); 参数dwFlags必须指定为0,你可以先用如下方式获得属性链表所需的空间大小:1. SIZE_T cbAttributeListSize = 0; 2. BOOL bReturn = InitializeProcThreadAttributeList( 3. NULL, 1, 0, &cbAttributeListSize); 4. / bReturn is FALSE but GetLastError
37、() returns ERROR_INSUFFICIENT_BUFFER cbAttributeListSize 返回创建属性链表所需的内存大小,该大小与dwAttributeCount参数相关,dwAttributeCount指定了属性链表中的 key/value对的数目。接下来你可以用cbAttributeListSize为属性链表分配空间:1. pAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST) 2. HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize); 然后再次调用InitializeProc
38、ThreadAttributeList初始化属性链表的内容:1. bReturn = InitializeProcThreadAttributeList( 2. pAttributeList, 1, 0, &cbAttributeListSize); 当属性链表初始化完成后,就可以调用UpdateProcThreadAttribute向其添加键/值对了:1. BOOL UpdateProcThreadAttribute( 2. PPROC_THREAD_ATTRIBUTE_LIST pAttributeList, 3. DWORD dwFlags, 4. DWORD_PTR Attri
39、bute, 5. PVOID pValue, 6. SIZE_T cbSize, 7. PVOID pPreviousValue, 8. PSIZE_T pReturnSize); pAttributeList是要添加键/值对的属性列表,Attribute可取 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS或PROC_THREAD_ATTRIBUTE_HANDLE_LIST,取前者时,pValue参数应指向另外一个进程的句柄,cbSize取值应为sizeof(HANDLE),否则,pValue指向子进程要继承的所有内核对象的句柄数组,cbSize取值应是sizeof(HANDLE)乘以该数组的大小。参数dwFlags、pPreviousValue和 pReturnSize是保留参数,应分别赋0、NULL和NULL。注意,如果在创建子进程时为其指定新的父进程,既使用了 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,那么在使用 P
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年中国太子佛工艺品市场调查研究报告
- 2025至2031年中国高压透镜行业投资前景及策略咨询研究报告
- 2025年艺术道闸项目可行性研究报告
- 2025年红外线按摩棒项目可行性研究报告
- 2025年电加热针织物呢毯预缩机项目可行性研究报告
- 成都四川成都天府国际竞技训练中心招聘运动员4人笔试历年参考题库附带答案详解
- 2025年曲印项目可行性研究报告
- 2025年揉切粉碎机项目可行性研究报告
- 2025年安康鱼野菜串项目可行性研究报告
- 2025至2031年中国信息插座模块行业投资前景及策略咨询研究报告
- 药企销售总经理竞聘
- 开封市第一届职业技能大赛健康照护项目技术文件(国赛)
- 饮酒与糖尿病
- 公路电子收费系统安装合同范本
- 医院培训课件:《伤口评估与测量》
- 期末试卷(试题)-2024-2025学年四年级上册数学沪教版
- 《第一单元口语交际:即兴发言》教案-2023-2024学年六年级下册语文统编版
- 情侣自愿转账赠与协议书范本
- 综合实践项目 制作水族箱饲养淡水鱼 教学设计-2024-2025学年鲁科版生物六年级上册
- 公转私付款合同模板
- 安徽省2024年高考语文模拟试卷及答案5
评论
0/150
提交评论