现在的位置: 首页 > 综合 > 正文

菜鸟之驱动开发8

2013年09月01日 ⁄ 综合 ⁄ 共 2166字 ⁄ 字号 评论关闭

在上一节中我们学习了驱动与应用程序的缓冲区模式的通信,这一节我们学习它们之间的直接模式通信。只是方式不一样,但实现的目的是一样的,即驱动与应用程序的通信。我们在上一节代码的基础上做一些修改就可以了。

首先修改ctl_code.h代码如下:

/*#ifndef  CTL_CODE
#pragma message("\n\n------------------exe 模式.please include winioctl.h")
#include<winioctl.h> //CTL_CODE
#else
#pragma message("\n\n------------------sys 模式.no need to include winioctl.h")
#endif*/
#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN, 	0x800, 	METHOD_IN_DIRECT,FILE_ANY_ACCESS)
#define sub_code CTL_CODE(FILE_DEVICE_UNKNOWN, 	0x801, 	METHOD_IN_DIRECT,FILE_ANY_ACCESS)

//有四种方式访问模式
//#define METHOD_BUFFERED                 0  缓冲区方式
//#define METHOD_IN_DIRECT                1  直接访问方式
//#define METHOD_OUT_DIRECT               2  直接访问方式
//#define METHOD_NEITHER                  3  其它访问方式

修改的部份是第三个参数: METHOD_BUFFERED  修改为METHOD_IN_DIRECT,注意应用程序程序与驱动都需要这个头文件,所以两边都需要修改。如果你的应用程序是VC6的开发,你需要取消预编译那段注释。因为我是VS2010的环境,不需要它了,因为它的include目录里有了这个头文件。

下面是修改驱动部份,驱动除了上面的头文件修改为,还需要修改一外:

int* OutputBuffer = (int*)pIrp->AssociatedIrp.SystemBuffer;

修改为:

int OutputBuffer =(int)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,
					NormalPagePriority
					);

 

直接内存操作方式METHOD_IN_DIRECT和METHOD_OUT_DIRECT模式都以相同方式处理。仅有的不同是它们访问用户模式缓冲区时所需的访问权限;METHOD_IN_DIRECT需要读权限;METHOD_OUT_DIRECT既需要读权限又需要写权限。使用这两种模式时,I/O管理器会为输入数据提供一个内核模式拷贝缓冲区(AssociatedIrp.SystemBuffer),为输出数据缓冲区提供一个MDL。

MdlAddress(PMDL)域指向一个内存描述符表(MDL),该表描述了一个与该请求关联的用户模式缓冲区。

当IRP_MJ_DEVICE_CONTROL请求的控制代码指定METHOD_IN_DIRECT或METHOD_OUT_DIRECT操作方式,则I/O管理器为该请求使用的输出缓冲区创建一个MDL。MDL本身用于描述用户模式虚拟缓冲区,但它同时也含有该缓冲区锁定内存页的物理地址。

 

//获取 PIrp->MdlAddres 然后通过MmGetSystemAddressForMdlSafe将这段内存映身到内核模式下 供直接访问。

 

所以我们只修改了得到输出buffer的代码,输入部份的buffer获取代码不变。

本节代码到此还有bug, 如果我们在代码任意位位置加入一个异常外理,如下:

__try
{
}
__except(EXCEPTION_EXCUTE_HANDLE)
{
}

在驱动卸载的时候就会蓝屏,其实并不是加入的异常外理有问题,其实我们原来代码有问题,因为在SSDTWrite.h里,有如下声明

#pragma INITCODE
VOID Driver_Unload(IN PDRIVER_OBJECT pDriverObject);
NTSTATUS CreateTheDevice(IN PDRIVER_OBJECT pDeviceObject);
NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp     );

code_seg("INIT")表示运行完后该代码会被卸载,那么其中的变量也就可能是无效的地址了,PDEVICE_OBJECT
pDevObj
;
是局部变量,该段代码运行完后它就无效了,驱动卸载的时候调用:

pDevObj = pDriverObject->DeviceObject;
IoDeleteDevice(pDevObj);

自然会出错,就蓝屏了。 但不知道为何,有时候有,有时候却不会。比如不加异常外理。

解决这个问题是声明的时候改

#pragma INITCODE

 为

#pragma PAGECODE

网上有人遇到相同问题:

http://bbs2.driverdevelop.com/read.php?tid-115400-page-e.html

http://bbs.pediy.com/showthread.php?t=112894

请参看完整源码

抱歉!评论已关闭.