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

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

// CRTIO.HPP

#ifndef__CRTIO_HPP
#define __CRTIO_HPP

#define LINEBYTES160

typedefunsigned
char byte ;
typedefunsignedword;
typedefunsigned
long dword;

class Crtio{

private :

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

protected :

void Scroll( int , int , int , int , int , int );
// 计算保存屏幕矩形所需内存长度.
wordRectSize( 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 wordCrtOff( int , int );
// 取字符属性.参数:彩显字符属性(如单显返回对应的单色字符属性,否则返回参数本身)
static int GetAttr( int );

public :

// 初始化屏幕,参数=0清屏,否则不清屏
static void Init( int = 0 );
// 恢复程序调用前的模式
void Close();
// 返回屏显段地址
wordCrtSeg();
// 返回当前的屏显模式
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();

};

inlinewordCrtio::CrtSeg()
{
return CrtMemSeg;
}

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

inlinewordCrtio::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 ;
wordCrtio::CrtMemSeg
= 0xb800 ;
wordCrtio::CrtMemOff
= 0 ;
byte Crtio::CursorType = 0 ;


void Crtio::Init( int flag)
{
asmmovax,40h
asmmoves,ax
asmmoval,es:[49h]
asmmovDGROUP:@Crtio@OldMode,al
asmmoval,es:[
61 ]
asmcmpal,
0
asmjeinitcur
asmmoval,
1
initcur:
asmmovDGROUP:@Crtio@CursorType,al
asmmoval,es:[10h]
asmandal,00110000b
asmcmpal,00110000b
asmjemda_yes
asmmovax,
3
asmmovbx,0b800h
asmjmpinitcrtend
mda_yes:
asmmovax,
7
asmmovbx,0b000h
initcrtend:
asmmovDGROUP:@Crtio@CrtMemSeg,bx
asmmovDGROUP:@Crtio@CrtMode,al
asmcmpwordptrflag,
0
asmjneinitcrtend1
asmcmpal,
byte ptrDGROUP:@Crtio@OldMode
asmjneinitcrtend0
asmpushds
asmxorsi,si
asmmovdi,1000h
asmmoves,DGROUP:@Crtio@CrtMemSeg
asmpushes
asmpopds
asmmovcx,
2000
asmcld
asmrepmovsw
asmpopds
initcrtend0:
asm
int 10h
initcrtend1:
}

void Crtio::Close()
{
asmmoval,DGROUP:@Crtio@OldMode
asmcbw
asmcmpal,
byte ptrDGROUP:@Crtio@CrtMode
asmjneclosecrtend
asmpushds
asmxordi,di
asmmovsi,1000h
asmmoves,DGROUP:@Crtio@CrtMemSeg
asmpushes
asmpopds
asmmovcx,
2000
asmcld
asmrepmovsw
asmpopds
asmxorbh,bh
asmmovah,
2
asmmovdx,1700h
closecrtend:
asm
int 10h
if ( ! CursorType)SetCursorType();
}

void Crtio::SetCursorType()
{
CursorType
= ! CursorType;
asmmovah,
1
asmmovch,
0
asmcmp
byte ptrDGROUP:@Crtio@CursorType, 0
asmjecursortype1
asmmovch,0ch
cursortype1:
asmmovcl,0dh
asm
int 10h
}

void Crtio::SetPos( int row, int col)
{
CrtMemOff
= CrtOff(row,col);
asmxorbh,bh
asmmovdh,
byte ptrrow
asmmovdl,
byte ptrcol
asmmovah,
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);
asmmoves,DGROUP:@Crtio@CrtMemSeg
asmmovdi,DGROUP:@Crtio@CrtMemOff
asmmovcx,n
asmmovah,al
asmmoval,
byte ptrchs
asmcld
asmrepstosw
}

#pragma warn-rvl

wordCrtio::CrtOff(
int row, int col)
{
asmmovax,row
asmmovcl,
4
asmshlax,cl
asmmovbx,ax
asmshlax,
1
asmshlax,
1
asmaddax,bx
asmaddax,col
asmshlax,
1
}

int Crtio::PutChars( int row, int startcol, char * s, int endcol, int attr)
{
SetPos(row,startcol);
GetAttr(attr);
asmmoves,DGROUP:@Crtio@CrtMemSeg
asmmovdi,DGROUP:@Crtio@CrtMemOff
asmmovcx,endcol
asmsubcx,startcol
asminccx
asmpushcx
asmmovah,al
asmcld
pushDS_
asmLDS_si,s
nextchs:
asmlodsb
asmcmpal,
32
asmjbputcharsend
asmstosw
asmloopnextchs
putcharsend:
popDS_
asmpopax
asmsubax,cx
}

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

int Crtio::GetAttr( int attr)
{
asmmovax,attr
asmcmpwordptrDGROUP:@Crtio@CrtMemSeg,0b000h
asmjneGetAttr1
asmmovcl,
4
asmshral,cl
asmcmpal,
3
asmjbeGetAttr2
asmmovax,70h
asmjmp
short GetAttr1
GetAttr2:
asmmovax,
7
GetAttr1:
}

#pragma warn.rvl

void Crtio::SaveRect( int row1, int col1, int row2, int col2, void far * buf)
{
CrtOff(row1,col1);
asmcld
asmmovsi,ax
asmlesdi,dwordptrbuf
asmmovax,row2
asmsubax,row1
asmincax
asmmovcx,ax
asmstosw
asmmovax,col2
asmsubax,col1
asmincax
asmmovdx,ax
asmstosw
asmpushds
asmmovds,DGROUP:@Crtio@CrtMemSeg
getnextrow:
asmpushcx
asmpushsi
asmmovcx,dx
asmrepmovsw
asmpopsi
asmpopcx
asmaddsi,LINEBYTES
asmloopgetnextrow
asmpopds
}

void Crtio::RestRect( int row, int col, void far * buf)
{
CrtOff(row,col);
asmmovdi,ax
asmpushds
asmmoves,DGROUP:@Crtio@CrtMemSeg
asmldssi,dwordptrbuf
asmcld
asmlodsw
asmaddax,row
asmcmpax,
25
asmjlerestcrt1
asmmovax,
25
restcrt1:
asmsubax,row
asmmovcx,ax
asmlodsw
asmmovdx,col
asmadddx,ax
asmcmpdx,50h
asmjlerestcrt2
asmmovdx,50h
restcrt2:
asmsubdx,col
asmshlax,
1
asmmovcol,ax
putnextrow:
asmpushcx
asmpushsi
asmpushdi
asmmovcx,dx
asmrepmovsw
asmpopdi
asmpopsi
asmpopcx
asmadddi,LINEBYTES
asmaddsi,col
asmloopputnextrow
asmpopds
}

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);
}
asmmovcx,row2
asmsubcx,row1
asminccx
asmmovdx,col2
asmsubdx,col1
asmincdx
asmcld
asmmovax,n
asmmovbx,LINEBYTES
asmcmpwordptrflag,
0
asmjnescroll0
asmcmpax,
0
asmjgscroll1
asmnegax
asmnegbx
scroll1:
asmsubcx,ax
asmjmp
short scroll3
scroll0:
asmcmpax,
0
asmjgscroll2
asmnegax
asmstd
scroll2:
asmsubdx,ax
scroll3:
asmmoves,DGROUP:@Crtio@CrtMemSeg
asmpushds
asmpushes
asmpopds
asmmovsi,off2
asmmovdi,off1
nextroll:
asmpushcx
asmpushsi
asmpushdi
asmmovcx,dx
asmrepmovsw
asmpopdi
asmpopsi
asmpopcx
asmaddsi,bx
asmadddi,bx
asmloopnextroll
asmpopds
}

void Crtio::Clear( int row1, int col1, int row2, int col2, int color)
{
CrtOff(row1,col1);
asmmovdi,ax
asmmovcx,row2
asmsubcx,row1
asmjns_clear1
asmnegcx
_clear1:
asminccx
asmmovdx,col2
asmsubdx,col1
asmjns_clear2
asmnegdx
_clear2:
asmincdx
asmcld
asmmoves,DGROUP:@Crtio@CrtMemSeg
asmmovah,color
asmxoral,al
nextcls:
asmpushcx
asmpushdi
asmmovcx,dx
asmrepstosw
asmpopdi
asmpopcx
asmadddi,LINEBYTES
asmloopnextcls
}

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 X25彩色; 10 80 X25彩色; 11 80 X25单色
6 - 7位,软盘驱动器数

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

asmmoval, es:[10h]
asmandal, 00110000b
asmcmpal, 00110000b

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值