您的位置:首页 > 编程语言

使用XMS扩展内存编程实例

2010-11-04 13:47 344 查看
粗略地讲,扩展内存和扩充内存在物理上都是指高内存区,只是由于管理程序的不同而给予不同的称呼,二者分别代表了两种不同的管理规范:EMS和XMS。它们以不同的方式提供了使用高内存的操作。二者都是在系统启动时加载驱动程序而控制高内存的,并为用户提供功能调用。

二者的另一相似之处都是采用句柄的方法进行管理。用户程序申请一块高内存,得到的是一个句柄,对此高内存块的访问都是通过这个句柄来完成的,用户程序调用管理规范提供的功能实现对此高内存块操作。

使用XMS,应在CONFIG.SYS文件中加入:

DEVICE=C:/DOS/HIMEM.SYS /MEMTEST:OFF

DEVICE=C:/DOS/EMM386.EXE /NOEMS

程序实例:

#include <mem.h>

#ifndef XRH_XMS_LIBRARY
#define XRH_XMS_LIBRARY

#include <DOS.H>
#include <STDIO.H>
#include <STDLIB.H>
struct XMS_Move_Data{
unsigned long far Move_Bytes;             // 移动的字节数
unsigned far Source_Handle;               // 源句柄
unsigned long far Source_Offset;          // 源偏移量
unsigned far Target_Handle;               // 目的句柄
unsigned long far Target_Offset;          // 目的偏移量
};
int  far XMS=0;

class MyXMS{
private:
int XMS;
int Xms_Err;
int IsErr(int Xms_Err_Num);
void (far *Xms)(void);
void  XMS_Get_Drive_Addr(void);
static int  MyXMS_Num;
public:
XMS_Move_Data  Xmd; // very important, the detail at above
int  XMS_Check(unsigned &Max_Block_Size,unsigned &Total_Size);
int  XMS_Get(unsigned &Handle,unsigned Size);
int  XMS_ReGet(unsigned Handle,unsigned ReSize);
int  XMS_Free(unsigned Handle);
int  XMS_Move();  // 设置好了结构体 Xmd 之后,主动调用本函数,可实现数据块的移动
int  base_to_xms(void far *base,unsigned handle,unsigned long length,unsigned long emboffset);
int  xms_to_base(void far *base,unsigned handle,unsigned long length,unsigned long emboffset);
MyXMS();
~MyXMS();
};

int  MyXMS::MyXMS_Num=0;
// XMS (Int 2F/43) 多路中断
// INT 2F - XMS 驱动程序安装检测
// 输入参数:AX = 4300h
// 返回值:  AL = 80h XMS 驱动程序已安装
// AL <> 80h 未发现XMS 驱动程序
// 注: XMS 使你可以访问扩充内存以及其它的高于640K的非EMS内存
//     其它程序不得使用与之相同的安装检测方式
int  XMS_Test(void)
{
asm {
mov ax ,0x4300
int 0x2F
}
if(_AL==0x80)
XMS=1;
else
XMS=0;
return XMS;
}

//  错误代码
//  80h 没有提供的功能
//  81h 检测到虚拟盘(Vdisk)
//  82h 发生A20地址线错误
//  8Eh 一般驱动程序错误
//  8Fh 致命的驱动程序错误
//  90h 高端内存(HMA)不存在
//  91h 高端内存(HMA)已被使用
//  92h DX is less than the /HMAMIN= parameter
//  93h 高端内存(HMA)未被分配
//  94h A20地址线已被激活
//  A0h 所有扩充内存已被分配
//  A1h 所有可用的句柄已被分配
//  A2h 无效的句柄
//  A3h 无效的源句柄
//  A4h 无效的源偏移
//  A5h 无效的目的句柄
//  A6h 无效的目的偏移
//  A7h 无效的长度
//  A8h 移动有非法的重叠
//  A9h 发生奇偶校验错误
//  AAh 块未加锁
//  ABh 块已被锁定
//  ACh 块锁定计数溢出
//  ADh 锁定失败
//  B0h 只有更小一些的UMB空间
//  B1h 没有可用的UMB空间
int  MyXMS::IsErr(int Xms_Err_Num)
{
switch(Xms_Err_Num)
{
case 0x80:
case 0x81:
case 0x82:
case 0x8E:
case 0x8F:
case 0x90:
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0xA0:
case 0xA1:
case 0xA2:
case 0xA3:
case 0xA4:
case 0xA5:
case 0xA6:
case 0xA7:
case 0xA8:
case 0xA9:
case 0xAA:
case 0xAB:
case 0xAC:
case 0xAD:
case 0xB0:
case 0xB1:
return 1;
default  :
return 0;
}
}

//  INT 2F - XMS - 获取驱动程序入口地址
//  输入参数:AX = 4310h
//  返回值:  ES:BX -> 驱动程序入口地址
//  请参见:  AX=4300h
//  AH中放功能号, 用远调用的方式调用驱动程序
//  BL中返回的错误代码
void  MyXMS::XMS_Get_Drive_Addr()
{
if (XMS)
{
asm {
mov ax,0x4310
int 0x2F
}
this->Xms=(void (far *)())(((unsigned long)(_ES)<<16)+_BX);
// Xms=(void (far *)())(((unsigned long)(_ES)<<16)+_BX);
}
return;
}

// 查询空闲的扩充内存空间, 不包括HMA
// 输入参数:AH = 08h
// 返回值:  AX = 最大的扩充内存块的大小(单位:K)
// 			DX = 总的扩充内存块的大小(单位:K)
// 			BL = 错误代码
int  MyXMS::XMS_Check(unsigned &Max_Block_Size,unsigned &Total_Size)
{
if (XMS)
{
asm mov ah,0x08
Xms();
Max_Block_Size=_AX;
Total_Size=_DX;
Xms_Err=_BL;
}
return (!(IsErr(Xms_Err)));
}

// 分配扩充内存
// 输入参数:AH = 09h
// 			DX = 要求分配的内存块大小(单位:K)
// 返回值:	AX = 0001h 成功
// 			DX = 内存块的句柄
// 			AX = 0000h 失败
// 			BL = 错误代码
int  MyXMS::XMS_Get(unsigned &Handle,unsigned Size)
{
unsigned Ax=0;
if (XMS)
{
asm {
mov ah,0x09
mov dx,Size
}
Xms();
Ax=_AX;
Handle=_DX;
Xms_Err=_BL;
if(!Ax) return 0;
return 1;
}
return 0;
// return(!(IsErr(Xms_Err)));
}

// 为句柄重新分配内存
// 输入参数:AH = 0Fh
// 			DX = 句柄
// 			BX = 新的块的容量(单位:K)
// 返回值:	AX = 0001h 成功
//             = 0000h 失败
//          BL = 错误代码
int  MyXMS::XMS_ReGet(unsigned Handle,unsigned ReSize)
{
unsigned Ax=0;
if (XMS)
{
asm {
mov ah,0x0F
mov dx,Handle
mov bx,ReSize
}
Xms();
Ax=_AX;
Xms_Err=_BL;
if(!Ax)
return 0;
return 1;
}
return 0;
}

// 释放指定句柄所分配的扩充内存
// 输入参数:AH = 0Ah
// 			DX = 内存块的句柄
// 返回值:	AX = 0001h 成功
//             = 0000h 失败
//          BL = 错误代码
int  MyXMS::XMS_Free(unsigned Handle)
{
unsigned Ax=0;
if (XMS)
{
asm {
mov ah,0x0A
mov dx,Handle
}
Xms();
Ax=_AX;
Xms_Err=_BL;
if(!Ax)
return 0;
return 1;
}
return 0;
//  return(!(IsErr(Xms_Err)));
}

// 移动扩充内存块
// 输入参数:AH = 0Bh
//      	DS:SI -> xms_mov 结构
// 返回值:	AX = 0001h 成功
//             = 0000h 失败
//          BL = 错误代码
// 注: 如果结构中任一句柄为0000h, 那么其对应32位偏移量将被视为常规内存
//     的绝对地址
int  MyXMS::XMS_Move()
{
unsigned Ax=0;
if (XMS)
{
asm push ds;
unsigned Xseg=FP_SEG(&(this->Xmd)),Xoff=FP_OFF(&(this->Xmd));
asm  {
mov ah,0x0B
mov si,Xoff
mov ds,Xseg
}
Xms();
asm pop ds;
Ax=_AX;
Xms_Err=_BL;
if(!Ax)
return 0;
return 1;
}
return 0;
}

int MyXMS::base_to_xms(void far *base,unsigned handle,unsigned long length,unsigned long emboffset)
{
unsigned seg,off;
unsigned long offset;
seg=FP_SEG(base);
off=FP_OFF(base);
offset=(((unsigned long)seg)<<16)+off;
Xmd.Move_Bytes=length;       //长度必须是偶数
Xmd.Source_Handle=0;         //句柄=0时,由下面的Offset给出地址
Xmd.Source_Offset=offset;
Xmd.Target_Handle=handle;
Xmd.Target_Offset=emboffset;
if(!XMS_Move())
return 0;
else
return 1;
}

int MyXMS::xms_to_base(void far *base,unsigned handle,unsigned long length,unsigned long emboffset)
{
unsigned seg,off;
unsigned long offset;
seg=FP_SEG(base);
off=FP_OFF(base);
offset=(((unsigned long)seg)<<16)+off;
Xmd.Move_Bytes=length;       //长度必须是偶数
Xmd.Source_Handle=handle;
Xmd.Source_Offset=emboffset;
Xmd.Target_Handle=0;         //句柄=0时,由下面的Offset给出地址
Xmd.Target_Offset=offset;
if(!XMS_Move())
return 0;
else
return 1;
}

MyXMS::MyXMS()
{
Xms_Err=0;
if (!MyXMS_Num)
::XMS_Test();
XMS=::XMS;
if(!XMS){printf("  XMS Not Found,Please Setup In 'Config.sys' File.");exit(1);}
MyXMS_Num++;
XMS_Get_Drive_Addr();
}

MyXMS::~MyXMS()
{
MyXMS_Num--;
}

#endif

void main()
{
MyXMS myxms;
char buff[32000];
memset(buff,'A',19);
buff[19]='/0';
printf("/nbuff=%s",buff);
unsigned handle=0;
unsigned size=10;	//10kb

if(!myxms.XMS_Get(handle,size))            //先申请XMS内存得到句柄handle
{                                          //size的单位是kb
printf("/nget memory error!");
return;
}
if(!myxms.base_to_xms(buff,handle,8,0))    //从基本内存移动8个字节到XMS内存
{                                          //长度必须是偶数
printf("/nbase to xms error!");
myxms.XMS_Free(handle);
}
memset(buff,'0',19);
printf("/nbuff=%s",buff);
myxms.xms_to_base(buff,handle,8,0);
printf("/nbuff=%s",buff);
myxms.XMS_Free(handle);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: