系统机能调用Windows操作系统原理实验,DOS程序员手册

  r.h.dh=24; /*右下角坐标*/

代码达成

“`

data segment

menu  db 0ah,0dh,’ Input number to chose your function’

db 0ah,0dh,’       1.Follow Typing’

db 0ah,0dh,’       2.Cover Typing’

; db 0ah,0dh,’       3.Ranking’

db 0ah,0dh,’       3.Exit’

db 0ah,0dh,’Please input your select:$’

mess1 db 0ah,0dh,’ This is the Follow Typing page.’

db 0ah,0dh,’     Please input accordance with those word!$’

mess2 db 0ah,0dh,’ This is the Cover Typing page.’

db 0ah,0dh,’     Please input accordance with those word!’

db 0ah,0dh,’ (Yellow is right, Red is wrong!)$’

mess3 db 0ah,0dh,’This is third select$’

mess4 db 0ah,0dh,’ Thank you for your use!$’

mess5 db 0ah,0dh,’Your right number is:$’

endline db 0ah,0dh,’$’

mess  db 255,?,255 dup(?)

text  db ‘New strides have been taken in strengthening national defense
and army building.$’

right db ‘0$’

sum  db ‘/80$’

num  db 0

data ends

code segment

assume cs:code,ds:data

start:

mov ax,data

mov ds,ax

let0:

mov ax,0

mov dx,offset menu ;展现菜单

mov ah,9

int 21h

mov ah,1 ;输入选用

int 21h

cmp al,’1′ ;输入为1,跳转到照打界面

jz prog1

cmp al,’2′ ;输入为2,跳转到覆盖打界面

jz prog2

cmp al,’3′ ;输入为3,跳转到排名界面

jz prog3

jmp prog4 ;输入不为1或2或3,退出程序

prog1:

jmp real_prog1

prog2:

jmp real_prog2

prog3:

jmp real_prog3

prog4:

jmp real_prog4

real_prog1: ;照打界面

mov ax,0003h ;清屏

int 10h

mov dx,offset mess1 ;展现提醒新闻

mov ah,9

int 21h

mov dx,offset endline ;换行

int 21h

mov dx,offset endline ;换行

int 21h

mov dx,offset text ;呈现小说

mov ah,9

int 21h

mov dx,offset endline ;换行

int 21h

mov dx,offset mess ;输入串

mov ah,10

int 21h

;输入实现,开端开始展览巡回相比

mov ax,0

mov di,0 ;存款和储蓄正确个数

mov cl,mess+1 ;输入的字母个数,即循环的次数

mov bx,2 ;第①个字符的单元地点

let1:

mov dl,text[bx-2]

cmp mess[bx],dl ;判断是还是不是输入正确

jz let2 ;输入正确 跳到let2

jmp out1 ;跳到公共出口 out1

let2: ;正确数+1

add ax,1

add di,1

out1:

dec cl ;循环次数-1

inc bx

cmp cl,0

jnz let1

jz out2

out2: ;检查完成,输出结果

mov dx,offset mess5

mov ah,9

int 21h

;输出正确个数

mov ax,di

mov bl,10

div bl

add ah,’0′

mov right,ah

add al,’0′

mov dl,al

mov ah,2

int 21h

mov dl,right

mov ah,2

int 21h

mov right,0 ;重置right为0

mov di,0

mov dx,offset sum

mov ah,9

int 21h

jmp let0 ;再次来到选取菜单

real_prog2: ;覆盖打界面

mov dx,offset mess2

mov ah,9

int 21h

mov ax,0003h ;清屏

int 10h

;置展现光标

mov ah,2

mov dh,4

mov dl,0

mov bh,0

int 10h

;显示串

mov dx,offset mess2

mov ah,9

int 21h

mov dx,offset endline ;换行

int 21h

mov dx,offset endline ;换行

int 21h

mov dx,offset text

mov ah,9

int 21h

;置输入光标

mov ah,2

mov dh,9

mov dl,0

int 10h

mov si,80 ;循环次数

mov bx,0 ;第3个字符的单元地点

mov di,0 ;正确个数

mov num,0 ;呈现列的职位

prog2_let1:

;输入字符

mov ah,1

int 21h

mov dl,text[bx]

cmp al,0DH ;判断是还是不是输入回车

jz prog2_out2

cmp al,dl ;判断是不是输入正确

jz prog2_let2 ;输入正确 跳到let2

cmp al,dl

jnz prog2_let3 ;输入错误,跳到let3

jmp prog2_out1 ;跳到公共出口out1

prog2_let2:

add di,1 ;正确数+1

;输入正确,改变为香艳

mov ah,06h

mov al,0

mov bh,0eh

mov ch,8

mov cl,num

mov dh,9

mov dl,num

int 10h

;置展现光标

mov ah,2

mov dh,9

mov dl,num

mov bh,0

int 10h

mov dl,text[bx]

mov ah,2

int 21h

jmp prog2_out1 ;跳到公共出口out1

prog2_let3:

;输入错误,响铃

mov ah,2

mov dl,7

int 21h

;输入错误,改变为革命

mov ah,06h

mov al,0

mov bh,04h

mov ch,8

mov cl,num

mov dh,9

mov dl,num

int 10h

;置显示光标

mov ah,2

mov dh,9

mov dl,num

mov bh,0

int 10h

mov dl,text[bx]

mov ah,2

int 21h

jmp prog2_out1 ;跳到集体出口out1

网赌十大信誉的平台,prog2_out1:

dec si ;循环次数-1

inc bx

inc num

cmp si,0

jnz jump_prog2_let1 ;si≠0,继续循环

jz prog2_out2

jump_prog2_let1:

jmp prog2_let1

prog2_out2: ;循环结束,输出结果

mov dx,offset mess5

mov ah,9

int 21h

;输出正确个数

mov ax,di

mov bl,10

div bl

add ah,’0′

mov right,ah

;add al,74

add al,’0′

mov dl,al

mov ah,2

int 21h

mov dl,right

mov ah,2

int 21h

mov right,0 ;重置正确个数为0

mov di,0

mov dx,offset sum

mov ah,9

int 21h

jmp let0

real_prog3: ;排行界面

mov dx,offset mess3

mov ah,9

int 21h

jmp let0 ;再次回到选取菜单

real_prog4: ;退出

mov dx,offset mess4

mov ah,9

int 21h

mov ah,4ch

int 21h

code ends

end start

“`

用来字符显示。

int86(0x10,&r,&r);

目的:

编辑英文打字练习软件,综合复习字符输入和展现,置光标、开窗口、颜色设置等显示屏作用;明白分支程序中字符相比及总结的主次设计,循环及排序程序设计方法;参预中断调用的计时作用。通过上述综合性练习,进一步加深对汇编语言的掌握和抓牢程序设计技术。

                                
                                                       

r.h.bl=attr

程序框图:

网赌十大信誉的平台 1

程序框图

    下列显示器类型也能鉴定识别:

r.h.ch=0; /*左上角坐标*/

内容:

1.荧屏出现打字练习菜单(格式自定,字体、字号、颜色)

2.菜单项目为4项:照打,覆盖打,排名,退出

mov si , Offset CIRRUS_BIOS_Sig

r.x.cx=1;

jmp Short Herc_exit

}

}

② 、在荧屏的制定区域内画框,在框内彰显字符串。(升高题)

个高速的先后变健康更易于。

{ union REGS r;

and word ptr [bx] , NOT ADAPTER_SYSTEM_MASK

  r.h.al=ch;

  
 页码(假使用户编写了和睦的窗口函数来直接存取显示屏内部存款和储蓄器,那么就不会受此限制)。而

  r.h.bh=0;

jmp short test_trident

r.h.bh=0;

db EGA OR MDA_MONITOR

  int86(0x10,&r,&r); /*系统机能调用*/

      mov al,es:65h     ; get last value sent to mode control

  r.h.ah=6; /*子效能号*/

mov si , OffSet PARADISE_BIOS_Sig

叁 、精通运用10H号作用调用(BIOS的突显I/O成效调用)来落实对荧屏的操作与操纵。

                regs.h.ah=0x06;

┗ 192

and word ptr [bx] , NOT ADAPTER_SYSTEM_MASK

┓ 191

    位数=log(16)/log(2)=1.20412/0.301003=4位

┏ 218

detect_SVGA: call SVGA_detect

  r.h.bh=7; /*7意味品蓝*/

push si

{ union REGS r;

        列表5.4

int86(0x10,&r,&r);

; It’s an ATI BIOS- -now identify the chipset

叁 、在屏幕上钦点区域内画框并以动画方式显得字符串。(选做题)

jb not_headland

r.h.dl=y;

·····000            白色前景(正常)

  r.h.ah=9;

mov bl,al ; Save it in BL

壹 、实验指标

or word ptr [bx] ,SVGA OR AHEAD

制表符   ASCII码

位      值

② 、领会用C语言完成系统机能调用的措施和手续。

     
有个别显得适配卡每行能彰显40或七十八个字符。基本的摄像显示格式是80*25每屏

清屏子程序:

#define VIDEO 0x10

  r.h.cl=0;

Call MDA_detect ; and MDA

  locate(x ,y);

jne svga_exit

┃ 179

姹紫嫣红文本格局位的意思。

void writech(int x , int y, char ch ,int attr)

98页

void cls(void)

test_vesa: mov ax,04F00h

壹 、在显示器的钦点区域内显示字符串。(必做题)

jmp test_vesa

 }

和pgprint()函数(见列表5.8)。

━ 196

#define UPPERLEFT 201

┛ 217

级的显示电路技术,以便提供更高品质的图像。

  r.h.dh=x; /*定位点坐标*/

那个意义是什么样发挥作用的。录像成效象本书介绍的别的主旨相同,它们也是在DOS和

{ union REGS r;

          void border( int lr,int lc, int rr,int rc);

  r.h.dl=79;

1000           8            灰色

在钦命地点写参数:

out dx,al

显示器画框能够用制表符来画。其关键方法是持续调用writech函数,在内定区域周围显示制表符,从而勾勒出三个窗口的大致。

PARADISE_BIOS_Sig db”VGA=”

void locate(int x, int y)

个完全的显得,而且当它成为近日突显时,用户观看的是弹指间的体现。

二 、实验内容

repe cmpsb

一 、熟习操作系统的类别机能调用。

if(i==lr) {

  r.h.al=0;   

jne test_vesa_isle

}

mov si,offset SecondarySystem

定位子程序:

              union REGS regs;

  r.h.ah=2; /*子功效号*/

mov si , Offset AHEAd_BIOS_sig

mov dx,003D6h ; Read version

push ax

cmp al,01Ah ; Successful call?

}

          Savewin(5,5,12,40);

    MDA_MONITOR            equ 001h SHL 3

ASCII码07),c纳瓦拉(ASCII码13)和LF(ASCII码10)字符;全体其他的“控制”字符就会显

and ax , MONITOR_MASK

      Listing 5.3 of DOS Programmer’S Reference*/

or al,080h ; Turn enable on

 

}

LiSting 5.7 of DOS Programmer’s Reference*/

HGA。这要运用MDA和HGA之间的差异:在MDA中,垂直同步位从不改变,而在HGA

mov dx,003C4h , Address of sequencer .

in al , dx

not_paradise :

CIRRUS_VSEVEN equ 003h SHL 10

            Sleep(5);

out dx,al

jne not_trident

          int i;

pop dx

mov al , 0AAh

                regs.h.bh=7;

      ·单色显示屏适配卡(MDA)

实用颜色和内部存款和储蓄器必要量之间的涉嫌。

   
在。例如,翻卷函数的变量中绝非页赋值变量。于是就不能选择那么些函数来给彰显内容编

dO_swap :

的。

                  long timeval, time();

B800h                     变化                    变化

cmp al , 1

                gotoxy(i,j);

                then clear that area and put a border around it.*/

mov ds,ax ,get new DS

EGA               单色

    ·XXX····       背景(见表5.5)

ega_table db EGA OR CGA_MONITOR

or PrimacySystem,ax ; set flags

              while(*str){

过量了本书的界定。

换呈现页就能便捷找到展现内容。
testpage.c样本程序能让用户尝试一下新的setpage()

      Hercules InColor卡                       SVGA

/* Function: putwin() */

生。恐怕要到以后(尽管有也很少)才会形成3个无人不知的科班。

要数次拿走那种结果,则必须在询问时使全部的刹车失效;不然,其他的活动就会偷走用

mov PrimarySystem,0

push bx

push dx

jmp short CGA_exit

int 10h ;  call video BIOS

····0···         寻常强度

or word ptr [ bx ] ,ATI18800W18810

jne swap_systems

mov bl,010h ; Attempt tO find EGA

and ax , ADAPTER_SYSTEM_MASK

          Listing 5.8 of DOS Programmer’S Reference*/

的数据转发而来的。 EGA和VGA卡也使程序员能够钦赐其它的用户—限定字符设置

            位

    UNKNOWN_BIOS             equ 000h SHL 6

            void wch(Ch,attr)

not_ati_bios:

GGA_detect endp

02h         文本        16          80*25                     X    
X         X           X

jne_not_everex_bios

loop CRTC_Delay

        int i,j;

                  regs.h.dl=rc;

5.2.3.识别录像显示适配卡

                pgprint(”DOS Programmer’S Reference”);

除总内部存款和储蓄器数的结果。再组成每行柒十多个文件字符,那么正是2*80*25,等于4000字节,或

for(i=lr;i<=rr;i++)

push dx

test_trident:

; Try Tseng

1010           10           淡绿色

 

哪三个摄像适配卡,那么就可以从来编写录像控制器程序,那会招致速度的戏剧性提升。

int 10h

表5.2罗列的形式0Eh的分辨率为640*200,即宽6叁十四个象素,深200个扫描行(象素)。

union REGS regs;

二进制        十进制        颜色

jne not_cirrus_510

je PVGA_detected

 

                union REGS regs;

or  PrimarySyStem , CGA OR CGA_MONITOR

16种颜色,那么它的等式便是:

功了,再持续形成下列两项任务:识别EGA或VGA BIOS没有注意的CGA或MDA卡,

口,并设置AX为1303h:

jne not_paradise

mov di,offset scratch_pad

            }

mov cx , 2

jne not_cti82C451

cmp ah , bl

or word ptr [bx] ,SVGA OR CIRRUS

      上面包车型客车实例汇编语言程序同意明亮的CGA背景:

              /*Chario.c

   
间接将先后书写到显示内部存款和储蓄器中去的程序员应该警觉一些项目标显得适配卡的H安德拉I

是差不多能够翻阅的)时才是实惠的,所以本书的重心放在80列格式上,它能与行业内部的

0011         3            青色

B000h               变化                变化

in al , dx

11h         图形        2            640*480           
                       X           X

mov ax,0c000h ; Point to ROM

      壹 、文本格局展现

读回来,就足以假若C凯雷德TC状态端口已经找到并且CGA或MDA已经固定。

B800h                     32K                     8

为代价)。

SVGA_detect endp

jmp test_vesa

·111····           白背景(逆向)

mov al , 00Ch

B800h                     变化                    变化

cmp ax , MDA_MONITOR

gotoxy(i, j);

and word ptr [bx] , NOT ADAPTER_SYSTEM_MASK

01h         文本      16          40*25                     X    
X         X           X

    VGA                   equ 005h

MDA_primary:

                regs.h.dl=C;

regs.h.ah=0x05;

   
CWranglerTC芯片,独立于电脑种类的操作之外,对突显内存区域进行描述并以存款和储蓄在这

            union REGs regs;

}

                sleep(2);

    void main()

    ·使显示与计时一起

mov al,bh ; Put secondary type in AL

cmp al , 055h

jne not_genoa_bios

序,最初编码便是在BASIC中进行的,它是为AppleII而开发的)。程序运维不荒谬后,能够

jne  CGA_exit

and ax , ADAPTER_SYSTEM_MASK ; What adapter?

        }

   
记住:DOS和BIOS只是为发出荧屏提供了构件块。程序员的想象力和技艺是使程序

mov ax , 0C000h

1·······         闪烁字符

    列表5.8

    }

0Ah         图形        4           640* 200                         
                               X

性。借助奇骏GB连接,那类监视器能跨越普通的增进的意义。那类监视器还足以萧规曹随其余

    与MDA兼容的(单色)

int r,C;

动。它们能呈现CGA图形,但不是万紫千红的。当中一部分监视器能注重阴影来表示颜色的差

mov di,0007Dh

Hercules_detect proc

cmp al , ‘2’

scratch_pad db 256 dup (?)

mov ah , al

    与CGA兼容的

inc dx ; Read global ID

jmp  test_vesa

mov ax,SecondarySystem ; How about the Secondary?

/*Function:cls()*/

          void upwin( int n, int lr, int lc, int rr,int rc);

push bx ; Preserve bx

or word ptr [si] , HERCULESINCOLOR

   
所选拔的监视器系统的体系之一。能够添加屏幕页控制,但毫无全数的函数都同意它的存

push cx

regS.h.dl=C;

CTI82c451 equ 001h SHL 10

and ax , ADAPTER_SYSTEM_MASK

    }

 

          clearwin(5,5,12,40);

je clarify_MDA ; If it iS, identify further

   
编写涉及摄像显示器和打印机设备的次第能够是简约的长河,也说不定是一对一复杂的。

  /* Wait 5 seconds and then Clear the window and fill it.*/

mov bh,al ; Save it

56页

    第4章DOS和BIOS接口

    本章介绍了用户程序访问DOS内核和BIOS所提供的各种服务的方法。为了访问这

些服务,我们可以从任何编程语言中调用各个软件中断,这些中断便是我们在本书中要重

点地讨论的内容。用户当然不必了解访问系统资源的所有细节,但要入门,确实要学习相

当多的这方面知识。

      本书重点介绍的是四种编程语言:汇编语言、C(极c++)、Pascal和BASIC。所讨论

的实现程序分别有Microsoft Macro Assembler(宏汇编)、Microsoft C/C++、Borland C/

C++、Turbo Pascal 7.1版(以及对早期版本的少量说明)和Microsoft Quick BASIC。所

有四种语言都带有允许直接访问DOS和BIOS功能的特性。但是,因为不是每一个功能

都是由语言内带特性所能提供的,因此,有些操作读者不得不自己去编程实现。在本章中,

我们将了解到哪些是由所学语言本身所具备的,哪些是读者必须自己去实现的,以及如何

去实现它。

                4.1从程序中访问DOS和BIOS

      要访问DOS和BIOS资源,只需按照下述简单的步骤来操作:

      1.以相应的值装入CPU的寄存器。

      2.产生一个软件中断来调用所需的硬件中断。

      3.通过CPU的寄存器来返回中断结果(如果有)。

      正常情况下,寄存器中的值都是8位或16位的数值参数或大型数据结构的地址。在

本书中所讨论的所有语言,都有一种约定的方式来装入CPU的寄存器,产生中断,并读取

返口值。有关CPU寄存器及其它们的用途,可参见第2章“DOS系统的结构”。

      图4.1以图解方式列出了在一个系统调用之前或之后的寄存器中的内容。

      根据所要调用的资源,在装入寄存器和产生中断之前,可能需要做一些额外的工作。

例如,许多面向文件的服务,都要求在中断产生之前,在寄存器中装入一个串或其它数据

结构的段:偏移值地址。(如果不熟悉表示地址的段:偏移值形式,可参阅第2章中的内存

分段与8086)。

      首先,用户程序必须得到数据项的地址。得到一个项的地址是一个相对简单的过程:

而如果有什么复杂之处的话,恐怕是与用户所使用的编程语言有关。对本书所涉及的每一

种语言,本章后面都有一个节来专门介绍如何得到数据项地址的方法。

 

57页

            图4.1一个典型的系统调用之前和之后,寄存器中的内容

    数据串或其它的项必须以某种相应的固定形式组织起来。许多DOS功能都要求所使

用的带参数采用ASCIIZ(ASCII加零)格式:各个字符以ASCII代码格式设置,而该串的

最后一个字符则是ASCII字符零(在C语言中为\0,在BASIC中是CHR$(0),而在Pas- 

cal里是chr(0)。图4.2显示了一个ASCIIZ的结构。

                                图4.2一个ASCIIZ串的结构

    如果用户程序是用C来写成的,读者也许会知道ASCIIZ在C语言中是如何精确地

存放它的格式的。在BASIC或Pascal里,要创建一个ASCIIZ,还额外需要一个步骤。在本

章后面的一些例子则显示了是如何完成这些工作的。

    因为汇编语言能提供对CPU和系统资源的最直接访问,因此,在后面各节中的介绍

性例子都用汇编语言来写成。有关访问DOS和BIOS资源基本原则的简介,可阅读下面

的各个小节;这些例子都非常清楚,哪怕是读者对汇编语言并不十分熟悉。

    在本章后面,将介绍如何通过高级语言来访问操作系统。首先,让我们先看看一些简

单的汇编语言例子,来探讨一下DOS和BIOS接口。

4.1.1一个对DOS的简单调用

    在本书中所介绍的每种编程语言,都有几个服务能提供对基本的DOS和BIOS中断

的访问。在这些语言中,最简单的语言是汇编语言,因为汇编语言允许程序直接访问Int

(中断)指令,而Int指令能直接地产生对BIOS或DOS功能的访问。

 

58页

      下面的代码片断,使用Int 21h的功能02h,将字符X输出到控制台,这是一个典型的

对DOS的访问:

      mov ah,2        ;字符输出功能

      mov dl'X'       ;字符X

      int 21h         ;执行DOS功能中断

      使用Int 21h功能02h确实很简单:

    1.以相应的值装入所需的寄存器:将值2装入AH来选择DoS功能2(控制台字符

输出)。字符X装入到DL中。

    2.产生中断:汇编语言中的助记符Int后面所跟的值21h,是通用的DOS中断号。因

为Microsoft的Macro Assembler(宏汇编程序,MASM)是一种衡量汇编语言兼容性的标

准,因此,用户所选择的任何汇编语言中都应该可以使用Int指令。

      因为Int 21h的功能2不返回任何值,因此这里就少了DOS调用模型的第三部分。下

面的例子则演示了第三步,并介绍了如何得到和传递比16位“宽”的数据项的地址给

DOS的基本技巧。

4.1.2传递字符串地址给DOS

      前面已提到过,当数据项的内容比16位多时,就需要将数据项的段和偏移值地址放

入到cpu的寄存器中。下面的代码片断演示了传递字符串地址的一种方法:

        ;Path_name含有将要打开的文件的名字

        mov ax, seg Path_Namee  ;路径的段地址

        mov ds,ax              ;放入Ds

        mov dx,offset Path_Name ;路径的偏移值 

        mov al, c2h            ;打开文件的模式

        mov ah,3dh             ;打开文件

        int 21h                   ;DOS中断

        jc error                   ;如果出错,置进位位

        mov file_Handle,ax      ;保存文件句柄

      此代码片断使用Int 21h,功能3Dh来打开一个文件。该功能要求DS和DX相应地包

含文件路径名的段地址和偏移值。该代码段的前三行按要求装入寄存器。接下来的一行

将C2h放入AL;AL中的值说明该文件被打开的模式(有关此值的模式编码将在本书的

“DOS参考手册”部分里详细描述)。将各寄存器正确地装入后,便随后产生DOS中断。

      像大多数DOS服务一样,如果服务失败,就会设置进位位(此处表示文件不能打开);

如果已设置了进位位,程序于是便跳转到一个处理错误的例程(jc Error)。但是,如果进位

位清除,则表明打开文件成功,文件句柄(由AX返回)放入内存中的一个位置处,以备将

来使用。

      注意最初的DOS服务(即由DOS1.0版提供的)并不使进位标志来指示出错。就像

cp/M中的服务(DOS的祖先是CP/M)一样,它们在AL寄存器中返回它们的信息。自

DOS1.0以来,一致性并不总是保持得那么坚定,因为,自1.0版以后,也并不是所有的随

 

59页

后服务都用进位标志来指示出错。某些服务(如3.0版中可用的Get PID服务)是不可能

出错的,因为它只不过返回由DOS保存在内存中的内容给调用者。这些调用有时会清除

标志位,但是有些DOS版本则直接从服务中返回,而将进位标志仍保持为调用DOS前的

状态。

      因此有必要指出的是,标志位是否指示出错,要看调用的功能在文档中是否是这么说

明的。如果此功能并没有正式公开,那么可参看本书后面参考手册中的那一部分,看看此

标志位是否指示出错,如果是,再看看它指示的什么错误。

                    4.2高级语言资源

    高级语言提供了许多不同的方法来调用DOS和BiOS例程。每种语言都有一种独特

的方法,在其它的语言中往往不能重复这一方法。甚至是在同一种语言内,不同的实现厂

家及不同的版本,也可能采用了不同的方法。 Turbo Pascal 3.0就提供了一种非内带的方

太式来访问所有的文件(满足通配符文件)(如C:\QTRLY\QTR?1993.DAT)。为了访问这

样一组文件,编程者不得不多写两个过程:一个是调用DOS Int 21h的功能4Eh来找出满

足匹配文件名说明的第一个文件,另一个则用于调用功能4Fh来找出满足匹配文件名说

明的余下文件。当Turbo Pascal 4.0推出后,它不仅允许用户自己去生成这样的例程,并

将它们保存到一个运行时刻库中,而且还提供了两个过程一FindFirst和FindNext来完

成这项工作(与其它一些过程一起,放在一个名为“unit”的运行时刻库中)。而到了Turbo

Pascal 5.0的问世,连这些例程的源代码也都可以得到了(尽管需要额外付费)。

    在以下各小节中,每一节都给出了两个实例程序。对每种语言,第一个实例程序是一

个较简单的程序,用于说明访问操作系统资源的基本方法,它使用BIOS Int 17h功能2来

检查打印机的状态。第二个例子则相对地较复杂一些,它解释了从系统调用中返回的结

果。

    较复杂的例子在不同的语言中差别很大。所遵循的原则是,用户不必再做无谓的工

作,给出的编程例子,在所选择的语言中不能提供这样的服务。BASIC例子显示了如何使

用DOS Int 21h的功能4Eh和4Fh来获取满足带有匹配符的文件,并将那些文件名赋值

给BASIC变量。因为类似的功能已由Turbo Pascal及C中内带,所以在这两种语言中给

出的例子就会执行不同的任务。Turbo Pascal的例子使用DOS Int 21h功能57h来获取一

个给定文件的日期和时间。C语言的例子则使用DOS的Int 21h功能43h来获得与设置

文件属性(归档、隐藏、系统及只读属性)。这两个例子根据需要使用了不同的功能来完成

必需的设置及清除工作。这些辅助的功能调用分别在程序文本和注释中作了说明。

避免做无谓的工作

    许多高级语言都有预定义的函数、过程或变量来提供方便地访问系统资源的方式。在

大多数情形下,这些语言成份所访问的DOS和BIOS功能与用户自己在需要时直接编程

所调用的系统资源是相同的;只不过提供该编程语言环境的厂家已为使用者编好了这些

代码。如果认为在此语言中使用系统资源,对你来说是件新鲜事——或者它是你所熟悉语

                                               

60页

言的一种新的实现版本,那么必须注意的一点就是,不要做事复的工作。在本书中反复强

调的一个原则是,仅在必要时才去访问系统。因此,作为编程者,应该尽量使用语言中内带

    的功能,除非有某些特别的要求,而所使用的语言资源满足不了这种要求。

      应该总是仔仔细细地阅读用户手册。下述基本建议值得反复强调:去查手册!许多程

序员,特别是那些新接触某个语言或操作系统的人,常常将大量的时间花费在一些无谓的

工作上。如果他们更仔细地阅读过所使用的语言手册,就不会浪费时间去编制一些业已存

    在的资源上。

    4.2.1C语言

      对与操作系统打交道来说,C是最合适的语言。如果读者读完了在其它节里介绍的其

它语言,就会发现,Pascal和BASIC中的高级特性都会导致使用者按照自己的想法去实

现,如果要深入地想看个究竟的话。因为这些语言在需要方便地访问DOS和BIOS资源

时,都禁止或限制用户访问系统级的数据结构和其它信息。

      由于C语言在访问高级和低级资源时都很方便,因此曾有人将它称为“高级汇编语

言”。当需要在字符或位级进行详细地设置或操作时,C能让使用者“像一个微处理器那样

    去考虑问题”。

      C与操作系统有着一些类似的组成:许多C函数都是“穿着C语言外衣的DOS”。这

些函数通常都与DOS采用相同的参数,并返回相同的结果;确实,这些C函数作为输入的

数据结构和返回的输出值,都与在DOS中所用的参数相同。

      接下来,在本节中要给出一个更复杂的实例程序,我们给出了两个版本:chmd.C直接

调用DOS,而chmc.c则调用等价的C函数。而只有一个版本的较为简单的例子名为

_Pronok.c;该例子所提供的功能,在Borland C++库中是不能直接得到的。

      本节所给出的C程序都是由Borland C/C++编译器开发的,有关Borland c++与

Microsoft C之间的不同之处,可阅读例子代码片断中给出的注释。

      访问寄存器和产生中断

      在C和DOS接口中所使用的数据结构,是由REGS联合及SREGS与REGPACK结

构定义的。这些对象都是在头文件DOS.H中声明的。它们的声明在下面的代码片段中列

    了出来:

    struct WORDREGS{ 

        unsigned int ax, bx, cx, dx, si, di, cflag, flags;

    };

    /* Microsoft C lacks flags element*/

    struct BYTEREGS{ 

        unsigned char al, ah, bl,bh, Cl, ch, dl, dh;

    };

    union REGS{ 

        struct WORDREGS x; 

        struct BYTEREGS h; 

    };

 

61页

          struCt SREGS{

            unSigned int es;

            unSigned int cs;

            unSigned int ss;

            unsigned int ds;

        };

        struct REGPACK{         /*Not defined in Microsoft c*/

            unSigned r_aX,r_bX,r_cx,r_dx;

            unSigned r_bp,r_Si,r_di,r_dS,r_es,r_flags;

        };                         。

    此外,在BorlandC++中CPU各个寄存器的内容也呵以通过伪变量AX、_AL、AH

等得到。每个8086的通用寄存器、偏移值及段寄存器(除了IP)都有相对应地伪变量。也

可使用对应于16位或8位的寄存器的变量(但却未声明),把它门当作相应的unsigned

int和unsigned char类型:

      unsigned int _AX;

      unsigned char _AL;

    在前面介绍的伪变量是不能在Microsoft C中使用的。因为缺少这些伪变量会给程

序带来少许变化,因此必须仔细地阅读厂述程序片断,如果想要让它们通过Microsoft C

编译器的话。

    DOS.H头文件中包含有下列C函数的原型,用于产生软件中断:

      int int86(int intno,union REGS*inregs, 

                        union REGS*outregs);

      int int86x(int intno,union REGS*inregs,

                        union REGS*intregs,

                              struct SREGS*segregs);

      int intdos(union REGS*inreg,

                union REGS*outregs);

      int intdosx(union REGS*inregs,

                union REGS*outregs);

                struct SREGS*segregs);

    void intr(int int_type,struct REGPACKOpreg);

    intdos()函数能产生Int 21h——最基本的DOS中断;int86()*intr()则产生由该函

数的第一个参数(intno或int_type)所指定的中断。每一个intdos和int86都有一个x版

本,它除了使用通用寄存器及偏移值寄存器外,还将使用段寄存器,在Microsoft C里是不

能使用intr()函数的。

    列表4.1中所给出的PRNOK.C显示了如何使用int86()函数来验证LPT1是否联机

的技术。

62页

    列表4.1

          /*prnok.c 

              Listing 4.1 of DOS Programmer'S ReferenCe*/

          #include<cOnio.h>

          #include<dOS.h> 

          #define PRN_INT 0x17/*Printer·serviCes interrupt */

          #define STAT_RQ 0x02/*Status·request Service number*/

          int prnok(void)

          {

              union REGS regs;

              regS.h.ah=STAT_RQ;   /*AH=02 for printer status*/

              regs.x.dX=0;          /*DX=00 for LPT1*/

              int86(PRN_INT,&regs, &regs);

              return (((regs.h.ah&0x80)==0x80)?1:0);

          } 

          main()

          { 

              if(prnok())

                    cputs("Ready to print!\n");

              else

                  Cputs("Please cheCk the printer!\n");

          }

    有关BIOs打印机状态请求的说明

      每种语言的第一个实例程序都使用BIOS Int 17h功能2来验证LPT1是否已联机。

对于这一功能,将2放入AH,而将打印机号(0为LPT1,1为LPT2,依此类推)放入DX。

此功能在返回后,AH内存有打印机的状态,放在AH中的各位含义如下:

     位                               意义(如果置上,即为1时)

     0                                time-out(超时)

     1                                unused(未用)

     2                                 unused(未用)

     3                                 I/Oerror(I/O错) 

     4                                printer is selected(打印机已选)

     5                                out of paper(无纸)

     6                                Acknowledge(确认)

     7                                printer not busy(打印机不忙) 

    只有位0和位3至位7的意义已定义好,但是在两个已配置好的硬件上进行测试,在

相同的环境下,会返回不同的结果。在每个测试情况下,当打印机已加电并已联机的情况

下,AH的高位都已置上。但是,当一台Toshiba(东芝)P351打印机与一台IBM Personal

System/2 Model 50(PS/2 50型)计算机相连接时,当打印机已连接但没有加电时,程序会

报告出“Ready to print(已准备打印)”的信息。而将一台Epson的RX-O打印机与一台

COMPAQ便携式计算机相连时,程序则以“please check the printert”的信息作为响应(如

果打印机已连接但却没有加电时)。这只是一个演示性的例程;一个真正起作用的状态程

序则需要更复杂的逻辑。

63页

      获取和设置文件属性

    本节给出了两个C的实例程序,用于改变一个指定文件的属性。这两个程序类似于

Norton Utilities中的很有用的FA(文件属性)程序;不同的是,它们都只接收一个确定的

文件名,而不是包含有通配符的文件说明。为了保证程序尽可能地简单,程序也不包括查

询文件属性的选项或一次改变多于一个属性的选项。这两个程序在运行时,要求在命令行

上指定一个要设置或清除的属性来作为参数,如果给了一个不正确的参数,程序就会给出

一条出错信息,并终止运行。

    如果读者已精于C编程,则不难增加更进一步的选项(如“查询”),以扩展此程序的

功能。本书中已提供了足够的信息,因而也很容易加进处理带有通配符文件名的功能。

    这两个程序的不同之处在于:一个直接地调用了DOS中断,而另一个则使用了相应

的C函数来调用此中断。第一个例子在列表4.2中给出,它直接调用了DOS的Int 21h功

能43h。

    列表4.2

          /*Chmod.c

          Listing 4.2 of DOS programmer'S Reference */

        #include <coniO.h>

        #inClude<Stdio.h>

        #include<ctype.h>

        #inClude<process.h>

        #include<dOS.h>

      #include"attrmask.h"        /*omit for Turbo c 2.0 */

        #define GS_FATTR        0x43

        #define GET_FATTR     0x00

        #define SET_FATTR       0x01

        /*For Turbo C 2.0,add these #define statements:

                define ARCHIvE_BIT FA_ARCH

                define HIDDEN_BIT       FA_HIDDEN

                define RDONLY_BIT     FA_RDONLY

          define sYsTEM_BIT FA_sYSTEM

          */

      typedef enum{clr,set} clrorset;

      void showattr(int attr);

    int parsearg(char*thearg,clPorset*actiOn,char*selection);

      main(int argc,char*argv[])

        { 

          extern char*sys_errlist[];/*provided by Turbo

          eXtern int errnO;             /*Ditto*/

          union REGS regs;

          struct SREGS sregs;

        clrorSet action;

        char SelectiOn;

        unsigned attPib,setting; 

        int goahead;

    if(argc==3)goahead=parsearg(argv[2],&action,&selection);

                                                                                             

64页

if(!goahead)

{

if(argc=3)

{

 CPUtS("Can't parse");

cputs(argv[2]);

}

else

cputS("No input");

exit(1);

}

switch(selection){

caSe 'A':setting=ARCHIVE_BIT;break;

caSe 'H':Setting=HIDDEN_BIT;break;

Case 'R':Setting=RDONLY_BIT;break;

caSe 'B':Setting=SYSTEM_BIT;break;

default:

cputS("Bad input:");cputS(argv[2];cputS("\n\r");

exit(1);

}

regS.h.ah=GS_FATTR;

regS.h.al=GET_FATTR;

regS.x.dx=(unsigned)argv[1];/* offset of first argument*/

sregS.dS=_DS;

/* - - - - - - - - - - - - - - - - - - - - -

For Microsoft C,use the following in place of the preceding line:

segread(&sregs);

*/

intdosx(&regs,&regs,&sregs);/*Get the current attribute wOrd*/

if(!regs.x.cflag){/*If carry is clear,success*/

 attrib=regS.x.Cx;

cputs("- - - - - - - - - - - - Initial - - - - - - - - - - - - \n\r");

showattr(attrib);

if(action==clr){

setting=((-setting)&attrib);

}else{

setting=lsetting|attrib);

}

regs.h.ah=GS_FATTR;

cegs.h.al=SET_FATTR;

regs.x.cx=setting;

regs.x.dx=(unsigned)argv[1];

SregS.ds=_DS;

/* - - - - - - - - - - - - - - - - - - - - - -

For Microsoft C, use the following in place of the preceding line:

segread(&sregs);

*/

intdosx(&regs,&regs,&sregs);/*Set the attribute*/

attrib=regs.x.cx;

cputs(" - - - - - - - -  - - - - Final - - - - - - - - - - - - - \n\r");

showattr(attrib);

}else{/*That is,if carry is not set*/

char*msg;

cputs("function 0x43 failed:");

65页

               switch(regs.x.ax){ 

                case 1: msg="Bad function code\n";break;

                case 2: msg="Bad file name\n";break;

                case 3: msg="Bad path\n";break;

                case 5: msg="can't change attribute\n";break;

                default: msg="Unknown cauSe\n";

                }

                cputs(msg);

            } 

      }/*End main*/

    Int 21h功能43h需要下列输入值:

      寄存器                          值

        AH                       43h

      AL                          0表示获取文件属性,1表示设置文件属性

      DS:DX                      段:文件路径名偏

该程序使用了#define处理指示符来“命名"DOs功能以及所需的操作(获敢或设

置)。文件名是由命令行参数提供的。

    对于一个在Turbo C下以小内存模式编译的程序,应使用下列语句来将路径名的段

和偏移值放入DS和DX:

      regs.x.dx=(unsigned)argv(1);

      sregs.ds=_DS;

    在其它的内存模式下儒要用到其它的赋值方法。因为MicrosoftC缺少寄器伪变量,

因此应使用下列语句来取而代之:

      segread(&sregs);

    如果操作成功,就会清除进位标志,并且在cx中包含有文件的属性字。下面的表描

述了属性字中的每一位以及所对应的属性含义:

        位                    含义(如果置位,为1时)

        0                               Read Only(只读)

        1                               Hidden(隐藏)

        2                               System(系统)

        5                               Archive(归档)

                   

    如果某位已设置,则此文件就具备所对应的属性(设置归档位表示此文件自从被创建

成上次修改后还未备份)。

    为了使用方便和便于阅读,我们使用了#有define指示符来创建属性字中各个含义位

的位屏蔽字(这些定义包含在ATTRMASK.H文件中;参见以下的代码片断)。我们在程

序中使用位屏蔽字来读取和修改文件的属性字。

      /*attmask.h-from chapter 4 of DOS Programmer's Reference*/

                                                                

66页

#define ARCHIVE_BIT 0x20 /*Bit 5 of CX is the archive bit*/

#define SYSTEM_BIT 0x04 /*Bit 2 of CX is the system bit*/

#define HIDDEN_BIT 0x02 /*Bit 1 of CX is the hidden bit*/

#define RDONLY_BIT 0x01 /*Bit 0 of CX is the red-only bit*/

列表4.3及列表4.4则给出了第二个实例程序版本所使用的一些杂用功能。

列表4.3

/*parsarg.c

Listing 4.3 of DOS Programmer's Reference*/

#include<conio.h>

#include<ctype.h>

typedef enum{clr,set}clrorset;

int parsearg(char*thearg,clrorset*action,char*selection)

{

if(*(thearg)=='/'){

switch(*(thearg+2)){

case '+':

*action=set;break;

case '-':

 *action=clr;break;

default:

CPUtS("USe '+' tO Set Or '-' tO Clear\n\r");

return (0);

}

*selection=toupper(*(thearg+1));

return (1);

} else{

 cputs("Usage:chmd filename/xy\n\r"

"where x=A(acchive) or H(hidden) or\n\r"

"R(read-only) or S(system),\n\r"

"and y=+(set) or -(clear)\n\r");

return (0);

}

}

列表4.4

/*showatr1.c

Listing 4.4 of DOS Programmer's Reference*/

#include<conio.h> 

#include"attrmaSk.h"

#define CLEAR 0

#define isclear(x,y) ((x&y)==CLEAR)/*Parens around x,y?*/

#define putStat(x,y) CPUtS(iSClear(x,y)?"clear":"set")

void showattr(int attr) 

{

CputS("Archive System Hidden Read-only\n\r");

putStat(attr,ARCHIVE_BIT);

putStat(attr,SYSTEM_BIT);

putStat(attr,HIDDEN_BIT);

putStat(attr,RDONLY_BIT);

cputS("\n\r");

}

 

67页

    如果把列表4.2(此程序的第一版)与列表4.5(第二版)相比,读者就会发现,在使用

中断的程序中,进行出错检查的工作要比使用C库函数更复杂一些。因为不同的C在库

函数上有一些不同之处,所以本程序只能在Turbo C下编译如果使用Microsoft C则需

要作些修改,因为它缺少_chmod函数。

列表4.5

/*chmod2.c.

Listing 4.5 of DOS Programmer's Reference*/

#include <conio.h>

#include <stdio.h>

#include <io.h>

#include <ctype.h>

#include <process.h>

#include "attrmaSk.h"

#define GET_FATTR 0X00

#define SET_FATTR 0X01

typedef enum {clr,set}clrorset;

void showattr(int attr); /*Show file attribute*/

int parsearglchar*thearg,/*Parse command-line argument*/

clrorset*action,/*Clear or set attribute*/

char*selection);/*Selected attribute*/

  main(int argc,char*argv[])

{

extern char*sys_errlist[];/*PrOvided by Turbo C*/

extern int errno;/*Ditto*/

clrorset action;

char selection;

 unsigned attrib, setting;

int goahead;

if(argc==3)goahead=parsearg(argv[2],&action,&selection);

if(!goahead)

{

if(argc==3)

{

cputs("Can't parSe");

 cputs(argv[2]);

}

else

cputs("NO input");

exit(1);

}

switch(selection){

caSe 'A': Setting=ARCHIVE_BIT;break;

caSe 'H': Setting=HIDDEN_BIT;break;

caSe 'R': Setting=RDONLY_BIT;break;

CaSe 'S': Setting=SYSTEM_BIT;break;

default:

cputS("Bad inpUt:"); cputS(argv[2]);cputS("\n\r");

exit(1);

}

 

68页

            attrib=Chmod(argv[1],GET_FATTR);

            if(attrib!=0xFFFF){ 

                Cputs("··········Initial········\n\r");

                shOwattr(attrib);

                  if(actiOn==clr){

                      setting=((-setting)&attrib);

                  }else{ 

                      setting=(setting|attrib);

                  }

                attrib = chmod(argv[1],SET_FATTR,setting);

                cputs("··········Final············\n\r");

                  showattr(attrib);

            }else{ 

                  cputs("funCtion_chmodfailed: \n\r");

                cputs(SyS_errlist[errnOn]);cputs("\n\r");

            }

        }/*end main*/

      注意chmod()C库函数返回文件属性字作为一个函数的返回值(-1表示有一个错

误出现),而Int 21h功能43h则在寄存器CX中返回文件属性字,并通过设置进位标志来

表示出错(象大多数DOS功能那样)。因为由C库函数所返回的结果与DOS功能在CX

中返回的结果是相同的,因此可在两个程序中都使用showattr()函数来解释属性字的含

义。

4.2.2Turbo Pascal 

      Turbo Pascal 4.0版在3.0版的基础上作了改进。新的版本都提供了对调用DOS和

BIOs功能的极好的支持。随后在升级到5.0版时,又恢复了几个在由3.0版到4.0版升

级时所丢掉的几个很有用的特性,并且又第一次内带了一个内带的调试器,这对于复杂程

序是一个非常有帮助的工具。在Turbo Pascal 5.5版中。加进了面向对象编程的功能,并

且还支持多种数学协处理器。Turbo Pascal 6.0版中加进了Turbo Vision,这是一个用于

DOS程序的面向对象的应用程序框架,此外还增加了一个增强的开发环境。 Turbo Pascal

7.0版则继续地增加了一些功能,以添加支持Windows的功能。

      该编程语言中已含有大量的内带设施,来访问系统资源,并最大限度地减少了程序员

自己去编写他们自己的系统级代码的可能性。

      文件和控制台输入/输出功能满足了几乎所有程序员的要求,大多数文件和目录操作

(获取文件大小、获取当前目录、改变目录、创建目录等等)都得到了完全的支持。我们在本

章前面曾提到过,4.0版和5.0版简化了编写需要选择一组含有通配符文件说明的程序

的过程。

      这类资源支持是如此地齐备,因此,很难找出需要直接从程序中调用DOS或BIOS

服务的地方。当Turbo Pascal已具备了对控制台输入和输出操作的完备支持的函数和过

程时,还有什么必要非得自己去调用相应的DOS或BIOS呢?

      但是,毕竟还是有需要直接访问DOS和BIOS的时候,那就是当用户程序需要某些

功能,而Turbo Pascal语言不能提供此类功能时,本节给出的实例程序,只是出于指导性

    

69页

目的;此程序重复的是在高级语言Turbo Pascal里可以得到的操作。

    在这些程序中,第一个使用了BIOS的Int 17功能2来检验打印机是否已联机(类似

的结果—以及相同的复杂错误检查功能,都可通过Turbo Pascal语言的内带过程和函

数来实现)。第二个实例程序,同样也是重复了Turbo Pascal 4.0所内带的函数,来得到一

个文件创建或最近修改时的日期和时间。

    访问寄存器和产生中断

    在Turbo Pascal中,用于访问各个寄存器的数据结构位于Registers记录中。此记录中

的这一结构,是在Turbo Pascal 4.0的DOS联合中定义的,下面给出了它的代码;在3.0

版中,此记录则必须由用户来定义:

      Type

      { Registers record used by Intr and MsDos } 

        Registers = Record

              Case Integer of

              0: (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : Word) ;

              1 : (AL,AH,BL,BH,CL,CH,DL,DH : Byte)

              End:<Rs>

    Turbo Pascal带有下列两个过程,用于产生中断:

    MsDos(vars Regs: Registers)

    Intr(IntNo :Byte; vars Regs :Registers)

    MsDos产生的是Int 21h中断,即“通用的”DOS中断。Intr则可以产生任何软件中

断,包括21h(在 3.0版中,Intr的第一个参数是一个整数)。

    Turbo Pascal程序的第一个例子—列表4.6 演示了一个简单的对BIOS的调用。

Printer Online函数调用BIOS的Int 17h功能2(打印机状态请求)以检查打印机是否已联

机。功能2在AH中返回一个字节,以指示打印机是否是忙、已选择、缺纸等等(必须保证已

读过本章前面的“高级语言资源”一节中对这个BIOS中断的说明)。但是,这个程序仅检

查了AH中的位7;如果此位已置上,表示打印机已选择上。

列表4.6

{ PRTRDEMO.PAS                } 

{ Listing 4.6 in DOS Programmer's Reference  } 

{ = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = } 

Program PrinterDemo;

Uses Dos ;

      Function PrinterOnline : Boolean ;

                Const

                PrnStatuSInt :Byte: $17;

                StatusRequest : Byte: $02 ;

                PrinterNum : Word:0;{ 0for LPT1,1for LPT2, etc.} 

              Var

            Regs : Registers;       {  Type is defihed in Dos unit.} 

        Begin

        Regs.AH := StatusRequest;

        Regs. DX := printerNum;

70页

        Intr( PrnStatusInt,Regs); 

            Printeronline := ( Regs.AH and $80) : $80

            End; 

      Begin      {  Program} 

      If Printeronline  Then

          WriteLn( '  Ready to print !' ) 

      ElSe

          Writeln(' please check the printer! ' ) 

      End

    读取一个文件的日期及时间标记

    通过DOS的Int 21h,可以获得一个文件在创建成最近修改时的日期或时间。名为

GeteDateAndTime Pascal过程演示了DOS功能的使用方法(参见列表4.7)。

列表 4.7

    { GETDTTM.PAS } 

    { Listing 4.7 in DOS Programmer's Reference       } 

    {Designed to be called from FILEDTTM.PAS              } 

    { = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = } 

    Procedure GetDateAndTime( Pathname:PathStr ;

                                  Var DateWord , TimeWord : Word) ;

        const

              GetDate AndTime:Byte=$57;

              CloseFile:Byte=$3E;

            var

              Regs;Registers ;

              Handle : Word ;

        Function CarryClear (Regs : Registers) : Boolean ;

        Begin CarnyClear :=( ( Regs. Flags and  1=0)End ;

        { = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = } 

        Function GetFileHandle( Pathname : PathStr): Word; 

              Const GetHandle : Byte = $3D; ReadAccess : Byte = 0;

              Var PathSeg , PathOfs : Word ;

        Begin

        Pathname: = pathname+Chr( 0) ;

        PathSeg : = Seg(Pathname[1]) ; Pathofs := ofs(Pathname[1] );

        Regs. AH: =  GetHandle ;  Regs. AL : = ReadAccess ;

        Regs,DS : = pathSeg ; Regs. DX : = pathofs;

        MSDos (Regs);

        If CarcyClear(Regs) Then

              GetFileHandle : =  Regs.AX{ No semicolon before ElSe !} 

        Else

              Begin

              WriteLn('Handle function failed!' ) ;

                  EXit

              End;{If carry is clear} 

        End ;                        {  Function GetFileHandle} 

    { = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = }

    Begin          {  Procedure GetDateAndTime} 

    Handle := GetFileHandle(Pathname) ;

    Regs.AH : = GetDateAndTime ;  Regs. AL :=0;Regs. BX : = Handle;

    MSDos( Regs) ;

    If CarryClear(Regs ) Then

        Begin DateWord: = Regs.DX;TimeWord : = Regs.CX End

    Else

 

71页

      Begin

            DateWord: = 0, TimeWord: = 0, { Error flag for Cailer}  

            End; 

      Regs.AH := CloseFile;       Regs. BX := Handle; 

      MSDOS (Regs);

        If NOT CarryClear(Regs ) Then

            WriteLn( 

                ' Warning: Procedure GetDateAndTime did not close' ,                    ·

                pathname)

      End ;              { Procedure GetDateAndTime}  

    功能57h要求的正确输入项是一个文件句柄。Turbo Pascal具备完整的面向文件的过

程和函数,但是,如果要进行更细致的系统级文件管理,还得靠程序员自己去努力。为了使

用功能57h,GetDateAndTime过程,必须“翻遍”Turbo的正常文件管理例程。因此,我们不

使用Pascal的文件打开过程(即名为Assign和Reset或Rewrite),而调用DOS的Int 21h

功能3Dh。此系统调用是由GetFileHandle函数执行的,它被嵌套在GetDateAndTime过程

内。

    功能3Dh要求得到一个ASCIIZ串的地址,此串中包含有文件的路径名。因为Turbo

Pascal串不是由一个零字节来结尾的,所以该函数必须自己附加Chr(0)到串Pathname

上。因为在Turbo Pascal串中,第一个字节位置存放的是串的长度,但却不能包含在DOS

功能3Dh的串参数中,因此,我们将Pathname[ 1] 的地址传递给了此函数。有了Seg和Ofs

函数,就可以直截了当地访问串地址的两个组成部分。

    在获得了文件句柄后,GetDateAndTime将它传递给了DOS功能57h。AL寄存器设

置为0,指定DOS功能应该获取(而不是设置)文件的日期和时间。如果功能57h成功(由

进位标志清除来指明),它在CX和DX寄存器中相应地返回文件的时间和日期。

    列表4.8显示了程序FILEDTTM.PAS,则显示了如何使用Turbo Pascal的GetDate- ·

AndTime函数的。

列表4.8

{ FILEDTTM.PAS  

{Listing 4.8 in DOS Programmer's Reference         }

{= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = }

Program FileDateAndTime ;

      Uses Dos;

      Type

            PathName Type = String[64];

            String5 = String[5] ;

            { Max DOS path is 63 ; add 1 for the null.}

      Var

            Pathname : PathNameType;

          DateWord , TimeWord : Word ;     { Use Integer in 3.0} 

          Hours, Mins, Secs, Year, Month, Day : Integer,

          Ch : Char;

{ $i GETDTTM.PAS} 

{ = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = } 

Begin         {  Program}

Write( ' pathname? >' );ReadLn(Pathname);

GetDateAndTime ( Pathname , DateWord , TimeWord);

If( DateWord<> 0) Then

72页

              Begin

              { Decode date} 

              Year     :=( ( DateWord AND $FE00)  SHR 9) +1980;

            Month:=(DateWord AND $01E0)SHR 5 ;

              Day      :=(DateWord AND $001 F);

              { Decode time} 

              Hours:=( TimeWord AND $F800)SHR 11 ;

              Mins    :=( TimeWord AND $07E0)  SHR 5 ;

              Secs     :=(TimeWord AND $001 F) SHL 1 ; {  Shift left to double} 

              WriteLn(' File Time:'  , Hours : 2,' :'  , Mins :02,':',Secs:2);

            Writeln(' File Date:' , Year:4,' /' , Month:02,'/'  ,  Day:2);

  End                      {  No semicolon before EIse} 

        Else

              Writeln(' GetDate And Time has failed!');

        End

4.2.3QuickBASIC

      QuickBASIC已包含了在BASIC及GW_BASIC中就已带有的,我们大家都很熟悉

的处理文件语句。如KILL FileName$语句删除文件,CHDIR用于改变当前目录,等等。

输入输出的例程也很灵活。

      但是,BASIC的文件处理功能在某些方面有些欠缺。例如,它处理包含有文件名通配

符(使用* 或?)的过程就非常地麻烦。我们不得不弯弯绕绕地,先将一个DOS命令传递给

SHELL,引导命令的输出到一个文件,然后从输出文件中将内容读进程序中,每次读一

行,分析出文件名(并要跳过一些干扰行)。磁盘驱动器为空、盘上贴有写保护标签,以及磁

盘已满,都有可能导致程序中止。并且,我们又怎么能知道所使用的SHELL的输出文件,

不会与某个已有的文件重名呢?

      而通过在DOS层上的编程,便可以避免所有这些麻烦。本节中给出的第二个实例程

序,便显示了如何去调用DOS的int 21h功能4Eh及4Fh,来找出匹配文件说明的所有文

件的名字,其说明中可以包含一个或多个通配字符(在DOS级上所进行的其它编程工作

的最佳应用,不仅可以使得编程更方便,而且也极大地方便了运行应用程序的各个用户)。

      首先,让我们来看一个简单的例子,它介绍了从BASIC中调用DOS的一些基础知

识。第一个QuickBASIC程序(就象其它语言中的第一个例子一样),使用BIOS的Int 17h

功能2来检查打印机是否已联机。

      访问寄存器和产生中断

      在QuickBASIC中,用于DOS及BIOS接口的基本数据结构是Register记录:

      TYPE Registers

            AX AS INTEGER

                BX AS INTEGER

                CX AS INTEGER

                DX AS INTEGER

                BP AS INTEGER

73页         SI AS INTEGER

              DI AS INTEGER

              SI AS INTEGER

              FLAGS AS INTEGER

              DS AS INTEGER

              ES AS INTEGER

      END TYPE

    我们通过DIM语句来声明寄器类型变量:

      DIM InRegs AS Registers,OutRegs AS Registers

因为这些变量遵守正常的作用范围规则,所以它们声明为过程内的局部变量。

    Quick BASIC内部带有下述两个过程,用于产生中断:

      CALL INTERRUPT(Int Number,InRegs,OutRegs)

      CALL INTERRUPTX(Int Number,InRegs,OutRegs)

    CALL INTERRUPT忽略DS和ES寄存器(或Registers记录参数中的DS和ES

域),而CALL INTERRUPTX则使用这些寄存器或域。如果想要在调用INTERRUPTX

时保持DS和ES不改变,则应给记录中的DS和ES域赋值-1。

    列表4.9显示了使用BIOS打印机状态请求的过程。因为此结果在各种硬件配置情况

下并不能保持完全的一致性,因此必须阅读"对BIOS打印机请求"一节中的注释(在本章

中有关C语言的小节内),这样才能在你的程序中使用此功能,并知道所起的作用。

列表4.9

"PRNOK.BAS-Listing 4.9 in DOS Programmer' s Reference

CONST PRN.Status.rq%=&H200            '2 in AH

CONST BIOS.PRN.INT%=&H17

TYPE Registers

        AX AS INTEGER

        BX AS INTEGER

        CX AS INTEGER

        DX AS INTEGER

        BP AS INTEGER

        SI AS INTEGER

        DI AS INTEGER

        FLAGS AS INTEGER

        DS AS INTEGER

        ES AS INTEGER

ENDTYPE

DIM InRegs AS Registers,outRegs AS Registers

InRegs.AX =  PRN. Status.rq% 

CALL INTERRUPT(BIOS.PRN.INT%, InRegs , OutRegs) 

IF((OutRegs. AX AND &H8000) = &H8000) THEN

        PRINT" Printer OK" 

ELSE

        PRINT" Please check the printer"

74页

        END IF

            END           ' PROGRAM

      找到匹配文件说明的文件

      通常,复杂而又细致的程序必须处理由带有通配符说明的一组文件。QuickBASIC并

未提供一个内带的设施,来找出匹配用户提供的文件名说明的一组文件。只有构造出这样

一个程序,才能使QuickBASIC语言发挥出更大的作用。

      DOS资源中,用于文件说明的是Int 21h的功能4Eh(FindFirst)和4Fh(FindNext)。这

些函数相应地找出第一个匹配的文件名以及任何剩下匹配的文件名。它们输出中的两个

地方——文件名和其它的信息,都位于DTA(磁盘传送区域)内。缺省时,DTA是一个128

字节的缓冲区,位于程序段前缀的偏移值80h处。但是,在本节中给出的样本程序,使用了

DOS功能1Ah来设置不同的DTA地址,来避免任何可能的对其它DOS功能的干扰。

      大多数BASIC的实现,也包括QuickBASIC在内,都没有将串保存在一个固定的位

置处。有一个4字节的串描述,保持着对每个串位置的跟踪。此描述符包含了一个16位的指

向该串的指针;这个指针中包含有进入该缺省数据区域的串的偏移值。我们不用担心去定

位此描述符并获取此地址,因为下面的QuickBASIC函数:

      SADD(TheString$)

    将返回作为参数的串的偏移值(如果需宴访问该串描述符,就可以通过VARSEG和

VARPTR函数来获取它的段值和偏移值)。SADD应该在用户程序访问此串之前立即被

调用,因为一个串可以在程序执行期间,在内存中“任意挪动”,特别是如果程序中改变了

串的长度。

      在列表4.10里列出的程序演示了使用功能4Eh和4Fh来获取匹配文件说明的文件名

的过程。

    列表4.10

    ' FILEDEMO.BAS- Listing  4.10 from DOS Programmer's Reference

    DECLARE SUB SetDTA(TheDTA$) 

    DECLARE SUB FindFirst(FileSpec$,FileName$) 

    DECLARE SUB FindNext ( FileName$) 

    DECLARE SUB BuildName (TheName$)

    TYPE Registers

        AX AS INTEGER

        BX AS INTEGER

        CX AS INTEGER

        DX AS INTEGER

        bP AS INTEGER

        SI AS INTEGER

        DI AS INTEGER

        FLAGS AS INTEGER

        DS AS INTEGER

        ES AS INTEGER

    END TYPE

    DTA$=SPACE$(43) 

75页

LINE INPUT "FileSpec? >" , FileSpec$

  CALL SetDTA( DTA$ )

 Get the first matching file name

CALL FindFirst ( ( FileSpec$) , FileName$)

IF FileName$ <> " " THEN

PRINT "First match: " ; FileName$

DO

CALL FindNext ( FileName$ )

IF FileName$ <> " "THEN

PRINT " Next match: " ; FileName$

END IF

LOOP UNTIL FileName$ = " "

ELSE

 PRINT "NO files match " ; FileSpec$

END IF

END  PROGRAM

 =====Subroutines =====

SUB BuildName (TheName$)

SHARED DTA$

EndofStr% = INSTR(31 , DTA$ , CHR$(0))

TheName$ = MID$(DTA$, 31 , Endofstr% - 31 )

END SUB

SUB FindFirst (FileSpec$, FileName$)

FileSpec$ = FileSpec$ + CHR$(0)  make ASCIIZ

DIM InRegs AS Registers, outRegs AS Registers

InRegs.AX = &H4E00  'find first matching file

InRegs . DX = SADD(FileSpec$) ' offset of FileSpec$

InRegs .DS = VARSEG(FileSpec$) ' seg of FileSpec$

InRegs.CX = 0 'normal files only- -no dirs, etc.

CALL INTERRUPT(&H21 , InRegs, OutRegs)

GOt a match? Yes, if CARRY FLAG(bit 0 of FLAGS) is Clear.



IF (OutRegs.FLAGS AND 1 ) = 0 THEN

CALL BuildName ( FileName$ ) :

ELSE 

FileName$ = "  "

END IF

END SUB

SUB FindNext (FileName$)

DIM InRegs AS Registers, outRegs AS Registers

InRegs.AX = &H4F00 'find next matching file

CALL INTERRUPT(&H21 , InRegs, outRegs)

IF (OutRegs.FLAGS AND 1 ) = 0 THEN

CALL BuildName ( FileName$ ) : 

ELSE

FileName$ =" "

END IF

END SUB

SUB SetDTA (DTA$)

DIM InRegs AS Registers, outRegs AS Registers

 Set the Disk Transfer Area address

InRegs.DX = SADD(DTA$) ' OffSet Of DTA

InRegs .DS = VARSEG(DTA$) ' segment Of DTA

InRegs.AX = &H1A00 'DOS function fon setting OTA addr

CALL INTERRUPT(&H21 , InRegs , outRegs)

76页

             no return value for function &H1A

          END SUB

      下面的过程:

        SetDTA(TheDTA$)

      将设置磁盘传送区的地址为它的串参数的地址:

      下面的过程:

        FindFirst(FileSpec$,FileName$)及FindNext (FileName$)

      将定位到所匹配的文件名。如果找到了匹配的文件名,这两个过程都把匹配的文件名

赋值给FileName$;如果未找到匹配的文件名,它们就会赋上空串(" " )。尽管此实例程序

只是简单地显示出文件名,但我们可以在自己的程序中利用所返回的结果来完成任何工

作。

                        4.3小    结

      我们在本章中介绍了在汇编语言、C、Pascal及BASIC内进行系统级编程的基础。用

于访问DOS和BIOS资源的过程有三个主要的组成部分:

      ·以相应的值装入寄存器

      ·产生一个软件中断

      ·在寄存器内返回中断的结果

      有时还需要一些额外的工作,如当应用程序需要将串或其它数据项的地址传送给系

统。每种编程语言都提供了各种资源,用于获取各个项的地址;使用各个地址的简单程度

依使用的各种的语言而有所变化。

      如果在已读完了本章各节中对每种语言(不仅仅是所选择的语言)的技术介绍后,读

者可能已注意到,在提供对DOS和BIOS资源的支持上,各种语言有很大的不同。在以后

进行的编程项目中选择语言时,应考虑到这些不同之处的。

 

wch(HORIZLINE, 7);

push bx

A000h               变化                变化

regs.h.ah=0x06;

cmp al ,2

cmp ax,VGA , Did we detect a VGA?

; If detected, r.etucns Z set; else Z ceset

        int lr,lc,rr,rc;

                    5.3录制效果

ATI18800REV2 equ 002h SHL 10

found_MDA:

运作平常化或看起来简捷的首要缘由。即便用户所企盼爆发的体现力量无法与编程技术相

mov ax , [ si ]

je MDA_Primary

mov dx,es :00463h

or PrimarySystem , MDA OR MDA_MONITOR

    己的法门来开发高档VGA(Super
VGA)。每一个适配卡都支持1个800*600录制格局(通

call GRTC_deteCt

jne not_cti_bios

or word ptr [bx] ,ATI18800REV1

        CRTC detect              endp

xor al,al ; Clear register

svga_exit :

0040h:0065h职位上的值,0DFh的字节使闪烁位变明晰,并将结果输出到端口03D8h

和cls()函数)。注意cls()只是clearwin(),它在显示屏的左上角和右下角设置数值,以对应

push dx

cpage=n;

or word ptr [bx] ,ATI18800REV2

          #include<dos.h>

          putwin()      把数量放进有个别窗口

; Although enhanced video BIOS call succeeded, no VGA was found

      ② 、图情势方法显示情势

mov ax,PrimarYSystem ; Set return values

pop dx

or al,al ; Locked?

cmp al, ‘1’ ; Which Chipset?

/* PrototypeS*/

Herc_exit :

je ahead_a

mov dx,003D4h ; If CGA, CRTC iS 3D4h

#define LOWERLEFT 200

cmp ax , VGA

    VESA SVGA              equ 007h

MCGA              文本

识别(如果是VGA适配卡)潜在的SuperVGA适配卡。

异。

mov cx,5 ; Length of Signature

pop bx

 and ax ,ADAPTER_SYSTEM_MASK ; What did we find?

/* Function: Clearwin()*/

          }

存在0040:004A处。纵然用户能够一直改动这几个数值,但那样做并不聪明,因为BIOS不

0·······         寻常字符

jmp Short not_Cirrus_Chip

别的环境,如DESQview包容。

      列表5.6

   
突显适配卡对录制数据的表明决定于彰显方式,该方法决定了数据在显示屏上冒出的

   
已经有了不少种类的展现监视器,并且直接都有越多的档次在相连地投入使用。本章

别的东西。

mov ax,SecondarySystem ; Is secondary system MDA?

CRTC_detect proc

jne is_HGC

            }

Out dx,al ; Write it out

/* Function:setpage()*/

jne not_cirrus_bios

        /*  Finally,clear the screen again and then end the

and al , 0EFh

regS.h.bh=cpage;

je vid_exit

cmp bl,010h ; Call failed?

mov al,020h ; Get enable value

mov ax,07000h , Extended BIOS call

          /*Display a screen full of lines*/

regs.h.ch=lr;

      展现监视器的类型

AHEAD_VERSION_B equ 002h SHL 10

. data

0111         7              白色

not+ahead_bios:

db EGA OR EGA_MONITOR

和EGA 用于计算机的PC种类,MCGA和VGA则用于Personal System/2体系。HGA 的

out dx,al

    MDA的CTLacrosseC状态端口常常是在I/O地址3B4h处,而CGA则在3D4h处。该程序

何地方。该RAM是显示器图象的三个录像缓冲区,并且也不无1024展现字符那么大的模

        }

    ;Procedure for identifying the video system(s)

je test_Hercules

jmp test_vesa

cmp al,070h ; OK?

inc dx

SVGA从VGA中分离出来需求尝试每一项SVGA识别技术;借使拥有技术都未成功,那

db UNKNOWN_ADAPTER OR UNKNOWN_MONITOR

cmp ax , MCGA

jmp short test_vesa

mov bx,offset adapter_table ; Get lookup byte

{

                        含义

no_ega_present :

              regS.h.ah=0x0e;

或V揽胜I,因为适配乌特勒支用展现内部存款和储蓄器的艺术各不一样。在少数字突显示适配卡中使用的内部存款和储蓄器是特

adapter_table db UNKNOWN_ADAPTER OR UNKNOWN_MONITOR

not everex_bios:

彩变味”(Chromablizzard)。要在那类系统中防止那些难点应运而生,应该只在HPRADOI或VEvoqueI期

还要,则失去了正规化库函数的造福和与UNIX或XENIX的包容性。

    若是探测到了是MDA适配卡,那么可进一步识别它是或不是3个家常的MDA或

ahead_a:

104页

cmp al,7 , Current mode is mono?

int 10h

          }

regS.h.ah=0x06;

Or word ptr [bx] ,SVGA OR TSENG_BASED

    
添加显示器——页控制的一条途径是改变路径,使之包涵3个脚下显示屏页号以及安装

cld

call Hercules_detect ; See if it’s a Hercules board

out dx,al

xor ah,ah ; Clear byte

              /* Sleep.C

; Main procedure for identifying the video systems

式与展现适配卡所产生的字符相对应。字符是从保存在适配卡中的ROM字符发生器内

gotoxy(i, rc); wch(VERTLINE, 7);

and word ptr [bx] , NOT ADAPTER_SYSTEM_MASK

      列表5.5

                        ret

and al , 00Fh

    #include<dos.h>

的未公开的功力雷同)。

        char ch;

; Wasn’t AHEAD. Test for ATI

CIRRUS_BIOS_Sig db “CL”

; EffOrts to find EGA failed too

CGA               文本

in al,dx ; Read old value

jne not_cirrus_chip

                  图形

push cx

106页

      探测并识别SVGA是3个幽默的标题。开发商们在开首仿制IBM的EGA和VGA

jne not_headland

mov al , es : 043h

                regs.h.ah=0x09;

能添加页控制,能够建立在当中使用了窗口和页作用的主次以保存展现内容,而只要求变

90页

pop bx

   
统,但决不一切系统都与该方法包容。借助此类调用,用户能够行使DOS级不能够

92页

int i, j;

db MCGA OR VGA_COLOR

 

    EVEREX                   equ 007h SHL 6

    识别摄像适配卡首先是尝试VGA或EGA特有的录像BIOS调用。假如那个调用成

指令出字符应该如何显示。表5.3显得单色文本方式的字符属性位的意思;表5.4则显得

jmp short not_circus_chip

regS.h.dh=25;

            void setpage(int n, int clrflg);

    /* Prototypes */

repe cmpsb

xchg ax ,SecondarySystem

          /* Function: cls()*/

如,EGA系统能从64种颜色的调色板上展现16种颜色。要提示出某些特定象素应该是

#define  LOWERRIGHT 188

方式号      方式       颜色数      分辨率          MDA      CGA    
EGA       MCGA      VGA          Pcjr

db (8 – 6) dup (EGA OR UNKNOWN_MONITOR)

                  文本

ATI18800REV1 equ 001h SHL 10

列表5.7

shr al , 1

mov bx,offset PrimarySystem

        ·接纳录制缓冲区

jmp test_vesa

out dx,al

0101         5              品红色

pop di

Seek_CGA:

    HEADLAND                 equ 006h SHL 6

db (16 – 13) dup (0)

nop

扫间隔(H瑞虎I)。类似地,电子束完毕3个周期后,它要从右下部移到左上部初始2个新的

; Start of simplified directives

用直白源于高档语言的服务;但在广大意况下,则必须运用较低级的劳务,如DOS或

mov dx,046E8h ; Turn setup back off

   
打算建立复杂展现的程序员不必然要从硬件级开端编制程序(实际上该级别是“最终避难

  之上。window.c(见列表5.3)
操纵着testscn.c所调用的窗口成效。借助于window.c中的

97页

regs.h.ah = 0x06,

          border(5,5,12,40);

   
当用户期待获得给C本田CR-VT的最快的、恐怕的出口并且想防止使用BIOS以保全与一般

push ax

Out dx,al

     
表5.5列举了种种颜色可能的岗位。不过,注意,因为平日的前景是由30个人决定的,

testscn.c 建立在文件windows.c、screen.c 和chario.c
所包蕴的一个大致意义集合体

not_headland:

or SecondarySystem , CGA OR CGA_MONITOR

示在荧屏上。字符放置在末了一行的终极一列时,也许光标在终极一行的即兴地方,此时

; Seems to be a CTI chip. Which version?

0Bh         —        保留        —

mov ax , PrimarySystem

mov si , offset PrimarySystem

   
最近,大家早就理解了荧屏显示的干活措施,那么就能够试一试简单的效益,来探望

13h         图形        256          320*200                          
X                   X

          savewin()     将窗口当前数据保存起来

. code

regS.h.cl=0;

void border(lr,lc,rr,rc)

and word ptr [bx] , NOT ADAPTER_SYSTEM_MASK

mov dx,003CEh ; Get i/o address

ret ; Return

图形方式中,各样显示器象素都由一多如牛毛的内存位所鲜明。每一个位提醒象素打开或关闭以及

        void main()

        char att;

A000h                     变化                    变化

·····001          下划线石黄前景

TRIDENT_8800CS equ 002h SHL 10

          void rch(char *Ch, char *attr);

功效去操纵录像,但有时是必须将规则手册和顺序置之于脑后。例如,使用BIOS录像

mov al,00Fh , Get index of enable register

mov ax,PrimarySystem ; Found MDA; primary or secondary?

and word ptr [bx] , NOT ADAPTER_SYSTEM_MASK

mov ah,00Fh ; Get current video mode

10h         图形        16           640*350                        
X                     X

/*Screen2.c

 and word ptp [ bx] ,NOT ADAPTER_SYSTEM_MASK

mov bl,al ; Save it

          clearwin(5,5,12,40);

jne not_ati_bios

; on entry, DX is the alleged CRTC port

gotoxy(lr, lc); wch(UPPERLEFT, 7);

个完全的扫描)。在每行的终极,电子束必须从荧屏的右端移到左端,那段时光称作水平回

dec dx

坏了兼容性,但却使速度(并使生产率)达到了最大值。

mov cx , 4

是因为还并未创立鲜明的规范。而且,与那种高分辨率显示屏定义相竞争的不少措施已经产

repe cmpsb

          sleep(5);

      HGA+(Hercules图形卡增强型)           VGA

该函数(见列表5.6)选用与Microsoft
c/c++同样的路线。在向前推进在此以前,它要等待,

int86(VIDEO,&regs,&regs);

jne not_everex_bios

CGA_exit :

04h         图形        4           320* 200                   X    
X         X           X         X

and ax,ADAPTer_SYSTEM_MASK

or word ptr [bx] ,GENOA OR SVGA

mov ah,al   ; Save what we read

ati_1 :

                  regs.h.cl=lC;

          void border(int lr,int lc, int rr, int rc);

not_trident:

and ax ,ADAPTER_SYSTEM MASK

的展现电路图就会发生字符的物量展现。在显示屏上各样字符就转化成一个点方式,该点模

cmp ax , MDA_MONITOR

          void gotoxy( int r, int c);

    借助BIOS 效用调用。那种存取突显的不二法门相当协作,并比DOS更快。大多数系

81页

mov ah,al , Save it

jmp $+2

out dx , al ; register

     
颜色数就是代表的颜料数,位数是所需的位数。对于每种EGA,显示器象素任几时候有

mov al,066h ; Write new value

repe cmpsb

mov bx,offset adapter_table ; Get lookup table

or word ptr [bx] ,AHEAD_VERSION_A

    口内的做事。

Int
29h是DOS使用得最多的不二法门(从2.0版本起先)并且因为它是ANSI.SYS替换展现

regs.h.bh=7;

and ax , ADAPTER_SYSTEM_MASK

pop es

          putwin(5,5,12,40);

在简要的字符I/O级别以上,编制程序会相当的慢就成变三个复杂的进度,尤其是与图片相关时更

B000h                     4K                      1

                  regs.h.dh=rr;

#define UPPERRIGHT 187

            {

      ·递增录制缓冲区地址计数器

仅在这几个内部存款和储蓄器地方上转移了数额,而且举办了情有可原安装摄像格局所必须的此外操作。

; We have a secondary system present

 

out dx,al

void cls()

        int lr,  lc, rr,rc;

   
显示器上的剧情的内部存款和储蓄器代表。表5.1来得了开始的内部存款和储蓄器缓冲区地址、缓冲村长度以及展现页

/* Function: Savewin()*/

 

                regs.h.ah=0x02;

current_color:

void savewin(lr,lc,rr,rc)

函数,能够做到下列工作:

   
假诺须要展开超过标准库函数的编制程序,那么必须如临深渊地权衡可能的优缺点。从专业库函

·000····           黑背景(正常)

if(clrflg) cls();

/* Function: border() */

mov di,0037h ; Read pointer

or word ptr [bx] ,CTI82C452 OR SVGA OR CTI_BASED

push bx , Save pointer

GENOA_BIOS_Sig db 77h , 11h , 99h , 66h

; It’s an AHEAd BIOS-now identify which chip version

and ax , 7

    GENOA                   equ 005h SHL 6

HGA               图形

个中的哪一种颜色,那么须要6个位。种种象素所需的位数可由下列等式表示:

}

各差异的。识别某些特定开发商的适配卡的技术将在种种适配卡的长河中开始展览描述。将

 

Cmp ax , 0004Fh

 

regS.h.Ch=0;

送出了LF,那三种状态下,显示器都会自动地卷起一行。

Or word ptr [bx] ,CTI82C451 OR SVGA OR CTI_BASED

          {

repe cmpsb

                  int86(vIDEO,&Pegs,&regS);

cmp al , 000h

周期。那段时日称作垂直回扫间隔。在H中华VI和VRAV4I时期,电子束都被关闭,显示屏上看不到

or word ptp [ bx ] , CIRRUS_510_520

mov ax , 06F00h

mov ax,PrimarySystem ;How about the primary?

   
独有的方法来开始展览的。每一个适配卡还协助部分有意识的分辨率或提供一些与众分歧效果,而其他

幕。因为40列格式常常唯有当录像显示器是合成都电子通信工程高校视设施(在那种装置中每行三十七个字符

87页

gotoxy(i,lc); wch(VERTLINE, 7);

repe cmpsb

                  str++;

no_vga_present :

用来体现的内部存款和储蓄器数目而发出转移。

pop bx ; Restore bx

cmp ax , MCGA

        for(i=lr;I<=rr;i++)

          char*str;

B800h                    64K                     1

的(即便为何应该中断阅读并非那么显然,但经验却显示它真的是在许多CGA卡

CTI82c452 equ 002h SHL 10

; Test for VGA presence

    mov ax,1303h

5.2.2视频体现格式

                  regs.h.Ch=lr;

cmp al , 010h

                regs.h.dh=r;

                (Note: Everything scrolls, including the window.)*/

vid_exit:

                union REGS regs;

是何许颜色。用于每一个象素的位数决定于显示适配卡类型以及正在使用的图样格局。例

            }

mov al,ch

   
为用来限制显示器的数据能够比那些多少显著地少占空间,所以有的显得适配卡能操纵

      高的本子下,ANSI.SYS
驱动程序让动用该存取情势的次序能透过决定编码种类

jnz not_cirrus_chip

   位数=log(颜色数)/log(2)

   
对于CGA,要免除前景的闪光天性并加上强度控制给前景,就亟须读取BIOS储存在

              while(time(NUL)<timeval+n);

jae vid_exit

mov ax , seg video_ident

     
IBM也关系了图方式方法体现形式,称它是APA,或称为全部点能够固定的主意,在

je do_swap

            program. */

              }

Call CRTC_detect

          clearwin()   清除窗口

VESA_BIOS_Sig db “VESA”

xor bx,bx

mov dx,00103h ; Read extended enable register

上这么进行的)。

    借助DOS功用调用。那是一种最匹配,但却是最慢的存取方式。在DOS2.0和更

if(i==lr||i==rr) {

                regs.h.al=0;

缓冲区的开始地址以及长度会趁机所利用的摄像显示器的体系、当前突显形式以及分配

    CIRRUS                   equ 003h SHL 6

   
图形荧屏幕的分辨率(参见5.21)用象一向代表,有品位和垂直多少个分辨率。例如,

jmp short swap_systems

            setpage(0,FALSE);

mov ch,al ; Save it–it’s the key to the chip ID

                  timeval=time(NULL);

用芯片,它能实施6845所提供的兼具基本功能,并能显明地增强6845的服从。视频控制

pop si

0000         0            黑色

LOOp VSYNC

    ADAPTER_SYSTEM_ MASK equ 007h

   
以上有关显示器中断的引导在向荧屏内部存款和储蓄器书写内容和从显示器内部存款和储蓄器阅读内容时都以有用

video_ident endp

jne current_color

call Hercules_detect ; Identify the specific MDA system

}

阅读该数值,那么你会看到1个叫做“雪花”的显得荧屏扭曲出现。

push ax

; Now that we found it, try to identify which board

; Routine tO detect SVGA cards

03B8h。

cmp al, 1 ; Unlocked?

                  pop dX

          mov es,ax

      mov eses : 65h,al   ;save value for future reference

swap_systems :

db EGA OR EGA_MONITOR

          /* screen.c

xlat

1001           9            淡蓝色

    SVGA                  equ 006h

能只在脚下展现的页上中国人民解放军海军事工业程高校业作,而不在非显示页上行事。

void putwin(lr,lc,rr,rc)

 

jmp test_vesa

; these will be used

PUSh di

的那种独一无二的天性和它缺乏间接来源BIOS或DOS服务的支撑,就印证了它的编制程序

                regs.h.bl=attr;

一对系统操作12分。

          #inClude<Stdio.h>

Try Headland

          Cls();

mov dx,003CDh

cmp dx,06780h

标、彰显属性和别的控制的存取。

CTI82C453 equ 003h SHL 10

 

je vid_exit

border(lr,lc,rr,rc);

0110         6            棕色

jmp short test_vesa_isle

    因为Int
29h尚无公开,所以在以往的DOS版本中能够收回它,但那不太大概,因为

void cls(void);

pop dx

HERCULESINCOLOR equ 003h SHL 10

                *ch=regs.h.al;

饱含进函数变量之中,那么就能够将函数如gotoxy()用于尚未展现的页。然后能够组织一

假设有CGA或EGA监视器或更好的监视器,那么执行顺序时,显示屏会转移井来得测试

PrimarySystem dw 0000 ; Primacy video system

mov dx,003B4h ; If MDA, CRTC iS 3B4h

not_cirrus_510:

100页

0Dh        图形        16          320*200                        
X                     X

in al , dx

          Void Savewin(int lr,int lc, int rr, int rc);

                  int86(VIDEO,&regs,&regs);

B800h                    16K                     1

      IBM借助标准BIOS和DOS服务,认可并支持上述专业(除HGA外)。 MDA、CGA

union REGS regs;

09h         图形        16          
320*200                                                         X

Hercules_detect  endp

or word ptr [bx] , VESA_SVGA

 or word ptr [bx] ,CTI82C453 OR SVGA OR CTI_BASED

mov bx,offset ega_table

found_Hercules:

编写时尽量选用最快的或者途径。在诸多实例中,因为是直接对硬件编制程序的,所以即使破

    
假设用户正在使用MicrosoftC/c++,那么她就没有版本4.0所需的sleep()函数。

          void cls(void);

    TSENG BASED              equ 009h SHL 6

    /* Window.c

03h         文本        16          80*25                     X    
X         X           X

   
读者大概会问为啥一流VGA(SVGA)没有作为PC机上的图样标准而被提到。那

out dx,al

   
不止一个的显得显示器。注意那里说的是显示器,而不是显得监视器。显示器或页是出现在

not_cti82c452 :

   
直接的单色监视器,能显得高分辨率文本和字符水平的图片。MDA能使得那个监视

push bx

no_secondary :

mov al,cl ; Get switch settings

mov dx,003C4h

表5.3单色字符属性

ret

pVGA_detected :

mov ax,primarySystem

性。字符就在与它一样地址的不行字节里,属性就在另一字节里。字符属性向显示适配卡

mov ax , Primarysystem

   
在硬件级上一贯开始展览编制程序。那种办法最不般配,因为在系统中会存在广泛的硬件

   
最终,那一个进度就探测到了五个录制硬件系统并分别哪些是活动的,哪个是非活动

cmp al , ‘3’

上举办活动。window.c函数则在有些窗口内行事。别的的函数能够增进进去操纵三个窗

   
宝马X3GB监视器运用独立的电子束(三枪)来分别显示各个原色(红,绿和蓝),从而在文

gotoxy(rr,rc); wch(LOWERRIGHT, 7);

      ·增强图形适配卡(EGA)

          #define TRUE       !FalSE

    and al,0DFh         ;clear blink control bit

cmp al,021h ; Version  B?

99页

        使用的图纸和别的显示器效果。

    PC机展现系统本来是以华为 6845
阴极射线管理控制制器(C宝马X3TC)芯片为底蕴的。

cmp al,020h ; Version A?

   
即便此书并非是关于图形方面包车型大巴完整手册,但它照旧提供了图片工作的中央尺度。在

; So far, so good. . .

void gotoxy(r,c)

and al , 00Fh

regs.h.dh=r;

int 10h

                  图形

                  pop CX

    PARADISE                 equ 008h SHL 6

regs.h.al=n;

93页

int n,lr,lc,rr,rc;

    在I/O端口3DAh查询CWranglerTC状态寄存器能够驾驭HCR-VI或CQX56I状态是或不是留存。0位

jne not_cirrus_chip

iS_HGC:

    借助DOs 和
BIOS的显示屏存取能够编写复杂的且实用的主次。落成复杂进程的次序

                regs.h.dl=80;

jne not_ati_bios

inc dx ; Select register

UNKNOWN_CHIP equ 000h SHL 10

je ati_2

or PrimacySystem,ax ; Set values

not_cti_bios:

或XENIX一起干活,有程序代码(它在各个操作系统之下可不加修改地拓展成功的编

   
那种修改唯有当录像形式被BIOS再度转移时才能保持有效;要使之对于具有的视

····1···           高强度

式(字形)。前边介绍的总结格局能支援用户鲜明可用的展现页数。

jne not_cirrus_610

}

    中则会改变。HGA能更进一步细分为HAG+、Hercules
InColor(内部颜色)卡,或规则的

int86(VIDEO,&regS,&regS);

间存取显示器内部存款和储蓄器。

inc dX , Get I/O address Of data

jne noVGA_detected

    ;—–Equates—–

; Change the model size to match the program in which

regs.h.bh = 7;

    VGA_MONO               equ 004h SHL 3

void upwin(n,lr,lc,rr,rc)

          #inClude<dOS.h>

jne not_cti_bios

regs.h.al=n;

cmp ax , MDA

test_vesa_isle:

间将一个字符放进呈现内部存款和储蓄器(假定标准的4.77MHz的体系速度)而没有发出荧屏中断。

    #define VIDEO  0x10

mov ax,SecondarySystem , Get current mode

cmp al,010h ; HGCPlus?

              {

    #define     COLS        80

   
就算已高达共同的认识认为:运维卓绝的DOS应用程序应该接纳BIOS,只怕最好使用DOS

适配卡是做不到这么些的。类似地,区别的支出商用来鉴定识别种种高级VGA适配卡的方法是

 

mov SecondarySystem,0

00h        文本        16          40*25                     X    
X         X           X

mov al,bl ; Get old value

 

#define BOOL int

          /*prototypes*/

     
因为用于显示那些差不多窗口系统的函数只涉及三个出示页(0页),所以它们独立于

的特征和二种作用(参见第8章“串行设备”)。

; Initialize structures

    #include<dos.h>

们的低分辨率在文件展现方式里不会发生令人满意的结果,除非选择40列的展现行。

0Eh         图形        16          640*200                        
X                     X

mov dx,SecondarySystem

      ·彩色图片适配卡(CGA)

int i,j;

cmp ax,MDA ; Is secondary system MDA?

    操作。

同等的话,那么他的显示屏就会是徒有其表的。

        列表5.2

/*Function:gotoxy()*/

                char*ch,*attr;

    EGA兼容的

B800h                    16K                     4/8

能则供给分外的驱动程序。BIOS或DOS都未曾内在的劳务,能够去丰裕利用HGA。HGA

jne no_vga_present

#define HORIZLINE 205

{

if(i==rr) {

          void cls()

}

或大致2K上空。利用那几个总括,可以很简单地看清为何CGA能从16K的缓冲区空间

仅提供录制系统的常见控制,而且要比DOS服务更快和灵活得多。
BIOS服务提供了对光

     
文本方式也号称字母数字艺术,大多数IBM文件都以这般提到的。文本格局中,内部存款和储蓄器

mov si , Offset ATI_BIOS_Sig

102页

xor al,al

jmp short found_MDA

    AHEAD                    equ 001h SHL 6

                  图形

只有超越7的值才能积存在前景之中,除非象刚才描述的这样触发了闪烁位。

能在不间接存取显示器展现的一些下运营。当先河与多职责环境如Windows或DESQview

     
screen.c函数对于任何显示屏展现是全局的(见列表5.4)。它们在三个显示器宽度的基础

      今后让大家看看两类呈现格局:文本和图片。

                int r,c;

增强其速度和复杂程序,使其尽大概地神速和紧密。使贰个健康的主次加火速度要比使一

      mov dx , 03D8h      get CGA mode control port address

HGA,要成功那一点可以洞察情形端口的少数位。

or word ptr [si] ,HGC

    Struct     charpos{

    通过探测COdysseyTC。可以辨认CGA或MDA适配卡。

          printf(“DOS Programmer’s Reference            “);

82页

其它DOS服务能用于显示器控制;唯有多少个DOS服务能用来新闻的荧屏呈现。

并不一一列举,以下所列只是里面包车型地铁一有些:

; May need to swap primany/secondary systems

一旦地址正确,那么就试着向光标地方低寄存器写入值。在短短的蘑菇后,如若数值能被

常那是规定1个适配卡是VGA或是SVGA的正式),但达到此目标却是以独家差别的、

所级别”)。超越二分一好的次第都初始于该限量的另一端点,即高级语言。主要的购买销售程序,

}

浮现函数去改变这些职分(见列表5.5)。

je found_8800BR

jmp short Herc_exit

                regs.h.bh=0;

and al , 00Fh

该芯片已用在MDA、CGA和HGA录制卡中。 EGA、VGA和多年来的种类都选拔定制的专

SecondarySystem dw 0000 ; Secondary video system

88页

call MDA_detect , Else look for MDA

CGA_detect proc

    整个荧屏。

jne no_MDA

xor bx,bx ; Special Headland BIOS call

pop bx

中获取几个显示页。

in al , dx

pop si

    对于EGA和最近的适配卡,触发闪烁位要简明得多。能够选择BIOS Int
10h处的接

   
是何其地不难。本章的目标决不想建立三个全体的窗口系统—那种努力超出了本书的

and word ptr [bx] ,NOT ADAPTER_SYSTEM_MASK

            Setpage(1,TRUE);

              Listing 5.5 of DOS Programmer’s Reference*/

je CGA_primary

HGCPLUS equ 002h SHL 10

union REGS regs;

          #include<dos.h>

        int 10h

    ;Monitor types

push dx ; Save registers

便利的机能。 Int
29h不象未公开的DOS输出作用那样,它将字符放到显示器上时并不每便

07h         文本        单色        80*25              X            
X                     X

   
合成彩色监视器中,它们的分辨率尤其差。该卡协助的安装处在该限量的低端,但它

   
在这一节,读者能够组织一些大约的窗口功效,以便看看BIOS和DOS功用的利用

and word ptr [bx] , NOT ADAPTER_SYSTEM_MASK

                  regs.h.al=*str;

                  pop bX

    PS/2兼容、单色的

   
PC机展现系统的规划,在答辩上是很简短的。PC机显示屏是内部存款和储蓄器映射设备,在里头,

;Try Paradise

static int cpage=0; /* Current display page*/

          #define         VIDEO  0X10

mov CX , 9

pop ax ; Restore CRTC

in al , dx

     
BIOS跟踪当前呈现格局并将艺术号保存在内部存款和储蓄器地址0400:00第49中学。每行的列数保

电脑刚刚要安装摄像内部存款和储蓄器地址到1个非双重端口适配卡中,且此时COdysseyTC正在此位点

ret

cmp ax,MDA ; Is secondary system MDA?

;—–Program Code – – – – –

Struct Charpos Screen[LINES][COLS];

            {

0010         2            绿色

push ax ; Save registers

 in al , dx

开拓了,问隔时间要形成时,位也随即关闭。因为编制程序时,H奥德赛I出现得更加多而且更易于探

cet

mov di,00031h ; ATI signature at C000:0031

je ati_1

适配卡并未超越此限制。

95页

jmp short detect_SVGA

缓冲区段地址             缓冲镇长度            呈现页数

户正等待的间隔时间。

                regs.h.ch=0;

jae vid_exit

96页

生的结果要好好一些。那些监视器使用同样的技巧(独立的奥德赛GB电子束),但运用了较高

mov al,01Fh , Get iD register

CGA_Primary:

    增强型汉兰达GB监视器能提供彩色文本和图片,并且输出结果比平时的本田CR-VGB监视器产

      pop es              ; restore saved segment register

 

; Identify the chip itself

该页号的途径。例如,能够变动screen.c,使之包涵一条setpage命令(见列表5.7)。

push es

共同工作时,就会起来对这一个存取级别感到满足。

Cmp bl,070h

{

          void putwin( int lr, int lc, int rr,int rc);

        而控制显示器。

mov al,bl ; Put primary type in AL

          sleep(5);

for(j=lc; j<=rc;j++) {

 

push ds ;save caller’s DS

and al , 070h

SVGA_detect proc

and al , 0C0h

    UNKNOWN_ADAPTER        equ 000h

    MDA                   equ 002h

VGA               单色

   
那么些小的函数集合体没有展开尖端复杂的尝尝。它只控制单一的、未覆盖的窗口,如

mov di,00025h ; Signature is at C000:0025

and word ptr [bx] , NOT ADAPTER_SYSTEM_MASK

jne test_vesa_isle

          /* Function:gotoxy()*/

BIOS级的劳务,来形成一定的职分。本章描述控制录像显示屏和打印机的DOS和BIOS

                *attr=regs.h.ah;

101页

; Attempt to detect CGA card

 

db MDA OR MDA_MONITOR

pop es

从没改观;用户只是看到有几分钟全体的东西都维持静态,然后就回去下贰个活动。不过

些适配卡,可以如法泡制CGA(段地址为B800h)和它们自个儿的起首段地址A000h。

91页

cmp ch ,0ECh ; 510/520?

 

            /*FunctiOn:rch()*/

; It’s a Cirrus BIOS- -now identify the chip

0001         1              蓝色

    要利用Int 29h,可就要展现的字符放进AL。寄存器,然后引入中断:

                int86(VIDEO,&regs,&regs);

      {

这几个数目表示显示屏幕总共有12八千个象素。当实行图片方面包车型地铁工作时,请牢记分辨率、

for(j=lc; j<=rc; j++) {

          /*    Wait 5 seconds and then scroll the screen again.

      ·多彩色图形阵列(MCGA)

    ATI                      equ 002h SHL 6

CRTC_Delay :

jmp short swap_systems

    在SuperVGA适配卡中,要进一步识别生产厂家和芯片的品种。

out dx,al

in al , dx

连串的监视器,并提供了拉长的呈现效果。

    的数目。

          ;For use with Microsoft C/C++

05h         图形        4           320*200                   X    
X         X           X         X

录像适配卡的不二法门体现寄存器的值,就能够赢得背景亮度值的一体化范围(以失去闪烁能力

pop bx

mov bx,offset SecondarySystem

or word ptr [bx] ,EVEREX OR SVGA

mov al,00Ch , Get Start address

; Routine tO detect Hercules MDA card

的章节中开始展览描述。但在那本书中,将对汉兰达S-232端口单独介绍,因为它们拥有无比

and al , 7

MDA_detect proc

not_HGCPlus:

                regs.h.ah=0x08;

cmp  ch,0EAh ; Video seven?

mov ah , al

cli ; Disable interrupts

   
在列表5.7中,加上pgprint()函数使用户能够将线打字与印刷到当前页上。通过向显示屏功

BIOS中才有用的。但与别的的编制程序范畴分歧的是,录像成效的优势只与BIOS相关。没有

          #inClUde<Stdio.h>

and ax , ADAPTER_SYSTEM_MASK

pop cx

HGC  equ 001h SHL 10

jne test_vesa

89页

                int86(vIDEO,&regs,&regs);

    列表5.3

in al,dx ; Get value

内部存款和储蓄器比“普通的”RAM要昂贵,所以任何的来得适配卡则或许忽略了那个细节。如若你的

pop ax

mov PrimarySystem,ax

1101           13           淡品色

regs.h.al=0;

出口工具。

regs.h.dl=80;

no_MDA:

in al , dx

Call CGA_detect ; Seek CGA

    表5.1显得出EGA、MCGA和,VGA都有四个例外的图样突显缓冲区发轫地址。那

miv  es , ax

jne svga_exit

        testscn.c
程序是二个简约的测试,它先在显示屏上填满数据,然后去掉显示器中央的卓殊

in al,dx ; Read it back

gotoxy(i,j);

虽说有关单个录像适配卡的详尽编制程序超出了本书的限量,不过规定出现的是哪三个摄像

; Try Trident/Everex

je seek_CGA ; Then look for a CGA

              void sleep(n)

          }

意义阅读并书写象素到荧屏上,从而编写3个油漆刷程序。不过,假使理解正在利用的是

83页

 

      EGA和VGA卡的缓冲区大小会转移,是因为它们能在64K到1M的内部存款和储蓄器中据为己有任

    /* Structure for each Character position–character and

not cti82c451:

A000h                     64K                      1

cmp ax , UNKNOWN_ADAPTER

    VGA COLOR              equ 005h SHL 3

           void pgprint(str)

              #include<stdio.h>

or bh,bh ; Secondary system detected?

    CGA_MONITOR         equ 002h SHL 3

这一章里,大家已支付了多少个用于系统一编写程的管事例程,构造了多少个万分重庆大学的、有效的

inc dx

是如此。

              regs.x.cx=1;

指令H福特ExplorerI是不是留存;二人则反应有关VCRUISERI的平等的音信。当回扫间隔初阶时,相应的位就

Out dx,al

1110           14           黄色

regs.h.dl=rc;

regs.h.dh=rr;

or al,010h

ATI18800w18810 equ 003h SHL 10

ATI_BIOS_Sig2 db “31”

pop bx

mov cl,4

     
除了单色和彩色文本彰显,还有二种其它项目标文书展现。它们中间的分别在于每行

   
本章研商录像显示屏和打字与印刷机那二种为主的输出设备。它们或然是总结机编制程序中最

Out dx,al

   
范围。依照一些用来分析BIOS和DOS效用利用的差不多的窗口呈现效果,能够检查显示器

or word ptr [bx] ,CIRRUS_610_620

   
多路同步监视器是当前所提供的能显得最高质量的公文和图片荧屏,并装有灵活

or al , 055h

中,要将它们拷贝给RAM并保险它们从来没有改观,这不是贰个家常的职分;而只变动

and ax, ADAPTER_SYSTEM_MASK

; what iS the primary System?

MDA               文本

BOOL clrflg;

路线。表5.2交由了在种种不相同的呈现卡上所能使用的彰显方式。

        /* Testpage.C

    表5.4单色字符属性

    CGA                   equ 001h

   
窗口(见列表5.2)。能够向显示屏书写更多的多少,然后将原本的窗口数量重回并卷起来。

Out dx,al

and ah,080h ; Isolate VSYNC

Cmp bh,066h ; Is new value correct?

          for(i=0;i<10; i++) {

              regs.h.bh=cpage;

jmp Short test_vesa

{

          void wch(char ch,char attr);

末节。当构造程序时,那几个腋务常常是最好用的,那有八个原因:

mov dx,003BAh ; Get status port

jne test_vesa

          #define VIDEO 0x10

          upwin()       将窗口往上滚动

    76543210

not_cirrus_610:

pop ax ; Restore registers

pop cx

/* Function: upwin() */

    UNKNOWN MONITOR       equ 000h shl 3

int 10h

noVGA_detected :

    ; video_id.asm

in al,dx ; Read register

clarify_MDA :

   
对于有着的函数,当前展示页的应用远没有未展现页的工作这样令人难忘。将显得页

regs.h.al = 0;

int 10h

   
那么程序员在什么样时候要根本关怀非敏感性和包容性呢?显著,要是与DOS和UNIX

的MS-DOS系统尽恐怕多的兼容性时,DOS的三个未公开的功效Int 29h已被认证是很

    直到钦定数量的秒数过去。

{

db UNKNOWN ADAPTER OR UNKNOWN_MONITOR

 mov ax,01A00h ; Read display code’s function

    #define       LINES     24

repe cmpsb

            for(i=0;i<50;i++)

; Now check for Cirrus

cmp ax,UNKNOWN_ADAPTER

mov si , off set ATI_BIOS_sig2

                regs.h.Cl=0;

CIRRUS_610_620 equ 002h SHL 10

gotoxy(lr, rc); wch(UPPERRIGHT, 7);

(即CGA的MDEvoque地址)。对于HGA或MDA,执行同一的操作,但将结果输送到端口

5.2.1储存和突显摄像数据

          {

int lr,lc,rr,rc;

频方式都灵验就须要改变Int 1Dh向量所提示的录像表。因为录像表平日驻留在ROM

                2 seconds for 10 steps,*/

mov dx,046E8h ; Put chip in setup mode

ror al , cl

     
screen.c中的成效决定与显示屏相关的函数,如光标定位和扫除荧屏(分别是gotoxy()

1011           11           淡青色

mov ax , 06F07h

xlat

sti ; Reenable interrupts

int lr, lC, rr, rc;

            Listing 5.6 of DOS programmer’S Reference*/

                                     显示卡

cmp al , 050h

    录制显示器能以下列二种途径中之一来进行存取:

    .通过利用规范的库函数,能够减掉程序对于DOS设计爆发转移的敏感性。

与别的的劳动差异,Int
29h应用已经存在的其它显示屏属性并且只辨认响铃(bell,

mov di,00040h ; “31” at C000:0040

驱动程序系统的内部存款和储蓄器部分。然而在选用它后面,应该估摸一下所冒的风险(那就象使用别

je no_ega_present

cmp ax ,MDA ; MDA?

        {

and word ptr [bX] , NOT ADAPTER_SYSTEM_MASK

                regs.h.dh=25;

        位

or word ptr [bx] ,HEADLAND OR SVGA

jmp test_vesa

cmp al , 0AAh

not_genoa_bios:

所彰显的字符数。

AHEAD_VERSION_A equ 001h SHL 10

                        end

    么那就是贰个大概VGA适配卡。

jmp short test_vesa

and ax , ADAPTER_SYSTEM_MASK

jmp short swap_systems

.model small

and ax , MONITOR_MASK

video_ident proc

xor cx,cx ; Loop a while

 

XOP CX , CX

     
列表5.1是用以识别录像适配卡的程序(注意:那决不是一个唯一标准的顺序)。

  表5.2录像格局

84页

     
将字符的ASCII码值保存在字符内部存款和储蓄器地方,并在性质字节中设置其质量后,适配卡

                regs.h.bh=0;

1100           12           淡红色

          /*   Scroll the inside of the window up one line every 

#include<dos.h>

and word ptr [bX] ,NOT ADAPTER_SYSTEM_MASK

          /*   Save the data in the rectangle(5,5)  tO (12,40),
and

push bx

and word ptr [ bx ] , NOT ADAPTER_SYSTEM_MASK

/*Function:pgprint()*/

要。这么些类别的系统中“雪花”是这般不佳,以至于用户用这么七个奇特的词来描述它:色

wch(screen[i][j].ch, screen[i][j].att);

push cx

#include<stdio.h>

db VGA OR VGA_COLOR

   
要提供稳定的图像,显示屏就要以每秒伍1九遍的速度更新(即电子束对任何荧屏举办一

              5.2探望突显系统的劳作方法

ret

ATI_BIOS_Sig db “761295520”

or SecondarySystem,ax ; Set flags

crosoft
Word会受此格局的掣肘。选拔此形式来写那几个品种的程序是不足承受的,除非在

    {

      MDA                                     EGA

    CTI BASED                equ 004h SKL 6

85页

     
差别。使用那种艺术的次序平时与被观望的PC包容的保有系统不匹配。该办法

器,HGA或EGA卡能够效仿单色适配卡。

        ·分明硬件光标的轻重缓急和地方

 

xlat

; Check for CTI

数移向DOS服务,会获得对出口操作的更大控制,并维持对系统设计的必定的非敏感性。

or word ptr [bx] , AHEAd_VERSION_B

二进制      十进制        颜色

   
BIOS服务对于不直接存取摄像内部存款和储蓄器的主要编程,它们平时是被增选的功力。它们不

                              表5.1显得适配卡的内部存储器配置

; Attempt  to detect the CRT controller

      int 29h

扫过整个荧屏。

pop ds ; Restore caller’s DS

ati_2:

jz no_secondary

12h         图形        16          
640*480                                               X

Call CGA_detect

TRIDENT_8800BR equ 001h SHL 10

器芯片管理着广大要害的显示职务,以便程序员不必去管理它们:

MDA_detect   endp

                regs.h.bh=0;

inc dx

regs.h.ah=0x02;

   
在C语言中,已经有充足的劳务能与显示屏和打字与印刷机一起工作,以形成典型的编制程序

服务。

      ·虚拟图形阵列(VGA)

                printf(“This is the Second Screen of the Demo       “);

1111           15           高强度墨绿

jmp Short Herc_exit

CIRRUS_510_520 equ e01h SHL 10

          void gotoxy(r,c)

; Attempt to detect SVGA  Systems

or word ptr [bx] ,SVGA OR PARADISE

    ;Adapter types

              }

jne found_Hercules

          #define FALSE 0

{

        attribute.*/

xor ah,ah ; Clear byte

out dx,al

     
注意表5.4中背景颜色只同意4位,前景颜色则为三位。原因是行业内部的摄像突显线路

mov es , ax

cmp bx,’7′

Cld

荧屏展现的便是总计机内部存款和储蓄器中的内容(见图5.1)。内部存款和储蓄器缓冲区存款和储蓄显示屏呈现的音信。内存

          for(i=0;  i<50;  i++)

     
PC机显示系统已从不难的早先方式演变成如下所示的现行使用的两样的科班:

db EGA OR MDA_MONITOR

or word ptr [bx] ,SVGA OR ATI

                                图5.十一个出示系统的彰显内部存款和储蓄器映射

db UNKNOWN_ADAPTER OR UNKNOWN_MONITOR

or SecondarySystem ,MDA OR MDA_MONITOR

in al , dx

   
在先后的最低层,荧屏字符函数使用户能看看单个的显示器地方照旧采用BIOS显示器

db EGA OR EGA_MONITOR

AHEAD_BIOS_Sig db “AHEAD”

                int86(VIDEO,&regs,&regs);

    /* Prototypes*/

pop cx

且,成效0Eh无法适用于全体BIOS ROM的兼具页。全数测试的非IBM的ROM中,该功

                  文本

    EGA                   equ 003h

for(i=lr;i<=rr;i++) {

103页

0Ch         —        保留        —

cmp al , 030h

                  5.1骨干的字符设备

                upwin(1,6,6,11, 39);

db CGA OR CGA_MONITOR

      push es             ;save the register

not_cirrus_chip:

            for(j=lc;j<=rc;j++){

void setpage(n,clrflg)

·····111             水泥灰前景(逆向)

}

     
在多用户或任务系统中也是不般配的。它的独到之处以及被一再利用的因由都源于

; Return to caller

}

mov al,006h , Extension control reg

      HGA                                     MCGA

   
DOS服务用起来更简约。每种DOS服务提供容易的输出机制,它能够重定向并与所

mov al,ch ; Get unlock password

5.3.1应用DOS和BIOS录制效果编制程序

都应用像BASIC原型之类的言语作为开发的起源(如Visicalc,它是土生土长的电子表格程

      ·Hercules图形适配卡(HGA)

union REGS regs;

jmp short vid_exit

in al,dx ; Read unlock password

                            含义

push ds

以及有256种颜色的彩色调色板等的图样。

int86(VIDEO,&regs,&regs);

jne not_HGCPlus

mov ax,PrimarySystem ; Found CGA; primary or secondary?

mov cx, 4

cmp bl,07Fh

in al , dx

out dx,ax

; on entry, BX is a pointer to the VGA system word

86页

mov al,00Fh ; Select (alleged) cursor low

not_cirrus_bios:

    /*   Basic screen-size definitions*/

les di,es:[di] , Dereference it

inc dx

本和图形方式下,都能产生清晰而又助长的花花绿绿输出。

db EGA OR MDA_MONITOR

            /*FunctiOn:wch()*/

B800h               变化                变化

普及性实际上使HGA在PC种类上改为高分辨率单色图形的科班,但要利用它的图形功

06h         图形        2           640*200                   X    
X         X           X         X

    5.3.2利用多个显示页

1·······         闪烁字符

卡时,他们制成的适配卡确实无法与原本的IBM适配卡区分开来。不过开发商以他们自

or word ptr [bx] ,TRIDENT_8800CS OR SVGA

    .
固然伏贴地使用了正式调用,那些调用还是能够使程序与UNIX或XENIX系统匹配。

      分辨率一栏中的数目代表文本情势的行和列,代表图形情势的象素。

int n;

mov ax , PrimarySystem

    page 55,132

inc dx

的七个字节安顿在显示屏突显的种种字符地方上:叁个字节拥有该字符,另二个则拥有其属

                  regs.h.bh=7;

mov cx , 2

Cmp ax , UNKNOWN_ADAPTER

94页

jmp test_vesa

jmp Short test_vesa

       
突显适配卡平日有4至256K的内部存储器,VGA适配卡一般都提供512K或1M内部存款和储蓄器。因

void Clearwin(lr, lc, rr, rc)

in al,dx ; Read port

                  int n;

          Listing 5.4 of DOS Programmer’s Reference*/

VSYNC :

or word ptr [Si] ,HGCPLUS

ja not_headland

粗粗4K。借使选取每行四十个公文字符(2*40*25),那么各种显示器就占用两千个字节,

gotoxy(rr,lc); wch(LOWERLEFT, 7);

    name video_id

                rch(&screen[i][j].ch,&screen[i][j].att);

        union REGS regs;

 

      ·探测光笔信号

and al,080h ; Save VSYNC bit

这么些可能用来突显帮忙消息的窗口。因为它没有使用比BIOS成效更低的东西,所以它与

out dx,al

int86(VIDEO, &regs, &regs);

found 8800BR:

        Cls();

                            表5.5花团锦簇文本格局下可能的位设置

80页

      mov al,‘A’

适配卡是VGA系统,它帮助15个显示格局。
VGA还扶助单色显示、每显示器43行的显得

0100         4            红色

    #include<stdio.h>

    };

jne not_cti82C452

所需寄存器是相比便于的。

#define VERTLINE 186

mov ah , 012h

里的音讯为根基来更新录制体现。实际的显示屏展现由电子束来发出,该电子束能在对荧屏

; Attempt to detect MDA card

cmp ch , 0CAh ; 610/ 620?

test_Hercules:

                  图形

push si

xor ax,ax , Find CRTC

push cx

      在那种上编制程序的快捷突显和便捷操作。

db VGA OR vga_MONO

80*244处理器终端显示屏紧凑同盟。

/* The screen is made up of LINES*COLS character positions*/

    /* Testscn.c

    MCGA                  equ 004h

and al,0F0h ; Check version

}

    PS/2兼容、彩色的

    ···· XXXX       前景(见表5.5)

pop bx ; Restore pointer

   
合成单色监视器是一矢双穿的单色(平常是深紫灰或铁青)监视器,能被CGA输出所驱

0Fh         图形        单色      640* 350                        
X                     X

}

0·······         寻常字符

mov Si , offset VESA_BIOS_Sig

; video chip types

     
MDA只补助叁个显示器显示方式(方式7),CGA补助捌个,EGA支持十二个。最复杂的

db EGA OR CGA_MONITOR

   
那种重新方法无法与实时交互功效程序一起很好地劳作。一些主次如1-2-3和Mi-

译)能使程序支付和维护工作不难化。那一个程序是超人的简要实用程序或交互功效程序。

          for(i=0;i<50; i++)

      out dx,al           ; send to CGA mode control port

jmp test_vesa

          gotoxy(24,0);

行,然后回到到显示屏已显得的一样内容上去。

and word ptr [ bx ] ,NOT ADAPTER_SYSTEM_MASK

    MONITOR_MASK             equ 007h SHL 3

pop ax

            int i;

#include<stdio.h>

cmp ah,0A5h ; Right global ID?

   
若是唯有单色监视器系统,那么哪些也看不到。当执行setpage()函数时,事实上荧屏

    EGA_MONITOR            equ 003h SHL 3

 本节列举了辨认下述展现适配卡类型的一层层进程:

测到,所以大多数一向的荧屏内部存款和储蓄器途径测试只用于HRI条件。当位一贯打开时,用户有时

    当用户与杰出的IBM CGA或CGA电路的其余复制口一起坐班时,那些标题尤其重

都检查Ctrl-C,所以它比较快。

08h         图形        16          
160*200                                                         X

mov al , 00Bh

out dx,al

      CGA卡

   
超过50%电脑书籍都将协助装置(智跑S-232端口)看作字符输出设备,并在与本章类似

; The enhanced video BIOS call failed

in  al , dx

        Listing 5.2 in DOS Programmer’s Reference*/

; Check for Genoa

db MCGA OR EGA_MONITOR

and dx,0FFF0h ; Get board number

out dx,al

in al,dx ; Get new value

Or word ptr [bx] ,TRIDENT_8800BR OR SGA

     
对于有着展现适配卡而言,文本格局的有效页数便是各类显示屏地点乘上八个字节去

                int86(VIDEO,&regs,&regs);

        mov ax , 40h             :address BIOS work area

          border()      围绕窗口设置三个边界

; Test for VESA BIOS

    ;SVGA BIOS types

or word ptr [bx] ,CIRRUS_VSEVEN

          #include<Stdio.h>

; we have VGA at least

                regs.h.al=ch;

的每一行实行扫描时,打开或关闭小的显示器点(称作象素)。电子束从左到右,从上到下地

      76543210

            void pgprint(char*str);

regs.h.cl = lc,

关键的配备,因为它们在先后和程序员之间负担着相互功能点的角色。

          void clearwin( int lr,int lc, int rr,int rc);

{

          void gotoxy(int i,int j);

安装背景域的要职为1,从而提供使每种字符闪烁开和关的意义。不过,通过修饰输送给

   
与其他章节一样,本章重视介绍与最高编码级别一起干活的实用程序。平常,应该使

jne not_ahead_bios

db MCGA OR VGA_MONO

            void rch(ch,attr)

105页

                char ch,attr;

 

殊的双重端口内部存款和储蓄器,总结机能在该内部存款和储蓄器中书写数值,同时C奥德赛TC能够阅读它们。因为那类

列表5.1

int 10h

mov Si , Offset GENOA_BIOS_Sig

mov es ,ax

显示屏类型    录像格局

mov cx , 4

mov di,6

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注