Concluindo solicitações de E/S no UMDF

Aviso

O UMDF 2 é a versão mais recente do UMDF e substitui o UMDF 1. Todos os novos drivers UMDF devem ser gravados usando UMDF 2. Nenhum novo recurso está sendo adicionado ao UMDF 1 e há suporte limitado para UMDF 1 em versões mais recentes do Windows 10. Os drivers universais do Windows devem usar o UMDF 2.

Os exemplos de UMDF 1 arquivados podem ser encontrados no Windows 11, versão 22H2 – Atualização de exemplos de driver de maio de 2022.

Para obter mais informações, consulte Introdução com UMDF.

Cada solicitação de E/S deve eventualmente ser concluída por um driver UMDF. Para concluir uma solicitação, o driver deve chamar o método IWDFIoRequest::Complete ou IWDFIoRequest::CompleteWithInformation . Quando o driver conclui a solicitação, ele indica um dos seguintes cenários:

  • A operação de E/S solicitada foi concluída com êxito.

  • A operação de E/S solicitada foi iniciada, mas falhou antes de ser concluída.

  • A operação de E/S solicitada não tem suporte ou não é válida no momento em que foi recebida e, portanto, não pode se comunicar com o dispositivo.

  • A operação de E/S solicitada foi cancelada.

O driver chama o método IWDFIoRequest::CompleteWithInformation para passar informações adicionais sobre a operação de solicitação. Por exemplo, para uma operação de leitura, o driver deve fornecer o número de bytes lidos.

Para concluir uma solicitação de E/S, o driver deve passar o status de conclusão apropriado para o parâmetro CompletionStatus na chamada para IWDFIoRequest::Complete ou IWDFIoRequest::CompleteWithInformation. O driver usa um código HRESULT para comunicar o status da solicitação concluída.

O processo de host do driver UMDF converte o código HRESULT em um código NTSTATUS antes de passar a solicitação concluída para o refletor (Wudfrd.sys). O refletor passa o código NTSTATUS para o sistema operacional. O sistema operacional converte o código NTSTATUS em um código de erro do Microsoft Win32 antes de apresentar o resultado para o aplicativo de chamada.

Para garantir que os códigos de erro do driver possam ser convertidos corretamente, você deve criar códigos de erro por uma das seguintes técnicas:

  • Use um código de erro do Winerror.h e aplique a macro HRESULT_FROM_WIN32.

  • Use um código de erro de Ntstatus.h e aplique a macro HRESULT_FROM_NT.

Para obter mais informações sobre essas macros, consulte a documentação SDK do Microsoft Windows.

O código de exemplo a seguir mostra como concluir uma solicitação com um código de erro adequado:

VOID
STDMETHODCALLTYPE
CMyQueue::OnWrite(
    __in IWDFIoQueue *pWdfQueue,
    __in IWDFIoRequest *pWdfRequest,
    __in SIZE_T BytesToWrite
    )
{
            -------------------- 
    if( BytesToWrite > MAX_WRITE_LENGTH ) {
        pWdfRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_MORE_DATA), 0);
        return;
    }
            ---------------------
}

Quando um driver conclui uma solicitação com êxito, ele retorna S_OK, que é um valor HRESULT. Como S_OK é equivalente a NO_ERROR no Winerror.h e STATUS_SUCCESS em Ntstatus.h, as macros de conversão não são necessárias.

Se o Verificador de Driver estiver habilitado para o refletor, ele identificará um código de status inválido e causará uma verificação de bugs do sistema.

Nota O Verificador de Driver para Windows XP causa incorretamente uma verificação de bugs do sistema para códigos de erro Win32 cujos valores excedem a decimal 1024 (1024L). Se o driver for executado no Windows XP, esteja ciente desse problema se você habilitar o Verificador de Driver para o refletor.

Se o driver enviou anteriormente uma solicitação para um driver de nível inferior, o driver requer notificação quando o driver de nível inferior conclui a solicitação. Para se registrar para notificação, o driver chama o método IWDFIoRequest::SetCompletionCallback para registrar a interface do método que a estrutura chama quando o driver de nível inferior conclui a solicitação. O driver implementa a função de retorno de chamada IRequestCallbackRequestCompletion::OnCompletion para executar as operações necessárias para concluir a solicitação.

Um driver não conclui uma solicitação de E/S criada chamando IWDFDevice::CreateRequest. Em vez disso, o driver deve chamar IWDFObject::D eleteWdfObject para excluir o objeto de solicitação, normalmente depois que um destino de E/S tiver concluído a solicitação.

Por exemplo, um driver pode receber uma solicitação de leitura ou gravação para uma quantidade de dados maior do que os destinos de E/S do driver podem lidar ao mesmo tempo. O driver deve dividir os dados em várias solicitações menores e enviar essas solicitações menores para um ou mais destinos de E/S. As técnicas para lidar com essa situação incluem:

  • Chamando IWDFDevice::CreateRequest para criar um único objeto de solicitação adicional que representa uma solicitação menor.

    O driver pode enviar essa solicitação de forma síncrona para um destino de E/S. A função de retorno de chamada IRequestCallbackRequestCompletion::OnCompletion da solicitação menor pode chamar IWDFIoRequest2::Reuse para que o driver possa reutilizar a solicitação e enviá-la para o destino de E/S novamente. Depois que o destino de E/S concluir a última das solicitações menores, a função de retorno de chamada OnCompletion poderá chamar IWDFObject::D eleteWdfObject para excluir o objeto de solicitação criado pelo driver e o driver poderá chamar IWDFIoRequest::Complete para concluir a solicitação original.

  • Chamar IWDFDevice::CreateRequest para criar vários objetos de solicitação adicionais que representam as solicitações menores.

    Os destinos de E/S do driver podem processar essas várias solicitações menores de forma assíncrona. O driver pode registrar uma função de retorno de chamada OnCompletion para cada uma das solicitações menores. Sempre que a função de retorno de chamada OnCompletion é chamada, ela pode chamar IWDFObject::D eleteWdfObject para excluir um objeto de solicitação criado pelo driver. Depois que o destino de E/S concluir todas as solicitações menores, o driver poderá chamar IWDFIoRequest::Complete para concluir a solicitação original.

Obtendo informações de conclusão

Para obter informações sobre uma solicitação de E/S que outro driver concluiu, um driver baseado em UMDF pode:

Além disso, um driver baseado em UMDF pode usar o método IWDFIoRequest2::GetStatus para obter o status atual de uma solicitação de E/S, antes ou depois da conclusão da solicitação.