Windows95下物理内存单元的可靠读写

来源:互联网 发布:免费企业即时通讯软件 编辑:IT博客网 时间:2019/09/17 14:28
计算机运行于DOS平台下时,内存寻址模式为实模式,采用80286的20位地址线的存储器分页线性管理技术,存储器容量最大为1MB,线性地址与物理地址一致,对物理内存单元读写直接、灵活。但因受限于640K基本内存,使大量的扩展内存的使用受到制约,同时,分页的64K范围限制影响了内存访问的连续性,从而使系统的内存资源难以得到充分利用。
  计算机运行于Windows95保护模式下时,由于系统或系统中的驱动程序兼容性不好等原因,系统可能处于两种内存寻址模式之一:或是保护模式下的内存寻址模式,或是保护模式下的虚拟8086内存寻址模式(V86模式)。对于这两种模式,要实现对物理内存单元的读写,方法截然不同。我们在运行含有进行内存读写的Windows程序时,常常因为不清楚系统目前处于何种寻址模式而导致访问失败,因此有必要对此进行一番探讨。
    2.保护模式下的内存寻址模式
  当CPU运行于分段管理的保护模式下时,可利用其32位地址线提供4G字节地址访问空间的虚拟存储器,通过特权位和界限值的检查实现完整的保护功能。此时,Windows的内存被全局描述符表(GDT)和局部描述符表(LDT)所控制,并以选择器(Selector)的方式供程序使用。每一个段的说明都对应描述符表中的一项,称为一个段描述符,分别对应一个相应的物理内存段。每个段描述符都由三个参数来构成:段基址(Base)规定线性地址空间的开始地址;段界限(Limit)表示段内的最大偏移量;保护属性(Property)表示此段的一些特征。物理内存访问的远指针由选择器(Selector):偏移量(Offset)构成,这里的selector不象实模式寻址那样代表某个段寄存器的真实地址,而是用来确定段描述符在描述符表中的入口地址,描述符表表中相应位置所存的数据内容才是其真正的物理内存地址。在没有分页的情况下(分页情况由Property来决定),将段描述符的Base左移16位再加上Offset的值就形成了32位内存物理地址。
  保护模式下的这种寻址模式打破了实模式下内存寻址所受到的制约,提高了内存资源的使用效率。
    3.保护模式下的V86模式为了使DOS实模式应用程序无需修改就可以在 dows95保护模式下直接运行,系统提供了V86模式。它与实模式下的内存寻址模式非常相似,提供了段内线性分页管理技术,由段的属性部分控制分页特征。当系统进入V86模式后,在应用程序中对物理内存单元的读写方法与DOS实模式下完全相同。当在保护模式方式下运行DOS实模式下的应用程序时,Windows的虚拟机器管理器(VMM)就创建一个虚拟的8086机器,它仿真了全部的8086处理器,包括内存、I/O设备和所有在启动Windows时运行着的TSR、设备驱动程序以及网络软件,以便使该应用程序在其上运行,执行完应用程序后再重新恢复原来的保护模式。值得注意的是,尽管V86模式下运行了DOS实模式的程序代码,但并不是和实模式相似的方式运行,而是和保护模式相似的方式运行,所以说V86模式实质是一种能运行实模式软件的保护模式。
  如果系统正处于V86模式,那么使用保护模式下的内存寻址模式就无法读写物理内存单元,而必须用实模式下的内存寻址模式来进行读写。在Windows95下你可以查看"控制面板|系统|性能"页,如果看到"驱动器C:正在使用兼容的分页存储技术""兼容的分页存储技术降低了整个系统性能"的信息,就表示系统正处于V86模式;如果看到的是"您的系统是按照最优性能配置的"的信息,则表示系统正处于保护模式下的内存寻址模式。
    4.Windows95下物理内存单元的可靠读写
  由于上述原因,我们在编写Windows95下内存读写程序时,必须兼顾两种寻址模式,使得程序不仅在真正的保护模式下能运行,在系统处于V86模式时也能正常运行,以提高程序运行的可靠性。下面是程序的主要代码:
(LONG FAR PASCAL _export WndProc(HWND hWnd,UNIT Message,
WPARPAM wParam,LPARAM lParam)
{
unsigned int i;
char far *pt; //内存单元读写指针
UINT Selector1,Selector2; 
WORD Segment,Offset,Start; 
DWORD Base,Limit; 
BOOL flag; 
flag=TRUE;
char Test[10]; 
switch(Message)
{
case WM_CREATE:
__asm move Selector1,DS; //将数据段寄存器DS作为模板
Selector2=AllocSelector(Selector1); //分配一个新选择器
if(Selector2==NULL) //保护模式失败
{
flag=FALSE; 
pt=(char far*)0xD000; //V86模式下的指针
}
else
{
Segment=0xD000; //访问的物理段基址
Offset=0x0100; //访问界限
Start=0x0000; //访问偏移起始地址
Base=((unsigned long)Segment)