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

来源:互联网 发布:剑灵人族御姐捏脸数据 编辑:程序博客网 时间:2024/06/11 07:55

        还是十几年前的老代码,一个完整的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( intintintintintint );
  
// 计算保存屏幕矩形所需内存长度.
  word RectSize( intintintint );
  
// 保存屏幕矩形内容. 参数: 屏幕左上角行,列,右下角行,列, 缓冲区
  void SaveRect( intintintintvoid far* );
  
// 恢复屏幕矩形内容到屏幕. 参数: 屏幕左上角行,列, 缓冲区
  void RestRect( intintvoid far* );
  
// 显示字符串. 参数: 行, 起始列, 字符串, 结束列, 显示属性. 如显示字符超过
  
// 结束列截断, 返回实际显示的字符个数
  int PutChars( intintchar*intint);
  
// 返回所给行列位置的屏显偏移地址
  static word CrtOff( intint );
  
// 取字符属性. 参数: 彩显字符属性(如单显返回对应的单色字符属性, 否则返回参数本身)
  static int GetAttr( int );

public:

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

#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:保留,0140 X 25彩色;1080 X 25彩色;1180 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

原创粉丝点击