关于CX寄存器中所谓"显示字符个数"这个参数的含义前面并未说明,通过这个程序我们对这个参数就能有所了解,这个参数表示待显示的字符所需重复显示的个数。运行这个程序之后还有一个问题值得注意:即当一串大写字母"A"出现在屏幕上后,光标究竟在什么地方?
前面使用0EH功能输出字符串时光标总是在最后一个字符的后面,而09H功能却正相反,光标在第一个字符下面闪烁,也就是说09H功能不会自动移动光标。这就给我们出了这样一个难题:如果需要在屏幕上光标位置处显示一个有属性的字符串,程序DISPSTR.ASM能行吗?
data segment assume ds:data msg db 'Take care,I want to sleep.',0 data ends code segment assume cs:code main proc far mov ax,data ;初始化DS寄存器 mov ds,ax mov bh,0 ;显示页号送入BH寄存器 mov bl,00010100b ;属性字节送入BL寄存器 mov cx,1 ;显示一个字符 mov si,offset msg ;SI寄存器指向字符串MSG outloop: lodsb ;从字符串中取得一个字符 or al,al ;已到字符串结尾了吗? jz end_out ;已到结尾,转END_OUT mov ah,09h ;利用10H中断的09H功能 int 10h ;输出AL寄存器中的字符以及BL中的属性 jmp outloop ;转至OUTLOOP继续输出下一个字符 end_out: mov ah,4ch ;结束进程 int 21h main endp code ends end main
表面看来这个程序是使用0EH功能的翻版,应该没有问题,可运行这个程序后除了能看到一个蓝底红色的句号外并没有看到任何文字,这就是09H功能没有移动光标的结果。其实每个字符都被显示了,只不过它们都显示在同一个地方,所以除了最后的一个句号外我们看不到其它的文字。我们可以在指令"INT 10H"后面插入一个"等待":
;**等待********************** mov ah,0 ;* int 16h ;* ;****************************
然后运行这个程序,可以看到字符一个个的显示在同一个位置,光标始终不移动。BIOS特别提供了一个功能调用用于移动光标:
功能号:02H
用 途:设置光标位置
参 数:DH=行号(0-24)
DL=列号(0-79)
BH=显示页号
调 用:INT 10H
返 回:无
程序DISPSTR1.ASM就是应用了这个功能修改之后的结果:
data segment assume ds:data msg db 'Take care,I want to sleep.',0 col db 0 ;光标所在列 data ends code segment assume cs:code main proc far mov ax,data ;初始化DS寄存器 mov ds,ax mov bh,0 ;显示页号送入BH寄存器 mov dx,0 ;设置光标位置 mov ah,02h ;移动光标至(0,0)处 int 10h next_line: mov bl,00010100b ;属性字节送入BL寄存器 mov cx,1 ;每次显示一个字符 mov si,offset msg ;SI寄存器指向字符串MSG outloop: lodsb ;取得一个字符 or al,al ;已到字符串结尾了吗? jz end_out ;已到结尾,转END_OUT mov ah,09h ;利用10H中断的09H功能 int 10h ;输出AL寄存器中的字符 inc dl ;准备将光标移动到下一列 mov ah,2 ;移动光标 int 10h ;*等待*** ********* ************** mov ah,0 ;* int 16h ;* ;******** ********* ************** jmp outloop ;转至OUTLOOP输出下一个字符 end_out: inc byte ptr col ;光标所在列加1 mov ah,02h ;选择10H中断的2号功能 inc dh ;光标所在行加1 cmp dh,24 ;已到最底行了吗? jz exit ;已到最底行,转EXIT结束程序 mov dl,col ;准备将光标移动到下一行第"COL"列 int 10h ;移动光标 jmp next_line ;在下一行重新输出字符串 exit: mov ah,4ch ;结束进程 int 21h main endp code ends end main
程序的运行结果倒是很有意思的,不过明眼人一眼就能看出这个程序有一个小"埋伏":它并没有在"当前光标所在位置"处显示字符串。09H功能确实能在当前光标位置处显示字符,但由于程序并不知道当前光标位置究竟在哪儿,所以在程序中无法设定DH和DL寄存器的值。要想解决这个问题,只能想办法找到"当前光标位置",这就要用到10H中断的03H功能。
功能号:03H
用 途:取得当前光标位置
参 数:BH=显示页号
调 用:INT 10H
返 回:DH=当前光标所在行号
DL=当前光标所在列号
CX=光标类型
程序DISPSTR1.ASM才是真正达到"在当前光标位置处显示有属性的字符串"这个目标的程序:
data segment assume ds:data msg db 'Take care,I want to sleep.',0 data ends code segment assume cs:code main proc far mov ax,data ;初始化DS寄存器 mov ds,ax mov bh,0 ;显示页号送入BH寄存器 mov ah,03h ;利用10H中断的03H功能 int 10h ;取得当前光标所在位置 mov bl,00010100b ;字符属性字节送入BL寄存器 mov cx,1 ;每次显示一个字符 mov si,offset msg ;SI寄存器指向字符串 outloop: lodsb ;从字符串中取得一个字符 or al,al ;已到字符串结尾了吗? jz end_out ;已到结尾,转END_OUT mov ah,09h ;利用10H中断的09功能 int 10h ;输出AL寄存器中的字符 inc dl ;光标所在列加1 mov ah,2 ;利用10H中断的02H功能 int 10h ;将光标移动到下一列 ;*等待* ********* ************** mov ah,0 ;* int 16h ;* ;****** ********* ************** jmp outloop ;转至OUTLOOP输出下一个字符 end_out: mov ah,4ch ;结束进程 int 21h main endp code ends end main
这里有必要说明一下返回CX中"光标类型"的含义。大家都知道文本屏幕上的光标的形状是可变的,最明显的就是当我们使用DOS中的编辑器"EDIT"时,在插入状态下光标是一粗横线,而按下"Insert"键后光标会变成一个方块。所以所谓光标类型其实就是指光标的高度。