iniwf

风是温柔的,雨是伤心的,云是快乐的,月是多情的,爱是迷失的,恋是醉人的,情是难忘的,天是长久的,地是永恒的

驱动开发之五 --- TDI之八 【译文】

转自http://hi.baidu.com/combojiang/blog/item/77082c24a85795368744f9cd.html

步骤8:关闭句柄
这个函数被两个句柄调用,传输句柄和上下文句柄。

NTSTATUS TdiFuncs_CloseTdiOpenHandle(HANDLE hTdiHandle, 

                                  PFILE_OBJECT pfoTdiFileObject) 



    NTSTATUS NtStatus 
= STATUS_SUCCESS; 


    
/* 

     * De-Reference the FILE_OBJECT and Close The Handle 

     
*/
 


    ObDereferenceObject(pfoTdiFileObject); 

    ZwClose(hTdiHandle); 


    
return NtStatus; 

}





其他资源


一旦你熟悉了,TDI接口就变得简单了。当写驱动时,最大的事情就是处理IRP。TDI似乎比socket有些复杂,但是它是内核接口。


如果曾经研究过TDI或者NDIS,你大概进入过Thomas Divine. 如果你想购买复杂的TDI或者NDIS示例,你可以找他们,或者他公司网站上的其他资源。在上面你也可以找到其他不同网站的指南。


IRP处理


下篇文章将粗微的谈到一些IRP的基本概念和怎样处理他们。实际上那里描述的东西有一些大的缝隙,为了保持下篇文章简单,所以在本篇我们将加快步伐,尽可能多的去填充这些缝隙。在这时,正面的揭示这些给驱动开发者,我们能非常简单的做这个。然而这里有大量的信息,并不是所有的都在示例代码中体现出来了。你需要自己试验这些IRP的处理,这是开发驱动的根本部分。

驱动请求


当写驱动的时候,有两次不同的揭示IRP. 即:发给你自己驱动的请求和你创建的IRP,发送给在其他驱动的请求两种。我记得,有一个驱动栈,栈里的每一个驱动在IRP中都有自己的栈区域。每次一个IRP沿着栈向下发送,IRP的当前栈区域是优先的。当它到达你的驱动时,你可以有少量的选择。

前进和遗忘


你可以使用IoCallDriver使IRP向前到栈中的下一个驱动。这是我们在其它驱动指南中的做法。我们向前了IRP并且忘记它。可是这里有一个问题,我们并没有考虑到STATUS_PENDING的情况。STATUS_PENDING是实现异步操作的一个方法。由底层驱动通知调用者,他们没有完成这个IRP。或许他们也正在一个单独的线程中完成这个IRP. 它的规则是如果你返回STATUS_PENDING,你必须在返回之前调用IoMarkIrpPending。如果你已经向前把IRP传给了下一个驱动,现在这仍然是个问题。在调用后,不允许你接触它。所以实际上你有两个选择。

   IoMarkIrpPending(Irp); 

   IoCallDriver(pDeviceObject, Irp); 


   
return STATUS_PENDING;



第二个选择是设置一个完成例程。你应该记得在第四篇文章中的代码,我们使用完成例程通过返回STATUS_MORE_PROCESSING_REQUIRED而不是STATUS_SUCCESS,停止了一个IRP的完成。,

   IoSetCompletionRoutine(Irp, CompletionRoutine, NULL, TRUE, TRUE, TRUE); 


   
return IoCallDriver(pDeviceObject, Irp);


 


   NTSTATUS CompletionRoutine(PDEVICE_OBJECT DeviceObject, 

                             PIRP Irp, PVOID Context) 

   


      
if(Irp->PendingReturned) 

      


        IoMarkIrpPending(Irp); 

      }
 


      
return STATUS_SUCCESS; 

   }
 

你可以在这里再一次的停止处理过程,如果你这么做,你需要使用IoMarkIrpPending。这里有个循环逻辑,如果你调用IoMarkIrpPending,那么你必须从你的驱动中返回STATUS_PENDING,如果你从你的驱动中返回STATUS_PENDING,你必须调用IoMarkIrpPending。记住,如果你停止一个完成的处理,那么这就意味着你必须完成它。我们在第四篇就是这么做的。


需要注意一点,如果一个完成例程不提供这些,I
/O管理器会把"IoMarkIrpPending"告诉给你。在这个或许你不想去相信的主题中,无论信息是多么分散,你要确信你所做的任何事情都是对的。

   向前和投递处理


这和我们在第四篇的处理有些细微的差别。我们需要考虑pending的情况,如果IRP从底层驱动中返回pending的状态,我们需要等待,直到底层驱动完成它。一旦驱动完成,我们需要唤醒原始线程,这样我们就可以处理和完成IRP. 作为一个最佳方式,如果pending状态返回,我们只想设置事件。如果任何事情被同步处理,就不需要增加前面的设置和等待事件。下面是代码示例。


IoSetCompletionRoutine(Irp, CompletionRoutine, 

                  
&kCompleteEvent, TRUE, TRUE, TRUE); 


   NtStatus 
= IoCallDriver(pDeviceObject, Irp); 



   
if(NtStatus == STATUS_PENDING) 

   


        KeWaitForSingleObject(
&kCompleteEvent, 

                     Executive, KernelMode, FALSE, NULL); 


        
/* 

         * Find the Status of the completed IRP 

         
*/
 


       NtStatus 
= IoStatusBlock.Status; 

   }
 


   
/* 

    * Do Post Processing 

    
*/
 


   IoCompleteRequest(pIrp, IO_NO_INCREMENT); 

     

   
return NtStatus; 

    

    


   NTSTATUS CompletionRoutine(PDEVICE_OBJECT DeviceObject, 

                                     PIRP Irp, PVOID Context) 

   


      
if(Irp->PendingReturned) 

      


         KeSetEvent(Context, IO_NO_INCREMENT, FALSE); 

      }
 


      
return STATUS_MORE_PROCESSING_REQUIRED; 

   }
 

posted on 2009-03-23 22:09 iniwf 阅读(665) 评论(0)  编辑 收藏 引用 所属分类: 驱动


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

统计

常用链接

留言簿(2)

随笔分类

随笔档案

收藏夹

IT技术

积分与排名

最新评论

阅读排行榜

评论排行榜