友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
富士康小说网 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

深入浅出MFC第2版(PDF格式)-第12部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!



中的哪些文件比                 中的文件更新,然后将其                    字段设为          。同时也 



        desFiles' '            srcFiles' '            bMatch        FALSE 

对存在于              中而不存在于                中的文件,令其               字段为          。 



           srcFiles' '               bIsNew       TRUE             DstDir  

最后,检查               中的所有文件,将                字段为         者,拷贝到            去。 



      destFiles' '               bMatch        FALSE  

并检查              中的所有文件,将               字段为           者统统杀掉。 



JBACKUP  的源代码与可执行文件放在书附盘片的Jbackup。01 子目录中。 



                                                                                        34 


…………………………………………………………Page 97……………………………………………………………

MFCCON :MFC Console 程序设计 



    当你的进度还在第1章的Win32 基本程序观念,我却开始讲如何设计一个MFC console 



    程序,是否有点时地不宜? 



    是有一点!所以我挑一个最单纯而无与别人攀缠纠葛的MFC 类别,写一个40 行的小 



    程序。目标纯粹是为了做一个导入,并与Win32 console 程序做一比较。 



    我所挑选的两个单纯的MFC 类别是CStdioFile 和CString : 



                             CObject 



                      CFile                   CString 



                           CStdioFile 



                           CMemFile 



                          CSocketFile 



                         COleStreamFile 



    在MFC 之中,CFile 用来处理正常的文件I/O 动作。CStdioFile 衍生自CFile,一个 



    CStdioFile       C runtime   f open          stream     Stream  

            对象代表以            函数       所开启的一个          文件。        文件 



    有缓冲区,可以文字模式(预设情况)或二进制模式开启。 



    CString 对象代表一个字符串,是一个完全独立的类别。 



    我的例子用来计算小于100 的所有费伯纳契数列(Fabonacci sequence )。费伯纳契数列 



    的计算方式是: 



               1 

    1。 头两个数为 。 



    2。 接下来的每一个数是前两个数的和。 



                                                                                35 


…………………………………………………………Page 98……………………………………………………………

                   以下便是  MFCCON。CPP  內容: 



                   #0001  // File   : MFCCON。CPP 

                   #0002  // Author : J。J。Hou / Top Studio 

                   #0003  // Date   : 1997。04。06 

                   #0004  // Goal   : Fibonacci sequencee; less than 100 

                   #0005  // Build  : cl /MT mfccon。cpp  (/MT means Multithreading) 

                   #0006 

                   #0007  #include  

                   #0008  #include  

                   #0009 

                   #0010  int main() 

                   #0011  { 

                   #0012  int lo; hi; 

                   #0013  CString str; 

                   #0014  CStdioFile fFibo; 

                   #0015 

                   #0016      fFibo。Open (〃FIBO。DAT〃; CFile::modeWrite | 

                   #0017                  CFile::modeCreate | CFile::typeText); 

                   #0018 

                   #0019      str。Format (〃%sn〃; 〃Fibonacci sequencee; less than 100 :〃); 

                   #0020      printf(〃%s〃; (LPCTSTR) str); 

                   #0021      fFibo。WriteString (str); 

                   #0022 

                   #0023      lo = hi = 1; 

                   #0024 

                   #0025      str。Format (〃%dn〃; lo); 

                   #0026      printf(〃%s〃; (LPCTSTR) str); 

                   #0027      fFibo。WriteString (str); 

                   #0028 

                   #0029      while (hi 《 100) 

                   #0030      { 

                   #0031          str。Format (〃%dn〃; hi); 

                   #0032          printf(〃%s〃; (LPCTSTR) str); 

                   #0033          fFibo。WriteString (str); 

                   #0034          hi = lo + hi; 

                   #0035          lo = hi lo; 

                   #0036      } 

                   #0037 

                   #0038      fFibo。Close (); 

                   #0039      return 0; 

                   #0040  } 



                   以下是执行结果(在  console  窗口和  FIBO。DAT 档案中,结果都一样): 



36 


…………………………………………………………Page 99……………………………………………………………

Fibonacci sequencee; less than 100  : 



1 1 2 3 5 8 



13 



21 



34 



55 



89 



这么简单的例子中,我们看到MFC Console 程序的几个重点: 



1。 程序进入点仍为main 



2。 需包含所使用之类别的头文件(本例为AFX。H ) 



3。 可直接使用与GUI 无关的MFC 类别(本例为CStdioFile 和CString ) 



4。 编辑时需指定/MT,表示使用多执行线程版本的C runtime  函数库。 



第4点需要多做说明。在MFC console 程序中一定要指定多线程版的C runtime  函数库, 



所以必须使用/MT 选项。如果不做这项设定,会出现这样的联结错误: 



Microsoft  (R) 32…Bit Incremental Linker Version 5。00。7022 



Copyright  (C) Microsoft Corp 1992…1997。 All rights reserved。 



/out:mfccon。exe 



mfccon。obj 



nafxcw。lib (thrdcore。obj)  : error LNK2001: unresolved external symbol __endthreadex 



nafxcw。lib (thrdcore。obj)  : error LNK2001: unresolved external symbol __beginthreadex 



mfccon。exe  : fatal error LNK1120: 2 unresolved externals 



表示它找不到__beginthreadex 和__endthreadex 。怪了,我们的程序有调用它们吗?没 



有,但是MFC 有!这两个函数将在稍后与执行线程有关的小节中讨论。 



MFCCON  的源代码与可执行文件放在书附盘片的mfccon。01 子目录中。 



                                                                                     37 


…………………………………………………………Page 100……………………………………………………………

                什么是C Runtime 函数库的多线程版本 



当C runtime  函数库于1970s 年代产生出来时,PC 的内存容量还很小,多任务是 



个新奇观念,更别提什么多执行线程了。因此以当时产品为基础所演化的C runtime  函 



数库在多线程(multithreaded)的表现上有严重问题,无法被多线程程序使用。 



利用各种同步机制(                          )如             、     、         、 

                 synchronous mechanism critical section mutex semaphore 



    ,可以重新开发一套支持多执行线程的                     函数库。问题是,加上这样的能 

event                              runtime  



力,可能导至程序代码大小和执行效率都遭受不良波及  即使你只激活了一个执行 

                                            … 



线程。 



Visual C++  的折衷方案是提供两种版本的C runtime  函数库。一种版本给单线程程序 



使用,一种版本给多线程程序使用。多线程版本的重大改变是,第一,变量如errno 者 



现在变成每个执行线程各拥有一个。第二,多线程版中的数据结构以同步机制加以保护。 



Visual C++ 一共有六个C runtime  函数库产品供你选择: 



  ◆              (    )  

    Single…Threaded static libc。lib 898;826 

      



               (    )  

    Multithreaded static libcmt。lib 951;142 

      

  ◆ 



    Multithreaded DLL msvcrt。lib 5;510;000 

      

  ◆ 



                       (    )  

    Debug Single…Threaded static libcd。lib 2;374;542 

      

  ◆ 



                     (    ) 

    Debug Multithreaded static libcmtd。lib 2;949;190 

      

 ◆ 



 ◆ Debug Multithreaded DLL msvcrtd。lib 803;418 

      



Visual C++ 编译器提供下列选项,让我们决定使用哪一个C runtime  函数库: 



 ◆                   (    ) 

    /ML Single…Threaded static 

      



 ◆                 (    ) 

    /MT Multithreaded static 

      



                        (                 ) 

    /MD Multithreaded DLL dynamic import library 

 ◆   



                            (   ) 

    /MLd Debug Single…Threaded static 

 ◆   



                          (    ) 

    /MTd Debug Multithreaded static 

 ◆   



 ◆                            (                 ) 

    /MDd Debug Multithreaded DLL dynamic import library 

      



                                                                             38 


…………………………………………………………Page 101……………………………………………………………

进程与执行线程 (                                             ) 

                         Process and Thread 



    OS/2 Windows NT    Windows 95                     PC  

        、           以及           都支持多执行线程,这带给           程序员一股令人兴 



    奋的气氛。然而它带来的不全然是利多,如果不谨慎小心地处理执行线程的同步问题,程 



    序的错误以及除错所花的时间可能使你发誓再也不碰「执行线程」这种东西。 



    我们习惯以进程(process )表示一个执行中的程序,并且以为它是CPU 排程单位。事 



    实上执行线程才是排程单位。 



  核心对象 



    首先让我解释什么叫作「核心对象」(kernel object )。「GDI 对象」是大家比较熟悉的 



                GDI                   Pen          Brush            GDI 

    东西,我们利用         函数所产生的一支笔(           )或一支刷(         )都是所谓的「 



    对象」。但什么又是「核心对象」呢? 



    你可以说核心对象是系统的一种资源(噢,这说法对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 

                    _ 

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



刻被暂停
返回目录 上一页 下一页 回到顶部 9 10
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!