หมายเลขบทความ (Article ID): 320275 - รีวิวครั้งสุดท้าย: 19 ตุลาคม 2553 - Revision: 1.0

วิธีการต่าง ๆ ของการจัดการ IRPs - แผ่นงาน cheat (ส่วนที่ 1 จาก 2)

เคล็ดลับของระบบThis article applies to a different operating system than the one you are using. Article content that may not be relevant to you is disabled.

เนื้อหาบนหน้านี้

ขยายทั้งหมด | ยุบทั้งหมด

สรุป

บทนำ

งานที่ดำเนินงานบ่อยที่สุดในโปรแกรมควบคุมรุ่นของโปรแกรมควบคุม Windows (WDM) อย่างใดอย่างหนึ่งคือส่งแพคเก็ตการร้องขอการอินพุต/เอาท์พุต (IRPs) จากโปรแกรมควบคุมที่หนึ่งไปยังโปรแกรมควบคุมอื่น ไดรเวอร์อย่างใดอย่างหนึ่ง IRP ของตนเองในการสร้าง และส่งไปยังโปรแกรมควบคุมที่ต่ำกว่า หรือโปรแกรมควบคุมที่ส่งต่อ IRPs ที่ได้รับจากโปรแกรมควบคุมอื่นที่มีแนบข้างต้น

บทความนี้อธิบายวิธีเป็นไปได้ทั้งหมดที่โปรแกรมควบคุมสามารถส่ง IRPs ไปยังโปรแกรมควบคุมที่ต่ำกว่าด้วยโค้ดตัวอย่าง annotated ทั้งนี้ขึ้นอยู่กับความต้อง ผู้เขียนโปรแกรมควบคุมสามารถทำตามแบบที่กำหนดไว้ในบทความนี้อย่างใดอย่างหนึ่ง และไม่ได้รับผลกระทบ โดย IRP เก่าที่กฎการจัดการ

ส่วนที่ 1 ของหัวข้อนี้แสดงสถานการณ์ 5 เกี่ยวกับวิธีการส่งต่อ IRP การให้โปรแกรมควบคุมอื่นจากขั้นตอนการส่ง และสถานการณ์ 7 คงเหลือที่ (แสดงในส่วนที่ 2 ของชื่อเรื่องนี้) กล่าวถึงวิธีการต่าง ๆ ของ IRP มีการสร้าง และส่งไปยังโปรแกรมควบคุมอื่น ส่วนที่ 2 ของชื่อเรื่องนี้อยู่ในบทความต่อไปนี้ของ Knowledge Base:
326315  (http://support.microsoft.com/kb/326315/ ) วิธีการต่าง ๆ ของการจัดการ IRPs - แผ่นงาน cheat (ส่วนที่ 2 จาก 2)
ก่อนที่คุณตรวจสอบในสถานการณ์ต่าง ๆ หมายเหตุเกี่ยวกับสถานะที่ถูกส่งกลับ โดยตามปกติเสร็จสมบูรณ์ต่อไปนี้:
ขั้นตอนการดำเนินการเสร็จสมบูรณ์ IRP สามารถกลับ STATUS_MORE_PROCESSING_REQUIRED หรือ STATUS_SUCCESS
ตัวจัดการทราน I/O ใช้กฎต่อไปนี้เมื่อโปรแกรมตรวจสอบสถานะ:
  • ถ้าสถานะเป็น STATUS_MORE_PROCESSING_REQUIRED หยุดทำ IRP ออกจากตำแหน่งที่ตั้งของกองซ้อนที่เทอร์ และส่งคืน
  • ถ้าสถานะเป็นสิ่งอื่นที่ไม่ใช่ STATUS_MORE_PROCESSING_REQUIRED ทำการดำเนินการ IRP upward
เนื่องจากตัวจัดการ I/O ที่ไม่มีการทราบว่ามีใช้ค่าที่ไม่ใช่ STATUS_MORE_PROCESSING_REQUIRED ใช้ STATUS_SUCCESS (เนื่องจากค่า 0 อยู่ได้อย่างมีประสิทธิภาพ loadable architectures ตัวประมวลผลส่วนใหญ่)

เมื่อต้องการปรับปรุง readability ของรหัส Windows XP SP1 และ Windows XP .NET ไดรเวอร์พัฒนา Kit Ntddk.h และ Wdm.h ส่วนหัวของแฟ้มจะมีใหม่เลขที่กำหนดที่มีชื่อ STATUS_CONTINUE_COMPLETION ซึ่งเป็นแฝงเพื่อ STATUS_SUCCESS ดังที่แสดงในรหัสต่อไปนี้:
// 
// 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 สามารถให้สมบูรณ์ synchronously หรือ asynchronously ขึ้นอยู่กับสถานะที่ถูกส่งกลับ โดยโปรแกรมควบคุมที่ต่ำลง
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 ซึ่งมักจะดำเนินการจัดการ IRPs PNP ตัวอย่างเช่น เมื่อคุณได้รับข้อความแสดงแบบ IRP IRP_MN_START_DEVICE คุณต้องการส่งต่อ 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 ในขั้นตอนการดำเนินการเสร็จสมบูรณ์ นี่คือเพื่อให้แน่ใจว่า ค่าสถานะที่กำหนดใน IoStatus ของ IRP บล็อก (Irp-> IoStatus.Status) จะเหมือนกับการส่งคืนสถานะของโปรแกรมควบคุมที่ต่ำกว่า
  • คุณต้องเผยแพร่ IRP สถานะรอค้างอยู่ตามที่ระบุ โดย Irp-> PendingReturned
  • คุณไม่ต้องเปลี่ยน synchronicity ของ IRP
ด้วยเหตุ มีเพียงรุ่น 2 ที่ถูกต้องของขั้นตอนการดำเนินการเสร็จสมบูรณ์ในสถานการณ์นี้ (31 และ 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: คิวสำหรับภายหลัง หรือส่งต่อ และนำมาใช้ใหม่

ใช้ snippet รหัสต่อไปนี้ในกรณีที่ที่โปรแกรมควบคุมที่ต้องการอย่างใดอย่างหนึ่งคิว IRP ข้อ และประมวลผลได้ในภายหลัง หรือส่งต่อ IRP โปรแกรมควบคุมที่ต่ำกว่า และนำมาใช้สำหรับหมายเลขเฉพาะของเวลาก่อนที่จะดำเนินการ IRP ขั้นตอนการส่ง IRP ค้างอยู่รอการทำเครื่องหมาย และส่งกลับค่า STATUS_PENDING เนื่องจากกำลัง IRP ที่ต้องทำให้สมบูรณ์ในภายหลังในเธรดอื่น ที่นี่ ขั้นตอนการดำเนินการเสร็จสมบูรณ์สามารถเปลี่ยนสถานะของการ IRP ถ้าจำเป็น (contrast เพื่อใช้ในสถานการณ์สมมติก่อนหน้านี้)
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 อย่างใดอย่างหนึ่ง คุณกลับ STATUS_MORE_PROCESSING_REQUIRED เฉพาะในกรณีที่คุณต้องการนำมาใช้ IRP จากเธรดอื่น และทำให้เสร็จสมบูรณ์ได้ในภายหลัง
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 ในขั้นตอนการส่ง สถานะของชุดคำสั่งส่งคืนควรตรงกับสถานะของค่าที่ถูกกำหนดในบล็อก IoStatus ของ IRP (Irp-> IoStatus.Status)
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 ของชื่อเรื่องนี้อยู่ในบทความต่อไปนี้ของ Knowledge Base:
326315  (http://support.microsoft.com/kb/326315/ ) วิธีการต่าง ๆ ของการจัดการ IRPs - แผ่นงาน cheat (ส่วนที่ 2 จาก 2)
  • Walter Oneyการเขียนโปรแกรมรุ่นโปรแกรมควบคุมของ Windowsสอง Edition บทที่ 5

ใช้กับ
  • Microsoft Windows XP Driver Development Kit
Keywords: 
kbinfo kbkmode kbwdm kbmt KB320275 KbMtth
แปลโดยคอมพิวเตอร์แปลโดยคอมพิวเตอร์
ข้อมูลสำคัญ: บทความนี้แปลโดยซอฟต์แวร์การแปลด้วยคอมพิวเตอร์ของ Microsoft แทนที่จะเป็นนักแปลที่เป็นบุคคล Microsoft มีบทความที่แปลโดยนักแปลและบทความที่แปลด้วยคอมพิวเตอร์ เพื่อให้คุณสามารถเข้าถึงบทความทั้งหมดในฐานความรู้ของเรา ในภาษาของคุณเอง อย่างไรก็ตาม บทความที่แปลด้วยคอมพิวเตอร์นั้นอาจมีข้อบกพร่อง โดยอาจมีข้อผิดพลาดในคำศัพท์ รูปแบบการใช้ภาษาและไวยากรณ์ เช่นเดียวกับกรณีที่ชาวต่างชาติพูดผิดเมื่อพูดภาษาของคุณ Microsoft ไม่มีส่วนรับผิดชอบต่อความคลาดเคลื่อน ความผิดพลาดหรือความเสียหายที่เกิดจากการแปลเนื้อหาผิดพลาด หรือการใช้บทแปลของลูกค้า และ Microsoft มีการปรับปรุงซอฟต์แวร์การแปลด้วยคอมพิวเตอร์อยู่เป็นประจำ
ต่อไปนี้เป็นฉบับภาษาอังกฤษของบทความนี้:320275  (http://support.microsoft.com/kb/320275/en-us/ )