C++老代码 -- DOS下文本方式的直接写屏

        还是十几年前的老代码,一个完整的DOS下文本方式直接写屏C++代码,本代码是在Borland C++ 3.1下编译的,因为其中有插入汇编码,其它C++编译器能否通过,就不得而知了,下面是代码:

//     CRTIO.HPP

#ifndef    __CRTIO_HPP
#define     __CRTIO_HPP

#define     LINEBYTES    160

typedef    unsigned 
char      byte ;
typedef    unsigned    word;
typedef unsigned 
long     dword;

class     Crtio    {

private :

  
static   byte  OldMode;         //  初始化前的屏显模式
   static   byte  CrtMode;         //  当前屏显模式
   static  word CrtMemSeg;     //  屏显内存段地址
   static  word CrtMemOff;     //  屏显内存偏移地址
   static   byte  CursorType;     //  当前光标类型(改写 0, 插入非 0)

protected :

  
void  Scroll(  int int int int int int  );
  
//  计算保存屏幕矩形所需内存长度.
  word RectSize(  int int int int  );
  
//  保存屏幕矩形内容. 参数: 屏幕左上角行,列,右下角行,列, 缓冲区
   void  SaveRect(  int int int int void  far *  );
  
//  恢复屏幕矩形内容到屏幕. 参数: 屏幕左上角行,列, 缓冲区
   void  RestRect(  int int void  far *  );
  
//  显示字符串. 参数: 行, 起始列, 字符串, 结束列, 显示属性. 如显示字符超过
  
//  结束列截断, 返回实际显示的字符个数
   int  PutChars(  int int char * int int );
  
//  返回所给行列位置的屏显偏移地址
   static  word CrtOff(  int int  );
  
//  取字符属性. 参数: 彩显字符属性(如单显返回对应的单色字符属性, 否则返回参数本身)
   static   int  GetAttr(  int  );

public :

  
//  初始化屏幕, 参数 = 0 清屏, 否则不清屏
   static   void  Init(  int   =   0  );
  
//  恢复程序调用前的模式
   void  Close();
  
//  返回屏显段地址
  word CrtSeg();
  
//  返回当前的屏显模式
   byte  Mode();
  
//  设置光标类型, 如当前为改写, 换为插入, 反之亦然
   void  SetCursorType();
  
//  返回当前光标类型
   int  GetCursorType();
  
//  移动光标. 参数: 行, 列
   void  SetPos(  int int  );
  
//  取当前光标行列. 参数: 行, 列
   void  GetPos(  int & int &  );
  
//  清屏. 参数: 屏幕左上角行,列,右下角行,列, 颜色
   void  Clear(  int int int int int  );
  
//  移行. 参数: 行数(0 清屏; >0 上移; <0 下移), 左上角行,列,右下角行,列, 空行属性
   void  RowRoll(  int int int int int int  );
  
//  移列. 参数: 列数(0 清屏; >0 左移; <0 右移), 左上角行,列,右下角行,列, 空行属性
   void  ColRoll(  int int int int int int  );
  
//  在当前光标处写字符. 参数: 字符, 显示个数, 显示属性
   void  PutChar(  int int int  );
  
//  返回所给行列位置的字符及属性, 低字节=字符, 高字节=属性. 参数: 行, 列
   int  GetChar(  int int  );
  
//  隐蔽光标
   void  HideCursor();

};

inline word Crtio::CrtSeg()
{
  
return  CrtMemSeg;
}

inline 
byte  Crtio::Mode()
{
  
return  CrtMode;
}

inline word Crtio::RectSize( 
int  Row1,  int  Col1,  int  Row2,  int  Col2 )
{
  
return ((((Row2  -  Row1  +   1 *  (Col2  -  Col1  +   1 ))  <<   1 +   4 );
}

inline 
int  Crtio::GetCursorType()
{
  
return  ( int )CursorType;
}

inline 
void  Crtio::HideCursor()
{
  SetPos( 
25 0  );
}

#endif

//     CRTIO.CPP

#pragma     inline

#include 
" crtio.hpp "
#include 
" asmrules.h "
#include 
< dos.h >

byte  Crtio::OldMode  =   3 ;
byte  Crtio::CrtMode  =   3 ;
word Crtio::CrtMemSeg 
=   0xb800 ;
word Crtio::CrtMemOff 
=   0 ;
byte  Crtio::CursorType  =   0 ;


void  Crtio::Init(  int  flag )
{
  asm    mov    ax, 40h
  asm    mov    es, ax
  asm    mov    al, es:[49h]
  asm    mov    DGROUP:@Crtio@OldMode, al
  asm    mov    al, es:[
61 ]
  asm    cmp    al, 
0
  asm    je    initcur
  asm    mov    al, 
1
initcur:
  asm    mov    DGROUP:@Crtio@CursorType, al
  asm    mov    al, es:[10h]
  asm    and    al, 00110000b
  asm    cmp    al, 00110000b
  asm    je    mda_yes
  asm    mov    ax, 
3
  asm    mov    bx, 0b800h
  asm    jmp    initcrtend
mda_yes:
  asm    mov    ax, 
7
  asm    mov    bx, 0b000h
initcrtend:
  asm    mov    DGROUP:@Crtio@CrtMemSeg, bx
  asm    mov    DGROUP:@Crtio@CrtMode, al
  asm    cmp    word ptr flag, 
0
  asm    jne    initcrtend1
  asm    cmp    al, 
byte  ptr DGROUP:@Crtio@OldMode
  asm    jne    initcrtend0
  asm    push    ds
  asm    xor    si, si
  asm    mov    di, 1000h
  asm    mov    es, DGROUP:@Crtio@CrtMemSeg
  asm    push    es
  asm    pop    ds
  asm    mov    cx, 
2000
  asm    cld
  asm    rep    movsw
  asm    pop    ds
initcrtend0:
  asm    
int     10h
initcrtend1:
}

void  Crtio::Close()
{
  asm    mov    al, DGROUP:@Crtio@OldMode
  asm    cbw
  asm    cmp    al, 
byte  ptr DGROUP:@Crtio@CrtMode
  asm    jne    closecrtend
  asm    push    ds
  asm    xor    di, di
  asm    mov    si, 1000h
  asm    mov    es, DGROUP:@Crtio@CrtMemSeg
  asm    push    es
  asm    pop    ds
  asm    mov    cx, 
2000
  asm    cld
  asm    rep    movsw
  asm    pop    ds
  asm    xor    bh, bh
  asm    mov    ah, 
2
  asm    mov    dx, 1700h
closecrtend:
  asm    
int     10h
  
if ( ! CursorType) SetCursorType();
}

void  Crtio::SetCursorType()
{
  CursorType 
=   ! CursorType;
  asm    mov    ah, 
1
  asm    mov    ch, 
0
  asm    cmp    
byte  ptr DGROUP:@Crtio@CursorType,  0
  asm    je    cursortype1
  asm    mov    ch, 0ch
cursortype1:
  asm    mov    cl, 0dh
  asm    
int     10h
}

void  Crtio::SetPos(  int  row,  int  col )
{
  CrtMemOff 
=  CrtOff( row, col );
  asm    xor    bh, bh
  asm    mov    dh, 
byte  ptr row
  asm    mov    dl, 
byte  ptr col
  asm    mov    ah, 
2
  asm    
int     10h
}

void  Crtio::GetPos(  int   & row,  int   & col )
{
  row 
=  CrtMemOff  /  LINEBYTES;
  col 
=  (CrtMemOff  %  LINEBYTES)  >>   1 ;
}

void  Crtio::PutChar(  int  chs,  int  n,  int  attr )
{
  GetAttr( attr );
  asm    mov    es, DGROUP:@Crtio@CrtMemSeg
  asm    mov    di, DGROUP:@Crtio@CrtMemOff
  asm    mov    cx, n
  asm    mov    ah, al
  asm    mov    al, 
byte  ptr chs
  asm    cld
  asm    rep    stosw
}

#pragma  warn    -rvl

word Crtio::CrtOff( 
int  row,  int  col )
{
  asm    mov    ax, row
  asm    mov    cl, 
4
  asm    shl    ax, cl
  asm    mov    bx, ax
  asm    shl    ax, 
1
  asm    shl    ax, 
1
  asm    add    ax, bx
  asm    add    ax, col
  asm    shl    ax, 
1
}

int  Crtio::PutChars(  int  row,  int  startcol,  char   * s,  int  endcol,  int  attr )
{
  SetPos( row, startcol );
  GetAttr( attr );
  asm    mov    es, DGROUP:@Crtio@CrtMemSeg
  asm    mov    di, DGROUP:@Crtio@CrtMemOff
  asm    mov    cx, endcol
  asm    sub    cx, startcol
  asm    inc    cx
  asm    push    cx
  asm    mov    ah, al
  asm    cld
    pushDS_
  asm    LDS_    si, s
nextchs:
  asm    lodsb
  asm    cmp    al, 
32
  asm    jb    putcharsend
  asm    stosw
  asm    loop    nextchs
putcharsend:
    popDS_
  asm    pop    ax
  asm    sub    ax, cx
}

int  Crtio::GetChar(  int  row,  int  col )
{
  CrtOff(row, col);
  asm    mov    bx, ax
  asm    mov    es, DGROUP:@Crtio@CrtMemSeg
  asm    mov    ax, es:[bx]
}

int  Crtio::GetAttr(  int  attr )
{
  asm    mov    ax, attr
  asm    cmp    word ptr DGROUP:@Crtio@CrtMemSeg, 0b000h
  asm    jne    GetAttr1
  asm    mov    cl, 
4
  asm    shr    al, cl
  asm    cmp    al, 
3
  asm    jbe    GetAttr2
  asm    mov    ax, 70h
  asm    jmp    
short  GetAttr1
GetAttr2:
  asm    mov    ax, 
7
GetAttr1:
}

#pragma     warn    .rvl

void  Crtio::SaveRect(  int  row1,  int  col1,  int  row2,  int  col2,  void  far  * buf )
{
  CrtOff( row1, col1 );
  asm    cld
  asm    mov    si, ax
  asm    les    di, dword ptr buf
  asm    mov    ax, row2
  asm    sub    ax, row1
  asm    inc    ax
  asm    mov    cx, ax
  asm    stosw
  asm    mov    ax, col2
  asm    sub    ax, col1
  asm    inc    ax
  asm    mov    dx, ax
  asm    stosw
  asm    push    ds
  asm    mov    ds, DGROUP:@Crtio@CrtMemSeg
getnextrow:
  asm    push    cx
  asm    push    si
  asm    mov    cx, dx
  asm    rep    movsw
  asm    pop    si
  asm    pop    cx
  asm    add    si, LINEBYTES
  asm    loop    getnextrow
  asm    pop    ds
}

void  Crtio::RestRect(  int  row,  int  col,  void  far  * buf )
{
  CrtOff( row, col );
  asm    mov    di, ax
  asm    push    ds
  asm    mov    es, DGROUP:@Crtio@CrtMemSeg
  asm    lds    si, dword ptr buf
  asm    cld
  asm    lodsw
  asm    add    ax, row
  asm    cmp    ax, 
25
  asm    jle    restcrt1
  asm    mov    ax, 
25
restcrt1:
  asm    sub    ax, row
  asm    mov    cx, ax
  asm    lodsw
  asm    mov    dx, col
  asm    add    dx, ax
  asm    cmp    dx, 50h
  asm    jle    restcrt2
  asm    mov    dx, 50h
restcrt2:
  asm    sub    dx, col
  asm    shl    ax, 
1
  asm    mov    col, ax
putnextrow:
  asm    push    cx
  asm    push    si
  asm    push    di
  asm    mov    cx, dx
  asm    rep    movsw
  asm    pop    di
  asm    pop    si
  asm    pop    cx
  asm    add    di, LINEBYTES
  asm    add    si, col
  asm    loop    putnextrow
  asm    pop    ds
}

void  Crtio::RowRoll(  int  n,  int  row1,  int  col1,  int  row2,  int  col2,  int  attr )
{
  
if ( n  &&  row2  >  row1 )
    Scroll( 
0 , row1, col1, row2, col2, n );
  
if ( n  >   0  )
    row1 
=  row2  +   1   -  n;
  
else   if ( n  <   0  )
    row2 
=  row1  -  n  -   1 ;
  Clear( row1, col1, row2, col2, attr );
}

void  Crtio::ColRoll(  int  n,  int  row1,  int  col1,  int  row2,  int  col2,  int  attr )
{
  
if ( n  &&  col2  >  col1 )
    Scroll( 
1 , row1, col1, row2, col2, n );
  
if ( n  >   0  )
    col1 
=  col2  +   1   -  n;
  
else   if ( n  <   0  )
    col2 
=  col1  -  n  -   1 ;
  Clear( row1, col1, row2, col2, attr );
}

void  Crtio::Scroll(  int  flag,  int  row1,  int  col1,  int  row2,  int  col2,  int  n )
{
  
int  off1, off2, n1;
  
if ! flag )
  {
    
if ( n  <   0  ) n1  =  row2;
    
else  n1  =  row1;
    off1 
=  CrtOff( n1, col1 );
    off2 
=  CrtOff( n1  +  n, col1 );
  }
  
else
  {
    
if ( n  <   0  ) n1  =  col2;
    
else  n1  =  col1;
    off1 
=  CrtOff( row1, n1 );
    off2 
=  CrtOff( row1, n1  +  n );
  }
  asm   mov    cx, row2
  asm    sub    cx, row1
  asm    inc    cx
  asm    mov    dx, col2
  asm    sub    dx, col1
  asm    inc    dx
  asm    cld
  asm    mov    ax, n
  asm    mov    bx, LINEBYTES
  asm    cmp    word ptr flag, 
0
  asm    jne    scroll0
  asm    cmp    ax, 
0
  asm    jg    scroll1
  asm    neg    ax
  asm    neg    bx
scroll1:
  asm    sub    cx, ax
  asm    jmp    
short  scroll3
scroll0:
  asm    cmp    ax, 
0
  asm    jg    scroll2
  asm    neg    ax
  asm    std
scroll2:
  asm    sub    dx, ax
scroll3:
  asm    mov    es, DGROUP:@Crtio@CrtMemSeg
  asm    push    ds
  asm    push    es
  asm    pop    ds
  asm    mov    si, off2
  asm    mov    di, off1
nextroll:
  asm    push    cx
  asm    push    si
  asm    push    di
  asm    mov    cx, dx
  asm    rep    movsw
  asm    pop    di
  asm    pop    si
  asm    pop    cx
  asm    add    si, bx
  asm    add    di, bx
  asm    loop    nextroll
  asm    pop    ds
}

void  Crtio::Clear(  int  row1,  int  col1,  int  row2,  int  col2,  int  color )
{
  CrtOff( row1, col1 );
  asm    mov    di, ax
  asm   mov    cx, row2
  asm    sub    cx, row1
  asm    jns    _clear1
  asm    neg    cx
_clear1:
  asm    inc    cx
  asm    mov    dx, col2
  asm    sub    dx, col1
  asm    jns    _clear2
  asm    neg    dx
_clear2:
  asm    inc    dx
  asm    cld
  asm    mov    es, DGROUP:@Crtio@CrtMemSeg
  asm    mov    ah, color
  asm    xor    al, al
nextcls:
  asm    push    cx
  asm    push    di
  asm    mov    cx, dx
  asm    rep    stosw
  asm    pop    di
  asm    pop    cx
  asm    add    di, LINEBYTES
  asm    loop    nextcls
}

        Crtio类可以工作在彩显文本和单显文本模式下,当然,现在想找个单色显示器恐怕很难了,但是十几年前还是比比皆是,主要代码还是采用插入汇编。为了便于理解代码,这里对其中Crtio::Init函数做一些解释,该函数在判断当前显卡和显示模式以及设置文本方式时没有使用int 10h,而是直接使用了BIOS的数据,BIOS的数据区在段地址0040h处,其中的0040:0049地址处的一个字节保存了当前屏幕的显示模式,通过它可以获取和设置当前的屏显模式;0040:0010地址保存了计算机的一些设备信息,也是一个字节,其表示法如下:

0位,软盘安装信息:0未安装,1安装
1位,协处理器安装信息:0未安装,1安装
2位,PC
/ AT机保留位,PS / 2机为点设备安装信息
3位,PC机内存安装信息,其它机型保留
4 - 5位,显示方式, 00 :保留, 01 40  X 25彩色; 10 80  X 25彩色; 11 80  X 25单色
6 - 7位,软盘驱动器数

所以Crtio::Init函数通过以下代码对0040:0010字节的4-5位进行判断,是否单显或彩显,如果是单显,显示模式设置为7,屏显地址设置为0x0b00,否则显示模式设置为3,屏显地址设置为0x0800:

  asm mov al, es:[10h]
  asm and al, 00110000b
  asm cmp al, 00110000b

直接写屏时,一个字符为2个字节,高字节为显示属性,即字符的前、背景颜色,低字节为要显示的字符。可能有人问,文本直接写屏能显示汉字吗?一般情况下,文本显示模式只能显示ASCIII码及扩展的ASCII码,但是,如果有影射写屏方式的中文DOS支持,如UCDOS,是可以显示汉字的,因为这种中文DOS表面看是使用的文本模式,内部却是使用的图形模式,如VGA彩显,内部就是使用12h图形模式,并对屏显地址进行了修改,看上去我们是对文本屏显地址0xb800直接写屏,其实都被影射到图形显存地址,使用它的图形字符画上去的。

        声明,文章的代码是1995年前的东西,只能供初学者们借鉴参考。有错误或建议,请来信:maozefa@hotmail.com

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值