




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第9讲 Windows进程进程是可运行资源的载体讲师:Gamebaby Rock Sun第9讲 Windows进程1.Windows进程和入口2.进程环境变量、亲缘性和当前目录3.进程默认堆和堆管理4.进程对象列表5.创建销毁进程、子进程6.重定向子进程的输入和输出7.枚举系统中的进程列表及PSAPI使用Windows进程进程是装入内存并准备执行的程序;在Windows中进程由两部分组成:一个是操作系统用来管理进程的内核对象。内核对象也是系统用来存放关于进程的统计信息的地方。另一个是地址空间,它包含所有可执行模块或DLL模块的代码和数据。它还包含动态内存分配的空间。如线程栈和堆空间。Windo
2、ws中,进程分为三大类:控制台应用窗口应用服务应用从本质上讲这些应用没有质的区别应用类型和入口控制台应用主要是弹出一个字符界面与用户进行交互入口是:ANSI版:main(与C/C+定义的一致)UNCODE版:wmain兼容版:_tmain窗口应用主要是通过显示窗口,并使用丰富的控件等界面元素与用户交互,入口是:ANSI版:WinMainUNICODE版:wWinMain兼容版:_tWinMain服务应用将在后面课程中专门讲解(以上入口函数原型请参阅MSDN)决定应用类型的编译选项很多时候,大多数程序员对应用类型和入口没有概念,导致错误的提供入口给不对应的应用类型,并且无法编译通过在VC+链接器
3、中有一个系统选项,如果指定了Windows (/SUBSYSTEM:WINDOWS)那么表示这个项目将需要一个WinMain或wWinMain入口;如果指定了控制台(/SUBSYSTEM:CONSOLE)则表示项目需要一个main或wmain入口;(没有为正确的项目类型指定正确的入口,这是很多初学者容易犯的错误)VC/C+嵌入入口在VC+中实际上并不调用你编写的进入点函数。它调用的是C/C+运行期启动函数。该函数负责对C/C+运行期库进行初始化,这样,就可以调用malloc和free之类的C库函数。它还能够确保已经声明的任何C+全局对象和静态对象能够在代码执行以前正确地创建。下表说明源代码中可
4、以实现哪个进入点以及何时使用该进入点:入口对应嵌入的入口WinMainWinMainCRTStartupwWinMainwWinMainCRTStartupmainmainCRTStartupwmainwmainCRTStartup入口参数main、wmain、_tmain入口函数的参数与标准C/C+语言定义和含义相同,此处就不再赘述WinMain、wWinMain、_tWinMain的4个入口参数含义:HINSTANCE hInstance:当前进程实例的实例句柄,一般保存该值在全局变量中或代表进程的C+类中,以便其它的API调用时使用该参数,在Windows中,该值其实就是Exe模块映射进
5、虚拟地址空间中的基址,Win32中该值为0 xHINSTANCE hPrevInstance:16位Windows遗留的产物,现在不用,总为NULL(ANSI)LPSTR lpCmdLine、(UNICODE)LPWSTR lpCmdLine、(TCHAR)LPTSTR lpCmdLine:进程启动时传入的命令行参数int nCmdShow:窗口显示的方式;主要指定程序主窗口在启动时应如何显示,如:最大化、最小化、隐藏、默认等进程的命令行与main和wmain函数不同在WinMain或wWinMain函数中,系统传递的命令行参数是一个字符串此时可以使用CommandLineToArgvW函数来
6、将命令行参数拆分成一个数组因为这个函数只有UNICODE版,所以需要将其它字符集的字符串转换成UNICODE版的字串后再调用此函数(有关UNICODE字符串处理和转换的内容请复习第二讲)该函数返回的内存,需要用HeapFree来释放命令行拆分示例嵌入入口和OnExit回调在main、wmain、WinMain、wWinMain等函数返回时,嵌入的入口函数除了清理全局对象或静态对象之外还会调用由_onexit添加的退出回调函数列表OnExit函数被调用的顺序与添加的顺序相反这个机制为自定义的退出时处理提供了方便的方法因为_onexit注册的回调函数总是先于全局对象或静态对象销毁之前调用,因此在这
7、些函数中仍可以正常使用这些全局对象和静态对象_onexit调用示例自定义入口在Windows平台上,应用程序入口其实只是一个语法上的要求,对于编译后的结果来说只需要一个明确的地址即可(函数指针)在VS2008项目属性-配置属性-链接器-高级-入口点 中设置自定义的入口函数即可通过这个自定义入口就可以绕开VC+的嵌入式入口,但此时所有的C/C+标准库初始化、全局对象初始化等工作就要自己来实现,当然如果只使用API而不用C/C+库函数的话这不是问题自定义入口示例进程环境变量进程可以通过GetEnvironmentStrings和GetEnvironmentVariable方法来捡取环境变量或者进程
8、可以使用C库函数getenv(_wgetenv、_tgetenv)方法来更方便的捡取环境变量值可以在“我的电脑”右键菜单属性对话框的高级属性页面中打开环境变量对话框来快捷的更改系统级的环境变量设置注意:很多情况下不推荐再使用环境变量的方式来存取一些进程需要的运行时变量的值或其它信息,替代的可以考虑使用注册表或者自定义的XML文件来存储。本课程推荐使用XML方式来存储,XML的操作在后续课程中讲详细讲解;进程当前目录默认情况下,进的当前目录就是用来建立进程的exe文件所在的目录程序可以通过调用GetCurrentDirectory方法得到当前的目录可以通过调用SetCurrentDirector
9、y方法改变当前目录当前目录将影响一些API的行为,比如打开一个文件或文件对话框等的默认路径这两个函数调用比较简单就不再演示调用方法继承子进程可以从父进程继承一些属性和资源;可以通过编程的方法禁止子进程从父进程继承任何东西;可供继承的资源有:由CreateFile打开的可继承句柄;如:文件、控制台、命名管道、串口、邮槽等;进程、线程、互斥对象、信标量、管道、文件映射等的可继承的句柄环境变量当前目录父进程的控制台(可以在创建子进程时通过标志的方法让子进程拥有独立的)CreateProcess函数的bInheritHandles参数指定子进程是否能够继承父进程的句柄,而其他对象都在创建时通过指定安全
10、属性结构体的方式明确指定可否继承缺省的情况下子进程继承父进程的环境变量和当前目录;继承子进程继承的句柄与父进程有相同的值和访问优先权要使用这些对象,子进程必须能够使用Open系列函数打开这些对象的句柄,这要求子进程能够知道这些对象的信息,比如:对象名称不能通过简单的传递句柄值的方式来继承这些对象,因为子进程和父进程在不同的进程虚拟地址空间中,而且句柄值也不相同,所有传递的句柄值实际上是没有意义的要想传递这些对象的有用信息,父进程可以通过命令行的方式或者进程间通信的方式告诉子进程进程间通信可以通过管道、SOCKET、共享内存等来实现进程堆Windows系统为每个进程都默认创建了一个进程默认堆使用
11、GetProcessHeap方法可以得到这个默认堆的句柄(详情请复习第一讲)使用GetProcessHeaps方法可以得到当前进程中所有堆的句柄数组(包括默认堆和用CreateHeap创建的堆)堆属于整个进程,因此进程中所有的线程都可以看到这些堆,并且可以平等的操作在多线程环境中一定要使用串行化堆(不要设置HEAP_NO_SERIALIZE标准,详情复习第一讲)进程的对象列表在第六讲中,演示了一个可以查看系统所有句柄和对象的程序利用这个程序,可以通过取得的句柄的ProcessID=GetCurrentProcessID方法来过滤出属于本进程的句柄对象列表需要注意的是一般情况下,任何属于进程的内
12、核对象,对于进程内的所有线程来说都是可以访问的,因此内核对象的一些API内部本身都是严格串行化的,也就是说多线程操作是安全的(GUI和GDI对象不是严格串行化的)进程的亲缘性可以通过调用SetProcessAffinityMask将进程中线程的调度运行限定在多核系统的某几个特定的CPU上(CPU子集)此函数的第二个参数dwProcessAffinityMask是一个位向量,每一个二进制位对应表示相应序号的CPU,当该位为1时表示使用这个序号的CPU,否则就是不使用这个CPUCPU序号从031,对应无符号32位值的相应位通过调用GetSystemInfo方法可以得到系统中CPU的个数(多核CPU
13、被认为是独立的CPU)在Vista以上系统中通过调用GetLogicalProcessorInformation方法可以得到关于CPU的详细信息,包括NUMA、SMT、Catch等信息本讲示例GetLogicCPU就是一个演示调用GetLogicalProcessorInformation获取CPU信息的例子注意:进程亲缘性会被子进程继承创建进程CreateProcess任何类型的应用程序都可以通过调用CreateProcess函数来创建一个新的进程BOOL WINAPI CreateProcess(LPCTSTR lpApplicationName,LPTSTR mandLine,LPSEC
14、URITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCTSTR lpCurrentDirectory,LPSTARTUPINFO lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation);这个新的进程将拥有新的独立的虚拟地址空间和独立的资源此新进程就是当前进程(调用CreateProcess的进程)的子进
15、程CreateProcess提供两种标识要执行程序的方法:lpApplicationName mandLine 如果lpApplicationName是NULL,那么程序就在 mandLine中指定如果CreateProcess成功,则返回包含新进程和其主线程的句柄与ID在PROCESS_INFORMATION结构体中即使通过安全描述符可以限制子进程句柄的访问权限,父进程对子进程的句柄仍然有完全的访问权创建进程CreateProcess通过STARTUPINFO结构体对象父进程可以指定与其子进程的主窗口有关的属性对于GUI进程来说,STARTUPINFO结构指定新进程第一次调用CreateWi
16、ndow和ShowWindow建立和显示重叠窗口时使用的缺省值:窗口的宽和高(单位:像素)窗口左上角位置ShowWindow的nCmdShow参数对于控制台进程而言,只有在新进程用CREATE_NEW_CONSOLE调用CreateProcess,或新进程自行调用AllocConsole时,STARTUPINFO才起作用,此时该结构控制如下内容:新控制台屏幕大小和位置(单位:字符)新控制台屏幕缓冲大小新控制台屏幕缓冲器字体和颜色等属性新控制台窗口标题CreateProcess示例使用多进程的一些提示何时使用多进程呢?会带来什么好处呢?这是一个需要思考的问题因为子进程是在独立的进程空间中执行,所
17、以它有一个先天的优势就是子进程的任何未处理异常不会迫使父进程退出(异常处理机制实际很多时候处理不了全部可能的异常)利用这个特点,可以将一些容易出错的任务创建成子进程比如:一个服务程序需要处理很多用户请求,但是可能潜在的攻击行为会使服务进程异常退出,此时就可以考虑将用户分成组,并为每组不同的用户创建不同的进程进行服务,这样即使被恶意攻击而导致进程异常退出,后果也只是哪一组用户数据丢失而已,可以将危害缩小到很小的范围终止进程下面几组条件之一成立时,进程终止:进程中任何线程调用了ExitProcess进程的主线程返回(隐含调用ExitProcess)进程的最后一个线程终止用进程句柄调用Termina
18、teProcess进程终止时发生下列事件:关闭进程打开的文件或其它对象的句柄(对象不一定销毁);进程对象的状态置为有信号的,使得等待该句柄的函数可以返回进程的终止状态从STILL_ACTIVE变成进程的退出代码父进程终止时,子进程不自动终止;终止进程ExitProcess将通知所有附属进程中的DLL,并保证进程中的全部线程都终止,因此它是终止进程的首先方法;(应用程序只需保证所有线程均正常终止即可)除非万不得已的情况下,不要调用TerminateProcess方法来终止进程,因为它不会通知dll进程退出(实际就是不调用dll的dllmain函数)调用ExitProcess和TerminateP
19、rocess时,进程中的所有线程是终止运行的,此时结构化异常处理中的_finally块也没有机会被执行,因此尽量不要自行调用这些函数来终止进程GetExitCodeProcess函数可以得到进程的终止状态,如果进程仍在运行,返回码是STILL_ACTIVE,否则就返回进程的退出代码重定向进程的输入和输出很多Windows命令程序都是控制台进程,默认情况下控制台应用都会输入输出信息到父进程的输入输出控制台中通过设置STARTUPINFO中dwFlags为STARTF_USESTDHANDLES,并指定相应的句柄值HANDLE hStdInput;HANDLE hStdOutput;HANDLE
20、hStdError;即可重定向标准输入、输出、错误信息到指定的句柄中以上的句柄值可以是CreateFile创建的标准控制台、文件、管道、串口等字符设备对象的句柄(在后面将详细讲解CreateFile函数)重定向示例其它的创建进程的方法默认情况下CreateProcess创建的进程,其所属用户组等安全信息是当前进程(调用CreateProcess的进程)的用户组通过调用CreateProcessAsUser方法可以指定创建一个不同的用户组身份的进程,此方法比CreateProcess多了一个代表不同用户组的访问字符串Token句柄,通过LogonUser方法可以得到不同用户组的Token,这样就
21、可以改变子进程的访问字符串特性(关于Token请复习第7讲)通过CreateProcessWithLogonW方法可以直接利用已知的用户名、域、密码信息创建一个不同身份Token的进程,这相当于在内部组合了LogonUser和CreateProcessAsUser方法这两个方法详情参见MSDN不再演示调用示例外壳中启动进程的方法在Windows外壳(shell)中有一个方便的根据文件类型启动相应进程的方法ShellExecute(更多信息版本ShellExecuteEx)可以用以下几种方式调用ShellExecute来达到不同的目的:打开一个文件夹: ShellExecute(hWnd, NU
22、LL, , NULL, NULL, SW_SHOWNORMAL);ShellExecute(hWnd, open, , NULL, NULL, SW_SHOWNORMAL);有资源管理器打开一个文件夹:ShellExecute(hWnd, explore, , NULL, NULL, SW_SHOWNORMAL);打开查找文件:ShellExecute(hWnd, find, , NULL, NULL, 0);打开Windows计算器、记事本等:ShellExecute(hWnd,open,calc.exe,NULL,NULL,SW_SHOW);ShellExecute(hWnd,open,notepad.e
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 【正版授权】 IEC 62290-1:2025 EN-FR Railway applications - Urban guided transport management and command/control systems - Part 1: System principles and fundamental concepts
- 2025年戏剧表演与导演课程考试试题及答案
- 2025年食品科学与工程试卷及答案
- 2025年法律学专业考生复习试题及答案
- 2025年翻译专业能力测试试题及答案
- 2025年公共卫生政策相关考试试卷及答案
- 2025年机关行政管理考试题及答案
- 餐饮合股合同协议书样本
- 2025年非机械驱动车辆合作协议书
- 一致行动协议书
- 网络系统集成(项目式微课版)-课程标准
- 2023年国家知识产权局知识产权检索咨询中心招聘笔试真题
- 人力资源管理:基于创新创业视角学习通超星期末考试答案章节答案2024年
- 安全环保职业健康法律法规清单2024年
- 2024年国家公务员考试《行测》真题卷(地市卷)-答案和解析
- 2024年注册安全工程师真题答案与解析【法规】
- 初中心理健康 开出友谊的新花朵 教案
- 个人换汇合同协议书范文
- 卫生院优化服务环境提升社会满意度整改方案
- 驾驶员心理疏导培训
- 2025年高级卫生专业技术资格考试传染性疾病控制(087)(副高级)试卷及答案指导
评论
0/150
提交评论