操作系统创建进程

操作系统创建进程

2023年6月23日发(作者:)

进程的创建与撤消

前言:Windows所创建的每个进程都从调用CreateProcess() API函数开始,该函数的任务是在对象管理器子系统内初始化进程对象。每一进程都以调用ExitProcess() 或TerminateProcess() API函数终止。通常应用程序的框架负责调用 ExitProcess() 函数。对于C++ 运行库来说,这一调用发生在应用程序的main() 函数返回之后。

一、实验目的:

熟悉有关进程管理函数的使用,加深对进程概念的理解,了解进程如何被创建和终止。

二、实验要求:

在一个进程运行过程中,按用户的要求再创建一个进程,结束该进程。

三、实验准备: 在实验过程中需要用到的函数,自己上网查找。

1. 创建进程

CreateProcess() 调用的核心参数是可执行文件运行时的文件名及其命令行。表

2-1详细地列出了每个参数的类型和名称。

表2-1 CreateProcess() 函数的参数

参数名称 使用目的

LPCTSTR 全部或部分地指明包括可执行代码的EXE文件lpApplivationName 的文件名

LPCTSTR lpCommandLine 向可执行文件发送的参数

LPSECURIITY_ATTRIBUTES 返回进程句柄的安全属性。主要指明这一句柄是lpProcessAttributes 否应该由其他子进程所继承

LPSECURIITY_ATTRIBUTES

返回进程的主线程的句柄的安全属性

lpThreadAttributes 一种标志,告诉系统允许新进程继承创建者进程的句柄

特殊的创建标志 (如CREATE_SUSPENDED) 的位DWORD dwCreationFlage

标记

向新进程发送的一套环境变量;如为null值则LPVOID lpEnvironment

发送调用者环境

LPCTSTR

新进程的启动目录

lpCurrentDirectory

STARTUPINFO STARTUPINFO结构,包括新进程的输入和输出配lpStartupInfo 置的详情

LPPROCESS_INFORMATION 调用的结果块;发送新应用程序的进程和主线程lpProcessInformation 的句柄和ID

BOOL bInheritHandle

可以指定第一个参数,即应用程序的名称,其中包括相对于当前进程的当前目录的全路径或者利用搜索方法找到的路径;lpCommandLine参数允许调用者向新应用程序发送数据;接下来的三个参数与进程和它的主线程以及返回的指向该对象的句柄的安全性有关。

然后是标志参数,用以在dwCreationFlags参数中指明系统应该给予新进程什么行为。经常使用的标志是CREATE_SUSPNDED,告诉主线程立刻暂停。当准备好时,应该使用ResumeThread() API来启动进程。另一个常用的标志是CREATE_NEW_CONSOLE,告诉新进程启动自己的控制台窗口,而不是利用父窗口。这一参数还允许设置进程的优先级,用以向系统指明,相对于系统中所有其他的活动进程来说,给此进程多少CPU时间。

接着是CreateProcess() 函数调用所需要的三个通常使用缺省值的参数。第一个参数是lpEnvironment参数,指明为新进程提供的环境;第二个参数是lpCurrentDirectory,可用于向主创进程发送与缺省目录不同的新进程使用的特殊的当前目录;第三个参数是STARTUPINFO数据结构所必需的,用于在必要时指明新应用程序的主窗口的外观。

CreateProcess() 的最后一个参数是用于新进程对象及其主线程的句柄和ID的返回值缓冲区。以PROCESS_INFORMATION结构中返回的句柄调用CloseHandle()

API函数是重要的,因为如果不将这些句柄关闭的话,有可能危及主创进程终止之前的任何未释放的资源。

CreateProcess

VB声明

Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String,

ByVal lpCommandLine As String, lpProcessAttributes As SECURITY_ATTRIBUTES, lpThreadAttributes As

SECURITY_ATTRIBUTES, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment

As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As

PROCESS_INFORMATION) As Long

说明

创建一个新进程(比如执行一个程序)

返回值

Long,非零表示成功,零表示失败。会设置GetLastError

参数表

参数 类型及说明

String,要执行的应用程序的名字。可设为vbNullString;在这种情况下,应用lpApplicationName

程序的名字应在lpCommandLine参数的起始处出现

String,要执行的命令行。可用GetCommandLine函数取得一个进程使用的命令行。Windows会尽可能地根据下述搜索顺序来查找执行文件:

(1)包含了父进程执行文件的目录

(2)父进程当前的目录

lpCommandLine

(3)由GetSystemDirectory返回的系统目录

(4)仅适于windows NT:16位系统目录

(5)由GetWindowDirectory返回的Windows目录

(6)由PATH环境变量指定的目录

SECURITY_ATTRIBUTES,指定一个SECURITY_ATTRIBUTES结构,或传递lpProcessAttributes

零值(将参数声明为ByVal As Long,并传递零值)——表示采用不允许继承的默认描述符。该参数定义了进程的安全特性

SECURITY_ATTRIBUTES,指定一个SECURITY_ATTRIBUTES结构,或传递lpThreadAttributes

零值(将参数声明为ByVal As Long,并传递零值)——表示采用不允许继承的默认描述符。该参数定义了进程之主线程的安全特性

bInheritHandles

Long,TRUE表示允许当前进程中的所有句柄都由新建的子进程继承 Long,来自文件的一个或多个下述常数之一,它们都带有前缀CREATE_。下面这些用于VB程序员:

CREATE_SEPARATE_WOW_VDM(仅适用于NT)

启动一个16位的Windows应用程序时,强迫它在自己的内存空间运行

启动一个16位的Windows应用程序时,CREATE_SHARED_WOW_VDM(仅强迫它在共享的16位虚拟机(VM)内适用于NT)

运行

立即挂起新进程。除非调用了CREATE_SUSPENDED

ResumeThread函数函数,否则它不会恢复运行

dwCreationFlags

也可能是下述常数之一,用于指定优先级

新进程应该有非常低的优先级——只IDLE_PRIORITY_CLASS

有在系统空闲的时候才能运行。基本值是4

新进程有非常高的优先级,它优先于大HIGH_PRIORITY_CLASS

多数应用程序。基本值是13。注意尽量避免采用这个优先级

标准优先级。如进程位于前台,则基本NORMAL_PRIORITY_CLASS

值是9;如在后台,则优先值是7

不要在VB中使用REALTIME_PRIORITY_CLASS

lpEnvironment

Any,指向一个环境块的指针(环境缓冲区的头一个字符,或者环境块的地址)

String,新进程的当前目录路径。调用函数的时候,可用vbNullString指定当前lpCurrentDriectory

目录

STARTUPINFO,指定一个STARTUPINFO结构,其中包含了创建进程时使用lpStartupInfo

的附加信息

PROCESS_INFORMATION,该结构用于容纳新进程的进程和线程标识符。大lpProcessInformation

多数情况下,一旦这个函数返回,父应用程序都会关闭两个句柄。

2. 正在运行的进程

如果一个进程拥有至少一个执行线程,则为正在系统中运行的进程。通常,这种进程使用主线程来指示它的存在。当主线程结束时,调用ExitProcess() API函数,通知系统终止它所拥有的所有正在运行、准备运行或正在挂起的其他线程。当进程正在运行时,可以查看它的许多特性,其中少数特性也允许加以修改。

首先可查看的进程特性是系统进程标识符 (PID) ,可利用GetCurrentProcessId() API函数来查看,与GetCurrentProcess() 相似,对该函数的调用不能失败,但返回的PID在整个系统中都可使用。其他的可显示当前进程信息的API函数还有GetStartupInfo()和GetProcessShutdownParameters() ,可给出进程存活期内的配置详情。

通常,一个进程需要它的运行期环境的信息。例如API函数GetModuleFileName()

和GetCommandLine() ,可以给出用在CreateProcess() 中的参数以启动应用程序。在创建应用程序时可使用的另一个API函数是IsDebuggerPresent() 。

可利用API函数GetGuiResources() 来查看进程的GUI资源。此函数既可返回指定进程中的打开的GUI对象的数目,也可返回指定进程中打开的USER对象的数目。进程的其他性能信息可通过GetProcessIoCounters()、GetProcessPriorityBoost() 、GetProcessTimes() 和GetProcessWorkingSetSize() API得到。以上这几个API函数都只需要具有PROCESS_QUERY_INFORMATION访问权限的指向所感兴趣进程的句柄。

另一个可用于进程信息查询的API函数是GetProcessVersion() 。此函数只需感兴趣进程的PID (进程标识号) 。本实验程序清单2-2中列出了这一API函数与GetVersionEx() 的共同作用,可确定运行进程的系统的版本号。

ExitProcess

VB声明

Declare Sub ExitProcess Lib "kernel32" Alias "ExitProcess" (ByVal uExitCode As Long)

说明

中止一个进程

参数表

参数

uExitCode

在VB中使用

应尽量避免用该函数来关闭进程。不要在自己的VB程序中使用它。此时,应试着向要关闭的那个程序的主窗口投递一条WM_CLOSE消息

类型及说明

Long,指定想中断的那个进程的一个退出代码

3. 终止进程

所有进程都是以调用ExitProcess() 或者TerminateProcess() 函数结束的。但最好使用前者而不要使用后者,因为进程是在完成了它的所有的关闭“职责”之后以正常的终止方式来调用前者的。而外部进程通常调用后者即突然终止进程的进行,由于关闭时的途径不太正常,有可能引起错误的行为。

TerminateProcess() API函数只要打开带有PROCESS_TERMINATE访问权的进程对象,就可以终止进程,并向系统返回指定的代码。这是一种“野蛮”的终止进程的方式,但是有时却是需要的。

如果开发人员确实有机会来设计“谋杀”(终止别的进程的进程) 和“受害”进程 (被终止的进程) 时,应该创建一个进程间通讯的内核对象——如一个互斥程序——这样一来,“受害”进程只在等待或周期性地测试它是否应该终止。

TerminateProcess

VB声明

Declare Function TerminateProcess Lib "kernel32" Alias "TerminateProcess" (ByVal hProcess As Long, ByVal

uExitCode As Long) As Long

说明

结束一个进程

在VB里使用

可以使用,但尽量不用

返回值

Long,非零表示成功,零表示失败。会设置GetLastError

参数表

参数

hProcess

uExitCode

类型及说明

Long,指定要中断的一个进程的句柄

Long,进程的一个退出代码

四、实验内容: 1. 创建进程

本实验显示了创建子进程的基本框架。该程序只是再一次地启动自身,显示它的系统进程ID和它在进程列表中的位置。

步骤1:登录进入Windows 2000 Professional。

步骤2:在“开始”菜单中单击“程序”-“Microsoft Visual Studio

6.0”–“Microsoft Visual C++ 6.0”命令,进入Visual C++窗口。

步骤3:“文件”->“新建”->“C++ Source File”,建立源程序。

清单2-1 创建子进程

// proccreate项目

# include

# include

# include

// 创建传递过来的进程的克隆过程并赋于其ID值

void StartClone(int nCloneID)

{

// 提取用于当前可执行文件的文件名

TCHAR szFilename[MAX_PATH] ;

:: GetModuleFileName(NULL, szFilename, MAX_PATH) ;

// 格式化用于子进程的命令行并通知其EXE文件名和克隆ID

TCHAR szCmdLine[MAX_PATH] ;

:: sprintf(szCmdLine, “”%s” %d”, szFilename, nCloneID) ;

// 用于子进程的STARTUPINFO结构 STARTUPINFO si;

:: ZeroMemory(reinterpret_cast (&si) , sizeof(si) ) ;

= sizeof(si) ; // 必须是本结构的大小

// 返回的用于子进程的进程信息

PROCESS_INFORMATION pi;

// 利用同样的可执行文件和命令行创建进程,并赋于其子进程的性质

BOOL bCreateOK = :: CreateProcess(

szFilename, // 产生这个EXE的应用程序的名称

szCmdLine, // 告诉其行为像一个子进程的标志

NULL, // 缺省的进程安全性

NULL, // 缺省的线程安全性

FALSE, // 不继承句柄

CREATE_NEW_CONSOLE, // 使用新的控制台

NULL, // 新的环境

NULL, // 当前目录

&si, // 启动信息

&pi) ; // 返回的进程信息

// 对子进程释放引用

if (bCreateOK)

{

:: CloseHandle(ss) ;

:: CloseHandle(d) ;

}

}

int main(int argc, char* argv[] )

{

// 确定进程在列表中的位置

int nClone(0) ;

if (argc > 1)

{

// 从第二个参数中提取克隆ID

:: sscanf(argv[1] , “%d” , &nClone) ;

}

// 显示进程位置

std :: cout << “Process ID: “ << :: GetCurrentProcessId()

<< “, Clone ID: “ << nClone

<< std :: endl;

// 检查是否有创建子进程的需要

const int c_nCloneMax = 25;

if (nClone < c_nCloneMax)

{

// 发送新进程的命令行和克隆号

StartClone(++nClone) ;

}

// 在终止之前暂停一下 (l/2秒)

:: Sleep(500) ;

return 0;

}

步骤4:单击“Build”菜单中的“Compile ”命令,系统显示:

This build command requires an active project workspace.

Would you like to create a default project workspace ?

(build命令需要一个活动的项目工作空间。你是否希望建立一个缺省的项目工作空间?)

单击“是”按钮确认。系统对进行编译。

步骤5:编译完成后,单击“Build”菜单中的“Build ”命令,建立可执行文件。

步骤6:在工具栏单击“Execute Program”(执行程序) 按钮,或者按Ctrl + F5键,或者单击“Build”菜单中的“Execute ”命令,执行程序。

步骤7:按Ctrl + S键可暂停程序的执行,按Ctrl + Pause (Break) 键可终止程序的执行。

发布者:admin,转转请注明出处:http://www.yc00.com/web/1687518544a16452.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信