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:
Use a interface IWDFRequestCompletionParams para obter a conclusão de uma solicitação de E/S status e outras informações.
Use a interface IWDFIoRequestCompletionParams para obter os buffers de memória de uma solicitação de E/S.
Use a interface IWDFUsbRequestCompletionParams para obter buffers de memória e outras informações relacionadas a uma solicitação que foi enviada para um objeto de pipe de destino USB.
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.