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

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

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



 8。               没什么其它动作,就只送出                    消息,准备让消息循 



   环中的GetMessage 取得,如步骤 ,结束消息循环。 

                               2 



                   图1…6 窗口的生命周期 ( 请对照图1…5) 



为什么结束一个程序复杂如斯?因为操作系统与应用程序职司不同,二者是互相合作的 



关系,所以必需各做各的份内事,并互以消息通知对方。如果不依据这个游戏规则,可 



能就会有麻烦产生。你可以作一个小实验,在窗口函数中拦截WM_DESTROY,但不调 



'O~APostQuitMessage 。你会发现当选择系统菜单中的Close  时,屏幕上这个窗口消失了, 



                              Def WindowProc    Destroy Window  

 (因为窗口摧毁及数据结构的释放是                           调用               完成的),但 



是应用程序本身并没有结束(因为消息循环结束不了),它还留存在内存中。 



                                                                             26 


…………………………………………………………Page 89……………………………………………………………

空闲时间的处理 : 

                         OnIdle 



    所谓空闲时间(idle time ),是指「系统中没有任何消息等待处理」的时间。举个例子, 



    没有任何程序使用定时器(timer ,它会定时送来WM_TIMER ),使用者也没有碰触键盘 



    和鼠标或任何外围,那么,系统就处于所谓的空闲时间。 



                                                 WM MO USEMO VE 

                                                   _ 

    空闲时间常常发生。不要认为你移动鼠标时产生一大堆的                                  ,事实上夹 



             WM MO USEMO VE  

                _ 

    杂在每一个                   之间就可能存在许多空闲时间。毕竟,计算机速度超乎想 



    像。 



    背景工作最适宜在空闲时间完成。传统的SDK 程序如果要处理空闲时间,可以以下列 



    循环取代WinMain  中传统的消息循环: 



      while  (TRUE) { 



        if  (PeekMessage (&msg; NULL; 0; 0; PM_REMOVE) { 



            if  (msg。message == WM_QUIT) 



                break; 



            TranslateMessage (&msg); 



            DispatchMessage (&msg); 



        } 



        else { 



          OnIdle (); 



        } 



      } 



    原因是PeekMessage 和GetMessage  的性质不同。它们都是到消息队列中抓消息,如果 



    抓不到,程序的主执行线程(primary thread,是一个UI 执行线程)会被操作系统虚悬住。 



    当操作系统再次回来照顾此一执行线程,而发现消息队列中仍然是空的,这时候两个API 



    函数的行为就有不同了: 



   ■GetMessage  

              会过门不入,于是操作系统再去照顾其它人。 



     PeekMessage  

               会取回控制权,使程序得以执行一段时间。于是上述消息循环进 

   ■ 



      入OnIdle  函数中。 



           HelloMFC           MFC               idle time p。403 

    第6章的           将示范如何在         程序中处理所谓的             (    )。 



                                                                             27 


…………………………………………………………Page 90……………………………………………………………

Console 程序 



    说到Windows 程序,一定得有WinMain 、消息循环、窗口函数。即使你只产生一个对 



         Dialog Box        Message Box          Windows API DialogBox  

    话窗(          )或消息窗(             ),也有隐藏在               (        和 



    MessageBox )内里的消息循环和窗口函数。 



                     C/C++             main  pr intf   

    过去那种单单纯纯纯的            程序,有着简单的         和     的好时光到哪里去 



    了?夏天在阴凉的树荫下嬉戏,冬天在温暖的炉火边看书,啊,Where did the good times 



    go ? 



    其实说到Win32 程序,并不是每个都如Windows GUI 程序那么复杂可怖。是的,你可 



       Visual C++     〃DOS…like〃  

    以在          中写一个          程序,而且仍然可以调用部份的、不牵扯到图形 



              GUI   Win32 API           console               console 

    使用者接口(       )的         。这种程序称为          程序。甚至你还可以在 



    程序中使用部份的MFC 类别(同样必须是与GUI 没有关连的),例如处理数组、串 



                collection classes CArray CList CMap       CFile 

    行等数据结构的                 (     、     、     )、与文件有关的         、 



    CStdioFile 。 



    我在BBS 论坛上看到很多程序设计初学者,还没有学习C/C++ ,就想直接学习Visual 



    C++                            Visual C++         C++  

       。并不是他们好高骛远,而是他们以为                    是一种特殊的       语言。吃过 



    苦头的过来人以为初学所说的Visual C++ programming 是指MFC programming ,所以大 



    吃一惊(没有一点C++ 基础就要学习MFC programming ,当然是大吃一惊)。 



    在Visual C++  中写纯种的C/C++ 程序?当然可以!不牵扯任何窗口、对话窗、控制组 



    件,那就是console 程序!虽然我这本书没有打算照顾 C++ 初学者,然而我还是决定 



    把console 程序设计的一些相关心得放上来,同时也是因为我打算以console 程序完成稍 



    后的多线程程序范例。第3章的MFC 六大技术仿真程序也都是console 程序。 



    其实,除了〃DOS…like〃,console 程序还另有妙用。如果你的程序和使用者之间是以巨量 



    文字来互动,或许你会选择使用edit 控制组件(或MFC  的CEditView )。但是你知道, 



    计算机在一个纯粹的「文字窗口」(也就是console 窗口)中处理文字的显现与卷动比较 



                                                                          28 


…………………………………………………………Page 91……………………………………………………………

     快,你的程序动作也比较简单。所以,你也可以在Windows 程序中产生console 窗口, 



     独立出来操作。 



     这也许不是你所认知的console 程序。总之,有这种混合式的东西存在。 



     这一节将以我自己的一个极简易的个人备份软件JBACKUP 为实例,说明Win32 



     console 程序的撰写,以及如何在其中使用Win32 API   (其实直接调用就是了)。再以另 



     一个极小的程序MFCCON 示范MFC console 程序(用到了MFC  的CStudioFile 和 



     CString )。对于这么小的程序而言,实在不需动用到整合环境下的什么项目管理。至于 



     复杂一点的程序,就请参考第4章最后一节「Console 程序的项目管理」。 



Console 程序与DOS  程序的差别 



     不少人把DOS 程序和console 程序混为一谈,这是不对的。以下是各方面的比较。 



   制造方式 



     在Windows 环境下的DOS Box  中,或是在Windows 版本的各种C++ 编译器套件的 



     整合环境(IDE )中(第4章「Console 程序项目管理」),利用Windows 编译器、联 



     结器做出来的程序,都是所谓Win32 程序。如果程序是以main 为进入点,调用C 



     runtime        GUI   Win32 API            console  console 

          函数和「不牵扯      」的        函数,那么就是一个          程序, 



     窗口将成为其标准输入和输出装置(cin 和cout )。 



     过去在DOS 环境下开发的程序,称为DOS 程序,它也是以main 为程序进入点,可 



     以调用C runtime  函数。但,当然,不可能调用Win32 API 函数。 



   程序能力 



     过去的DOS 程序仍然可以在Windows  的DOS Box  中跑(Win95  的兼容性极高, 



     WinNT  的兼容性稍差)。 



                                                                  29 


…………………………………………………………Page 92……………………………………………………………

  Console 程序当然更没有问题。由于console 程序可以调用部份的Win32 API                  (尤其是 



  KERNEL32。DLL 模块所提供的那一部份),所以它可以使用Windows 提供的各种高级 



                       processes                 threads 

  功能。它可以产生进程(                  ),产生执行线程(              )、取得虚拟内存的信息、 



  刺探操作系统的各种资料。但是它不能够有华丽的外表…因为它不能够调用与GUI 有 



  关的各种API 函数。 



  DOS       console               pr intf    cout               scanf  

       程序和         程序两者都可以做            输出和       输出,也都可以做            输 



  入和cin 输入。 



可执行档格式 



  DOS 程序是所谓的MZ 格式(MZ 是Mark Zbikowski  的缩写,他是DOS 系统的一位 



                Console                   Win32                  PE   Portable 

  主要构造者)。              程序的格式则和所有的               程序一样,是所谓的            ( 



  Executable                            Win32  

           )格式,意思是它可以被拿到任何                    平台上执行。 



  Visual C++  附有一个DUMPBIN 工具软件,可以观察PE 文件格式。拿它来观察本节 



  的JBACKUP 程序和MFCCON 程序(以及第3章的所有程序),得到这样的结果: 



  H:u004progjbackup 。01》dumpbin /summary jbackup 。exe 



  Microsoft  (R) COFF Binary File Dumper Version 5。00。7022 



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



    Dump of file jbackup 。exe 



    File Type: EXECUTABLE IMAGE 



           Summary 



             5000  。data 



             1000  。idata 



             1000  。rdata 



             5000  。text 



  拿它来观察DOS 程序,则得到这样的结果: 



                                                                                    30 


…………………………………………………………Page 93……………………………………………………………

       C:UTILITY》dumpbin /summary dsize。exe 

       Microsoft (R) COFF Binary File Dumper Version 5。00。7022 

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



       Dump of file dsize。exe 

       DUMPBIN : warning LNK4094: 〃dsize。exe〃 is an MS…DOS executable; 

       use EXEHDR to dump it 



            Summary 



Console  程序的编译联结 



       你可以写一个makefile,编译时指定常数/D_CONSOLE ,联结时指定subsystem 为 



       console  ,如: 



           #0001  # filename : pedump。mak 

           #0002  # make file for pedump。exe 

           #0003  # usage : nmake pedump。msc (Visual C++ 5。0) 

           #0004 

           #0005  all : pedump。exe 

           #0006 

           #0007  pedump。exe: pedump。obj exedump。obj objdump。obj mon。obj 

           #0008     link /subsystem:console /incremental:yes  

           #0009          /machine:i386 /out:pedump。exe  

           #0010          pedump。obj mon。obj exedump。obj objdump。obj  

           #0011          kernel32。lib user32。lib 

           #0012 

           #0013  pedump。obj : pedump。c 

           #0014     cl /W3 /GX /Zi /YX /Od /DWIN32 /D_CONSOLE /FR /c pedump。c 

           #0015 

           #0016  mon。obj : mon。c 

           #0017     cl /W3 /GX /Zi /YX /Od /DWIN32 /D_CONSOLE /FR /c mon。c 

           #0018 

           #0019  exedump。obj : exedump。c 

           #0020     cl /W3 /GX /Zi /YX /Od /DWIN32 /D_CONSOLE /FR /c exedump。c 

           #0021 

           #0022  objdump。obj : objdump。c 

           #0023     cl /W3 /GX /Zi /YX /Od /DWIN32 /D_CONSOLE /FR /c objdump。c 



       如果是很简单的情況,例如本节的  JBACKUP  只有一个  C  原代码,那么这样也行 (在 



       命令列之下): 



           cl jbackup。c     A 将获得 jbackup。exe 



                                                                                              31 


…………………………………………………………Page 94……………………………………………………………

    注意,环境变量要先设定好(请参考本章稍早的「如何产生Generic。exe 」一节)。 



    第3章的Frame_ 程序则是这样完成的: 



    cl my。cpp mfc。cpp       my。exe 

                              将获得 



    至于到底该联结哪些链接库,全让CL。EXE 去伤脑筋就好了。 



JBACKUP :Win32 Console 程序设计 



    撰写console 程序,有几个重点请注意: 



    1。 进入点为main 。 



             pr intf scanf cin cout  

    2。 可以使用      、     、   、    等标准输出入装置。 



    3。 可以调用和GUI 无关的Win32 API 。 



    我的这个JBACKUP 程序可以有一个或两个参数,用法如下: 



      C:SomeoneDir》JBACKUP SrcDir 'DstDir' 



      例如JBACKUP g: k: 



      将磁盘目录SrcDir  中的新文件拷贝到磁盘目录DstDir , 



      并将DstDir  的赘余文件杀掉。 



                 DstDir      k:                  …MO … 

      如果没有指定          ,预设为      (那是我的可写入光驱              的代码啦) 



      并将k:  的磁盘目录设定与SrcDir 相同。 



      例如JBACKUP g: 



      而目前g: 是g:u002doc 



                 g:u002doc   k:u002doc        k:u002doc  

      那么相当于把              备份到            中,并杀掉             的赘余文件。 



    JBACK 检查SrcDir  中所有的文件和DstDir  中所有的文件,把比较新的文件从SrcDir 



    中拷贝到DstDir 去,并把DstDir  中多出来的文件删除,使ScrDir 和DstDir  的文件保 



                                                                              32 


…………………………………………………………Page 95……………………………………………………………

持完全相同。之所以不做xcopy 完全拷贝动作,为的是节省拷贝时间(做为备份装置, 



通常是软盘或磁带或可擦写光盘MO,读写速度并不快)。 



JBACKUP 没有能力处理SrcDir 底下的子目录文件。如果要处理子目录,漂亮的作法是 



使用递归(recursive ),但是有点伤脑筋,这一部份留给你了。我的打字速度还算快,多 



切换几次磁盘目录不是问题,呵呵呵。 



JBACKUP 使用以下数个Win32 APIs : 



       GetCurrentDirectory 



       FindFirstFile 



       FindNextFile 



       pareFileTime 



       CopyFile 



       DeleteFile 



在处理完毕命令列参数中的SrcDir 和DstDir 之后,JBACKUP 先把SrcDir  中的所有 



文件(不含子目录文件)搜寻一遍,储存在一个数组srcFiles' '  中,每个数组元素是一 



个我自定的SRCFILE 数据结构: 



     typedef struct _SRCFILE 



     { 



         WIN32_FIND_DATA fd; 



         BOOL bIsNew; 



     } SRCFILE; 



     SRCFILE srcFiles'FILEMAX'; 



    WIN32_FIND_DATA fd; 



         // prepare srcFiles''。。。 



         bRet = TRUE; 



         iSrcFiles = 0; 



         hFile = FindFirstFile (SrcDir; &fd); 



         while  (hFile  != INVALID_HANDLE_VALUE && bRet) 



         { 



              if  (fd。dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) { 



                  srcFiles'iSrcFiles'。fd = fd; 



                  srcFiles'iSrcFiles'。bIsNew = FALSE; 



                  iSrcFiles++; 



              } 



                                                                                    33 


…………………………………………………………Page 96……………………………………………………………

       bRet = FindNextFile (hFile; &fd); 



     } 



再把DstDir  中的所有文件(不含子目录文件)搜寻一遍,储存在一个destFiles' ' 数组 



中,每个数组元素是一个我自定的DESTFILE 数据结构: 



     typedef struct _DESTFILE 



     { 



         WIN32_FIND_DATA fd; 



         BOOL bMatch; 



     } DESTFILE; 



     DESTFILE destFiles'FILEMAX'; 



     WIN32_FIND_DATA fd; 



        bRet = TRUE; 



        iDestFiles = 0; 



        hFile = FindFirstFile (DstDir; &fd); 



        while  (hFile  != INVALID_HANDLE_VALUE && bRet) 



        { 



             if  (fd。dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) { 



                 destFiles'iDestFiles'。fd = fd; 



                 destFiles'iDestFiles'。bMatch = FALSE; 



                  iDestFiles++; 



             } 



            bRet = FindNextFile (hFile; &fd); 



     } 



然后比对srcFiles' ' 和destFiles' ' 之中的所有文件名称以及建档日期,找出scrFiles' ' 



               desFiles' '                     bIsNew          TRUE 

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