ID do artigo: 320275 - Última revisão: terça-feira, 19 de julho de 2005 - Revisão: 5.0

Maneiras de manipular IRPs - trapacear folha (parte 1 de 2)

Dica do SistemaEste artigo aplica-se a um sistema operativo diferente do que está a utilizar. Foi desactivado o conteúdo do artigo, que pode não ser relevante para si.

Nesta página

Expandir tudo | Recolher tudo

Sumário

Introdução

Uma das tarefas com mais freqüência feitas nos drivers WDM (Windows Driver Model) está enviando pacotes de solicitação de entrada/saída (IRPs) de um driver para outro driver. Um driver cria seu próprio IRP e envia para um driver inferior ou o driver encaminha os IRPs que ele recebe de outro driver que está conectado acima.

Este artigo descreve todas as maneiras possíveis que um driver pode enviar os IRPs para um driver inferior com código de exemplo com anotações. Dependendo da necessidade, gravadores de driver podem seguir um dos modelos fornecidos neste artigo e não é afetados por antigo IRP regras de manipulação.

Parte 1 desse assunto mostra 5 cenários sobre como encaminhar um IRP para outro driver de uma rotina de expedição e os cenários de 7 restantes (listados na parte 2 desse assunto) discutem maneiras de criar um IRP e enviá-lo para outro driver. Parte 2 desse assunto está contida no seguinte artigo da Base de dados de Conhecimento:
326315  (http://support.microsoft.com/kb/326315/ ) Maneiras de manipular IRPs - trapacear folha (parte 2 de 2)
Antes de examinar vários cenários, observe o seguinte sobre o STATUS é retornado por rotinas de conclusão:
Uma rotina de conclusão de IRP pode retornar STATUS_MORE_PROCESSING_REQUIRED ou STATUS_SUCCESS.
O Gerenciador de E/s usa as regras a seguir quando ele examina o status:
  • Se o status for STATUS_MORE_PROCESSING_REQUIRED, parada concluir o IRP, deixe o local de pilha inalterado e retornar.
  • Se o status for diferente de STATUS_MORE_PROCESSING_REQUIRED, continue a concluir o IRP para cima.
Como o Gerenciador de E/s não é necessário saber qual valor STATUS_MORE_PROCESSING_REQUIRED não é usado, use STATUS_SUCCESS (porque o valor 0 é carregável com eficiência na maioria das arquiteturas de processador).

Para melhorar a legibilidade do código, arquivos de cabeçalho do Windows XP SP1 e Windows XP .NET Driver Development Kit Ntddk.h e wdm.h terá um novo # define chamado STATUS_CONTINUE_COMPLETION, que é o alias para STATUS_SUCCESS como mostrado no código a seguir:
// 
// 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;
				

Mais Informações

Cenário 1: Encaminhar e esquecer

Use o seguinte código se um driver quiser apenas encaminhar o IRP para baixo e nenhuma ação adicional. O driver não é necessário definir uma rotina de conclusão nesse caso. Se o driver for um driver de nível superior, o IRP pode ser concluído forma síncrona ou assíncrona, dependendo do status retornado pelo driver inferior.
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);
} 

Cenário 2: Avançar e aguarde

Use o código a seguir se quiser que um driver encaminhar o IRP para um driver inferior e aguarde a retornar para que ele possa processar o IRP. Isso é feito com freqüência ao manipular os IRPs de PNP. Por exemplo, quando você recebe um IRP IRP_MN_START_DEVICE, você deve encaminhar o IRP para baixo para o driver de barramento e aguarde a conclusão antes de iniciar o dispositivo. O sistema do Windows tem uma nova função chamada IoForwardIrpSynchronously que você pode usar para executar esta operação facilmente.
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;  
} 
				

Cenário 3: Direta com uma rotina de conclusão

Nesse caso, o driver define uma rotina de conclusão, encaminha o IRP para baixo e, em seguida, retorna o status do driver inferior como está. O objetivo de definir a rotina de conclusão é modificar o conteúdo do IRP de seu caminho de volta.
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);

} 
se você retornar o status do driver inferior de sua rotina de expedição:
  • Você não deve alterar o status do IRP na rotina de conclusão. Isso é garantir que os valores de status definida na IoStatus do IRP bloco (Irp-> IoStatus.Status) são as mesmas o status de retorno de drivers inferiores.
  • Você deve propagar o status pendente do IRP conforme indicado pelo IRP-> PendingReturned.
  • Você não deve alterar a sincronia do IRP.
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; 
} 

				

Cenário 4: Enfileirar para mais tarde, ou encaminhar e reutilizar

Use o seguinte trecho de código em uma situação onde o driver deseja em fila um IRP e processá-lo mais tarde ou encaminhar o IRP para o driver inferior e reutilizá-la para um número específico de vezes antes de concluir o IRP. A rotina de expedição marca o IRP pendente e retorna STATUS_PENDING porque o IRP está prestes a ser concluída posteriormente em um thread diferente. Aqui, a conclusão rotina pode alterar o status do IRP de se necessário (em comparação com o cenário anterior).
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 ;

}
a rotina de conclusão ou pode retornar STATUS_CONTINUE_COMPLETION ou STATUS_MORE_PROCESSING_REQUIRED. Você retornar STATUS_MORE_PROCESSING_REQUIRED somente se você pretende reutilizar o IRP de outro segmento e concluí-la mais tarde.
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 ; 
} 
				

Cenário 5: Concluir o IRP na rotina de expedição

Esse cenário mostra como concluir um IRP na rotina de expedição.

importante Quando você concluir um IRP na rotina de expedição, o status de retorno da rotina de expedição deve corresponder ao status do valor é definido no bloco de IoStatus do 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;
} 

Referências

Parte 2 desse assunto está contida no seguinte artigo da Base de dados de Conhecimento:
326315  (http://support.microsoft.com/kb/326315/ ) Maneiras de manipular IRPs - trapacear folha (parte 2 de 2)
  • Walter Oney. programação Windows Driver Model , Second Edition, capítulo 5.

A informação contida neste artigo aplica-se a:
  • 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
Palavras-chave: 
kbmt kbinfo kbkmode kbwdm KB320275 KbMtpt
Tradução automáticaTradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine Translation ou MT), não tendo sido portanto traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 320275  (http://support.microsoft.com/kb/320275/en-us/ )