文章編號: 320275 - 上次校閱: 2005年7月19日 - 版次: 5.0

不同的方法可以處理 IRP-欺騙工作表 (步驟 1 之 2)

系統提示本文適用於您使用的作業系統之外的作業系統。與您不相關的文章內容已停用。

在此頁中

全部展開 | 全部摺疊

結論

簡介

Windows 驅動程式模型 (WDM) 驅動程式的最常完成的工作之一,將輸入/輸出要求封包 (IRP) 從一個驅動程式傳送至另一個驅動程式。驅動程式會建立自己的 IRP 設定,並將其傳送至較低的驅動程式或驅動程式會轉送 IRP,它會接收從另一個上面附加的驅動程式。

本文將告訴您某個驅動程式可以傳送給較低的驅動程式已加上註解的範例程式碼的 IRP 的所有可能方法。 依據上的需要驅動程式撰寫人員可以遵循本文中提供的範本,且不會受到舊 IRP 處理規則。

此主題的第 1 部份顯示有關如何轉寄給另一個驅動程式的 IRP,分派常式從 5 案例和剩餘的 7 案例 (列在此主題的第 2 部份) 討論建立的 IRP,以及將它傳送到另一個驅動程式的不同方式。此主題的第 2 部分,都包含在下列 「 知識庫 」 文件中:
326315? (http://support.microsoft.com/kb/326315/ ) 不同的方法可以處理 IRP-欺騙工作表 (步驟 2 之 2)
檢查各種案例之前請注意下列有關由完成常式所傳回的狀態:
IRP 完成常式可以傳回 STATUS_MORE_PROCESSING_REQUIRED 或 STATUS_SUCCESS。
時它會檢查狀態,I/O 管理員會使用下列規則:
  • 如果狀態是 STATUS_MORE_PROCESSING_REQUIRED 停駐點完成 [IRP 保持不變的堆疊位置,並傳回。
  • 如果狀態是 STATUS_MORE_PROCESSING_REQUIRED 以外的其他,繼續完成 IRP 往上。
因為 I/O 管理員並不需要知道使用哪一個非 STATUS_MORE_PROCESSING_REQUIRED 值,使用 STATUS_SUCCESS (因為值為 0 的大多數的處理器架構為有效率地載入)。

若要改善程式碼的可讀性,Windows XP SP1 和 Windows XP.NET 驅動程式開發套件 Ntddk.h 和 Wdm.h 標頭檔會有一個新 # define 名為是 STATUS_SUCCESS 的別名,如下列程式碼所示的 STATUS_CONTINUE_COMPLETION:
// 
// This value should be returned from completion routines to continue
// completing the IRP upwards. Otherwise, STATUS_MORE_PROCESSING_REQUIRED
// should be returned.
// 
#define STATUS_CONTINUE_COMPLETION      STATUS_SUCCESS
// 
// Completion routines can also use this enumeration instead of status codes.
// 
typedef enum _IO_COMPLETION_ROUTINE_RESULT {
    
    ContinueCompletion = STATUS_CONTINUE_COMPLETION,
    StopCompletion = STATUS_MORE_PROCESSING_REQUIRED

} IO_COMPLETION_ROUTINE_RESULT, *PIO_COMPLETION_ROUTINE_RESULT;
				

其他相關資訊

案例 1: 轉寄和忘記

如果驅動程式只是想要向下轉送 [IRP 並採取任何額外的動作,請使用下列程式碼。若要在這種情況下設定完成常式沒有驅動程式。如果驅動程式最上層的驅動程式,[IRP 可以完成同步或非同步,取決於由較低的驅動程式傳回的狀態。(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
NTSTATUS
DispatchRoutine_1(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    // 
    // You are not setting a completion routine, so just skip the stack
    // location because it provides better performance.
    // 
    IoSkipCurrentIrpStackLocation (Irp);
    return IoCallDriver(TopOfDeviceStack, Irp);
} 

案例 2: 轉寄並等待

如果驅動程式要轉寄至較低的驅動程式 IRP,並等候它傳回,所以它可以處理 [IRP,請使用下列程式碼。這經常會完成處理 PNP IRP 時。例如當您收到 IRP_MN_START_DEVICE IRP,您必須轉寄 IRP 向匯流排驅動程式,然後等候它完成才能開始您的裝置。Windows XP 系統有新的函式,名為 IoForwardIrpSynchronously 可讓您輕鬆地執行這項作業。
NTSTATUS
DispatchRoutine_2(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    KEVENT   event;
    NTSTATUS status;

    KeInitializeEvent(&event, NotificationEvent, FALSE);

    // 
    // You are setting completion routine, so you must copy
    // current stack location to the next. You cannot skip a location
    // here.
    // 
    IoCopyCurrentIrpStackLocationToNext(Irp);

    IoSetCompletionRoutine(Irp,
                           CompletionRoutine_2,
                           &event,
                           TRUE,
                           TRUE,
                           TRUE
                           );

    status = IoCallDriver(TopOfDeviceStack, Irp);

    if (status == STATUS_PENDING) {
        
       KeWaitForSingleObject(&event,
                             Executive, // WaitReason
                             KernelMode, // must be Kernelmode to prevent the stack getting paged out
                             FALSE,
                             NULL // indefinite wait
                             );
       status = Irp->IoStatus.Status;
    }
    
    // <---- Do your own work here.


    // 
    // Because you stopped the completion of the IRP in the CompletionRoutine
    // by returning STATUS_MORE_PROCESSING_REQUIRED, you must call
    // IoCompleteRequest here.
    // 
    IoCompleteRequest (Irp, IO_NO_INCREMENT);
    return status;

}
NTSTATUS
CompletionRoutine_2(
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp,
    IN PVOID            Context
    )
{ 
  if (Irp->PendingReturned == TRUE) {
    // 
    // You will set the event only if the lower driver has returned
    // STATUS_PENDING earlier. This optimization removes the need to
    // call KeSetEvent unnecessarily and improves performance because the
    // system does not have to acquire an internal lock.  
    // 
    KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
  }
  // This is the only status you can return. 
  return STATUS_MORE_PROCESSING_REQUIRED;  
} 
				

案例 3: 轉寄與完成常式

在這種情況下驅動程式設定完成常式、 向下,轉送 [IRP,然後傳回原狀較低的驅動程式的狀態。設定完成常式的目的是要修改上一路回 IRP 內容。
NTSTATUS
DispathRoutine_3(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    NTSTATUS status;

    // 
    // Because you are setting completion routine, you must copy the
    // current stack location to the next. You cannot skip a location
    // here.
    // 
    IoCopyCurrentIrpStackLocationToNext(Irp); 

    IoSetCompletionRoutine(Irp,
                           CompletionRoutine_31,// or CompletionRoutine_32
                           NULL,
                           TRUE,
                           TRUE,
                           TRUE
                           );
    
    return IoCallDriver(TopOfDeviceStack, Irp);

} 
如果您從分派常式傳回較低的驅動程式的狀態:
  • 不,您必須變更中完成常式 IRP 狀態。這是確定狀態值設定在 [IRP IoStatus 區塊 (-> [IoStatus.Status Irp) 和是相同的較低的驅動程式傳回的狀態。
  • 所指定的-> [PendingReturned Irp,您必須傳播擱置中的 [IRP 狀態。
  • 不,您必須變更 [IRP synchronicity。
As a result, there are only 2 valid versions of the completion routine in this scenario (31 and 32):
 
NTSTATUS
CompletionRoutine_31 (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp,
    IN PVOID            Context
    )
{   

    // 
    // Because the dispatch routine is returning the status of lower driver
    // as is, you must do the following:
    // 
    if (Irp->PendingReturned) {
        
        IoMarkIrpPending( Irp );
    }
    
    return STATUS_CONTINUE_COMPLETION ; // Make sure of same synchronicity 
}

NTSTATUS
CompletionRoutine_32 (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp,
    IN PVOID            Context
    )
{   
    // 
    // Because the dispatch routine is returning the status of lower driver
    // as is, you must do the following:
    // 
    if (Irp->PendingReturned) {
        
        IoMarkIrpPending( Irp );
    }
    
    //    
    // To make sure of the same synchronicity, complete the IRP here.
    // You cannot complete the IRP later in another thread because the 
    // the dispatch routine is returning the status returned by the lower
    // driver as is.
    // 
    IoCompleteRequest( Irp,  IO_NO_INCREMENT);  

    // 
    // Although this is an unusual completion routine that you rarely see,
    // it is discussed here to address all possible ways to handle IRPs.  
    // 
    return STATUS_MORE_PROCESSING_REQUIRED; 
} 

				

案例 4: 佇列為稍後,或轉寄並重複使用

在驅動程式想要任一個佇列的 IRP,並稍後處理或轉寄到較低的驅動程式 IRP 並且重複使用它之前先完成 [IRP 特定次數的情況中使用下列程式碼片段。分派常式標記暫止的 IRP,並傳回 STATUS_PENDING,因為 [IRP 即將要稍後在不同的執行緒內完成。這裡,完成例行 可以 變更 IRP 必要 (相對於前一個案例) 時的狀態。
NTSTATUS
DispathRoutine_4(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    NTSTATUS status;

    // 
    // You mark the IRP pending if you are intending to queue the IRP
    // and process it later. If you are intending to forward the IRP 
    // directly, use one of the methods discussed earlier in this article.
    // 
    IoMarkIrpPending( Irp );    

    // 
    // For demonstration purposes: this IRP is forwarded to the lower driver.
    // 
    IoCopyCurrentIrpStackLocationToNext(Irp); 

    IoSetCompletionRoutine(Irp,
                           CompletionRoutine_41, // or CompletionRoutine_42
                           NULL,
                           TRUE,
                           TRUE,
                           TRUE
                           ); 
    IoCallDriver(TopOfDeviceStack, Irp);

    // 
    // Because you marked the IRP pending, you must return pending,
    // regardless of the status of returned by IoCallDriver.
    // 
    return STATUS_PENDING ;

}
STATUS_CONTINUE_COMPLETION 或 STATUS_MORE_PROCESSING_REQUIRED,不論是可以傳回完成常式。如果您想要重複使用來自另一個執行緒 IRP,稍後再完成,您就會傳回 STATUS_MORE_PROCESSING_REQUIRED。
NTSTATUS
CompletionRoutine_41(
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp,
    IN PVOID            Context
    )
{ 
    // 
    // By returning STATUS_CONTINUE_COMPLETION , you are relinquishing the 
    // ownership of the IRP. You cannot touch the IRP after this.
    // 
    return STATUS_CONTINUE_COMPLETION ; 
} 


NTSTATUS
CompletionRoutine_42 (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp,
    IN PVOID            Context
    )
{  
    // 
    // Because you are stopping the completion of the IRP by returning the
    // following status, you must complete the IRP later.
    // 
    return STATUS_MORE_PROCESSING_REQUIRED ; 
} 
				

案例 5: 完成分派常式中 IRP

這個案例示範了如何完成分派常式中的 IRP。

重要當您完成 [分派常式中的 IRP 時分派常式的傳回狀態應符合的 IRP (-> [IoStatus.Status Irp) IoStatus 區塊中設定的值的狀態。
NTSTATUS
DispatchRoutine_5(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    // 
    // <-- Process the IRP here.
    // 
    Irp->IoStatus.Status = STATUS_XXX;
    Irp->IoStatus.Information = YYY;
    IoCompletRequest(Irp, IO_NO_INCREMENT);
    return STATUS_XXX;
} 

?考

此主題的第 2 部分,都包含在下列 「 知識庫 」 文件中:
326315? (http://support.microsoft.com/kb/326315/ ) 不同的方法可以處理 IRP-欺騙工作表 (步驟 2 之 2)
  • 烏 Oney。程式設計 Windows 驅動程式模型,第二版第 5 章。

這篇文章中的資訊適用於:
  • Microsoft Win32 Device Driver Kit for Windows 2000
  • Microsoft Windows XP Driver Development Kit
  • Microsoft Windows Server 2003 Driver Development Kit (DDK)
  • Microsoft Windows NT 4.0
  • the operating system: Microsoft Windows 2000
  • the operating system: Microsoft Windows XP
關鍵字:?
kbmt kbinfo kbkmode kbwdm KB320275 KbMtzh
機器翻譯機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:320275? (http://support.microsoft.com/kb/320275/en-us/ )
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。