Dos下的屏保程序实现

.286
.MODEL SMALL
.CODE
;-------数据段---------
CLOCK DB 8 DUP(?)
OLD1C LABEL DWORD	;旧1c中断
OLD1COFF DW ?
OLD1CSEG DW ?
oldint9 dd ?
time dw 91
oldint60 dd ?
oldint1c dd ?
;-----------------------
soundf proc
	push dx
	push ax
	push cx
	mov 	dx,10
	in 		al,61h
	and		al,0fch
sound:
	xor		al, 02
	out		61h, al
	
	mov		cx, 1400h
wait1:
	loop	wait1
	dec 	dx
	jne		sound
	pop cx
	pop ax
	pop dx
	ret
soundf endp
;-----------------------
dispclock proc 
	  PUSH AX
      PUSH BX
      PUSH CX
      PUSH DX
      PUSH SI
      PUSH DS

	  mov cs:time, 18
	  LEA  SI,CLOCK
      MOV  AH,02H
      INT  1AH
      MOV  AH,CH
      MOV  AL,CL		;获取系统时间
      
	  MOV  CL,4
      SHR  CH,CL
      OR   CH,30H
      MOV  DS:[SI],CH
      INC  SI			;送ascii码,小时 高位
      
	  MOV  CH,AH
      AND  CH,0FH
      OR   CH,30H
      MOV  DS:[SI],CH
      INC  SI			;送ascii码,小时 低位
      
	  MOV  DL,3AH
      MOV  DS:[SI],DL
      INC  SI			;冒号
      
	  MOV  AH,AL
      SHR  AL,CL
      OR   AL,30H
      MOV  DS:[SI],AL
      INC  SI			;送ascii码,分钟 低位
      
	  MOV  AL,AH
      AND  AL,0FH
      OR   AL,30H
      MOV  DS:[SI],AL
      INC  SI			;送ascii码,分钟 低位
      
	  MOV  DS:[SI],DL
      INC  SI			;冒号
	  MOV  AH,DH
      SHR  DH,CL
      OR   DH,30H
      MOV  DS:[SI],DH
      INC  SI
      MOV  DH,AH
      AND  DH,0FH
      OR   DH,30H
      MOV  DS:[SI],DH
      INC  SI			;秒

	  ;push es
	  ;push di
	  ;mov ax, 0
	  ;mov di, ax
	  ;mov ax, 0b800h
	  ;mov es, ax
	  ;mov al, 20h
	  ;mov ah, 07h
	  ;mov cx, 2000
	  ;cld
	  ;rep stosw
	  ;pop di 
	  ;pop es
		
	  mov 	ah, 6		;清屏
	  mov 	al, 0
	  mov 	bh, 7
	  mov 	ch, 0
	  mov 	cl, 0
	  mov 	dh, 24
	  mov 	dl, 79
	  int 	10h

      LEA  SI,CLOCK
      PUSH ES
      PUSH DI
      MOV  AX,072AH
      MOV  DI,AX
      MOV  AX,0B800H
      MOV  ES,AX		;采用写显存的方式输出
      MOV  CX,8			;循环次数
      MOV  AH,34H		;属性值


DISP: PUSH CX
      MOV   AL,[SI]      
      INC   SI
      MOV   CX,1
      STOSW
      POP   CX
      LOOP  DISP
	  call soundf
quit:
	  cli
      POP   DI
      POP   ES
	  
	  POP DS
      POP SI
      POP DX
      POP CX
      POP BX
      POP AX
	  ret 
dispclock endp
;-------------------------------------------------------------
newint60 proc far
	sti
	push ax
	push dx
	push ds
	mov dx, cs:word ptr oldint9
	mov ds, cs:word ptr oldint9[2]
	mov ax, 2509h		;还原中断向量9 
	int 21h

	mov dx, cs:word ptr oldint1c
	mov ds, cs:word ptr oldint1c[2]
	mov ax, 251ch		;还原中断向量1ch
	int 21h

	mov dx, cs:word ptr oldint60
	mov ds, cs:word ptr oldint60[2]
	mov ax, 2560h		;还原中断向量
	int 21h

	pop ds
	pop dx
	pop ax
iret
newint60 endp
;-----------------------
newint9 proc far 
		mov cs:time, 91
		jmp cs:oldint9
newint9 endp
;-----------------------
newint1c PROC FAR
	  sti
      mov al,20h
      out 20h,al		;开中断
	  dec  cs:time 
	  jnz exit

	  call dispclock
	  
EXIT: IRET
newint1c ENDP
prog_len EQU $-CLOCK
;---------------主程序---------------------------
INIT: 
    PUSH CS
    POP  DS

	mov ax,351ch
    int 21h
    LEA  DX,newint1c
    CMP  DX,BX
    JE   EX
    lea di, oldint1c
    mov word ptr [di], bx
    mov word ptr [di+2], es
    mov dx,offset newint1c   
    mov ax,seg newint1c
    mov ds,ax 
    mov ax,251ch                      
    int 21h
		
	mov ax,3509h
   	int 21h
	lea di, oldint9
	mov word ptr [di], bx
	mov word ptr [di+2], es
	mov dx, offset newint9
	mov ax, seg newint9
	mov ds, ax
	mov ax, 2509h
	int 21h

    mov ax,3560h
    int 21h
    lea di, oldint60
    mov word ptr [di], bx
    mov word ptr [di+2], es
    mov dx,offset newint60   
    mov ax,seg newint60
    mov ds,ax 
    mov ax,2560h                      
    int 21h

    ;中断屏蔽(只响应计时器中断)
    pop ds                             
    in al,21h
    and al,11111110b
    out 21h,al
    sti
	;中断驻留
       mov ah,31h
   mov al,0
   mov dx,((prog_len+15)/16)+16                   ;驻留区大小
   int 21h
EX:   
	MOV  AH,4CH
    INT  21H
END  INIT
程序运行效果

Dos下的屏保程序实现_第1张图片

因为程序是几个月前写的,没什么注释,我现在也有点看不懂了,不过屏保程序的关键是键盘检测部分,要在键盘按下时,将计时器复位重新计时进入屏保。修改键盘中断int9,重写newint9为新键盘中断,在每次进入键盘中断的时候,先把计时器复位,然后程序跳转到原来int9的的部分,代码如下:

newint9 proc far 
		mov cs:time, 91
		jmp cs:oldint9
newint9 endp


因为程序是驻留内存在,在程序编译期间可是纠结死我了,因为我的电脑是64位的,MASM只有32位的,每次编译的时候都要先进dosbox,执行

Dos下的屏保程序实现_第2张图片

这样才能跳转到编辑目录。因为是程序中驻留了内存,每次只要程序出错,得强制关闭doxbox才能终止程序,于是根据内存驻留的原理,写了一个解除内存驻留的remove.exe

code segment 
assume cs:code, ds:code
start:
	jmp initialize
remove proc near
	;mov al,60h
	;mov ah,35h
	;int 21h
	;mov ax,es
	;cmp ax,0
	;jz done
	int 60h
	;push es
	;mov ax, es:[2ch]	
	;mov es, ax
	;mov ah, 49h		;解除环境块
	;pop es
	;mov ah, 49h		;解除程序块
	;int 21h
	done:ret
remove endp

initialize: call remove
	mov ax, 4c00h
	int 21h
code ends
	end start

只能说这么多了,具体细节我真想不起来了。农大的学弟学妹们,如果你们上汇编课的话,并且如果是沈翠华老师,每年的题目都是dos下的屏保程序,当然还可以自选题目,学姐的程序在这里了,两个晚上的呕心沥血,拿去吧!

你可能感兴趣的:(汇编语言)