实验2Windows应用程序基础和进程控制.docx
- 文档编号:8835057
- 上传时间:2023-02-02
- 格式:DOCX
- 页数:20
- 大小:28.38KB
实验2Windows应用程序基础和进程控制.docx
《实验2Windows应用程序基础和进程控制.docx》由会员分享,可在线阅读,更多相关《实验2Windows应用程序基础和进程控制.docx(20页珍藏版)》请在冰豆网上搜索。
实验2Windows应用程序基础和进程控制
实验二:
Windows进程控制
1.实验目的
每个进程都有一个独立的受到保护的地址空间,其他进程不能访问。
一个进程可以包含一个或更多的线程。
进程能够在其内部创建新的、独立的线程,并且管理对象间的通信和同步。
通过对Windows系统编程,进一步熟悉操作系统的基本概念,较好地理解Windows操作系统的系统结构和编程特点。
2.进程控制
Windows所创建的每个进程都从调用CreateProcess()API函数开始,该函数的任务是在对象管理器子系统内初始化进程对象。
每一进程都以调用ExitProcess()或TerminateProcess()API函数终止。
通常应用程序的框架负责调用ExitProcess()函数。
对C++运行库来说,这一调用发生在应用程序的main()函数返回之后,如果采用C运行库,则调用WinMain()函数。
通过创建进程、观察正在运行的进程和终止进程的程序设计和调试操作,进一步熟悉操作系统的进程概念,理解Windows进程的生命周期。
2.1进程控制相关的API
基本的Win32进程管理函数是CreateProcess,它可以创建拥有单个线程的进程。
因为进程需要代码,所以有必要指定可执行程序文件名作为CreateProcess调用的一部分。
CreateProcess有10个参数支持其灵活性和强大功能。
该函数并不返回一个HANDLE,而是在一个结构(在调用中指定)中返回表示进程和线程的两个句柄。
2.1.1创建进程CreateProcess()函数
函数格式:
BOOLCreateProcess(LPCTSTRlpApplicationName,LPTSTRlpCommandLine,
LPSECURITY_ATTRIBUTESlpProcessAttributes,
LPSECURITY_ATTRIBUTESlpThreadAttributes,
BOOLbInheritHandles,DWORDdwCreationFlags,
LPVOIDlpEnvironment,LPCTSTRlpCurrentDirectory,
LPSTRATUPINFOlpStartupInfo,
LPPROCESS_INFORMATIONlpProcessInformation);
参数:
(1)lpszApplicationName和lpCommandLine指定了新进程将使用的可执行文件和传递给新进程的命令行字符串。
lpszCommandLine可以设定CreateProcess中用于创建新进程的命令行。
CreateProcess在解析lpszCommandLine字符串的时候,它先查看字符串中的第一个符号。
如果它是一个可执行文件名且不含有扩展名,就假定它的扩展名为EXE。
CreateProcess将按照以下顺序来搜索可执行文件:
1)含有调用进程的EXE文件的目录;
2)调用进程的当前目录;
3)Windows系统目录,该目录由GetSystemDirectory函数得到;
4)Windows目录,该目录由GetWindowsDirectory函数得到;
5)列在PATH环境变量中的目录。
当然,如果文件名中包含完整的路径,系统就使用完整路径搜索可执行文件。
如果系统找到了可执行文件,就创建一个新进程,并为它生成一个4GB的地址空间,从而使可执行文件的代码和数据映射到这个地址空间。
(2)lpProcessAttribute和lpThreadAttribute是指向进程和线程安全属性结构的指针。
当用NULL表示时,为默认的安全性。
(3)FInheritHandles表明新进程是否继承调用进程的打开句柄的副本。
继承的句柄与原来的句柄具有相同属性。
(4)FdwCreate是几个标志的组合。
其中包含以下几个标志:
1)CREATE_SUSPENDED:
新进程的主线程创建时处于挂起状态,直到调用ResumeThread函数时才能运行。
2)DETACHED_PROCESS和CREATE_NEW_CONSOLE相互排斥,二者不能同时使用。
第一个标志是创建没有控制台的进程,第二个标志是创建新的有控制台的进程。
如果二者都没有设置,进程将继承父进程的控制台。
3)CREATE_NEW_PROCESS_GROUP指定新进程是新进程组的根进程。
如果组中所有的进程都共享同一控制台,则它们都将接收控制台的控制信号。
(5)lpvEnvironment指向新进程的环境块。
如果此值为NULL,进程会使用父进程的环境块。
环境块包含名称和值字符串,如搜索路径。
(6)lpszCurDir指向新进程的驱动器和目录。
若为NULL,将使用父进程的工作目录。
(7)lpsiStartInfo指向新进程的主窗口外观和标准设备句柄。
使用GetStartupInfo函数得到父进程信息。
(8)lpProcessInformation指向包含返回的进程和线程句柄、进程和线程标识符的PROCESS_INFORMATION结构的指针。
返回值:
如果进程和主线程创建成功,则返回TRUE。
该函数可使系统创建一个进程内核对象和一个线程内核对象。
且打开进程和线程对象,并将与进程相关的每个对象句柄放入PROCESS_INFORMATION的结构中。
PROCESS_INFORMATION结构定义如下:
Typedefstruct_PROCESS_INFORMATION
{
HANDLEhProcess;//新创建进程的句柄
HANDLEhThread;//新创建进程的主线程的句柄
DWORDdwProcessId;//新创建进程的标识
DWORDdwThreadId;//新创建进程的主线程的标识
}PROCESS_INFORMATION,*LPPROCESS_INFORMATION;
为了保护被创建的对象,系统定义了对象的安全属性结构,其定义如下:
Typedefstruct_SECURITY_AFFRIBUTES
{
LPVOIDlpSecurityDesriptor;
BOOLhInheritHandle;
}
其中,nLength代表这个结构的以字节为单位的大小,lpSecurityDescriptor是控制共享该对象的安全描述符的指针。
如果该值为0,该对象被赋予默认的安全描述符。
bInheritHandle是一个布尔值,指示返回的对象句柄是否可被新创建进程继承,TRUE表示可以继承。
2.1.2获得当前进程的标识符GetCurrentProcessId()函数
函数格式:
DWORDGetCurrentProcessId(void);
参数:
无。
返回值:
返回当前进程的标识符。
2.1.3挂起当前的执行线程Sleep()函数
函数格式:
VOIDSleep(DWORDdwMilliseconds);
参数:
dwMilliseconds为指定的挂起执行线程的时间,以毫秒为单位。
取值为0时,该线程将余下的时间片交给处于就绪状态的同一优先级的其他线程。
若没有处于就绪状态的同一状态的其他线程,则函数立即返回,该线程继续执行。
若取值为INFINITE则造成无限延迟。
返回值:
该函数没有返回值。
2.1.4关闭对象CloseHandle()函数
函数格式:
BOOLCloseHandle(HANDLEhObject);
参数:
hObject代表一个已打开对象的句柄。
返回值:
执行成功返回TRUE,否则返回FALSE,并可以调用GetLastError()获知失败原因。
关闭一个内核对象,其中包括文件、文件映射、进程、线程、安全和各种同步对象等。
在创建或打开对象成功返回该对象的句柄时,系统会为该对象设置一个打开计数,且将该内核对象的计数加1.该函数的作用与释放动态申请的内存空间类似,这样可以保证系统资源不会泄漏,程序可以在安全的状态下运行。
CloseHandle()函数使指定的对象句柄数减1。
当对象的句柄计数为0时,该对象就从系统中被删除。
2.1.5创建子进程的程序示例
例1:
通过显示创建子进程的基本框架,来观察子进程的创建情况。
//创建子进程的文件proc_create.cpp
#include
#include
#include
//创建一个克隆的进程并赋予其ID值
voidStartClone(intnCloneID)
{
//获得用于当前可执行文件的文件名
TCHARszFilename[MAX_PATH];
GetModuleFileName(NULL,szFilename,MAX_PATH);
//创建子进程命令行的格式化,获得应用程序的EXE文件名和克隆进程的ID值
TCHARszCmdLine[MAX_PATH];
sprintf((char*)szCmdLine,"\"%s\"%d",szFilename,nCloneID);
STARTUPINFOsi;//用于子进程的STARTUPINFO结构
ZeroMemory(reinterpret_cast
si.cb=sizeof(si);
PROCESS_INFORMATIONpi;//说明一个用于记录子进程的相关信息的结构变量
BOOLbCreateOK=CreateProcess(
szFilename,//可执行的应用程序的名称
szCmdLine,//指定创建一个子进程的符号标识
NULL,//缺省的进程安全性
NULL,//缺省的线程安全性
FALSE,//不继承打开文件的句柄
CREATE_NEW_CONSOLE,//使用新的控制台
NULL,//新的环境
NULL,//当前目录
&si,//启动信息
&pi);//返回进程和线程信息
//运行结束,关闭进程和其线程的句柄
if(bCreateOK)
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
intmain(intargc,char*argv[])
{
//确定进程在列表中的位置
intnClone(0);
if(argc>1)
{
//从第二个参数中提取克隆ID
sscanf(argv[1],"%d",&nClone);
}
//显示进程位置
printf("ProcessID:
%d,CloneID:
%d\n",GetCurrentProcessId(),nClone);
//创建2个子进程
constintc_nCloneMax=2;
if(nClone { StartClone(++nClone);//发送新进程的命令行和克隆号 Sleep(1000);//暂停1秒 } Sleep(500);//在终止之前暂停0.5秒 return0; } 本例程序展示了一个简单的使用CreateProcess()API函数的例子。 首先形成简单的命令行,提供当前的EXE文件的指定文件名和代表生成克隆进程的号码。 大多数参数都可取缺省值,但是创建标志参数使用了CREATE_NEW_CONSOLE标志,指示新进程分配它自己的控制台,这使得运行该程序时,在任务栏上产生许多活动标记。 然后该克隆进程的创建方法关闭传递过来的句柄并返回main()函数。 在关闭程序之前,每一进程的执行主线程暂停一下,以便让用户看到其中的至少一个窗口。 2.2进程对象相关的函数 操作系统将当前运行的应用程序看做是进程对象,利用系统提供的进程唯一的称为句柄(HANDLE)的标识,就可与对应的进程对象交互。 2.2.1得到当前进程的句柄GetCurrentProcess()函数 函数格式: HANDLEGetCurrentProcess(void); 参数: 无。 返回值: 若函数调用成功,返回值为当前进程的句柄。 2.2.2打开一个进程OpenProcess()函数 函数格式: HANDLEOpenProcess(DWORDdwDesiredAccess,BOOLbInheritHandle,DWORDdwProcessId); 参数: (1)dwDesiredAccess为指定进程对象的访问权限; (2)bInheritHandle为若要子进程获得对该对象的访问权限,就设置为TRUE,否则设为FALSE; (3)dwProcessId为指定系统范围内的进程标识符。 返回值: 若函数调用成功,则返回进程对象的句柄;否则,返回FALSE。 2.2.3获得进程的优先级类别GetPriorityClass()函数 函数格式: DWORDGetPriorityClass(HANDLE); 参数: HANDLE为指定进程的句柄。 返回值: 若函数调用成功,返回值为指定进程的基本优先级;若函数调用失败,返回值为0。 如果要了解进程的返回码,就需要有PROCESS_QUERY_INFORMATION的访问权限。 2.2.4改变进程优先级SetPriorityClass()函数 函数格式: BOOLSetPriorityClass(HANDLEhProcess,DWORDdwPriorityClass); 参数: hProcessy为指定进程的句柄,dwPriorityClass为指定进程要设置的优先级。 返回值: 函数成功调用,返回值为非0,否则返回值为0。 2.2.5获得系统中当前进程的快照CreateToolhelp32Snapshot()函数 函数格式: HANDLECreateToolhelp32Snapshot(DWORDdwFlags,DWORDth32ProcessID); 参数: dwFlags为指定快照中包括系统线程的情况,th32ProcessID为指定进程的标识符。 返回值: 若函数调用成功,则返回值为进程快照的句柄。 若参数dwFlags为TH32CS_SNAPPROCESS,则表明快照包括系统中的所有线程,且th32ProcessID为包括在快照中进程的进程标识符。 2.2.6将指定的存储空间清0ZeroMemory函数 函数格式: VOIDZeroMemoery(PVOIDDestination,SIZE_TLength); 参数: Destination为指向分配空间的起始地址,Length为分配空间字节长度。 返回值: 该函数没有返回值。 2.2.7获得系统中的第一个进程的快照信息Process32First()函数 函数格式: BOOLProcess32First(HANDLEhSnapshot,LPPROCESSENTRY32lppe); 参数: hSnapshot为指定快照句柄;lppe为指向PROCESSENTRY32结构指针。 返回值: 如果返回值为真,则将系统快照中的第一个进程信息复制到PROCESSENTRY32结构的缓冲区中,否则不做任何操作。 用Process32Next()函数指向下一个进程信息,其中PROCESSENTRY32结构定义如下: typedefstructtagPROCESSENTRY32 { DWORDdwSize; DWORDcntUsage; DWORDth32ProcessID; ULONG_PTRth32DefaultHeapID; DWORDth32ModuleID; DWORDcntThreads; DWORDth32ParentProcessID; LONGpcPriClassBase; DWORDdwFlags; TCHARszExeFile[MAX_PATH]; }PROCESSENTRY32,*PROCESSENTRY32; 2.2.8获得系统下一个进程的快照信息Process32Next()函数 函数格式: BOOLProcess32Next(HANDLEhSnapshot,LPPROCESSENTRY32lppe); 参数: hSnapshot为指定快照句柄;lppe为指定一个PROCESSENTRY32结构。 返回值: 如果进程列表的下一入口点被复制到缓冲区,返回值为真。 2.2.9获得与进程相关的时间信息GetProcessTimes()函数 函数格式: BOOLGetProcessTimes(HANDLEhProcess,LPFILETIMElpCreationTime, LPFILETIMElpExitTime,LPFILETIMElpKernelTime, LPFILETIMElpUserTime); 参数: ·hProcess为一个进程句柄; ·lpCreationTime为包含有进程的创建时间的一个FILETIME结构; ·lpExitTime为包含有进程的终止时间的一个FILETIME结构; ·lpKernelTime为包含有进程在核心态执行时所消耗的时间的一个FILETIME结构; ·lpUserTime为包含有进程在用户态执行时所消耗的时间的一个FILETIME结构。 返回值: 如果函数成功调用,返回值为非0;如果失败,返回值为0。 2.2.10获得进程句柄的程序示例 例2: 获得和使用进程句柄 //获得进程句柄的文件prochandle.cpp #include #include //确定自身优先级的一个简单应用程序 voidmain() { //调用如下函数,以获得当前进程的句柄 HANDLEhProcessThis=GetCurrentProcess(); //获得该进程所属的优先级类 DWORDdwPriority=GetPriorityClass(hProcessThis); //显示当前进程所属的优先级类型 printf("currentprocesspriority: "); switch(dwPriority) { caseHIGH_PRIORITY_CLASS: printf("High\n"); break; caseNORMAL_PRIORITY_CLASS: printf("Normal\n"); break; caseIDLE_PRIORITY_CLASS: printf("Idle\n"); break; caseREALTIME_PRIORITY_CLASS: printf("Realtime\n"); break; default: printf(" break; } } 本例列出的是一种获得进程句柄的方法。 对于进程句柄可进行的唯一有用的操作是在API调用时,将其作为参数传送系统,如程序中的GetPriorityClass()函数的调用所带的就是进程的句柄。 在这种情况下,系统查看进程对象,以决定其优先级,然后将此优先级返回给应用程序。 使用OpenProcess()和CreateProcess()函数也可以用于获得进程句柄,前者获得的是已经存在的进程的句柄,而后者创建一个新进程,并返回其句柄。 2.2.11利用句柄获得进程详细信息的程序示例 例3: 利用进程句柄查出进程的详细信息。 //获得进程句柄信息的文件proclist.cpp // #include #include #include usingnamespacestd; #pragmacomment(lib,"kernel32.lib") //当在用户态及核心态下都提供所耗时间时,计算在核心态下所消耗的时间(以64位表示) DWORDGetKernelModePercentage(constFILETIME&ftKernel, constFILETIME&ftUser) { //将FILETIME结构转化为64位整数 ULONGLONGqwKernel=(((ULONGLONG)ftKernel.dwHighDateTime)<<32)+ftKernel.dwLowDateTime; ULONGLONGqwUser=(((ULONGLONG)ftUser.dwHighDateTime)<<32)+ftUser.dwLowDateTime; //将消耗时间相加,然后计算消耗在核心态下所用时间百分比 ULONGLONGqwTotal=qwKernel+qwUser; DWORDdwPct=(DWORD)(((ULONGLONG)100*qwKernel)/qwTotal); returndwPct; } //应用程序显示当前运行进程名字以及在核心态下占用时间的百分比 voidmain() { //获得系统当前进程的快照 HANDLEhSnapshot=CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS,//获得当前进程 0);//如果是当前进程,就将其忽略 //初始化过程入口 PROCESSENTRY32pe;//声明进程入口的PROCESSNTRY32结构的变量 ZeroMemory(&pe,sizeof(pe));//为pe分配存储空间,并将其清0 pe.dwSize=sizeof(pe); BOOLbMore=Process32First(hSnapshot,&pe);//获得系统快照中的第一个进程信息 while(bMore) { //打开用于读取的进程 HANDLEhProcess=OpenProcess( PROCESS_QUERY_INFORMATION,//指明要得到信息 FALSE,//不必继承这一句柄 pe.th32ProcessID);//要打开的进程 if(hProcess! =NULL) { //找出进程的时间 FILETIMEftCreation,ftKernelMode,ftUserMode,ftExit; GetProcessTimes( hProcess,//所感兴趣的进程 &ftCreation,//进程的启动时间 &ftExit,//结束时间 &ftKernelMode,//在核心态下消耗的时间 &ftUserMode);//在用户态下消耗的时间 //计算核心态下消耗的时间百分比 DWO
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验 Windows 应用程序 基础 进程 控制
![提示](https://static.bdocx.com/images/bang_tan.gif)