第9章底层开发Word文档格式.docx
- 文档编号:20692991
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:44
- 大小:33.49KB
第9章底层开发Word文档格式.docx
《第9章底层开发Word文档格式.docx》由会员分享,可在线阅读,更多相关《第9章底层开发Word文档格式.docx(44页珍藏版)》请在冰豆网上搜索。
尽管没有任何异常,但
是用户得不到真正的IO操作。
这是因为WindowsNT/2000的安全机制不允许用户态的应用程序直接访问硬件,
从而摧毁和搞垮WindowsNT/2000无懈可击的稳定性。
WindowsNT/2000规定用户态
程序所有的IO操作必须借助于DeviceIOControl函数和内核驱动程序进行通信实现,
然而和内核的通信势必会造成大量的时钟周期浪费和开销。
WindowsNT/2000只允许内核态的应用程序存取所有端口,对于用户态的程序,
它通过设置IOPL实现了对IO操作的屏蔽。
为了实现在用户态的直接IO操作,用户
必须通过编写驱动程序去掉对读写端口的屏蔽。
我们知道WindowsNT实现IO读写保护是有原因的,一方面它使系统异常的稳
定,用户再也不必为Windows9x下的蓝屏和异常而苦恼了。
用户可以放心大胆地调
试应用程序,即便程序出现死锁,系统也会干脆利落地把它杀死,而不会波及到整个
系统。
IO读写保护与Windows98保护8253定时器端口是一样道理,它的目的就是防
止用户使用简单的in/out指令,从而把系统搞垮。
但是,对于大量的信号采集的系统
而言,应用程序开发人员会更关心系统的实时性,更习惯于在程序中直接使用in/out
指令实现信号采集。
因此必须打破WindowsNT环境下的IO瓶颈,使得用户态的应用
程序拥有IO读写权限,实现实时控制。
弄清楚如何把IO存取权授权给用户态的应用程序,用户必须了解WindowsNT
环境下IO保护是如何实现的。
WindowsNT本身并不能实现IO保护,由于CPU能够
捕捉尝试的IO存取,WindowsNT利用了80x86这一特征。
80x86采用了特权级别系
统,它总共定义了0、1、2、3四个级别,即我们所说的Ring环。
出于对ALPHA平
台的兼容性,80x86仅使用了权限最高的Ring0和最低的ring3,CPU的当前运行权
限级(CPL)保存在CS代码段寄存器的两位中。
IO权限并不是由CPU静态定义的。
CPU在处理器的标志寄存器Eflags的某两位
定义了当前的IO权限级别(IOPL),通过比较当前的IO权限级和CPU的当前运行权限
级,来决定IO指令能否自由使用。
由于当前的IO权限级总是大于等于0,因此运行
在Ring0环的内核模式的设备驱动程序,总是可以直接对IO端口进行存取。
而运行
在用户态的应用程序,工作在Ring3环,WindowsNT把当前的IO权限级设置为0,
因此,用户态的程序尝试端口存取时,必须经过保护机制。
判断CPL>IOPL,仅仅是保护机制的第一步,I/O保护要么全有,要么全无。
处
理器采用了更为灵活的机制,使得操作系统能够根据任务的不同,对端口的任何子集
进行授权。
CPU是采用了一个位屏蔽矩阵(IOPM)实现这一步的。
这个矩阵由0,1组成,每
一个二进制位对应一个输入输出端口。
这样,65536个端口共需要8192个字节,如
果某一二进制位值为0,那么程序对该端口的读写就会不加阻拦。
当然用户不能对一
个只读端口进行写操作,只能对端口进行读操作。
位屏蔽矩阵(IOPM)保存在主存的任务状态段结构中,我们可以通过NTOSKRNL
库提供的一些内核模式设备驱动例程,实现对该位屏蔽矩阵进行读写,以便对某些端
口进行授权。
注意这些服务例程,在DDK帮助文档中并没有说明,并不能保证下个版本是否
支持。
我们可以通过VisualStudio提供的ViewDependcy工具打开windows/system32/
driver/videoprt.sys,发现它调用了ntoskrnl.exe中的几个未见文档的服务例程。
尽管没
有说明,但顾名思义,我们也可以看出这些函数要干什么。
extern"
C"
{
voidKe386SetIoAccessMap(int,NTPORT*);
//复制位图影像到NTPORT结构指针中
//int:
1复制缓冲区,0用0xff填充
voidKe386QueryIoAccessMap(int,NTPORT*);
//查询当前IOPM
voidKe386IoSetAccessProcess(PEPROCESS,int);
1允许I/O,0禁止I/O
}
PsGetCurrentProcess()获得当前进程
设备驱动程序的加载是一个非常麻烦的事情。
对于一个不是硬件的虚拟设备,用
户不得不创建一个安装程序,或者编写一个.inf文件,利用控制面板中的添加新硬件
功能,加入一个其它设备,或者直接编辑注册编辑表,把驱动程序复制到WINNT系
统目录的Drivers32子目录中,有时还需要用户重新启动计算机。
而用户需要的功能
仅仅是一次(也许是最后一次)辅助驱动用户的小程序。
正因为这个原因,本程序提供了一个设备驱动程序加载工具,实现设备驱动程序
的动态加载,用户不用做任何添加新硬件的操作,也不用编辑注册表和重新启动计算
机。
驱动程序不一定位于系统目录中,但要求和程序提供的NTPORT.dll文件位于同
一目录。
本程序参考了NumegaDriveStudio提供的loaddrv例子程序。
下面简要介绍一下程序调用的有关API函数。
(1)首先使用OpenSCManager函数与指定服务控制管理器建立联系,打开指定
的服务控制管理数据库。
schSCManager=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
(2)利用CreateService函数创建一个服务对象,并把它加入到指定的服务控制管
理数据库中。
SC_HANDLEschService=CreateService(SchSCManager,DriverName,
DriverName,SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,ServiceExe,NULL,NULL,NULL,NULL,NULL);
具体参数请参考MSDN。
(3)用函数StartService启动一个服务,启动前用OpenService打开服务。
BOOLStartService(SC_HANDLEhService,DWORDdwNumServiceArgs,LPCTSTR
*lpServiceArgVectors);
(4)用CreateFile打开设备,设备名为驱动程序中用IoCreateSymbolicLink服务创
建的符号连接名。
如果执行成功,用户就可以利用DeviceIOControl函数接口与驱动程
序进行通信了。
例9-1DirectIO实现。
#include<
ntddk.h>
#defineDEVICE_NAME_STRINGL"
ZNtPort"
#defineIOPM_VERSION110
#defineIOPM_TEST00123
#defineIOPM_TEST11234
#defineIOPM_TEST22345
#defineIOPMD_TYPE0xF100
#defineIOCTL_IOPMD_READ_TESTCTL_CODE(IOPMD_TYPE,0x900,
METHOD_BUFFERED,FILE_ANY_ACCESS)
#defineIOCTL_IOPMD_READ_VERSIONCTL_CODE(IOPMD_TYPE,0x901,
#defineIOCTL_IOPMD_CLEAR_LIOPMCTL_CODE(IOPMD_TYPE,0x910,
#defineIOCTL_IOPMD_SET_LIOPMCTL_CODE(IOPMD_TYPE,0x911,
#defineIOCTL_IOPMD_GET_LIOPMBCTL_CODE(IOPMD_TYPE,0x912,
#defineIOCTL_IOPMD_GET_LIOPMACTL_CODE(IOPMD_TYPE,0x913,
//Interactwithkernel
#defineIOCTL_IOPMD_ACTIVATE_KIOPMCTL_CODE(IOPMD_TYPE,0x920,
#defineIOCTL_IOPMD_DEACTIVATE_KIOPMCTL_CODE(IOPMD_TYPE,0x921,
#defineIOCTL_IOPMD_QUERY_KIOPMCTL_CODE(IOPMD_TYPE,0x922,
#defineZNtPort_PARAMCOUNT3
#defineZNtPort_PARAMCOUNT_BYTESZNtPort_PARAMCOUNT*4
#defineIOPM_SIZE0x2000
typedefUCHARIOPM[IOPM_SIZE];
IOPM*IOPM_local=0;
voidKe386SetIoAccessMap(int,IOPM*);
voidKe386QueryIoAccessMap(int,IOPM*);
voiddisp_ACTIVATE_KIOPM(void)
Ke386IoSetAccessProcess(PsGetCurrentProcess(),1);
Ke386SetIoAccessMap(1,IOPM_local);
voiddisp_DEACTIVATE_KIOPM(void)
Ke386IoSetAccessProcess(PsGetCurrentProcess(),0);
voiddisp_QUERY_KIOPM(void)
Ke386QueryIoAccessMap(1,IOPM_local);
voiddisp_CLEAR_LIOPM(void)
intn;
for(n=0;
n<
IOPM_SIZE;
n++)(*IOPM_local)[n]=0xFF;
NTSTATUSZNtPort_Dispatch(INPDEVICE_OBJECTDeviceObject,INPIRPpIrp)
intIx,B;
PIO_STACK_LOCATIONpIrpStack;
NTSTATUSStatus;
PULONGpIOBuffer;
ULONGInBufferSize;
ULONGOutBufferSize;
ULONGOutByteCount;
ULONGIoControlCode;
pIrpStack=IoGetCurrentIrpStackLocation(pIrp);
Status=STATUS_NOT_IMPLEMENTED;
OutByteCount=0;
switch(pIrpStack->
MajorFunction){
caseIRP_MJ_CREATE:
Status=STATUS_SUCCESS;
break;
caseIRP_MJ_CLOSE:
caseIRP_MJ_DEVICE_CONTROL:
InBufferSize=pIrpStack->
Parameters.DeviceIoControl.InputBufferLength;
OutBufferSize=pIrpStack->
Parameters.DeviceIoControl.OutputBufferLength;
pIOBuffer=(PULONG)pIrp->
AssociatedIrp.SystemBuffer;
IoControlCode=pIrpStack->
Parameters.DeviceIoControl.IoControlCode;
switch(IoControlCode){
caseIOCTL_IOPMD_READ_TEST:
pIOBuffer[0]=IOPM_TEST0;
pIOBuffer[1]=IOPM_TEST1;
pIOBuffer[2]=IoControlCode;
OutByteCount=ZNtPort_PARAMCOUNT_BYTES;
caseIOCTL_IOPMD_READ_VERSION:
pIOBuffer[0]=IOPM_VERSION;
caseIOCTL_IOPMD_CLEAR_LIOPM:
disp_CLEAR_LIOPM();
caseIOCTL_IOPMD_SET_LIOPM:
Ix=pIOBuffer[0]&
0x1FFF;
B=pIOBuffer[1]&
0xFF;
(*IOPM_local)[Ix]=B;
disp_ACTIVATE_KIOPM();
caseIOCTL_IOPMD_GET_LIOPMB:
disp_QUERY_KIOPM();
B=(*IOPM_local)[Ix];
pIOBuffer[1]=B&
0x000000FF;
caseIOCTL_IOPMD_GET_LIOPMA:
if(OutBufferSize<
IOPM_SIZE){
Status=STATUS_INVALID_PARAMETER;
}else{
for(Ix=0;
Ix<
Ix++)
((PUCHAR)pIOBuffer)[Ix]=(*IOPM_local)[Ix];
OutByteCount=IOPM_SIZE;
caseIOCTL_IOPMD_ACTIVATE_KIOPM:
caseIOCTL_IOPMD_DEACTIVATE_KIOPM:
disp_DEACTIVATE_KIOPM();
caseIOCTL_IOPMD_QUERY_KIOPM:
default:
Status=STATUS_INVALID_DEVICE_REQUEST;
pIrp->
IoStatus.Status=Status;
IoStatus.Information=OutByteCount;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
returnStatus;
VOIDZNtPort_Unload(INPDRIVER_OBJECTDriverObject)
WCHARDOSNameBuffer[]=L"
\\DosDevices\\"
DEVICE_NAME_STRING;
UNICODE_STRINGuniDOSString;
if(IOPM_local)MmFreeNonCachedMemory(IOPM_local,sizeof(IOPM));
RtlInitUnicodeString(&
uniDOSString,DOSNameBuffer);
IoDeleteSymbolicLink(&
uniDOSString);
IoDeleteDevice(DriverObject->
DeviceObject);
NTSTATUSDriverEntry(INPDRIVER_OBJECTDriverObject,INPUNICODE_STRING
RegistryPath)
PDEVICE_OBJECTdeviceObject;
NTSTATUSstatus;
WCHARNameBuffer[]=L"
\\Device\\"
UNICODE_STRINGuniNameString,uniDOSString;
IOPM_local=MmAllocateNonCachedMemory(sizeof(IOPM));
if(IOPM_local==0)returnSTATUS_INSUFFICIENT_RESOURCES;
uniNameString,NameBuffer);
status=IoCreateDevice(DriverObject,0,&
uniNameString,IOPMD_TYPE,
0,FALSE,&
deviceObject);
if(!
NT_SUCCESS(status))returnstatus;
status=IoCreateSymbolicLink(&
uniDOSString,&
uniNameString);
DriverObject->
MajorFunction[IRP_MJ_CREATE]=ZNtPort_Dispatch;
MajorFunction[IRP_MJ_DEVICE_CONTROL]=
ZNtPort_Dispatch;
DriverUnload=ZNtPort_Unload;
returnSTATUS_SUCCESS;
为了方便使用,这里把通信代码封装到一个COM组件中,提供了简单的接口。
接口的主要代码如下:
#include"
resource.h"
//主符号
NTPort.h"
classATL_NO_VTABLECDirectIO:
publicCComObjectRootEx<
CComSingleThreadModel>
publicCComCoClass<
CDirectIO,&
CLSID_DirectIO>
publicIDispatchImpl<
IDirectIO,&
IID_IDirectIO,&
LIBID_NTPortLib,
/*wMajor=*/1,/*wMinor=*/0>
public:
CDirectIO(){}
DECLARE_REGISTRY_RESOURCEID(IDR_DIRECTIO)
BEGIN_COM_MAP(CDirectIO)
COM_INTERFACE_ENTRY(IDirectIO)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULTFinalCons
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 底层 开发