总版主
|
阅读:2464回复:9
Windows文件系统过滤驱动开发教程(10)
Windows文件系统过滤驱动开发教程
注: 有任何问题与建议请加QQ16191935,邮箱MFC_Tan_Wen@163.com 工作忙,好久没有来过了,请大家谅解。 10 自己发送Irp完成读请求 关于这个有一篇文档解释得很详细,不过我认为示例的代码有点太简略了,这篇文档在IFS所附带的OSR文档中,请自己寻找。 为何要自己发送Irp?在一个文件过滤驱动中,如果你打算读写文件,可以试用ZwReadFile.但是这有一些问题。Zw系列的Native API使 用句柄。而句柄是有线程环境限制的。此外也有中断级别的限制。再说,Zw系列函数来读写文件,最终还是要发出Irp,又会被自己的过滤驱动 捕获到。结果带来判断上的困难。对资源也是浪费。那么最应该的办法是什么呢?当然是直接对卷设备发Irp了。 但是Irp是非常复杂的数据结构,而且又被微软所构造的很多未空开的部件所处理。所以自己发irp并不是一件简单的事情。 比较万能的方法是IoAllocateIrp,分配后自己逐个填写。问题是细节实在太多,很多无文档可寻。有兴趣的应该看看我上边所提及的 那篇文章“Rolling Your Own”。 有意思的是这篇文章后来提到了捷径,就是利用三个函数: IoBuildAsynchronousFsdRequest(...) IoBuildSynchronousFsdRequest(...) IoBuildDeviceIoControlRequest(...) 于是我参考了他这方面的示例代码,发现运行良好,程序也很简单。建议怕深入研究的选手就可以使用我下边提供的方法了。 首先的建议是使用IoBuildAsynchronousFsdRequest(),而不要使用同步的那个。使用异步的Irp使irp和线程无关。而你的过滤驱动一 般很难把握当前线程(如果你开一个系统线程来专门读取文件那例外)。此时,你可以轻松的在Irp的完成函数中删除你分配过的Irp,避免去追 究和线程相关的事情。 但是这个方法有局限性。文档指出,这个方法仅仅能用于IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_FLUSH_BUFFERS,和IRP_MJ_SHUTDOWN. 刚好我这里仅仅要求完成文件读。 用Irp完成文件读需要一个FILE_OBJECT.FileObject是比Zw系列所用的句柄更好的东西。因为这个FileObject是和线程无关的。你可以 放心的在未知的线程中使用他。 自己要获得一个FILE_OBJECT必须自己发送IRP_MJ_CREATE的IRP.这又不是一件轻松的事情。不过我跳过了这个问题。因为我是文件系 统过滤驱动,所以我从上面发来的IRP中得到FILE_OBJECT,然后再构造自己的IRP使用这个FILE_OBJECT,我发现运行很好。 但是又出现一个问题,如果IRP的irp->Flags中有IRP_PAGING(或者说是Cache管理器所发来的IRP)标记,则其FileObject我获得并使 用后,老是返回错误。阅读网上的经验表明,带有IRP_PAGINGE的FileObject不可以使用.于是我避免使用这时的FileObject.我总是使用不带 IRP_PAGING的Irp(认为是用户程序发来的读请求)的FileObject。 好,现在废话很多了,现在来看看构造irp的代码: _inline wd_irp *wd_irp_fsd_read_alloc(wd_dev *dev, wd_void *buf, wd_ulong length, wd_lgint *offset, wd_io_stat_block *io_stat) { return IoBuildAsynchronousFsdRequest(IRP_MJ_READ,dev, buf,length, offset, io_stat); } io_stat我不知道是做何用,我一般填写NULL.类型是PIO_STATUS_BLOCK.buf则是缓冲。在Irp中被用做UserBuffer接收数据。offset是 这次读的偏移量。 以上函数构造一个读irp.请注意,此时您还没有设置FileObject.实际上我是这样发出请求的: irp = wd_irp_fsd_read_alloc(dev,buf,len,&start,NULL); if(irp == NULL) return; irpsp = wd_irp_next_sp(irp); wd_irpsp_file_set(irpsp,file); wd_irp_comp(irp,my_req_comp,context); 请注意wd_irp_next_sp,我是得到了这个irp的下一个IO_STACK_LOCATION,然后我设置了FileObject.接下来应该设置了完成后,我就 可以发送请求了!请求发送完毕后,一旦系统完成请求就会调用你的my_req_comp. 再看看my_req_comp如何收场: wd_stat my_req_comp(in wd_dev *dev, in wd_irp *irp, in wd_void *context) { // 请注意,无论成功还是失败,我都得在这里彻底销毁irp wd_irp_send_by_myself_free(irp); // 返回这个,仅仅是因为irp我已经销毁,不想让系统再次销毁它而已。 return wd_stat_more_processing; } wd_stat_more_prcessing就是STATUS_MORE_PROCESSING_REQUIRED。之所以返回这个,是因为我已经把irp给删除了。我不想windows系 统再对这个irp做什么。所以干脆说我还要继续处理,这样避免了io管理器再去动用这个irp的可能。 最后是那个irp删除函数的代码: _inline wd_void wd_irp_send_by_myself_free(wd_irp *irp) { if (irp->MdlAddress) { MmUnmapLockedPages(MmGetSystemAddressForMdl(irp->MdlAddress), irp->MdlAddress); MmUnlockPages(irp->MdlAddress); IoFreeMdl(irp->MdlAddress); } IoFreeIrp(irp); }; 因为我自己没有分配过MdlAddress下去过。所以如果下边返回了MDL,我得附带清理它。 好了,祝愿你心情愉快。如果你何我一样懒惰的话,不妨就用上边的简单方法自己发irp来读文件了。 |
沙发#
发布于:2004-12-07 20:00
牛~~!
顶一顶。 |
|
板凳#
发布于:2004-12-08 08:58
ding
|
|
地板#
发布于:2004-12-08 10:40
不错
|
|
地下室#
发布于:2004-12-08 11:45
多谢了!
|
|
5楼#
发布于:2004-12-11 22:42
顶,牛
|
|
|
总版主
|
6楼#
发布于:2004-12-14 16:46
我自己顶
|
7楼#
发布于:2004-12-14 19:14
用户被禁言,该主题自动屏蔽! |
|
8楼#
发布于:2005-01-31 16:34
谢了。
|
|
9楼#
发布于:2005-04-12 20:31
顶上去
|
|
|