友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
一世书城 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

深入浅出MFC第2版(PDF格式)-第23章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!






                                        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 

                    _ 

常数中比较常用的是                     ,它会使得子进程产生之后,其主执行线程立 



刻被暂停执行。 



第七个参数lpE nvironment 可以指定进程所使用的环境变量区。通常我们会让子进程继 



承父进程的环境变量,那么这里要指定NULL 。 



第八个参数lpCur rentDirectory 用来设定子进程的工作目录与工作磁盘。如果指定 



NULL ,子进程就会使用父进程的工作目录与工作磁盘。 



第九个参数lpSt artupInfo 是一个指向STAR TUPINF O 结构的指针。这是一个庞大的结 



构,可以用来设定窗口的标题、位置与大小,详情请看API 使用手册。 



                  PROCESS  INF ORMA TION  

                        _ 

最后一个参数是一个指向                         结构的指针: 



                                                                  42 


…………………………………………………………Page 105……………………………………………………………

        typedef struct _PROCESS_INFORMATION { 



               HANDLE hProcess; 



               HANDLE hThread; 



               DWORD dwProcessId; 



               DWORD dwThreadId; 



       } PROCESS_INFORMATION; 



当系统为我们产生「进程对象」和「执行线程对象」,它会把两个对象的handle 填入此结 



构的相关字段中,应用程序可以从这里获得这些handles 。 



如果一个进程想结束自己的生命,只要调用: 



       VOID ExitProcess(UINT fuExitCode); 



就可以了。如果进程想结束另一个进程的生命,可以使用: 



       BOOL TerminateProcess(HANDLE hProcess; UINT fuExitCode); 



很显然,只要你有某个进程的handle,就可以结束它的生命。TerminateProcess 并不被 



建议使用,倒不是因为它的权力太大,而是因为一般进程结束时,系统会通知该进程所 



开启(所使用)的所有DLLs,但如果你以TerminateProcess 结束一个进程,系统不会 



做这件事,而这恐怕不是你所希望的。 



前面我曾说过所谓割断脐带这件事情,只要你把子进程以CloseHandle 关闭,就达到了 



目的。下面是个例子: 



      PROCESS_INFORMATION ProcInfo; 



      BOOL fSuccess; 



      fSuccess = CreateProcess(。。。;&ProcInfo); 



      if  (fSuccess) { 



               CloseHandle (ProcInfo。hThread); 



               CloseHandle (ProcInfo。hProcess); 



      } 



                                                                                43 


…………………………………………………………Page 106……………………………………………………………

一个执行线程的诞生与死亡 



    程序代码的执行,是执行线程的工作。当一个进程建立起来,主执行线程也产生。所以每一个 



    Windows 程序一开始就有了一个执行线程。我们可以调用CreateThread 产生额外的执行 



    线程,系统会帮我们完成下列事情: 



    1。 配置「执行线程对象」,其handle 将成为CreateThread  的传回值。 



                 1 

    2。 设定计数值为 。 



    3。 配置执行线程的context 。 



    4。 保留执行线程的堆栈。 



        context                SS                 IP 

    5。 将     中的堆栈指针缓存器(          )和指令指针缓存器(  )设定妥当。 



    看看上面的态势,的确可以显示出执行线程是CPU 分配时间的单位。所谓工作切换(context 



    switch )其实就是对执行线程的context  的切换。 



    程序若欲产生一个新执行线程,调用CreateThread  即可办到: 



        CreateThread (LPSECURITY_ATTRIBUTES lpThreadAttributes; 



                  DWORD dwStackSize; 



                  LPTHREAD_START_ROUTINE lpStartAddress; 



                  LPVOID lpParameter; 



                  DWORD dwCreationFlags; 



                  LPDWORD lpThreadId 



                  ); 



    第一个参数表示安全属性的设定以及继承,请参考API 手册。Windows 95 忽略此一参 



    数。第二个参数设定堆栈的大小。第三个参数设定「执行线程函数」名称,而该函数的参 



                                           0 

    数则在这里的第四个参数设定。第五个参数如果是 ,表示让执行线程立刻开始执行,如 



       CREA TE SUSPENDED  

              _ 

    果是                   , 则是要求执行线程暂停执行( 那么我们必须调用 

                                                     



    ResumeThread 才能令其重新开始)。最后一个参数是个指向D WORD  的指针,系统会 



    把执行线程的ID 放在这里。 



    上面我所说的「执行线程函数」是什么?让我们看个实例: 



        
返回目录 上一页 下一页 回到顶部 0 1
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!