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.
Uma das tarefas mais frequentemente efectuadas nos controladores de modelo de controlador do Windows (WDM, Windows Driver Model) está a enviar pacotes de pedido de entrada/saída (IRPs) de um controlador para outro controlador. Um controlador ou cria a suas próprias IRP e envia-a um controlador inferior, ou o controlador reencaminha os IRPs recebe de outro controlador que está anexado acima.
Este artigo aborda todas as formas possíveis que um controlador pode enviar IRPs para um controlador inferior com código de exemplo anotado. Consoante a necessidade, escritores de controlador podem seguir um dos modelos indicados neste artigo e não ser afectados por antigo IRP processamento de regras.
Parte deste assunto mostra 5 cenários como reencaminhar um IRP para outro controlador a partir de uma rotina de distribuição e os cenários de 7 restantes (listados na segunda parte deste assunto) descrevem diferentes formas de criar um IRP e enviar para outro controlador. Segunda parte deste assunto incluído o seguinte artigo da Knowledge Base:
326315
(http://support.microsoft.com/kb/326315/
)
Formas diferentes de processamento IRPs - folha de batota (faz parte 2 de 2)
Antes de examinar os vários cenários, tenha em atenção o seguinte sobre o STATUS é devolvido pelas rotinas de conclusão:
Uma rotina de conclusão de IRP pode devolver ou STATUS_MORE_PROCESSING_REQUIRED STATUS_SUCCESS.
O Gestor de E/s utiliza as seguintes regras quando examina o estado:
Se o estado for STATUS_MORE_PROCESSING_REQUIRED, parar a concluir o IRP, deixe a localização de pilha inalterada e devolver.
Se o estado for diferente de STATUS_MORE_PROCESSING_REQUIRED, continue a concluir o IRP para cima.
Uma vez que o Gestor de E/s não é necessário saber o valor não STATUS_MORE_PROCESSING_REQUIRED é utilizado, utilize STATUS_SUCCESS (porque o valor 0 é eficiente carregável na maior parte das arquitecturas de processador).
Para melhorar a legibilidade do código, ficheiros de cabeçalho do Windows XP SP1 e Windows XP .NET Driver Development Kit Ntddk.h e wdm.h terão um novo # Definir denominado STATUS_CONTINUE_COMPLETION é alternativo para STATUS_SUCCESS como é mostrado no seguinte código:
//
// 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;
Utilize o seguinte código se um controlador apenas pretender reencaminhar o IRP para baixo e não efectuar nenhuma acção adicional. O controlador não tem de definir uma rotina de conclusão neste caso. Se o controlador é um nível superior, o IRP pode ser concluído a síncrona ou de forma assíncrona, dependendo do estado devolvido pelo controlador 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);
}
Utilize o seguinte código se um controlador pretende reencaminhar IRP para um controlador inferior e aguarde que devolver para que possa processar o IRP. Isto é feito frequentemente quando processa os IRPs de PNP. Por exemplo, quando receber um IRP IRP_MN_START_DEVICE, deve reencaminhar IRP até o controlador de barramento e aguardar concluir antes de iniciar o dispositivo. O sistema Windows XP tem uma função nova denominada IoForwardIrpSynchronously que pode utilizar para efectuar 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;
}
Neste caso, o controlador define uma rotina de conclusão, reencaminha o IRP para baixo e, em seguida, devolve o estado do controlador inferior tal como está. O objectivo de definir a rotina de conclusão é modificar o conteúdo do IRP na respectiva forma novamente.
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 devolver o estado do controlador minúsculas da rotina de distribuição:
Não tem de alterar o estado do IRP na rotina de conclusão. Este é certificar-se de que os valores de estado é definido no IRP IoStatus bloco (Irp-> IoStatus.Status) são as mesmas o estado devolvido de controladores inferiores.
Tem a propagar o estado pendente de IRP conforme indicado pelo Irp-> PendingReturned.
Não tem de alterar synchronicity 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: Fila para utilização posterior, ou reencaminhar e reutilizar
Utilize o seguinte fragmento de código numa situação em que o controlador pretende em fila um IRP processá-la mais tarde ou reencaminhar IRP para o controlador inferior e reutilizá-la para um número específico de vezes antes de concluir o IRP. A rotina de despacho marca IRP pendentes e devolve STATUS_PENDING porque o IRP vai ser concluída mais tarde num thread diferente. Aqui, a conclusão rotina pode alterar o estado do IRP se necessário (em contraste com o exemplo 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 devolver STATUS_CONTINUE_COMPLETION ou STATUS_MORE_PROCESSING_REQUIRED. Retorno STATUS_MORE_PROCESSING_REQUIRED apenas se pretender reutilizar o IRP de outro thread e concluí-lo 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 ;
}
Este exemplo mostra como efectuar um IRP na rotina de distribuição.
importante Quando concluir um IRP na rotina emissão, o estado devolvido a rotina de distribuição deve corresponder o estado do valor definido no bloco de IRP (Irp-> IoStatus.Status) 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;
}
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 revisto ou traduzido por humanos. A Microsoft tem artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais. O objectivo é simples: oferecer em Português a totalidade dos artigos existentes na base de dados do suporte. Sabemos no entanto que a tradução automática não é sempre perfeita. Esta pode conter erros de vocabulário, sintaxe ou gramática? erros semelhantes aos que um estrangeiro realiza ao falar em Português. A Microsoft não é responsável por incoerências, erros ou estragos realizados na sequência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza actualizações frequentes 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/
)
Qual foi o esforço que despendeu pessoalmente para utilizar este artigo?
Muito baixo
Baixo
Moderado
Elevado
Muito elevado
Diga-nos porquê e o que podemos fazer para melhorar estas informações
Obrigado! Os seus comentários são utilizados para ajudar-nos a melhorar o conteúdo do nosso suporte. Para obter mais opções de assistência, visite a Home Page de Ajuda e Suporte.