软件注册站
热情软件屋

 
Windows9x下绝对读写硬盘扇区的例程
编号: QA002045    
建立日期: 1999年11月16日 最后修改日期: 1999年11月16日
所属类别: C/C++ - 磁盘、文件和目录
C/C++ - DDK与硬件设备
   
文章     摘自“上海代码热线”(http://www.pchome.net/~/vc/win/readsect.html
    由于win9x下由win32程序对硬盘的写操作被屏蔽,所以绝对硬盘的读写的思路在于设法转入16位程序,因此有两种方法可以达到这种目的:使用THUNK机制调用16位DLL或用VxD转到16位方式,我觉得用THUNK太麻烦,其实VxD挺好编的,而且用起来也方便, 当时也是出于学习目的,编了这么一个VxD,还是挺好用的,我看精华区对这个问题的讨论好像没有什么结果,就把它贴出来,算是班门弄斧吧!
    我是用DDK编的,主要是因为我当时是出于学习。
     //这是程序的主要部分,其中有一些宏定义,从字面上就能知道是干什么的,我就不罗嗦
    
//了
    
DWORD _stdcall CVXD_W32_DeviceIOControl(LPDIOC lpDIOCParms,
    
CLIENT_STRUCT *pRegs)
    
{
    
DWORD dwRetVal = 0,retu;
    
DWORD *i;
    
PVMMCB hVM;
    
DIOC_REGISTERS *lpReg,*lpOutReg;
    
CLIENT_STRUCT saveregs;
    
DWORD PageNum;
    
WORD PageOff;
    
DWORD Address;
    
DWORD V86PageNum,MyPage;
    
WORD seg,offset;
    

    
hVM=Get_Cur_VM_Handle();
    
i=(DWORD *)(lpDIOCParms->lpvOutBuffer);
    
lpReg=(DIOC_REGISTERS *)(lpDIOCParms->lpvInBuffer);
    
lpOutReg=(DIOC_REGISTERS *)(lpDIOCParms->lpvOutBuffer);
    
switch(lpDIOCParms->dwIoControlCode)
    
{
    
.
    
.
    
.
    
case 2:
    
if(lpDIOCParms->cbInBuffer!=sizeof(DIOC_REGISTERS))
    
return dwRetVal=-1;
    

    
//保存当前虚拟机的寄存器状态
    
_asm push edi
    
_asm lea edi,saveregs
    
VMMCall(Save_Client_State);
    
_asm pop edi
    

    
//输入的参数,具体怎么用看INT13的说明吧
    
_ClientEAX=lpReg->reg_EAX;
    
_ClientEDX=lpReg->reg_EDX;
    
_ClientECX=lpReg->reg_ECX;
    
_ClientEFlags=lpReg->reg_Flags;
    

    
/* 以下这一段是编写这个VxD时要考虑的主要问题:把缓冲区的地址映射入虚拟86的地址
    
区,Win32中用的都是线性地址,先根据它求出页面号,再把缓冲区所在的页映射到虚拟86区
    
中去,下面程序中有一个Bug,它没有考虑到缓冲区所占页面大于一页时的情形,事实上,缓
    
冲区可能处在叶面的边界上,而且它的大小可能超过一页,这些都要根据上面参数中给出
    
的缓冲区大小计算,当时我嫌麻烦,随便应付了一下.用的时候要把这段代码改一下
    
*/

    
PageNum=(lpReg->reg_EBX)>>12;
    
PageOff=(lpReg->reg_EBX)&0xfff;
    
_asm{
    
push 0
    
push 1
    
push 10
    
push hVM
    
push PageNum
    
}
    
VMMCall(_LinMapIntoV86);
    
_asm add esp,14h
    
_asm mov retu,eax
    
_asm mov MyPage,edx //返回的页面号在edx寄存器中
    
if(retu==0) return 3;//这是我自己胡乱选的错误码,你可以自己定成
    
//其它值
    
Address=(MyPage<<12)+PageOff;//计算新的线性地址
    
seg=LOWORD(Address>>4); //把线性地址转化成传统的段:偏
    
offset=LOWORD(Address-(seg<<4)); //移量的形式
    
_ClientAltES=seg;//这里一定不能弄错了,在Win32 Ring3程序中用的
    
//是_ClientES,而虚拟86方式下用的段寄存器则在
    
//_ClientAltES中,所以要用它
    
_ClientBX=offset;
    

    
//xixi,好戏开始了
    
VMMCall(Begin_Nest_V86_Exec);//这一句使得系统转入虚拟86方式
    
_asm mov eax,13h
    
VMMCall(Exec_Int);//发出int 13h中断调用
    
//保存返回值
    
if(lpDIOCParms->cbOutBuffer==sizeof(DIOC_REGISTERS))
    
{
    
lpOutReg->reg_Flags=_ClientEFlags;
    
lpOutReg->reg_EAX=_ClientEAX;
    
lpOutReg->reg_EBX=_ClientEBX;
    
lpOutReg->reg_ECX=_ClientECX;
    
lpOutReg->reg_EDX=_ClientEDX;
    
}
    
End_Nest_Exec();//退出虚拟86方式
    

    
//轻轻地我走了,正如我轻轻地来,我挥一挥衣袖,不带走一片云彩
    
_asm push esi
    
_asm lea esi,saveregs
    
VMMCall(Restore_Client_State);
    
_asm pop esi
    
//这一段取消原来的映射
    
VMMCall(_GetNulPageHandle);
    
_asm mov PageNum,eax
    
_asm{
    
push 0
    
push 0
    
push 1
    
push 10
    
push hVM
    
push PageNum
    
}
    
VMMCall(_MapIntoV86);
    
_asm add esp,18h
    

    
//OK
    
return dwRetVal=0;
    
}
    
return dwRetVal;
    
}
    
    相关书籍:
    
《WINDOWS设备驱动程序技术内幕 》
    《实用技术:WINDOWS NT与WINDOWS 2000设备驱动及开发》
    《Windows 设备驱动程序(VXD 与 WDM)开发实务 含盘》
    《虚拟设备驱动程序开发起步与进阶》
    《WIN 9X虚拟设备驱动程序编程指南》

    

文章来源:上海代码热线

附加关键字:编程, 源程序, programming, source code, C/C++, MFC, C++ Builder, Borland C++, Turbo C, C, BCB, 磁盘、文件和目录, disk, file, fat, directory, folder, DDK与硬件设备, hardware, ddk, vtoolsd, driver studio, winrt

   
 
把这个问题推荐给朋友
   
 
   
您的意见类别
您的名字
您的电子邮件
您的建议(请尽可能详细)
 
 

版权所有 1997-2008 热情软件屋
如果您有任何建议和意见, 请给我发个电子邮件 askpro@china-askpro.com
Web Designed by ZebraStudio