首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 嵌入开发 > 驱动开发 >

Window XP驱动开发(十六) 驱动程序调用驱动程序(经过设备指针)

2012-08-10 
Window XP驱动开发(十六) 驱动程序调用驱动程序(通过设备指针)转载请标明是引用于 http://blog.csdn.net/c

Window XP驱动开发(十六) 驱动程序调用驱动程序(通过设备指针)

转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家提出意见,一起讨论!

代码及EzDriverInstaller下载地址 : http://www.rayfile.com/zh-cn/files/9840cf8f-c41f-11e1-b25b-0015c55db73d/

(编译环境:VS2008+DDK库(参考:IoGetDeviceObjectPointer( __in PUNICODE_STRING ObjectName, __in ACCESS_MASK DesiredAccess, __out PFILE_OBJECT *FileObject, __out PDEVICE_OBJECT *DeviceObject );

第一个参数ObjectName:设备名,用UNICODE字符串表示;

第二个参数DesiredAccess :以什么样的权限得到设备句柄;

第三个参数FileObject:同时会返回一个和设备相关的文件对象指针;

第四个参数DeviceObejct:返回的设备对象指针。

Windows内核会为每一个对象指针保存一个“引用计数”,当对象被创建时引用计数为1。如果想引用这个对象,计数会加1。

如果删除对象时,Windows先将引用计数减1,如果引用计数不是0,系统不会删除对象。

当调用IoGetDeviceObjectPointer内核函数后,设备对象的引用计数就会加1,当用完这个设备对象后,应用调用ObDereferenceObject内核函数,

使其引用计数减1。


当第一次调用IoGetDeviceObjectPointer内核函数时,会根据设备名打开设备,这时文件对象指针计数为1。此后如果再次调用

IoGetDeviceObjectPointer打开设备,就不是真正地打开设备了,而是只将引用计数加1。打开设备时,系统会创建一个

IRP_MJ_CREATE类型的IRP,并将这个IRP传递到驱动程序的派遣函数中。

每次调用ObDereferenceObject内核函数都会将“引用计数”减1,如果减至0就会关闭设备。关闭设备时,系统会创建一个IRP_MJ_CLOSE类型的IRP,

将将其传递到相应驱动的派遣函数中。

从上述内容可以看出IoGetDeviceObjectPointer和ObDereferenceObject内核函数完全正确可以代替ZwCreateFile和ZwCloseFile内核函数。另外,这种方法还能获

得设备对象指针关联的文件对象指针。

1、2 创建IRP传递给驱动的派遣函数

本节介绍如何手动创建IRP,并将 其传递给相应的程序程序。这样的好处是比ZwReadFile内核灵活。ZwReadFile内核函数是针对设备句柄操作的,而传递IRP是通过设备对象的指针操作。

(1)可以通过IoBuildSynchronousFsdRequest和IoBuildAsynchronousFsdRequest两个内核函数创建IRP,它们分别用来创建同步类型的IRP和异步类型的IRP。

这两个内核函数可以创建IRP_MJ_PNP、IRP_MJ_READ、IRP_MJ_WRITE、MJ_FLUSH_BUFFERS和IIRP_MJ_SHUTDOWN类型的IRP。

可以通过IoBuildDeviceIoControlRequest内核函数创建IRP_MJ_INTERNAL_DEVICE_CONTROL和IRP_MJ_DEVICE_CONTROL两个类型的IRP,

这两个内核函数只能创建同步类型的IRP。

另外,还可以使用IoAllocateIrp内核函数,它可以创建任意类型的IRP。IoBuildSynchronousFsdRequest、IoBuildAsynchronousFsdRequest、IoBuildDeviceIoControlRequest这三个内核函数都是属于靠近上层的内核函数。

而IoAllocateIrp是比较底层的内核函数,以下三个内核都是通过IoAllocateIrp实现的。

(2)创建完IRP后,还要构造IRP的I/O堆栈,每层I/O堆栈对应一个设备对象。由于示例程序DriverA是单层驱动程序,所以只需要构造IRP的第一层I/O堆栈。

(3)最后是通过IoCallDriver内核函数调用相应的驱动。IoCallDriver 内核函数会根据IRP的类型,找到相应的派遣函数。

总结一下,手动创建IRP有以下几个步骤:

(1)先得到设备的指针。一种方法是用IoGetDeviceObjectPointer内核函数得到设备对象的指针;

                                             另一种方法是通过ZwCreateFile内核函数先得到设备句柄,然后调用ObReferenceObjectByPointer内核函数通过设备句柄得到设备对象指针。

(2)手动创建IRP,有4个内核函数可以选择,它们是IoBuildSynchronousFsdRequest、IoBuildAsynchronousFsdRequest、IoBuildDeviceIoControlRequest和

         IoAllocateIrq,其中IoAllocateIrp内核函数是最灵活的,使用也最复杂。

(3)构造IRP的I/O堆栈。

(4)调用IoCallDriver内核函数,其内部会调用设备对象的派遣函数。

 

1、3  用IoBuildSynchronousFsdRequest创建IRP

函数声明如下:

第一个参数MajorFunction:这个参数是创建的IRP的主类型,IoBuldSynchronousFsdRequest函数只支持IRP_MJ_PNP、IRP_MJ_READ、IRP_MJ_WRITE、MJ_FLUSH_BUFFERS和IIRP_MJ_SHUTDOWN。

第二个参数DeviceObject:这个参数是设备对象指针,IRP将会传递给这个设备对象。

第三个参数Buffer:对于IRP_MJ_READ和IRP_MJ_WRITE,Buffer指的是输入和输出缓冲区

第四个参数Length:这个参数是缓冲区的大小

第五个参数StartingOffset:这个参数是偏移量;

第六个参数Event:这个参数是同步事件,这个创建同步类型的IRP的关键,后面会有介绍。

使用IoBuildSynchronousFsdRequest内核函数创建同步类型的IRP,关键在于第六个参数Event 。

在调用IoBuildSynchronousFsdRequest之前,需要准备一个事件,这个事件会和IRP请求关联,当IRP请求被结束时该事件被触发。

IoBuildSynchronousFsdRequest和IoBuildAsynchronousFsdRequest内核函数之间的区别就是是否提供事件。

下面的代码演示了如何使用IoBuildSynchronousFsdRequest内核函数创建同步类型IRP(在代码中的DriverB工程中):


测试方法:

(1) 标准驱动DriverA的设计与文章(

1、4  用IoBuildAsynchronousFsdRequest创建IRP

这个内核函数比IoBuildSynchronousFsdRequest内核函数少一个事件参数。

 

1、5 用IoAllocate创建IRP

热点排行