按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
对象」。但什么又是「核心对象」呢?
你可以说核心对象是系统的一种资源(噢,这说法对GDI 对象也适用),系统对象一
旦产生,任何应用程序都可以开启并使用该对象。系统给予核心对象一个计数值(usage
count )做为管理之用。核心对象包括下列数种:
核心对象 产生方法
event CreateEvent
mutex CreateMutex
semaphore CreateSemaphore
file CreateFile
file…mapping CreateFileMapping
process CreateProcess
thread CreateThread
前三者用于执行线程的同步化:file…mapping 对象用于内存映射文件(memory mapping
file process thread
), 和 对象则是本节的主角。这些核心对象的产生方式(也就是我们
39
…………………………………………………………Page 102……………………………………………………………
API handle
所使用的 )不同,但都会获得一个 做为识别;每被使用一次,其对应的计
1 CloseHandle
数值就加 。核心对象的结束方式相当一致,调用 即可。
process
「 对象」究竟做什么用呢?它并不如你想象中用来「执进程序代码」;不,程序代码
的执行是执行线程的工作,「process 对象」只是一个数据结构,系统用它来管理进程。
一个进程的诞生与死亡
执行一个程序,必然就产生一个进程(process )。最直接的程序执行方式就是在shell (如
Win95 的文件总管或Windows 3。x 的文件管理员)中以鼠标双击某一个可执行文件图标
App。exe App shell CreateProcess
(假设其为 ),执行起来的 进程其实是 调用 激活的。
让我们看看整个流程:
1。 shell 调用CreateProcess 激活App。exe 。
1
2。 系统产生一个「进程核心对象」,计数值为 。
3。 系统为此进程建立一个4GB 地址空间。
4。 加载器将必要的码加载到上述地址空间中,包括App。exe 的程序、资料,以及
DLLs DLLs
所需的动态联结函数库( )。加载器如何知道要加载哪些 呢?它
们被记录在可执行文件(PE 文件格式)的。idata section 中。
5。 系统为此进程建立一个执行线程,称为主执行线程(primary thread )。执行线程才是
CPU 时间的分配对象。
6。 系统调用C runtime 函数库的Startup code 。
7。 Startup code 调用App 程序的WinMain 函数。
8。 App 程序开始运作。
9。 使用者关闭App 主窗口,使WinMain 中的消息循环结束掉,于是WinMain 结束。
10。 回到Startup code 。
ExitProcess
11。 回到系统,系统调用 结束进程。
40
…………………………………………………………Page 103……………………………………………………………
可以说,透过这种方式执行起来的所有Windows 程序,都是shell 的子进程。本来,母
进程与子进程之间可以有某些关系存在,但shell 在调用CreateProcess 时已经把母子之间
的脐带关系剪断了,因此它们事实上是独立实例。稍后我会提到如何剪断子进程的脐带。
产生子进程
你可以写一个程序, 专门用来激活其它的程序。关键就在于你会不会使用
CreateProcess API
。这个 函数有众多参数:
CreateProcess(
LPCSTR lpApplicationName;
LPSTR lpmandLine;
LPSECURITY_ATTRIBUTES lpProcessAttributes;
LPSECURITY_ATTRIBUTES lpThreadAttributes;
BOOL bInheritHandles;
DWORD dwCreationFlags;
LPVOID lpEnvironment;
LPCSTR lpCurrentDirectory;
LPSTARTUPINFO lpStartupInfo;
LPPROCESS_INFORMATION lpProcessInformation
);
第一个参数lpAppl icationName 指定可执行档档名。第二个参数lp mandLine 指定欲
传给新进程的命令列(mand line )参数。如果你指定了lpAppl icationName,但没有
扩展名,系统并不会主动为你加上。EXE 扩展名;如果没有指定完整路径,系统就只在
lpAppl icationName NULL
目前工作目录中寻找。但如果你指定 为 的话,系统会以
lp mandLine 的第一个「段落」(我的意思其实是术语中所谓的token )做为可执行档
档名;如果这个档名没有指定扩展名,就采用预设的〃。EXE〃 扩展名;如果没有指定路
径,Windows 就依照五个搜寻路径来寻找可执行文件,分别是:
1。 调用者的可执行文件所在目录
2。 调用者的目前工作目录
3。 Windows 目录
4。 Windows System 目录
41
…………………………………………………………Page 104……………………………………………………………
5。 环境变量中的path 所设定的各目录
让我们看看实例:
CreateProcess(〃E:CWIN95NOTEPAD。EXE〃; 〃README。TXT〃;。。。);
系统将执行E:CWIN95NOTEPAD。EXE ,命令列参数是〃README。TXT〃。如果我们这
样子调用:
CreateProcess(NULL; 〃NOTEPAD README。TXT〃;。。。);
系统将依照搜寻次序,将第一个被找到的NOTEPAD。EXE 执行起来,并转送命令列参
数〃README。TXT〃 给它。
建立新进程之前,系统必须做出两个核心对象,也就是「进程对象」和「执行线程对象」。
CreateProcess 的第三个参数和第四个参数分别指定这两个核心对象的安全属性。至于第
五个参数(TR UE 或FALSE )则用来设定这些安全属性是否要被继承。关于安全属性及
其可被继承的性质,碍于本章的定位,我不打算在此介绍。
第六个参数dwCreationFlags 可以是许多常数的组合,会影响到进程的建立过程。这些
CREA TE SUSPENDED
_
常数中比较常用的是 ,它会使得子进程产生之后,其主执行线程立
刻被暂停执行。