• DOS程序员手册(十五)


    837页

              writeln('TRACING Current Buffer===');

              holdup;

              bcbtrc(cvtbase^.curbfr);

              writeln;

              holdup ;

              writeln('TRACING       Buffer Chain===');

              holdup ;

              bCDtrc(Cvtbase^bfrchn);

            END.

        CVT3.PAS是用Turbo Pascal语言写成的。从5.0版开始,该程序已在任何版本上

    (包括版本7.0)得到了验证并编译成功。这份用于VCT3.PAS的列表清单虽然初看上去

    令人生畏,但实质上,它也不过如此。这一列表是由几个相当简单的过程拼凑起来的。其

    中,前几页只是简单地定义了所有的CVT结构,以便CVT3.PAS能够引用它们。接下来,

    该列表定义了许多实用程序功能,以协助显示输出。在这些实用程序功能,出现在该列表

    中的是一些跟踪功能,用于监视每一个主要结构。最后,将上述所有的内容拼接在一起,便

    构成了主程序。下面不妨让我们来一点一点地详细探讨一下。

    数据结构

        CVT3程序的开始是几种特殊的数据类型,其中,一种用于每个CVT结构,另一种则

    作为指向cVT结构的指针。因此,BCB把缓冲控制块定义成了记录(等效于C语言中的

    结构),并且bcptr定义了一个指向这种记录的指针。

        同样,mcb和mcbptr定义的是内存控制块结构;dpb和dpbptr定义着驱动器参数块

    结构;chn和chptr定义着用于DCB和FCB链中的链路头;dcb和dcbptr定义着设备控制

    块的格式(也可供系统FCB使用);ldt和ldtptr定义着逻辑驱动器表;并且cvt定义的是

    CVT。

        余下的数据类型被分别定义为dtstr(用于报告日期和时间的字符串大小),pstrg(在

    报告指针值时使用的大小和memst(用于报告内存使用情况的大小)。这里所以定义了这

    三种数据类型,是因为Turbo Pascal考虑到仅有两种不同string[8]定义过于笼统;而定义

    了这些特殊的数据类型不仅允许编译程序的类型检查能正常地运转,并且还公开了如何

    使用更短的字符串。

        定义了这些特殊的数据类型,便可依次用它们来推断出该程序使用的其它全局工作

    变量:cvtbase是将作为CVT的基址而被返回的指针;curbuf、curmcb、curdpb、curchn、cur-

    dcb、curfcb和curldt是指向种种被跟踪的当前指针;余下的变量则可用来报告生成进程

    的情况。

    实用程序功能

        定义了数据类型和变量之后,该程序接着定义的是许多实用程序功能。hexn用来传

    送一个单字节,并把该字节的低4位转换成一个十六进制数字,以便在返回时可将它作为

    一个ASCII字符。接着,hexb分两次使用hexn(在第一次调用时转换4个位),以便把一个

    完整的字节转换成2个字符的字符串;hexw按照同样的方法来使用hexb,以把一个16

    位的字转换成一个16进制数字的字符串,并且hexl再一次使用这种方法来转换一个32

     

    838页

    位值。当某种方法比较简明有效时,就应使用这样的方法。

          当全局PawsFlag出错时,在跟踪进程期间每产生一个输出行后就调用的进程holdup

    将不会起任何作用。这样,如果把报告重定向给打印机或文件,系统便允许继续进行输出。

    如果PawsFlag是正确的,则holdup会增加行计数lctr,并且,如果lctr值大于23(看起来

    较舒服的完整屏幕),holdup便会复位lctr,并等待在返回之前按下Enter键。

          功能xp是一种较为特殊的功能,它通过使用hexw来进行2进制至16进制的指针

    转换;从而把指针值转换成常规的ASCII形式,即SSSS:OOOO。

          最后一个进程为dmp,dmp是一个通用的建成块,可将它用在任何地方以创建一个

    类似于DEBUG的且可由任意16个连续字节(可采用十六进制格式和AsCII格式)组成

    的列表。它接收一个远指针作为输入,并接着把指针值写给屏幕,在这里,指针值为采用十

    六进制格式的16个字节和同样的16个被转换成了ASCII的字节(除掉了高位,并且把控

    制字符转换成了“.”,以防混淆)。以上所介绍的进程大多数可以直接或间接地通过dmp

    来使用。此外报告进程使用dmp来显示内存区域如缓冲区的内容。

    跟踪DPBs

          过程dpbtrc能实现两方面的功能,即跟踪驱动器参数块并报告驱动器参数块的内

    容。它定义了一个局部过程dpbrpt来实现报告功能。不过,只有当其它例程不能使用该过

    程时,才能从dpbtrc内调用dpbrpt;此外,能否使用这样一种“局部的”过程是区别Pascal

    语言和C语言的重要标志之一。

          dpbrpt过程是在正确地设置了curdpt指针的基础上通过把驱动器代码转换成字母

    及其它内容,来把数从指针指定的DPB格式中转换成更适合于显示的描述格式。其中一

    些显示采用十六进制格式,并且还有一些输出采用十进制,所有这些的目的是增强报告的

    可读性。因此,也可以把这一过程看作一个裸骨式的“专家系统”,因为它把DPB格式的内

    容转换成了人们容易理解的且十分浅显易懂的语言。

          接下来的是dpbrpt过程,该过程是通过设置一个指向传入的指针值(从CVT中传

    入)的全局指针currdpb而开始的。然后,它把局部变量ofsv设置为0;这样,便保存了每一

    个记录内的下一个DPB指针的偏移值;当这个值变成了FFFFh时,跟踪循环便会终止。

          设置了上述变量之后,该过程便打印出一个标题行,并进入由SV控制的跟踪循环。

    该循环过程中的每一步骤上,ofsv的值都被改变,该过程会调用dpbrpt来报告当前DPB

    中所保存的每一件东西,并把curdpb设置成在下一个DPB指针内找到的值。在ofsv未变

    成FFFFh之前,该循环会一直进行下去,以便报告出所有有效的DPB。在该过程中,每当

    屏幕显示出内容时,holdup便可以创造一次等待,以便于用户有时间读清屏幕上的内容。

          在显示完了最后一个DPB报告之后,dpbtrc便会通过“write(# 12)”把一个换页字符

    送给它的输出。这一行只有CRT上显示一个图形字符;但是,如果是把输出发送给打印

    机,该行将强迫下一个跟踪功能的输出出现在新的页面上。在返回到主调用例程之前,大

    多跟踪过程能迅速地实现上述过程。

    跟踪BCBs

          过程bcbtrc跟踪并报告缓冲控制块。与dpbtrc一样,该过程也包括一个局部报告功

     

    839页

    能,其专用名为bcbrpt。

          与dpbrpt一样,bcbrpt也把来自于缓冲区的信息转换成更为通用的格式,并在屏幕

    上显示出这一信息。接着,它在返回到bcbrc之前,使用dmp来显示出缓冲器的全部内容。

          与dpbtrc一样,bcbtrc也是一种必不可少的外围程序,它首先初始化与之自身相关的

    变量,接着通过调用bcbrpt来循环,直到它到达缓冲链的末端。当到达缓冲链的末端时,

    该过程将输出一个换页,并返回到其调用者处。

          但是,与dpbtrc不一样,bcbtrc不能使用全局变量来保存其用于bcbrpt的指针,因为

    系统是为两个不同的链而调用bcbtrc的。确切地讲,该指针是作为一个独立参数而被传送

    给上述的每一个过程。

    DCBs

          跟踪并报告设备控制块和系统FCBs(与设备控制块共享同一结构)的过程较为复杂

    一些。除了定义它的局部报告例程-dcbrpt外,该过程还定义了一对功能,即f_tm(把

    保存在DCB中的时间值转换成常规显示格式)和f_dt(对日期值进行同样的转换)。

          f_tm和f_dt都可作为我们通常称之为“暴力”编程的直接例子。例如,在f_tm中,输

    入时间参数(按照DOS指定的文件目录格式而被紧紧地压缩过)将会根据请求而被移位

    并被屏蔽为每小时一个字节,并且,随后进行的DIV和MOD操作会把该字节转换成一个

    两位十进制值(加在这里的值48是ASCII字符0的二进制值)。对于分和秒来说,处理过

    程是相同的。

          这样,当系统把被压缩的值扩展成为类型dtstr字符串之后,该字符串就会作为该功

    能的值而被返回。f_dt功能对月、日和年值所采用的处理方式也是相同的。

          由于DCB可以保存有关文件或设备的信息,并且根据保存的是文件还是设备,对信

    息的描述是不相同的,因此,dcbrpt相对要复杂一些。它包括用来确定每个DCB引用的是

    文件还是设备的代码以及用于相应地改变报告的判断结构。

          另一个复杂因素是将DCB按次序组合成链路的方式,以及如何通过指针将这些链路

    链接起来。为了便于跟踪,系统会传送给dcbrpt一个计数(n),告诉它在返回到dcbtrc之

    前,应报告出多少个DCBs,dcbtrc例程维护,链与链之间的链接。由于dcbrpt能引用DCB

    或FCB,因此,传送给它的合适字符串应为t—一种类型dtstr参数。

          当最终到达dcbtrc(在这里,全局和局部变量都被初始化)的起始处时,dcbtrs几乎是

    从天而降。与在前面介绍的跟踪例程中一样,它也是沿着链路往下循环,直到它到达链的

    末端,即nexLnk指针中的偏移值FFFFh指定的地方。

    跟踪MCB链

          MCB跟踪程序过程-memtrc采用的是目前较为通用的方式,即一种局部报告过

    程memrpt,并且该过程含有一种局部功能memu。但是,这些与我们曾见到的过程要短得

    多。

          memu功能可解释每个MCB控制的内存块的第一个字符,以准确地推猜出该内存块

    的用途。由于所有程序都开始于PSP,并且PSP依次通过字节CDh和20h(用于Int 20h

    的操作码)来开始,因此,如果memu发现CDh为第一个字节,它就会推测到程序是在这

     

    840页

    里。如果程序不在这里,并且如果第一个字节时ASCII中的一个大字字母,memu就会推

    测所遇到的是一个环境块;否则,将见到的内容报告为一个保存数据。memu将描述字串

    符之一作为它的值而返回。

          指定给memrpt过程的参数块有三个,即5、0和9,它们分别为大小,拥有者和第一个

    字节的地址。如果拥有者为0000,表明内存块是自由的内存块;否则,它就是为其保留着

    块的进程的进程ID。

          memtrc例程根据主程序传送给它的值来初始化cumcb全局指针,显示报告标题,并

    接着进入循环。该循环为当前MCB调用memrpt,根据当前段大小计算出下一个MCB段

    值,并把curmcb设置给这一地址,只要能在每个MCB的第一个字节中找到MCB标识符

    字节M,循环就会继续下去。当循环失败时,在第一个字节Z标识的是最后一个有效的

    MCB块;任何其它值都表示MCB链已经出错。所有这些检查都是memtrc通过有限的几

    种状态来实现的。

    LDT跟踪

          最后一个跟踪例程是ldttrc,它可显示用来保存系统中每个逻辑驱动器的当前目录信

    息的区域,并且,还可用此区域来记录被替代的(SUBSTed)和指定的驱动器信息。

          在调用局部报告例程ldtrpt时,它可获取一个指向第一个LDT的指针,以及在范围0

    至逻辑驱动器号(减去1,因为驱动器代码是以0为基数的)。它把驱动器代码转换成供报

    告使用的字母值,并接着检查LDT中的状态字节,以确定事实上是不是已定义了驱动器。

          如果已经定义了驱动器,那么系统就会把保存在LDT的当前目录信息与逻辑驱动器

    字母一起打印出来,并转换和显示状态字节(以及尚未对其含义进行编码的LDT项)。

          ldttrc进程首先设置curldt并显示一个标题。接着,它将传送给它的逻辑驱动器计数

    减去1,以便校正为以0为基数的驱动器代码用法。至此,ldttrc进程便沿着每个可能逻辑

    驱动器的LDT循环起来,为每个LDT调用ldtrpt,并把curldt设置为指向下一个LDT,

    同时,还根据每一项的大小计算出LDT的地址。

    主例程

          已经检查完了每个跟踪模块,我们就把它们全部放在主调用序列中。主例程是通过使

    用中断21h,功能30h(通过Turbo Pascal库进程MsDos来调用)来检查在DOS 3.x版本

    下运行的程序而开始的。如果程序不是在DOS版本3.X下进行,该程序就会显示出一个

    出错信息,并返回出错代码255。

          如果DOS版本正确,操作会继续进行,此时,如果出现在DOS命令行上的程序名,伴

    随有参数,那系统会把全局变量PawsFlag设置为正确,若出现在DOS命令行上只有一个

    程序名,该全局变量就会被设置为出错。该功能允许通过配置或删除某个参数来控制屏幕

    暂停功能;在此过程中,所提供的其它任何参数都无需用到。

          该程序接着初始化在需要进行全屏幕暂停时,由holdup使用的lctr全局变量,接着,

    它使用未公开的中断21h,功能52h来从DOS中获取CVT的地址,把返回的偏移值减去

    8,并把结果保存在全局指针cvbase中。

          cvt地址可用来获取静态系统数,并接着把它们显示在屏幕上,这在CVT用来保存

     

    841页

        它们的序列中是不需要的,甚至可以说,在一种可能更利传送信息的序列中,这个值是多

        余的。

          显示了这些项之后,该程序接着调用所有的跟踪/报告例程。holdup例程可保证用户

        有充足的时间来读完该程序显示的每一个全屏消息。到这一步,整个CVT3程序便完成

        了。

          可以轻易地改编程序的任何部分以处理某一个区域。例如,通过改变memtrc例程来

        搜索而不是显示数据的话,那么只使用该例程就可以创建一道能访问DOS主环境的程

        序,而不管它所运行的外壳程序嵌套得有多么深。

        D.3.3 CVT4.PAS把CVT3.PAS升级为版本4

          在版本4问世以后,由于对未公开的DOS结构进行了一些改变,使得原有的CVT3.

        PAS不能应用于新的版本。从这一点上看,正好说明了它是在使用未公开的功能时存在

        的一个重大的缺陷——它们中的一切都能随着版本的改变而变化。至于这一点,我们在本

        附录一开始就提醒过读者。

          由于在CVT3.PAS中定义数据所采用的方式的独特性,它使得我们无法让该程序运

        行于其它版本。这样,我们便不得不对该程序进行必要的改变,并推出一种新的程序,这就

        是CVT4.PAS。在以下对CVT4.PAS的介绍中(见Listing 3.2),我们所介绍的只是改变

        的部分;余下部分与CVT3.PAS相同。CVT4.PAS也可通过Turbo Pascal的版本5.0至

        7.0来编译。

                {cvt4.pas-  TurbO Pascal V5.0 version for DOS 4.x

                *       copyright 1987, 1988, 1989 Jim Kyle -All Rights Reserved

                *       The program, and the information it contains, may be freely

                *       distributed and used so long as this entir  comment section

                *       is not altered.

                }

                PROGRAM CVT4;

                {$A-,B-,D+,E-,F-,I+,L+,N+,O-,R-,S+,V-}

                {$M 8192, 0, 0}

                USESDOS;

                TYPE 

                  bcb=RECORD                  {Buffer Control Block format,v4}

                          prcb     : word ;                {  +00 prev  one in chain}

                          nxcb     : word;                  {  +02 next one in chain}

                          ldrv   :byte ;                    { +04 logical drive code}

                          action : byte ;                   { +05 action code         }

                          lsect : longint;                 { +06 logical sector #  }

                          nf       : byte;                 { +0A nbr FATs or 01      }

                          secf     : word ;                { +0b sectors/FAT or 00}

                          pdrv   zpointer;                {  +0D phys drv tbl  tr   }

                          fill2:word ;                      { +11 unknown            }

                          fill3 : byte ;                    { +13 unknown            }

                          buf      : array[ 0 .. 511 ]  of byte ; { +14 the buffer itself}

                        END;

                  bcbptr=^bcb;

                   bcblnk = RECORD              { BCB link record , new in V4          }

                              bxval : word ;                {  +00 , unknown          }

                              pagebase : bcbptr;         { +02 , points to a BCB}

     

    842页

    usrs : byte;  { +06, count of usage }

    fill : longint; { +07, unknown }

    END ;

    bcblkp = ^bcblnk ;

    bufctl = RECORD { EMS control for buffers, new in V4 }

    Inkptr : bcblkp; { +00, point to pagebase }

    pgs : word; { +04, number of pages }

    fill1 : longint; { +06, unknown }

    fill2 : word; { +0A, unknown }

    emsflg : byte; { +0C, FF if no EMS used }

    emshdl : word; { +0D, EMS handle }

    emsppg : byte; { +0F, EMS physical page }

    END ;

    bcptp = ^bufctl;

    nam8 = array[1 . .8] of char;

    mcb = RECORD { Mem Alloc Block header format }

    flag : char; { +00 must be M or Z }

    owner : word; { +01 PSP seg or 0000 }

    siz : word; { +03 Number paragraphs }

    junk : array[5..7] of byte; { +05-+07 not used }

    name : nam8; { +08 Name of owner }

    END ;

    mcbptr = ^mcb ;

    dpb = RECORD { Physical Drive Table forMat }

    drvc : byte; { +00 drive code }

    dunit : byte; { +01 unit number }

    bps : integer; { +02 bytes per sector }

    spc : byte; { +04 sec per cluster -1 }

    pwr2 : byte; { +05 power of 2 }

    nsrvs : integer; { +06 reserved sectors }

    nfats : byte; { +08 number of FATs }

    dirsiz : word; { +09 root dir size }

    fus : word; { +0B first usable sectr }

    tcc : word; { +0D total clstr ct +1 }

    spf : word; { +0F sec per FAT **CHG**}

    fds : word; { +11 first dir sector }

    drvr : pointer; { +13 driver pointer }

    mcode : byte; { +17 media code }

    accflg : byte; { +18 access flag }

    nxt : pointer; { +19 next table ptr }

    lastused : word; { +1D last used cluster }

    filler : word; { +1F usually FFFF }

    END ;

    dpbptr = ^dpb ;

    chn = RECORD { Chain links for DCB, FCB chains }

    nxtlnk : pointer; { +00 next link or FFFF }

    nmbr : integer; { +04 number blocks here }

    END ;

    Chnptr = ^ chn ;

    dcb = RECORD { Device Control Block format }

    nusers : integer; { +00 users for this DCB }

    mode : integer; { +02 0,1,2 per OPEN }

    datrb : byte; { +04 disk attrib byte }

    dvatr : byte; { +05 device attrib (hi) }

    atrb2 : byte; { +06 2nd device attrib }

    pdrvr : pointer; { +07 points to driver }

    frstc : word; { +0B first cluster nbr }

    modtm : word; { +0D file time word }

    moddt: word; { +0F file date word }

     

    843页

    totsiz : longint; { +11 total file size }

    curpos : longint; { +15 current byte pos }

    clsctr : word; { +19 total cluster ctr }

    curcls : word; { +1B current cluster }

    dirsec : word; { +1D directory sector }

    dirndx : byte; { +1F dir entry index 0. .}

    name : array[0. .7] of char; { +20 dev/file name }

    ext : array[0..3] of char; { +28 file extension }

    fill2 : word; { +2B unknown }

    fill3 : word; { +2D unknown }

    fill4 : word; { +2F unknown }

    owner : word; { +31 PSP of owner proc }

    fill5 : word; { +33 unknown }

    fill6 : word; { +35 unknown }

    fill7 : word; { +37 unknown }

    fill8 : word, { +39 unknown }

    END :

    dcbptr = ^dcb ;

    ldt = RECORD { Logical Drive Table format }

    name : array[0. .67] of char;{ +00 drive and path }

    code : byte; { +44 drive in use code }

    mydpb : dpbptr; { +45 DPB fOr this drive }

    dirclu : word; { +49 directory cluster }

    filler2: word; { +4B unknown }

    filler3: word; { +4D unknown }

    patlen : word; { +4F SUbST path length }

    filler4: byte; { +51 unknown   }

    filler5: word; { +52 unknown   }

    filler6: word; { +54 unknown }

    filler7: word; { +56 unknown }

    END ;

    ldtptr  = ^ ldt ;

    cvt = RECORD { Configuration Variable Table }

    curbfr : bcbptr; { current pos in chain }

    memchn : mcbptr; { stact of MCB chain }

    pdrvs : dpbptr; { Fn $52 points to here }

    dcbchn : dcbptr; { set up by FILES= }

    clkdev : pointer; { set by DEVICE= (clock$)}

    condev : pointer; { set by DEVICE= (con) }

    secsiz : integer; { maximum block size }

    bfrchn : bcblkp; { set up by BUFFERS= }

    ldrvs : ldtptr; { set up by LASTDRIVE= }

    fcbchn : chnptr; { set up by FCBS= }

    filler : integer; { number of FCBs to keep }

    npdrvs : byte;  { set by driver list }

    nldrvs : byte; {set by LASTDRIVE= }

    END ;

    cvtptr = ^ cvt ;

    dtstr = string[8] ; { date -time Strings }

    pstrg = string[9] ; { pointer-conversion fmt }

    memst = string[12] ; { memory usage string }

    VAR

    cvtbase : cvtptr;

    curbuf : bcbptr;

    curmcb : mcbptr;

    curdpb : dpbptr;

    curchn : chnptr;

    curdcb ,

    curfcb : dcbptr;

    curldt : ldtptr;

    844页

    bcbctr,

    dcbctr : integer ;   { counters }

    b : Registers;

    PawsFlag: Boolean; { controls screen-full pausing }

    lctr : integer; { counts lines displayed }

    function hexn(b:byte) : char; { convents nibble to char }

    begin

    b := b and 15; { force to only 4 bits }

    if b > 9 then inc(b,7); { adjust for hex digits }

    hexn := chr(b+48) ; { convert to character }

    end ;

    function hexb(b:byte) : string;

    begin

    hexb := hexn(b shr 4) + hexn(b);  { assemble the nibbles }

    end ;

    function hexw(w:word) : string;

    begin

    hexw := hexb(w shr 8) + hexb(w); { assemble the bytes }

    end ;

    function hexl(l: longint) : string;

    begin

    hexl := hexw(l shr 16) + hexw(l); { assemble the words }

    end ;

    procedure outcstr( var s  : nam8); { output ASCIIZ string }

    VAR

    i : integer;

    BEGIN

    i : = 1 ;

    while (s[i] <> #0) and (i < 9) do

    begin

    write ( s [ i] ) ;

    inc ( i ) ;

    end ;

    END ;

    PROCEDURE holdup; { count lines and wait if full }

    BEGIN

    IF PawsFlag THEN

    SEGIN

    inc ( lctr ) ;

    if lctr > 23 then

    BEGIN

    lCtr := 0;

    readln ;

    END

    END

    END ;

    FUNCTION xp( p : pointer ) : pstrg; { displays pointer P }

    BEGIN

    xp := hexw(seg(p^) ) + ' : ' + hexw(ofs(p^) ) ;

    END ;

    PROCEDURE dmp(f  : pointer); { display hex dump of data to CRT }

    VAR

    x : ^byte;

    i : integer;

    c : char;

    BEGIN

    X : = f ;

     

    845页

    write( xp(f) , '> ' ) ;

    FOR i:=0 to 15 DO

    BEGIN

    write( hexb(x^) ;

    if i=7 then write( ' - ' )

    else write ( ' ' );

    x := pointer(longint(x) + 1) ;

    END ;

    write( ' ' ) ;

    X : = f ;

    FOR i:=0 tO 15 DO

    BEGIN

    c := char($7f AND x^) ;

    if c< ' ' then c : = ' . ' ;

    write( c );

    if i=7 then write( ' ' ) ;

    x := pointer(longint(x) + 1);

    END ;

    writeln ;

    holdup ;

    END ;

    PROCEDURE dpbtrc(a: pointer) ; { trace andreport DPB data }

    VAR

    ofsv : word;

    PROCEDURE dpbrpt; { reports each DPB's content }

    BEGIN

    writeln ;

    hOldup ;

    write( 'Drive' , char (curdpb^ .drvc+ord( 'A' ) ) ) ;

    write( ' : (unit , ' curdpb^.dunit, ' of driver at ' , xp(curdpb^.drvr) ) ;

    writeln( ' ) media code = ' , hexb(curdpb^ .mcode) ) ;

    holdup ;

    write( ' ' , curdpb^ .bps:3, ' bytes per sector, ' ) ;

    write( ' ' , curdpb^ .spc+1 :2, ' sectors per cluster, ' ) ;

    writeln( ' ' , curdpb^ .tcc-1 :4, ' total cluster count ' ) ;

    holdup ;

    write( ' Res sectors: ' , curdpb^ . rsrvs, ' ' ) ;

    write( ' ' , curdpb^ .nfats, ' FAT' 's, ' , curdpb^ . spf :2, ' sec ea ') ;

    write( ' FAT entry: ' ) ;

    IF (curdpb^.tcc) > $0FFC

    THEN write( 16 )

    ELSE Write( 12 );

    writeln( ' bits Root: ' , curdpb^.dirsiz:3, ' entries' ) ;

    holdup ;

    write(' First root sector: ', hexwlcurdpb^.fds) );

    write(' First data sector: ', hexw(curdpb^.fus) );

    writeln( ' Last cluster used:  ',hexw(curdpb^ . lastused) ) ;

    holdup ;

    END; { of dpbrpt proc }

    BEGIN

    curdpb := a;

    ofsv := 0;

    writeln ;

    holdUp ;

    writeln( ' DRIVE PARAMETER BLOCK (DPB) DATA- - ' ) ;

    holdup ;

    WHILE (ofsv <> $FFFF) DO

    BEGIN

    ofsv := word(longint( curdpb^ .nxt ) ) ;

    846页

    dpbrpt ;

    curdpb : = dpbptr (curdpb^ . nxt ) ;

    END ;

    write (#12 ) ;

    END; { of dpbtrc proc }

    PROCEDURE bcbtrc2(a : pointer) ;

    VAR

    ofsv : word;

    ofst : word;

    PROCEDURE bcbrpt(a : bcbptr);

    VAR

    i : integer;

    x : pointer;

    BEGIN

    writeln ;

    holdup ;

    inc ( bcbctr ) ;

    write( 'Buffer Control Block ' , bcbctr:2, ' at ' , xp(a) ) ;

    write( ' Prev: ' , hexw(a^ .prcb) ) ;

    writeln( ' Next : ' , hexw(a^ .nxcb) ) ;

    holdup ;

    write ( ' Logical ' ' ' , char ( ord ( ' A ' ) +a^ . ldrv ) ) ;

    write ( ' : ' ' , Sector ' , hexl ( a^ . lsect ) ) ;

    writeln ( ' Action code : ' , hexb(a^ . action ) ) ;

    holdup ;

    write( ' NFATS: ' , hexb( a^ .nf) ) ;

    write( ' SPF: ' , hexw(a^ . secf) ) ;

    writeln( ' DPB address : ' , xp(a^ . pdrv) ) ;

    holdup ;

    write ( ' FILL2 : ' , hexw( a^ . fill2 ) ) ;

    writeln ( ' FILL3 : ' , hexb ( a^ . fill3) ) ;

    holdup ;

    x := addr(bcbptr(a) ^ .buf[0] ) ;

    FOR i:=0 to 31 DO

    dmp (pointer ( longint (x) + ( i SHL 4) ) ) ;

    END; { of bcbrpt proc }

    BEGIN { bcbtrc2 routine }

    bcbctr := 0 ;

    ofSv := 0;

    ofst := ofs(a^) ;

    WHILE (ofsv <> ofst) DO

    BEGIN

    ofsv : =bcbptr(a) ^ . nxcb ;

    bcbrpt (a);

    a := ptr(seg(a^ ) ,ofsv) ;

    END ;

    write ( #12 ) ;

    END ; { bcbtrc2 routine}

    PROCEDURE bcbtrc1 ( a : pointer) ;

    PROCEDURE bcbtrl ( a : bcblkp ) ;

    BEGIN

    writeln ;

    holdup ;

    writeln( ' Page base is at ' , xp(a^ .pagebase) ) ;

    holdup ;

    write ( 'BX Val = ' , hexw(a^.bxval) );

    write ( ' Users = ' , hexb(a^.usrs) );

    writeln(  ' Fill = ' , hexl(a^ .fill) ) ;

    holdup ;

    bcbtrc2 ( a^ . pagebase ) ;

     

    847页

    END ;

    BEGIN

    writeln( ' Link table is at ' , xp(bcptr(a) ^ . lnkptr) ) ;

    hOldup ;

    write ( 'Page count = ' , bcptr(a)^.pgs:4 );

    write ( Fill1 = ' , hexl(bcptr(a)^.fill1) );

    writeln ( ' Fill2 = ' , hexw(bcptr(a) ^ .fill2) ) ;

    holdup ;

    write ( 'EMS Flag = ' , hexb(bcptr(a)^.emsflg) ) ;

    write ( ' Handle = ' , hexw(bcptr(a)^.emshdl) ) ;

    writeln ( ' Physpg = ' , hexb (bcptr(a) ^ . emsppg ) ) ;

    holdup ;

    bcbtrl( bcptr(a) ^ . lnkptr) ;

    END ;

    PROCEDURE dcbtrc(t : dtstr; a : pointer);

    VAR

    ofsv : word;

    FUNCTION f_tm(n : word) : dtstr;

    VAR

    buf : dtstr;

    b : byte;

    BEGIN

    b := ((n SHR 11) AND 31);

    buf[1] :=char((b DIV 10) + 48);

    buf[2] :=char((b MOD 10) + 48);

    buf[3] :=': ' ;

    b := ((n SHR 5) AND 63);

    buf[4] :=char((b DIV 10) + 48);

    buf[5] :=char((b MOD 10) + 48);

    buf[6] :=': ' ;

    b := ((n SHL 1) AND 63);

    buf[7] :=char((b DIV 10) + 48);

    buf[8] :=char((b MOD 10) + 48);

    f_tm := buf;

    END ;

    funCTION f_dt(n : word) : dtstr;

    VAR

    buf : dtstr;

    b : byte;

    BEGIN

    b:=((n shR 5) AND 15);

    buf[1]:=char((b DIV 10) + 48);

    buf[2]:=char((b MOD 10) + 48);

    buf[3]:= '/';

    b:=(n   AND 31);

    buf[4]:=char((b DIV 10) + 48);

    buf[5]:=char((b MOD 10) + 48);

    buf[6]:='/';

    b:=((n SHR 9) AND 15) + 80;

    buf[7]:=char( (b DIV 10) + 48) ;

    buf[8] :=char((b MOD 10) + 48);

    f_dt   buf;

    END ;

    PROCEDURE dcbrpt( var t : dtstr; n : integer );

    type

    acctyp = array[0. .31 of string[7] ;

    const

    actyp : acctyp = ('READ ','WRITE', 'R/W' , unknown'} ;

    Var

    848页

    isdvc : Boolean;

    BEGIN

    WHILE (n > 0) DO

    BEGIN

    INC (dcbctr) ;

    writeln ;

    holdup ;

    write (t, ' ', dcbctr:2 );

    IF (curdcb^ . name[0] = #0) THEN

    BEGIN

    writeln('at ' , xp(curdcb),'not used since bootup' );

    holdup ;

    END

    else

    BEGIN

    isdvc := (curdcb^.dvatr and 128) <> 0;

    write( ' for') ;

    IF isdvc

    THEN write('device ' )

    ELSE write( 'file ' ) ;

    write ( curdcb ^ . name [ 0 ] , curdcb^ . name [ 1 ] , curdcb^ . name [ 2 ] ) ;

    write ( curdcb^ . name [ 3 ] , curdcb ^ . name [ 4 ] , curdcb^ . name [ 5 ] ) ;

    write (curdcb^ . name[6] , curdcb^ . name[ 7] ) ;

    IF (NOT isdvc) THEN { block driver}

    write('. ' , curdcb^ . ext[0] , curdcb^ .ext[1 ] , curdcb^ . ext [2] ) ;

    write(' at ' , xp( curdcb ) );

    write('shows ' , curdcb^ .nusers) ;

    writeln( ' OPENs ' ) ;

    holdup ;

    write( ' opened for ' , actyp[3 AND (curdcb^ .mode) ] ) ;

    write('access' ) ;

    IF ($FFFC AND (curdcb^ .mode) )<>0 THEN

    write( ' ( ' , hexw(curdcb^ .mode) , ' ) ' ) ;

    writeln( ' by process ' , hexw(curdcb^ .owner) ) ;

    holdup ;

    IF( isdvc ) THEN { Device }

    BEGIN

    write( ' Device driver at ' , xp(curdcb^ .pdrvr) );

    write( ' is in ' ) ;

    if ((curdcb^ .dvatr) AND 32)<>0 THEN write( 'Raw' )

    ELSE write( ' Cooked ' ) ;

    write( ' mode and is ' ) ;

    if ((curdcb^ .dvatr) AND 64)=0 THEN write( ' not ' ) ;

    writeln ( ' ready ' ) ;

    holdup ;

    END

    else { File }

    BEGIN

    write( ' File is on drive ' , char(ord( 'A' )+( (curdcb^ .dvatr) AND 31 ) ) ) ;

    write( ' : (driver at ' , xp(curdcb^ .pdrvr) ) ;

    write( ' ) and has ' ) ;

    if ( (curdcb^ .dvatr) AND 64)<>0 THEN write( ' not ' ) ;

    writeln( ' been written to . ' ) ;

    holdup ;

    writeln( ' File ' ' s attribute byte = ' , hexb(curdcb^ .datrb) ) ;

    holdup ;

    END ;

    write (' Mod Time/date: ' );

    write (f_tm(curdcb^.modtm) , ' , ' ) ;

    writeln ( f_dt ( curdcb^ . moddt ) ) ;

    holdup ;

    write ( ' Dir Sector: ' , hexw(curdcb^.dirsec) , ' ' ) ;

    849页

    writeln ( ' Dir Index : ' , curdcb^ . dirndx : 4 , ' ' ) ;

    holdup ;

    write ( ' First Cluster: ' , hexw(curdcb^.frstc) , ' ' ) ;

    write ('Prev Clusters: ' , curdcb^.clsctr:4, ' ' ) ;

    writeln( ' Current Cluster: ' , hexw(curdcb^ .curcls) , ' ' ) ;

    holdup ;

    write ( ' Directory size: ' , curdcb^ .totsiz:6, ' ' ) ;

    writeln( ' Curr byte count: ' , curdcb^ .curpos:6 ) ;

    holdup ;

    write ( ' Fill2=' , hexw(Curdcb^ .fill2) , ' ' ) ;

    write ( ' Fill3=' , hexw(curdcb^.fill3) , ' ' ) ;

    write ( ' Fill4=' , hexw(curdcb^ .fill4) , ' ' ) ;

    writeln ( ' Fill5= ' , hexw(curdcb^ . fill5) ) ;

    holdup ;

    write ( ' Fill6=' , hexw(curdcb^ .fill6) , ' ' ) ;

    write ( ' Fill7=' , hexw(curdcb^ .fill7) , ' ' ) ;

    writeln ( ' Fill8= ' , hexw( curdcb^ . fill8) ) ;

    holdup ;

    END ;

    curdcb := pointer(longint(curdcb) + sizeof(dcb) - 1 ) ;

    DEC( n );

    END; { n >= 0 loop }

    END ; { of dcbrpt }

    BEGIN

    curchn := chnptr(a) ;

    dcbctr := 0;

    ofsv := 0 ;

    WHILE (ofsv <> $FFFF) DO

    BEGIN

    ofsv : = word ( longint (curchn^ . nxtlnk ) ) ;

    curdcb : = dcbptr( longint (curchn )+sizeof (chn) ) ;

    writeln ;

    holdup ;

    write ( 'Link at ' , xp(curchn) , ' contains ' ) ;

    writeln( curchn^ .nmbr, ' ' , t, ' s -- ' ) ;

    hOldup ;

    dcbrpt (t, curchn^ .nmbr) ;

    curchn : = chnptr(curchn^ . nxtlnk ) ;

    END ;

    write ( #12 ) ;

    END ;

    PROCEDURE memtrc(a : pointer) ;

    VAR

    z : longint;

    PROCEDURE memrpt(s,o,a : word; var n : nam8);

    FUNCTION memu(a : word) : memst; { determine memory use }

    Var

    x : char;

    BEGIN

    x := char( mem[a:0] );

    CASE x OF

    #$CD :

    memu : = 'Program' ;

    'A' . . 'Z' :

    memu := ' Environment ' ;

    else

    memu : ='Data ' ;

    End ;

    END ;

    850页

    BEGIN

    z := longint(s) SHL 4;

    write( z:6, ' bytes ' );

    IF (O<>0) THEN

    begin

     write ('USED by proc ' , hexw(o));

    write ( ' , at ' , hexw( a ), ' :0000, for ' , memu(a) ) ;

    if n[1] in [ 'A'. . 'Z'] then

    begin

    write( ' . Pgm name:');

    outcstr( n );

    writeln ;

    end

    else

    writeln( ' . No program name' ) ;

    end

    else

    writeln( 'FREE at ' , hexw( a ) , ' :0000' ) ;

    holdup ;

    END; { of memrpt }

    BEGIN

    curmcb := mcbptr(a) ;

    writeln ;

    holdup ;

    writeln ( ' MEMORY ALLOCATION CHAIN ' ) ;

    holdup;

    WHILE (curmcb^ .flag = 'M' ) DO

    BEGIN

    menrpt ( curmcb^ . siz, curmcb^ . owner, SEG(curmcb^ )+1 , curmcb^ . name) ;

    curmcb := ptr( seg(curmcb^) + (curmcb^.siz + 1), 0 );

    END ;

    IF (curmcb^ .flag <> 'Z' ) THEN

    BEGIN

    writeln(#13, #10, 'MEmoRY ALLOCATION ERROR at ' , xp(curmcb) ) ;

    halt ( 255 ) ;

    END ;

    memrpt ( curmcb^ . siz , curmcb^ .owner, SEG(curmcb^ ) +1 , curmcb^ . name) ;

    write (#12 ) ;

    END; { of memtrc }

    PROCEDURE ldttrc( a: ldtptr; n: byte );

    PROCEDURE ldtrpt( 1: ldtptr; d: byte ) ;

    VAR

    ldrive : char;

    i : integer;

    BEGIN

    ldrive := chr( $41 + d );

    if (l^ . code AND byte($40) )=0 then

    writeln( 'Logical Drive ' , ldrive, ' not yet defined' )

    else

    begin

    write ( 'Logical Drive' , ldrive );

    writeln( ' = Physical drive',  l^.name[0] ) ;

    holdUp ;

    write ('The current (full) pathspec is: ' );

    i : = 0 ;

    repeat

    write ( 1^.name[i] );

    inc(i);

    851页

    until (l^ .name[ i] ~~ #0) ;

    writeln ;

    end ;

    holdup ;

    if (l^ . code = $50) then

    writeln( 'Code = 0*50 - - result of SUBST command' )

    else if(l^ .code = $40) then

    writeln( 'Code = 0*40 -- physical (or aliased) device' )

    else

    writeln( ' Code = 0x ' , hexb(l^ . code) , ' - - unknown ' ) ;

    hOldUp ;

    writeln( 'Directory Cluster x . , hexw( ~~ -dirclu ) ) `,

    holdUp ;

    writeln( 'Path Length to ignore = ' , hexw( l^.patlen ) ) ;

    hOldup ;

    write('Filler2 =', hexw(1^ .filler2) , ' ' );

    write (Filler3 = ' , hexw(l^ .filler3) ,' ') ;

    writeln( Filler4 =', hexb( 1^ . filler4) ) ;

    holdup ;

    write ( 'Filler5 =' ,  hexw(l^ .fillers) ,' ') ;

    write ( 'Filler6 = ' , hexw(l^ .filler6) , ' ' ) ;

    writeln( Filler7 = ', hexw( l^ . filler7) ) ;

    holdup ;

    writeln ;

    holdup ;

    END; { of ldtrpt }

    VAR

    o : byte;

    BEGIN

    Curldt := a;

    writeln ;

    holdup ;

    writeln( ' LOGIcAL DRIVE TABLES t set by LASTDRIVE=, SUBST, etc . ) : ' )

     ;

    holdup ;

    dec( n ) ; { convert for zero-based reference }

    for o := 0 to n do { loop through continuous tables }

    begin

    ldtrpt (curldt , o) ;

    curldt : = ptr(seg(curldt^ ) , ( ofs(curldt^ ) + sizeof(ldt) ) ) ;

    end ;

    write ( #12 ) ;

    END; { of ldttrc }

    { main }

    BEGIN

    b.ah := $30; { Check for correct DOS version }

    MsDos ( b ) ;

    .if b.al < 4 then { If not V4.x or higher, get Out }

    begin

    writeln('Wrong DOS version: ' , b.al, ' . ' , b.ah ) ;

    halt (255) ; { return ErrorLevel=255}

    end ;

    PawsFlag := ParamCount = 0;. { else set up for paging output }

    852页

    lctr := 0;

    writeln('Configuration Variables, DOS version', b.al, ' . ' , b.ah ) ;

    holdup ;

    b.ah :=  $52; { Get CVT pointer set up }

    msdos (b) ; { (using undocumented function ) }

    cvtbase := ptr(b.es, b.bx-8); { hold pointer to CVT }

    writeln ;

    holdup ;

    writeln('CVT is located at ' , xp(cvtbase) ) ;

    holdup ;

    write ('No. of Phys Drives (al', xp(@cvtbase^.npdrvs));

    writeln( ' ) : , cvtbase^ .npdrvs) ;

    holdup ;

    write ( 'No. of Log. Drives (at ' , xp(@cvtbase^.nldrvs)) ;

    writeln( ' ) : ' , cvtbase^ . nldrvs) ;

    holdup ;

    write ( ' Clock Device (ptr at ' , xp(@cvtbase^.clkdev));

    writeln ( ' ) : ' , xp(cvtbase^ . clkdev));

    holdup ;

    write ( ' CON Device (ptr at ' , xp(@cvtbase^.condev));

    writeln( ' ) : ' , xp(cvtbase^ . condev) ) ;

    holdup ;

    write ('Sector Size(?) (at ' , xp(@cvtbase^.secsiz)) ;

    writeln( ' ) : ' , hexw( cvtbase^ . secsiz ) ) ;

    holdup ;

    write ( ' FCBs to keep (at ' , xp(@cvtbase^.filler)) ;

    writeln ( ' ) : ' , hexw(cvtbase^ . filler) ) ;

    holdup ;

    write ( '1. Memory Chain (ptr at ' , xp(@cvtbase^.memchn)) ;

    writeln ( ') : ' , xp(cvtbase^ . memchn ) ) ;

    holdup ;

    write ( '2. DCB Chain (ptr at', xp(@cvtbase^.dcbchn) ) ;

    writeln ( ' ) : ' , xp(cvtbase^ . dcbchn ) ) ;

    holdup ;

    write ( '3. DPB Chain (ptr at ' , xp(@cvtbase^.pdrvs) ) ;

    writeln (') :',  xp(cvtbase^ . pdrvs ) ) ;

    holdup ;

    write ( '4. FCB Chain (ptr at ' , xp(@cvtbase^.fcbchn)) ;

    writeln ( ' ) : ' , xp(cvtbase^ . fcbchn) ) ;

    holdup ;

    write ( '5. LDT Chain (ptr at ' , xp(@cvtbase^.ldrvs) );

    writeln( ' ) : ' , xp(cvtbase^ . ldrvs) ) ;

    holdup ;

    write ('6. Current Buffer (ptr at ' , xp(@cvtbase^.curbfr));

    writeln( ' ) : ' , xp(cvtbase^ . curbfr) ) ;

    holdup ;

    write ( '7. Buffer Chain (link at ' , xp(@cvtbase^.bfrchn) ) ;

    writeln( ' ) : ' , xp(cvtbase^ . bfrchn) ) ;

    holdup ;

    writeln ;

    holdup ;

    writeln ( ' TRACING MCB Chain=== ' ) ;

    holdup ;

    memtrc ( cvtbase ^ . memchn ) ;

    writeln ;

    holdup ;

    writeln ( ' TRACING DCB Chain=== ' ) ;

    holdup ;

    853页

                    dcbtrc(' DCB ' ,cvtbase^.dcbchn);

                    writeln;

                    holdup;

                    writeln('TRACING          DPB Chain===');

                    holdup;

                    dpbtrc ( cvtbase^ . pdrvs);

                    writeln ;

                    holdup;

                    writeln('  TRACING        FCB Chain===');

                    holdup;

                    dcbtrc('FCB',cvtbase^. fcbchn);

                     writeln;

                     holdup;

                    writeln(' TRAcING        LDT Chain===');

                    holdup;

                    ldttrc(cvtbase^.ldrvs,cvtbase^.nldrvs);

                    writeln;

                    holdup;

                   writeln('  TRACING Buffer Chain from current buffer===');

                    holdup;

                    DcbtrC2(cvtbase^.Curbfr);

                    writeln ;

                    holdup;

                    writeln( ' TRACING   Buffer Chain thru EMS link record===' );

                    holdup;

                    bcbtrc1 (cvtbase^ .bfrchn);

                  END.

        缓冲区控制块和EMS链接

            同CVT3相比,在CVT4中的一个主要改变是bcb记录的定义。这种昔日为一个指向

        下一个缓冲器的4字节远指针(nxcb)变成了一对2字节的近指针,分别指向前一个缓冲

        区(prcb)和下一个缓冲区(nxcb)。在控制块中,余下的功能大体上是相同的,不同之处有

        lsect元素(逻辑扇区号)从16位值变成了32位值,以及secf元素(每FAT的扇区数)从一

        个字节扩展成了一个16位的字。由于这些改变,BCB的大小也相应地由16个字节变成了

      20个字节。

            为了适应DOS随着版本4的出现而开始对扩展内存的使用,该程序中也加进了两个

        新的结构。它们在CVT4中分别被定义为bcblink,一种保存着散列值(bxval)并指向相应

        的BCB(而基)的链接记录;以及bufcbt—一种把EMM句柄与bcblnk记录连结在一起

        的记录,并且还保存其它供EMS软件使用的数据。正如上述所介绍的一样,并非这两种

        记录中的所有字段都得到了完全的编码。与这两种记录相应的指针类型分别被定义为

        bcblkp(指向bcblnk记录)和bcptr(指向bufctl记录)。

            由于在缓区处理上发生了许多变化,bcbtrc和bcbrpt过程也几乎是彻底地改头换面

        了,只是从最初的模块特征上才可能看出昔日的面貌。bcbrpt的改变直接反映出了在版本

        4 BCB所出现的新信息。在版本4中,两种新的过程(bcbtrc1)和(bcbtrc2)代替了原有的

        bcbtrc例程,以便能处理访问缓冲方法上的改变并能适应新的EMS链接结构。至于另一

     

    854页

        个新的过程bcbtrl则是出现在bcbtrcl中。

          称作bcbrpt的循环最初是bcbtrc中的,而现在,它被定位在bcbtrc2中。bcbtrl过程可

    从bcblnk记录中报告出页基数据,并接着调用bcbtrc2;bcbtrc1在从bufctl记录中报告出

    数据之后,便会把一个bcblnk指针传送到bcbtrl。这些改变表面上看起来似乎无惊人之

    处,但却是必须的,只有这样才能处理输入数据时的重大改变。这也是足以说明了模块化

    设计用在这些程序上的威力。

    内在控制块

          在版本4中,对MCB的改变是次要的;目前,用于程序装载的MCB包括程序的名字

    (去掉扩展名,该名字就是从中装载该程序的文件的名字)。CVT4是通过定义一种新类型

    -nam8(它是一个字符数组,而不是一个字符串,因为MCB既不含Pascal长度字节,也

    没有采用C语言的字符串结尾字节)来处理这种改变的,并且把mcb记录的范围扩展到

    包括nam8字段。

    程序名的增加要求改变memrpt过程,以便在程序名存在时,系统能报告出nam8字段。不

    过,除此之外,再也没有其它改变了。

    驱动器参数块

          在版本3和版本4之间,对DPB的唯一改变是每FAT的扇区数这一字段在大小上

    从一个字节变成了一个字,这样,dPb记录的定义也相应地作了修改,以适应其变化。从概

    念上看,此修改很细微,但却是CVT3不能追寻DOS V4系统的一个主要原因;dpb记录

    中spf元素的大小的改变,改变了nxt指针的位置,而nxt指针则用于搜索DPB链,而程

    序便无法再正常工作。

    设备控制块

          在DOS V4里,DCB的大小扩展了6个字节。在dcb记录的定义里增加了3个字(其

    含义未知),用于反映这一变化。

          dcbrpt过程也作了改变,来报告新增的字,但是,不必再进行其他的修改来跟踪或报

    告DCB和FCB。

    逻辑设备表

          在DOS V4里,LDT的大小也扩展了7个字节。程序在ldt记录的定义中增加了1个

    字节及3个字(意义均未知),来保持修改同步。

          因为增加了数据,所以对ldtrpt也进行了细微的修改来报告新字段里的内容。

    CVT定义的本身

          在版本4中,对CVT记录只进行了唯一的一点改变,这个改变是如此之小,以致于容

    易引起人们的忽视,这就是指针bfrchn的类型从bcbptr(版本3中)变成了bcblkp(版本4

    中)。但,这一细微的改变却有其重大的意义。

    实用程序例程

          在CVT4中增加了一种实用程序例程,即outcstr,以便为新的nam8数据类型(供改

     

    855页

    变后的MCB使用)提供输出功能。把nam8变量的地址传送给该例程,它就能不断地输出

    字符,直到它处理完了全部8个变量或者遇到了00h字节。它只能由memrpt例程使用。

    主例程

          在主调用序列中的第一个变化是,CVT4通过DOS版本4而不是版本3来检查操

    作,并且当不是版本4时,CVT4便会终止。

          在总结静态报告的措词方面的改变是很轻微的,仅仅只反映出CVT记录中的curbfr

    字段在含义上的改变。类似地还有,用于缓冲器跟踪的标题也一定程度地有所改变,因为

    整个链接页(或在没有使用EMs时为所有缓冲器)是在CVT3仅仅用来报告当前缓冲器

    的同一点上被报告出来的。

          但是,程序之间的改变与DOS版本之间的实际变化相比,往往总是要简单得多。

                                D.4小        结

          本附录介绍了一种可使用未公开的DOS功能的方法,以探索DOS内部的工作,并

    列举了一个读者可以修改的例子,以便在DOS运行时,利用可以得到的信息。

          但是,必须记住:无论何时,只要DOS的主版本号出现了变化,使用这些功能都会令

    人十分头痛。因此,在程序中应尽量少用未公开的功能,这样便能在商业领域中或在大众

    化的范围内使开发的产品具有更为广阔的天地,也能为每个用户拓宽应用前景以及减少

    不必要的麻烦。

    856页

    附录E 支持资源清单

    E.1 硬  件

    Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, Redmond, Washington,

    1991.

    Intel Corporation. 80286 and 80287 Programmer's Reference Manual. Intel Corporation,

    Santa Clara, California, 1987.

    Intel Corporation. 80386 Programmer's Reference Manual. Intel Corporation, Santa Clara,

    California. 1986.

    Intel Corporation. 80387 Programmer's Reference Manual. Intel Corporation, Santa Clara,

    Califormia, 1987.

    Intel Corporation. i486 Microprocessor Programmer's Reference Manual. Intel Corpora-

    tion, Santa Clara, California, 1989.

    Intel Corporation. iAPX 86/88, 186/188 User's Manual. Intel Corporation, Santa Clara,

    California. 1987.

    International Business Machines Corporation. Mouse Technical Reference. IBM, Boca Raton,

    Florida. 1987.

    International Business Machines Corporation. Personal Computer Technical Reference.

    IBM, Boca Raton, Florida, 1984.

    International Business Machines Corporation . Personal System/2 and Personal Computer

    BIOS Technical Reference. IBM, Boca Raton, Florida, 1987.

    Morse, Stephen P. The 8086/8088 Primer, 2nd Edition. Hayden Book Company, Rochelle

    Park, New Jersey, 1982.

    Woram, John. The PC Configuration Handbook. Bantam Books, New York, New York, 1987.

    E.2 MS-DOS 和BIOS 编程

    Brown, Raif, and Kyle, Jim. PC Interrupts. Addison-Wesley, Reading, Massachusetts, 1991 .

    Campbell, Joe. C Programmer's Guide to Serial Communications. Howard W. Sains and

    Company, Indianapolis, Indiana, 1987.

     

    857页

    Chesley, Harry R. and Mitchell Waite. Supercharging C with Assembly Language. Addison-

    Wesley, Reading, Massachusetts, 1987.

    Duncan, Ray. Advanced MSDOS Programming, Second Edition. Microsoft Press, Redmond,

    Washington, 1988.

    Hyman, Michael. Memery Resident Utilities, Interrupts, and Disk Management with MS

    and PC DOS. MIS Press, Portland, Oregon, 1986.

    Jamsa, Kris. DOS Programming: The Complete Reference. Osborne/McGraw-Hill, Berkeley,

    California. 1991 .

    Jourdain, Robert, and Norton, Peter. Programmer's Problem Solver, 2nd Edition. Brady

    Books, New York, New York, 1986.

    Kyle, Jim. DOS Developer's Guide, New Edition. Sams Publishing, Carmel, Indiana, 1993.

    Lai, Robert S. Writing MS-DOS Device Drivers. Addison-Wesley, Reading, Massachusetts,

    1987.

    Phoenix Technologies Ltd. System BIOS for IBM PCs, Compatibles, and EISA Computers,

    2nd Edition. Addison-Wesley, Reading, Massachusetts, 1991 .

    Porter, Kent. Stretching Turbo Pascal. Brady Books, New York, New York, 1987.

    Schulman, Andrew. Undocumted DOS Addison-Wesley, Reading, Massachusetts, 1990.

    Wadlow, Thomas A. Memory Resident Programming on the IBM PC. Addison-Wesley,

    Reading, Massachusetts, 1987.

    Williams, AL DOS 5: A Developer's Guide. M&T Books, Redwood City, California, 1991 .

    Wilton, Richard. Programmer's Guide to PC and PS/2 Video Systems. Microsoft Press,

    Redmond, Washington, 1987.

    E.3 编程语言

    Abel, Peter. Assembler for the IBMPC and PC-XT Reston Publishing, Reston, Virginia,1984.

    Feldman, Phil and Tom Rugg. Using QuickBASIC 4 . Que Corporation, Carmel, indiana, 1988.

    Harbison, Samuel P. and Guy L.Steele, Jr. C:A Referme Manual. Prentice Hall, Engewood

    Cliffs, New Jersey, 1987.

    Holzner, Steve, and Peter Norton Computing, Inc. Advanced Assembly Language. Brady

    Books, New York, New York, 1991 .

    Johnson, Marcus. Assembly Language for Reat Programmers ONLY! Sams Publishing,

    Carmel, Indiana, 1993.

    Lafore, Robert. Microsoft C Programming for the PC, 2nd Edition. Howard W. Sams and

    Company, Indianapolis, Indiana, 1990.

    Scanlon, Leo. IBM PC and XT Assembly Language.Brady Books, Bowie, Maryland,1983.

    Socha, John, and Norton, Peter. Peter Norton's Assembly Language Book for the IBM PC

    Brady Books, New York, New York, 1986.

     

    858页

    Wyatt, Allen. Advanced Assembly Language. Que Corporation, Carmel, Indiana, 1992.

    Wyatt, Allen. Using Assembly Language, 3rd Edition. Que Copooration, Carinel, Indiana,

    1992.

    Yester, Michael. Using Turbo Pascal 6, 2nd Edition. Que Corporation, Carmel, Indiana, 1991 .

     E.4 一般编程技术

    Birrell, N.D. and M.A. Ould. A Practical Handbook for Software Development. Cambridge

    University Press, Cambridge, England, 1986.

    Ledgard, Henry. Software Engineering Concepts. Addison-Wesley, Reading, Massachusetts,

    1987.

    Liffick, Blaise W. The Software Developer's Handbook. Addison-Wesley, Reading, Massachu-

    setts, 1985.

    Yourdon, Edward. Techniques of program Structure and Design. Prentice Hall, Englewood

    Cliffs, New Jersey, 1975

    其实句柄、API之类的概念在DOS中就有很大发展了,所以耐心看完这本书绝对大有好处!


    ---------------------------------------------------------------完------------------------------------------------------------------------

  • 相关阅读:
    记第一次为开源代码报漏洞
    入职第三周——总结前两周学习内容
    入职一星期之感想
    毕业季之礼
    基于mint-ui的移动应用开发案例二(项目搭建)
    基于mint-ui的移动应用开发案例一(简介)
    工作笔记一——杂项
    微信小程序实战小小应用——豆瓣电影
    React学习之坑(二)- 基础入门
    React学习笔记(一)- 环境搭建
  • 原文地址:https://www.cnblogs.com/Chaobs/p/3838570.html
Copyright © 2020-2023  润新知