ITEEDU

第1章 Iczelion的Win32汇编教程

第2章 Iczelion的ODBC教程

第3章 Iczelion的VxD教程

第4章 Iczelion的PE教程

第5章 罗云彬的Win32汇编教程

第6章 Win32ASM经验点滴

第7章 X86汇编语言编程

第8章 加密解密

第9章 病毒的分析和防治

图形显示方式屏幕的保存和恢复

概述:

在程序中常常要暂时的保存图形显示方式屏幕上的内容,然后把自己的信息输出到屏幕上,结束后再恢复原来的屏幕内容,特别在内存驻留程序弹出一个窗口时更要用到,但是图形方式下显示缓冲区的容量巨大,在常用的 80 x 25 文本方式下,显示缓冲区仅大小仅为 80 x 25 x 2 = 4000 字节,而在模式 13H 320 x 200 x 256 色时为 320 x 200 = 64000 字节,现在常用的高彩色、真彩色下如 800 x 600 x 65535 色时为 800 x 600 x 2 = 960000 字节,涉及到如此大的数据量程序必须使用磁盘交换方法或用到 XMS 做为数据保存缓冲区,使编程复杂化。
本文用了 INT 10H 中不清除显示内存设置新显示模式的方法,使不管在什么显示方式下,用到的缓冲区大下都在 10K 左右,即使在 1024 x 768 x 16.7M 色也能正常保存。
本程序的适用范围为保存屏幕后自己的程序仅仅使用文本模式 3 的情况,如果要用到图形模式,那么还是要保存全部的显示缓冲区。在兼容性方面,由于使用 VESA 标准功能,在现在的 PCI/VESA 显示卡上都能正常运行,我发现唯一不能运行的是有一段时期生产的 TVGA 8900/9000 卡,因为此卡在 VESA 功能刚出现的时候生产,支持 VESA 的伪彩色显示模式,却又不支持很多其他的 VESA 功能。大家找到克服的方法告诉我一声。
本程序要用到的一些中断的说明如下:

INT 10H 的 00H 功能,设置显示模式:

功能 入口参数 出口参数
INT 10H 的 00H功能
设置显示模式
AH = 00H  
AL = 模式(如果位 7 置位,则不清除显示缓冲区)

INT 10H 的 1BH 功能,检测是否 VGA 卡:

功能 入口参数 出口参数
INT 10H 的 1BH功能
取 VGA/MCGA 的功能、状态信息
AH = 1BH AL = 1BH 成功(说明显示卡为 VGA 以上)
ES:DI 返回状态信息
BX = 0000
AL <> 1BH 非VGA/MCGA 显示卡
ES:DI 指向 64 字节缓冲区

INT 10H 的 1CH 功能,保存/恢复视频状态:

功能 入口参数 出口参数
INT 10H 的 1C00H 功能
返回状态缓冲区容量
AX = 1C00H AL = 1CH 成功
BX = 需要的 64 字节块数目
INT 10H 的 1C01H 功能
保存视频状态
AX = 1C01H  
ES:BX 指向缓冲区
INT 10H 的 1C02H 功能
恢复视频状态
AX = 1C01H  
CX = 要求的状态
位 0 = 恢复视频硬件状态
位 1 = BIOS 数据区
位 2 = 彩色寄存器和 DAC 状态
ES:BX 指向缓冲区(用1C01H功能保存下来的)

INT 10H 的 4FH 功能,VESA 功能:

功能 入口参数 出口参数
INT 10H 的 4F00H功能
取显示卡 VESA 信息
AX = 4F00H AL = 4FH 说明显示卡支持VESA
AH = 00H 成功
AH = 01H 失败
ES:DI 指向缓冲区 (256 字节) AL <> 4FH 显示卡不支持VESA
INT 10H 的 4F05H功能
控制对 VESA 显示卡视频 RAM 的访问
BH = 00H 选视频内存窗口
DX = 视频内存窗口地址
AH = 00H 成功
AH = 01H 失败
BH = 01H 取视频内存窗口 AH = 00H 成功
DX = 视频内存窗口地址
AH = 01H 失败

INT 33H 的 16H/17H 功能,保存/恢复鼠标驱动程序状态:

功能 入口参数 出口参数
INT 33H 的 0015H功能
确定保存鼠标驱动程序状态所需
的空间
AX = 0015H BX = 所需大小
INT 33H 的 0016H功能
保存鼠标驱动程序状态
AX = 0016H  
BX = 缓冲区大小(用 0015H 获得)
ES:DX 指向缓冲区
INT 33H 的 0017H功能
恢复鼠标驱动程序状态
AX = 0017H  
BX = 缓冲区大小(用 0015H 获得)
ES:DX 指向缓冲区

源程序:

;by Luo Yun Bin
;http://asm.yeah.net 

;这个子程序用来检测显示卡的类型,鼠标状态等等
;在程序初始化时执行

;文中要用到的一些缓冲区请自己定义,注意大小!

        FLAG  DB        ?           ;标志位,位 7 置 1 表示安装了鼠标
    VGA_TYPE  DB        ?           ;显示卡类型
  VIDEO_MODE  DB        ?           ;显示模式
    VGA_WIN1  DW        ?           ;视频窗口,暂存 VESA 的窗口状态
    VGA_WIN2  DW        ?           ;
    VGA_WIN3  DW        ?           ;

                ...

    TEST_VGA  PROC

              PUSH      0           ;检测是否安装鼠标驱动程序
              POP       DS
              CMP       WORD PTR DS:[33H*4],0
              JZ        NO_MOUSE
              OR        CS:FLAG,10000000B       ;has mouse installed
   NO_MOUSE:
              PUSH      CS
              POP       DS
              MOV       AH,1BH      ;检测是否是 VGA 以上显示卡
              XOR       BX,BX
              MOV       DI,OFFSET FILE_END
              INT       10H
              CMP       AL,1BH
              JNZ       TV_NO_VGA
              MOV       AX,4F00H    ;检测是否支持 VESA 功能
              MOV       DI,OFFSET FILE_END
              INT       10H
              CMP       AL,4FH
              JZ        TV_IS_VESA
              MOV       DX,3C4H     ;检测是否 TVGA 9000 卡
              MOV       AL,0EH      ;这一段是照抄的,找不到资料
              OUT       DX,AL
              INC       DX
              IN        AL,DX
              MOV       BL,AL
              XOR       AL,AL
              OUT       DX,AL
              IN        AL,DX
              XCHG      AL,BL
              OUT       DX,AL
              TEST      BL,2
              JNZ       TV_IS_TVGA
              MOV       DX,3CDH     ;检测是否 ET6000 卡
              IN        AL,DX
              MOV       AH,AL
              MOV       AL,11H
              OUT       DX,AL
              IN        AL,DX
              XCHG      AH,AL
              OUT       DX,AL
              CMP       AH,11H
              JZ        TV_IS_TSENG
              MOV       VGA_TYPE,4
              RET
 TV_IS_VESA:
              MOV       VGA_TYPE,1
              RET
 TV_IS_TVGA:
              MOV       VGA_TYPE,2
              RET
            TV_IS_TSENG:
              MOV       VGA_TYPE,3
              RET
  TV_NO_VGA:
              INT       20H         ;非 VGA 卡退出

    TEST_VGA  ENDP

                ...

;================================================================
;保存显示缓冲区内容并设置新的显示模式到 80 x 25 文本 (模式 3)
    SAVE_SCR  PROC
              PUSH      DS
              PUSH      ES
              TEST      FLAG,10000000B          ;见前面
              JZ        SS_NO_MOUSE
              MOV       AX,16H      ;保存鼠标状态
              MOV       DX,OFFSET MOUSE_BUFFER
              INT       33H
            SS_NO_MOUSE:
              MOV       AX,1C01H    ;保存视频状态
              MOV       BX,OFFSET VIDEO_BUFFER
              MOV       CX,7
              INT       10H
              MOV       AH,0FH      ;保存原显示模式
              INT       10H
              MOV       VIDEO_MODE,AL
              CMP       AL,3        ;80 x 25 x 16 色
              JZ        SS_MODE3
              CMP       AL,7        ;80 x 25 黑白
              JZ        SS_MODE7
              XOR       AX,AX       ;以下为图形方式保存显示缓冲区
              CALL      VGA_PAGE
              CALL      VGA_BASE
              CALL      SAVE_VRAM
              MOV       AX,0083H    ;设置新的显示模式,不清除显示内存
              INT       10H

              PUSH      0B800H
              POP       DS          ;保存显示内存
              XOR       SI,SI
              MOV       CX,1000H
              MOV       DI,OFFSET RAM_BUFFER
              PUSH      CS
              PUSH      DS
              CLD
              REP       MOVSB
              XOR       DI,DI       ;
              MOV       CX,80*25
              MOV       AX,57B1H    ;填充背景,不然有乱字符
              CLD
              REP       STOSW
    SCR_RET:
              POP       ES
              POP       DS
              RET
   SS_MODE3:
              CALL      SAVE_VRAM   ;显示模式 3 保存显示 RAM
              JMP       SHORT SCR_RET
   SS_MODE7:
              PUSH      0B000H      ;显示模式 7 保存显示 RAM
              POP       DS
              CALL      SAVE_VRAM1
              MOV       AX,3
              INT       10H
              CALL      RESTORE_VRAM
              JMP       SHORT SCR_RET
    SAVE_SCR  ENDP
   SAVE_VRAM  PROC
              PUSH      0B800H      ;把显示内存保存到自己的缓冲区
              POP       DS
 SAVE_VRAM1:
              PUSH      CS
              POP       DS
              XOR       SI,SI
              MOV       DI,OFFSET RAM_BUFFER
              MOV       CX,2000H
              CLD
              REP       MOVSB
              RET

   SAVE_VRAM  ENDP
            RESTORE_VRAM  PROC

              PUSH      0B800H      ;恢复显示缓冲区内容
              POP       ES
          RESTORE_VRAM1:
              XOR       DI,DI
              PUSH      CS
              POP       DS
              MOV       SI,OFFSET RAM_BUFFER
              MOV       CX,2000H
              CLD
              REP       MOVSB
              RET

            RESTORE_VRAM  ENDP
    VGA_PAGE  PROC
              CMP       VGA_TYPE,1
              JNZ       OTHER_VGA1
              CMP       AH,1
              JZ        VP_VESA2
              CMP       AH,2
              JZ        VP_VESA1
              MOV       AX,4F05H    ;保存 VESA 显示卡状态
              MOV       BX,0100H
              INT       10H
              MOV       VGA_WIN1,DX
              MOV       AX,4F05H
              MOV       BX,0101H
              INT       10H
              MOV       VGA_WIN2,DX
   VP_VESA1:
              MOV       AX,4F05H
              XOR       BX,BX
              XOR       DX,DX
              INT       10H
              MOV       AX,4F05H
              MOV       BX,0001H
              XOR       DX,DX
              INT       10H
              RET
   VP_VESA2:
              MOV       AX,4F05H
              XOR       BX,BX
              MOV       DX,VGA_WIN1
              INT       10H
              MOV       AX,4F05H
              MOV       BX,0001H
              MOV       DX,VGA_WIN2
              INT       10H
              RET
 OTHER_VGA1:
              CMP       VGA_TYPE,3
              JNZ       OTHER_VGA2
              MOV       DX,3CDH
              CMP       AH,1
              JZ        VP_TSENG2
              CMP       AH,2
              JZ        VP_TSENG1
              IN        AL,DX
              MOV       VGA_WIN3,AL
  VP_TSENG1:
              XOR       AL,AL
              OUT       DX,AL
              RET
  VP_TSENG2:
              MOV       AL,VGA_WIN3
              OUT       DX,AL
     VP_RET:
              RET
 OTHER_VGA2:
              CMP       VGA_TYPE,2
              JNZ       VP_RET
              MOV       AL,0EH
              MOV       DX,03C4H
              CMP       AH,1
              JZ        VP_TVGA2
              OUT       DX,AL
              INC       DX
              IN        AL,DX
              CMP       AH,2
              JZ        VP_TVGA1
              MOV       VGA_WIN3,AL
              XOR       AL,AL
              OUT       DX,AL
              RET
   VP_TVGA1:
              MOV       AL,2
              OUT       DX,AL
              RET
   VP_TVGA2:
              MOV       AH,VGA_WIN3
              OUT       DX,AX
              RET
    VGA_PAGE  ENDP
    VGA_BASE  PROC
              MOV       DX,3C4H     ;这一段是照抄的,找不到资料
              MOV       AX,402H
              OUT       DX,AX
              MOV       AX,704H
              OUT       DX,AX
              MOV       DX,3CEH
              MOV       AX,0FF08H
              OUT       DX,AX
              MOV       AX,0C06H
              OUT       DX,AX
              MOV       AX,204H
              OUT       DX,AX
              MOV       AX,5
              OUT       DX,AX
              RET
    VGA_BASE  ENDP

;====================================================
;本子程序为恢复原来的显示内容
;在自己的程序执行完后使用
 RESTORE_SCR  PROC
              PUSH      CS
              POP       DS
              MOV       AL,VIDEO_MODE           ;根据不同的原显示模式不同处理
              CMP       AL,3
              JZ        RS_MODE3
              CMP       AL,7
              JZ        RS_MODE7
              PUSH      0B800H      ;以下为图形方式恢复显示内容
              POP       ES
              PUSH      CS
              POP       DS
              MOV       SI,OFFSET RAM_BUFFER
              XOR       DI,DI
              MOV       CX,1000H
              CLD
              REP       MOVSB       ;恢复显示 RAM

              MOV       AH,2
              CALL      VGA_PAGE
              CALL      VGA_BASE
              CALL      RESTORE_VRAM
              XOR       AH,AH       ;恢复到原来的显示模式
              MOV       AL,VIDEO_MODE
              OR        AL,80H
              INT       10H
              MOV       AH,1
              CALL      VGA_BASE
              JMP       SHORT RS_MODE31
   RS_MODE3:
              CALL      RESTORE_VRAM
  RS_MODE31:
              PUSH      CS
              POP       ES
              PUSH      CS
              POP       DS
              MOV       AX,1C02H    ;恢复视频状态
              MOV       BX,OFFSET VIDEO_BUFFER
              MOV       CX,7
              INT       10H
              TEST      FLAG,10000000B
              JZ        RS_NO_MOUSE
              MOV       AX,17H      ;恢复鼠标状态
              MOV       DX,OFFSET MOUSE_BUFFER
              INT       33H
            RS_NO_MOUSE:
              RET
   RS_MODE7:
              MOV       AX,7        ;显示模式 7 恢复
              INT       10H
              PUSH      0B000H
              POP       ES
              CALL      RESTORE_VRAM1
              JMP       SHORT RS_MODE31
 RESTORE_SCR  ENDP