编程中的进程管理_第1页
编程中的进程管理_第2页
编程中的进程管理_第3页
编程中的进程管理_第4页
编程中的进程管理_第5页
已阅读5页,还剩62页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Windows系统编程实用教程授课教师:职务:第7章 进程编程课程描述大多数应用程序都以进程的形式运行,有时还需要在应用程序里运行或结束其他进程。本章将介绍Windows进程编程的方法。本章知识点7.1 进程编程基础7.2 基本进程编程7.3 进程间通信7.1 进程编程基础7.1.1 什么是进程7.1.2 进程的状态7.1.1 什么是进程进程是正在运行的程序的实例。每个运行的Visual C+项目都对应一个进程,每个进程至少包含一个线程,它从main()函数开始执行,直到执行return语句返回,主线程结束,该进程也被从内存中卸载。进程由如下几个部分组成。与程序相关联的可执行代码的映像;内存空

2、间(通常是虚拟内存中的一些区域),其中保存可执行代码、进程的特定数据、用于记录活动例程和其他事件的调用栈、用于保存实时产生的中间计算结果的堆(heap)。分配给进程的资源的操作系统描述符(比如文件句柄)以及其他数据资源。安全属性,比如进程的所有者和权限。处理器的状态,比如寄存器的内容、物理内存地址等。7.1.2 进程的状态7.2 基本进程编程7.2.1 创建进程7.2.2 枚举系统进程7.2.3 终止进程7.2.1 创建进程在应用程序中可以调用CreateProcess()函数创建一个新进程、运行其他程序,函数原型如下:BOOL WINAPI CreateProcess( _in LPCTST

3、R lpApplicationName, _in_out LPTSTR lpCommandLine, _in LPSECURITY_ATTRIBUTES lpProcessAttributes, _in LPSECURITY_ATTRIBUTES lpThreadAttributes, _in BOOL bInheritHandles, _in DWORD dwCreationFlags, _in LPVOID lpEnvironment, _in LPCTSTR lpCurrentDirectory, _in LPSTARTUPINFO lpStartupInfo, _out LPPROCE

4、SS_INFORMATION lpProcessInformation);参数说明lpApplicationName,要执行的应用程序名,可以包括结对路径和文件名,通常可以为NULL。lpCommandLine,要执行的命令行。lpProcessAttributes,新进程的安全描述符。lpThreadAttributes,指定主线程的安全描述符。如果为NULL,则使用默认的安全描述符。bInheritHandles,指示新进程是否从调用进程处继承句柄。dwCreationFlags,指定附加的、用来控制优先类和进程创建的标志。lpEnvironment,指向新进程的环境块。如果为NULL,则

5、使用调用CreateProcess()函数的进程的环境。【例7.1】调用CreateProcess()函数运行Windows计算器程序,并显示新进程的ID号,及其主线程的Id号,代码如下:#include stdafx.h#include int _tmain(int argc, _TCHAR* argv)char szCommandLine=calc.exe;STARTUPINFO si = sizeof(si);PROCESS_INFORMATION pi;si.dwFlags = STARTF_USESHOWWINDOW; / 指定wShowWindow成员有效si.wShowWindo

6、w = TRUE; / 显示新建进程的主窗口接上BOOL bRet = CreateProcess (NULL, / 不在此指定可执行文件的文件名szCommandLine, / 命令行参数NULL,/ 默认进程安全性NULL,/ 默认进程安全性FALSE,/ 指定当前进程内句柄不可以被子进程继承CREATE_NEW_CONSOLE, / 为新进程创建一个新的控制台窗口NULL,/ 使用本进程的环境变量NULL,/ 使用本进程的驱动器和目录&si,&pi) ; if(bRet)/ 关掉不使用的句柄CloseHandle(pi.hThread);CloseHandle(pi.hProcess);

7、printf(新进程的ID号:%dn,pi.dwProcessId);printf(新进程的主线程ID号:%dn,pi.dwThreadId); system(pause);return 0;【例7.1】的运行结果ShellExecute()函数HINSTANCEShellExecute(HWNDhwnd,/ 指定显示用户界面和错误信息的窗口句柄LPCTSTRlpOperation,/ 对指定文件要执行的操作LPCTSTRlpFile,/ 要执行操作的文件或对象LPCTSTRlpParameters,/ 指定传送给应用程序的参数LPCTSTRlpDirectory,/ 指定执行操作的工作目录I

8、NTnShowCmd/ 指定应用程序如何显示。SW_HIDE表示隐藏窗口,SW_MAXIMIZE表示最大化窗口,SW_MINIMIZE表示最小化窗口,SW_SHOW表示在当前位置上以当前大小显示窗口,等等);pOperation参数的取值取 值说 明edit打开一个文档文件进行编辑。如果参数lpFile指定的不是一个文档文件,则操作失败explore打开资源管理器查看指定文件所在的目录find从参数lpDirectory指定的目录开始搜索open打开指定的对象print打印指定的对象。如果参数lpFile指定的不是一个文档文件,则操作失败NULL执行默认的操作,通常执行open操作【例7.2】

9、【例7.2】调用ShellExecute ()函数访问google网站,代码如下:#include stdafx.h#include windows.h”int _tmain(int argc, _TCHAR* argv)ShellExecute(NULL, open, , , , SW_SHOW);return 0;7.2.2 枚举系统进程1使用EnumProcesses()函数2使用进程快照1使用EnumProcesses()函数BOOL WINAPI EnumProcesses( _out DWORD* pProcessIds,/ 用于接收进程标示符列表的数组 _in DWORD cb,

10、/ 数组pProcessIds的大小,单位是字节 _out DWORD* pBytesReturned/ 数组pProcessIds中返回数据的大小,单位是字节);如果函数执行成功,则返回一个非0值;否则返回0。【例7.3】调用EnumProcess ()函数枚举当前Windows运行进程的标示符(PID),代码如下:#include stdafx.h#include #include #pragma comment(lib, Psapi.lib)int _tmain(int argc, _TCHAR* argv) / 用于接收返回的进程ID信息的数组 DWORD dwProcs1024*2;

11、 DWORD dwNeeded;/返回进程数组的大小 /枚举所有进程ID。接上 if (!EnumProcesses( dwProcs, sizeof(dwProcs), &dwNeeded) /输出出错信息。 printf(EnumProcesses failed (%d).n, GetLastError(); else DWORD dwProcCount = dwNeeded / sizeof(DWORD);for(int i=0; idwProcCount; i+)printf(PID: %dn,dwProcsi); system(pause);return 0;【例7.3】的运行结果2

12、使用进程快照HANDLE WINAPI CreateToolhelp32Snapshot( DWORD dwFlags, /指定快照中包含的对象 DWORD th32ProcessID / 指定获取进程快照的PID。如果为0,则获取当前系统进程列表);如果函数执行成功,则返回进程快照的句柄;否则返回INVALID_HANDLE_VALUE。Process32First()函数调用Process32First()函数可以从进程快照中获取第1个进程的信息,函数原型如下:BOOL WINAPI Process32First( HANDLE hSnapshot, / 之前调用createtoolhel

13、p32napshot()函数得到的进程快照句柄 LPPROCESSENTRY32 lppe / 包含进程信息的结构体);结构体LPPROCESSENTRY32LANA_ENUM结构体中包含当前逻辑网络适配器的数量。当一个物理网络适配器绑定到一个网络协议时,就对应一个逻辑网络适配器。执行NCB命令NCBENUM可以向LANA_ENUM结构体中填充逻辑网络适配器的个数和逻辑网络适配器编号,此时NCB结构体中的ncb_buffer成员变量指向LANA_ENUM结构体。LANA_ENUM结构体的定义代码如下:typedef struct _LANA_ENUM UCHAR length; UCHAR l

14、anaMAX_LANA;LANA_ENUM, *PLANA_ENUM;参数说明如下:length,系统中包含的逻辑网络适配器数量。lanaMAX_LANA,系统中包含的逻辑网络适配器编号数组。Process32Next()函数调用Process32Next()函数可以从进程快照中获取下一个进程的信息,函数原型如下:BOOL WINAPI Process32Next( HANDLE hSnapshot, 、/ 之前调用createtoolhelp32napshot()函数得到的进程快照句柄 LPPROCESSENTRY32 lppe / 包含进程信息的结构体);如果函数执行成功,则返回TRUE;

15、否则返回FALSE。【例7.4】利用进程快照枚举当前Windows运行进程的信息,代码如下:#include stdafx.h#include windows.h#include tlhelp32.hint _tmain(int argc, _TCHAR* argv)PROCESSENTRY32 pe;/设置结构体pe的大小pe.dwSize = sizeof(pe);/获取系统内进程的快照HANDLE hProcessSnap = :CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);if (hProcessSnap = INVALID_HANDLE

16、_VALUE) printf(CreateToolhelp32Snapshot error.n);return -1;接上/遍历进程快照,显示每个进程的信息BOOL bMore = :Process32First(hProcessSnap,&pe);while (bMore) printf(=n);printf(Process Name:%sn,pe.szExeFile);printf(PID:%un,pe.th32ProcessID);printf(Number of Thread:%un,tThreads);printf(=n);bMore = :Process32Next(hProces

17、sSnap,&pe);/释放snapshot对象:CloseHandle(hProcessSnap);system(pause);return 0;4ASTAT结构体ASTAT结构体用于描述网络适配器的状态和名字信息,定义代码如下:typedef struct ADAPTER_STATUS adapt; NAME_BUFFER NameBuff30; ASTAT;参数adapt表示网络适配器的状态信息,参数NameBuff表示网络适配器中保存的本地网络名字信息。【例7.4】的运行结果7.2.3 终止进程进程从主函数的第一行代码开始执行,直到主函数结束时终止;也可以强制结束一个进程。当进程被终止

18、时,系统会进行下面的操作:进程中的所有线程都被标记为“终止”状态;分配给进程的所有资源都会被释放掉;所有与该进程相关的内核对象都会被关闭;从内存中移除该进程的代码;系统设置进程的退出代码;将该进程对象设置为“受信”(Sigaled)状态。GetExitCodeProcess()函数调用GetExitCodeProcess()函数可以获取进程的终止状态,函数原型如下:BOOL WINAPI GetExitCodeProcess( _inHANDLE hProcess,/ 进程句柄 _outLPDWORD lpExitCode/ 用于接收进程的终止状态);如果函数执行成功,则返回TRUE;否则返回

19、FALSE。当进程在运行中时,其终止状态为STILL_ACTIVE。当进程被终止时,其终止状态变成退出代码。ExitProcess()函数在进程中调用ExitProcess()函数终止其自身中所有的线程,函数原型如下:VOID WINAPI ExitProcess( _inUINT uExitCode/ 退出代码);TerminateProcess()函数调用TerminateProcess()函数可以终止指定的进程,函数原型如下:BOOL WINAPI TerminateProcess( _inHANDLE hProcess,/ 要终止的进程句柄 _inUINT uExitCode/退出代码

20、);7.3 进程间通信7.3.1 通过自定义消息进行通信7.3.2 通过管道进行通信7.3.3 使用互斥体7.3.4 通过共享内存进行通信7.3.1 通过自定义消息进行通信1定义自定义消息的代码2发送消息3消息处理函数1定义自定义消息的代码为了唯一标识自定义消息,需要为其定义一个消息代码。自定义的消息代码都比WM_USER要大,因为0 WM_USER-1是保留给系统消息使用。可以使用下面的代码定义一个自定义消息WM_MY_MESSAGE:#define WM_MY_MESSAGE (WM_USER+100)2发送消息调用PostMessage()函数将消息放置到与创建指定窗口的进程相关联的消息

21、队列中,函数不需要等待接收方接受和处理消息就直接返回。函数原型如下:BOOL PostMessage( HWND hWnd, / 接收消息的窗口句柄,使用HWND_BROADCAST表示所有顶层窗口 UINT Msg, / 发送消息的代码 WPARAM wParam, / 指定消息的附加信息 LPARAM lParam / 指定消息的附加信息); FindWindow()函数HWND FindWindow( LPCTSTR lpClassName, /窗口类名,通常为NULL LPCTSTR lpWindowName / 要查找窗口的标题); 3消息处理函数在接收端需要设计一个消息处理函数,它

22、的格式如下:LRESULTOnMyMsg(WPARAM wParam, LPARAM lParam)/ 处理代码return 0;参数wParam和lParam用于接收PostMessage()函数发送消息时指定的参数。将消息与其处理函数映射起来定义消息处理函数后还要将消息与其处理函数映射起来。在每个MFC对话框对应的.cpp文件中,都在BEGIN_MESSAGE_MAP宏和END_MESSAGE_MAP()宏之间定义消息与其处理函数映射的,例如:BEGIN_MESSAGE_MAP(CReceiverDlg, CDialog)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_

23、WM_QUERYDRAGICON()/AFX_MSG_MAPEND_MESSAGE_MAP()BEGIN_MESSAGE_MAP宏BEGIN_MESSAGE_MAP宏用于标识消息映射的开始,其原型如下:BEGIN_MESSAGE_MAP(theClass, baseClass )参数theClass指定消息映射所属的类,通常是窗口类;参数baseClass指定参数theClass的基类。在BEGIN_MESSAGE_MAP宏和END_MESSAGE_MAP()宏之间添加一条ON_MESSAGE宏用于定义自定义消息及其处理函数的映射。ON_MESSAGE宏的原型如下:ON_MESSAGE(mes

24、sage, memberFxn )参数message用于指定自定义消息的代码,参数memberFxn指定消息处理函数。【例7.5】设计一个利用自定义消息实现进程间通信的例子。1设计发送端项目2设计接收端项目1设计发送端项目创建一个基于对话框的MFC应用程序Sender,定义自定义消息WM_MY_MESSAGE,代码如下:#define WM_MY_MESSAGE (WM_USER+999)单击“发送消息”按钮的代码void CSenderDlg:OnBnClickedButtonSendmsg()HWND hWnd = :FindWindow(NULL, Receiver); :PostMes

25、sage(hWnd,WM_MY_MESSAGE, (WPARAM)999, NULL );2设计接收端项目创建一个基于对话框的MFC应用程序Receiver,定义自定义消息WM_MY_MESSAGE,代码如下:#define WM_MY_MESSAGE (WM_USER+999)编写消息处理函数OnMyMsg(),代码如下:LRESULT CReceiverDlg:OnMyMsg(WPARAM wParam, LPARAM lParam)char msg100;sprintf(msg, %d, (int)wParam);MessageBox(msg, 收到消息);return 0;添加自定义消

26、息及其处理函数的映射BEGIN_MESSAGE_MAP(CReceiverDlg, CDialog) ON_MESSAGE(WM_MY_MESSAGE, OnMyMsg) / 映射消息和处理函数/AFX_MSG_MAPEND_MESSAGE_MAP()7.3.2 通过管道进行通信管道(Pipe)是由标准输入输出流构成的进程链。一个进程的输出直接作为下一个进程的输入。每个连接都是一个匿名管道。管道包含一个写句柄和一个读句柄。一个进程使用写句柄向管道里写入数据,另一个进程使用读句柄从管道中读取数据。调用CreatePipe()函数可以创建管道,函数原型如下:BOOL WINAPI CreatePi

27、pe( _out PHANDLE hReadPipe,/ 管道的读句柄 _out PHANDLE hWritePipe, _in LPSECURITY_ATTRIBUTES lpPipeAttributes, _in DWORD nSize);【例7.6】设计一个利用管道实现进程间通信的例子。主进程Server的代码如下:#include stdafx.h#include int _tmain(int argc, _TCHAR* argv)HANDLE hRead; / 管道读句柄HANDLE hWrite; / 管道写句柄SECURITY_ATTRIBUTES sa; / 设置管道属性sa.

28、nLength = sizeof(SECURITY_ATTRIBUTES);sa.lpSecurityDescriptor = NULL;sa.bInheritHandle = TRUE;/ 指定管道句柄可以被子进程继承BOOL bRet = CreatePipe(&hRead, &hWrite, &sa, 0); / 创建匿名管道if (bRet = TRUE)printf(成功创建匿名管道!n);elseprintf(创建匿名管道失败,错误代码:%dn, GetLastError(); 接上/ 得到本进程的当前标准输出,以备将来恢复HANDLE hTemp = GetStdHandle(S

29、TD_OUTPUT_HANDLE); / 设置标准输出到匿名管道SetStdHandle(STD_OUTPUT_HANDLE, hWrite); STARTUPINFO si; GetStartupInfo(&si); / 获取本进程的STARTUPINFO结构信息,包括标准设备的句柄PROCESS_INFORMATION pi; / 创建客户端子进程Client.exe,它会继承父进程的标准输出,因此Client.exe的标准输出是到hWrite管道的bRet = CreateProcess(NULL, Client.exe, NULL, NULL, TRUE, NULL, NULL, NU

30、LL, &si, &pi); SetStdHandle(STD_OUTPUT_HANDLE, hTemp); / 恢复本进程的标准输出if (bRet = TRUE) / 输入信息printf(成功创建子进程!n); elseprintf(创建子进程失败,错误代码:%dn, GetLastError(); 接上/ 读管道直至管道关闭char ReadBuf100;DWORD ReadNum;/ 循环从管道中读取数据while (Read, ReadBuf, 100, &ReadNum, NULL) ReadBufReadNum = 0;printf(从管道读取%d字节数据:【%s】n, Rea

31、dNum, ReadBuf);if (GetLastError() = ERROR_BROKEN_PIPE) / 输出信息printf(管道被子进程关闭n);elseprintf(读数据错误,错误代码:%dn, GetLastError(); return 0;子进程Client的代码#include stdafx.h#include #include using namespace std;int _tmain(int argc, _TCHAR* argv)for (int i = 0; i 10; i+) / 发送一些数据到标准输出和标准错误printf(i = %d; , i); / 打

32、印提示cout 标准输出: i endl; / 打印到标准输出cerr 标准错误: i endl; / 打印到标准错误return 0;【例7.6】的运行结果7.3.3 使用互斥体HANDLE WINAPI CreateMutex( _in LPSECURITY_ATTRIBUTES lpMutexAttributes,/ 互斥体对象的安全属性,如果为NULLZ,则互斥体对象不能被子进程继承 _in BOOL bInitialOwner,/ 初始化互斥对象的所有者 _in LPCTSTR lpName/ 指定互斥对象的名字);如果在不同进程间使用互斥体,则该互斥体对象是全局的。全局互斥体对象的

33、名字必须以“Global”为前缀,而本地互斥体对象的名字则以“Local”为前缀。【例7.7】设计一个利用互斥体防止运行一个应用程序的多个实例的例子Mutex,代码如下:int _tmain(int argc, _TCHAR* argv)CreateMutex(NULL,TRUE, GlobalMyMutex001); if(GetLastError()=ERROR_ALREADY_EXISTS) printf(应用程序已经运行!n);exit(0); printf(已进入应用程序n);system(pause);return 0;第1次运行Mutex.exe的结果7.3.4 通过共享内存进行

34、通信每个Windows进程都有其私有的内存空间。任何进程都不能修改其他进程的内存空间,包括变量和对象等。但是多个进程间可以通过一块共享内存进行通信。共享内存是允许多个进程同时访问的内存,不同的进程可以通过共享内存进行通讯,也可以避免在不同的程序中保存多余的数据备份。通常可以使用内存映射文件实现共享内存,用内存映射文件是由一个文件到一块内存的映射。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的内存区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。使用内存映射文件处理存储于磁盘上的文

35、件时,将不必再对文件执行过多的I/O操作,因此,内存映射文件在处理大数据量的文件时能起到相当重要的作用。Create()函数HANDLE Create( HANDLE hFile, LPSECURITY_ATTRIBUTES lp, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCTSTR lpName );参数说明hFile:创建映射对象的文件句柄,如果使用INVALID_HANDLE_VALUE,则在物理内存中创建映射对象。lp:被忽略,必须为NULL。flProtect,文件视图的保护方式。dwMa

36、ximumSizeHigh,指定文件映射对象最大大小的高32位。dwMaximumSizeLow,指定文件映射对象最大大小的低32位。lpName,映射对象的名字,如果是全局映射对象,则名字可以以“Global”前缀开始。MapViewOfFile()函数调用MapViewOfFile()函数可以将指定的文件视图映射到调用进程的地址空间,函数原型如下:LPVOID MapViewOfFile( HANDLE h, /文件映射对象的句柄,通常由Create()函数返回 DWORD dwDesiredAccess, / 对文件视图的访问类型 DWORD dw, / 指定开始映射的文件偏移量的高32

37、位 DWORD dw, / 指定开始映射的文件偏移量的低32位 DWORD dwNumberOfBytesToMap / 指定文件映射的字节数。如果为0,则映射整个文件。);Open()函数HANDLE WINAPI Open( _in DWORD dwDesiredAccess,/ 访问权限 _in BOOL bInheritHandle,/ 指定子进程是否可以继承句柄 _in LPCTSTR lpName/指定要打开指定的文件映射对象的名字);如果函数执行成功,则返回打开指定的文件映射对象句柄;否则返回NULL。可以调用GetLastError()函数获取错误代码。UnmapViewOfF

38、ile()函数调用UnmapViewOfFile()函数可以从调用进程的地址空间中解除文件视图的映射。函数原型如下:BOOL UnmapViewOfFile( LPCVOID lpBaseAddress / 要解除的文件视图映射的基地址);【例7.8】计一个创建文件映射对象,并向映射视图中写入数据的例子Process1,代码如下:#include stdafx.h#include #include #include #define BUF_SIZE 256/ 共享内存的大小TCHAR szName=TEXT(GlobalMy);/文件映射对象的名字TCHAR szMsg=TEXT(Message from process1); / 向共享内存中写入的数据int _tmain(int argc, _TCHAR* argv) HANDLE hMapFile; LPCTSTR pBuf;接上/ 创建文件映射对象 hMapFile = Create( INVALID_HANDLE_VALUE, / 使用页文件 NULL, PAGE_READWRITE, / 可读写 0, BUF_SI

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论