Выполнение запросов ввода-вывода в UMDF
Предупреждение
UMDF 2 является последней версией UMDF и заменяет UMDF 1. Все новые драйверы UMDF должны быть написаны с помощью UMDF 2. В UMDF 1 новые функции не добавляются, а поддержка UMDF 1 в более новых версиях Windows 10 ограничена. Универсальные драйверы Windows должны использовать UMDF 2.
Архивные примеры UMDF 1 можно найти в Windows 11 версии 22H2 — обновление примеров драйверов за май 2022 г.
Дополнительные сведения см. в разделе начало работы с помощью UMDF.
В конечном итоге каждый запрос ввода-вывода должен быть выполнен драйвером UMDF. Для выполнения запроса драйвер должен вызвать метод IWDFIoRequest::Complete или IWDFIoRequest::CompleteWithInformation . Когда драйвер завершает запрос, он указывает на один из следующих сценариев:
Запрошенная операция ввода-вывода успешно завершена.
Запрошенная операция ввода-вывода запущена, но завершилась сбоем.
Запрошенная операция ввода-вывода не поддерживается или недействительна на момент ее получения и поэтому не может взаимодействовать с устройством.
Запрошенная операция ввода-вывода была отменена.
Драйвер вызывает метод IWDFIoRequest::CompleteWithInformation для передачи дополнительных сведений об операции запроса. Например, для операции чтения драйвер должен указать количество прочитанных байтов.
Для выполнения запроса ввода-вывода драйвер должен передать соответствующее состояние завершения параметру CompletionStatus в вызове IWDFIoRequest::Complete или IWDFIoRequest::Complete. Драйвер использует код HRESULT для передачи состояния завершенного запроса.
Хост-процесс драйвера UMDF преобразует код HRESULT в код NTSTATUS перед тем, как он передает завершенный запрос отражателю (Wudfrd.sys). Отражатель передает код NTSTATUS операционной системе. Операционная система преобразует код NTSTATUS в код ошибки Microsoft Win32, прежде чем будет представлен результат вызывающему приложению.
Чтобы убедиться, что коды ошибок драйвера можно преобразовать правильно, следует создать коды ошибок с помощью любого из следующих методов:
Используйте код ошибки из Winerror.h и примените макрос HRESULT_FROM_WIN32.
Используйте код ошибки из Ntstatus.h и примените макрос HRESULT_FROM_NT.
Дополнительные сведения об этих макросах см. в документации по Microsoft Windows SDK.
В следующем примере кода показано, как выполнить запрос с подходящим кодом ошибки:
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;
}
---------------------
}
Когда драйвер успешно завершает запрос, он возвращает S_OK, который является значением HRESULT. Поскольку S_OK эквивалентна NO_ERROR в Winerror.h и STATUS_SUCCESS в Ntstatus.h, макросы преобразования не требуются.
Если средство проверки драйверов включено для отражателя, он определяет недопустимый код состояния и вызывает проверку системных ошибок.
Примечание Средство проверки драйверов для Windows XP неправильно вызывает проверку системных ошибок для кодов ошибок Win32, значения которых превышают десятичные значения 1024 (1024L). Если ваш драйвер работает в Windows XP, обратите внимание на эту проблему, если вы включили средство проверки драйверов для отражателя.
Если драйвер ранее отправлял запрос драйверу более низкого уровня, драйвер должен получить уведомление, когда драйвер нижнего уровня завершает запрос. Чтобы зарегистрироваться для получения уведомлений, драйвер вызывает метод IWDFIoRequest::SetCompletionCallback , чтобы зарегистрировать интерфейс метода, вызываемого платформой, когда драйвер нижнего уровня завершает запрос. Драйвер реализует функцию обратного вызова IRequestCallbackRequestCompletion::OnCompletion для выполнения операций, необходимых для выполнения запроса.
Драйвер не завершает созданный им запрос ввода-вывода путем вызова IWDFDevice::CreateRequest. Вместо этого драйвер должен вызвать IWDFObject::D eleteWdfObject , чтобы удалить объект запроса, как правило, после завершения запроса целевым объектом ввода-вывода.
Например, драйвер может получить запрос на чтение или запись для объема данных, который больше, чем может обрабатываться целевыми объектами ввода-вывода драйвера за один раз. Драйвер должен разделить данные на несколько небольших запросов и отправить эти небольшие запросы в один или несколько целевых объектов ввода-вывода. Ниже приведены методы обработки этой ситуации.
Вызов IWDFDevice::CreateRequest для создания одного дополнительного объекта запроса, представляющего запрос меньшего размера.
Драйвер может отправить этот запрос синхронно в целевой объект ввода-вывода. Функция обратного вызова IRequestCallbackRequestCompletion::OnCompletion меньшего запроса может вызывать IWDFIoRequest2::Reuse , чтобы драйвер смог повторно использовать запрос и снова отправить его в целевой объект ввода-вывода. После того как целевой объект ввода-вывода завершит последний из небольших запросов, функция обратного вызова OnCompletion может вызвать IWDFObject::D eleteWdfObject для удаления созданного драйвером объекта запроса, а драйвер может вызвать IWDFIoRequest::Complete для завершения исходного запроса.
Вызов IWDFDevice::CreateRequest для создания нескольких дополнительных объектов запросов, представляющих запросы меньшего размера.
Целевые объекты ввода-вывода драйвера могут асинхронно обрабатывать эти несколько небольших запросов. Драйвер может зарегистрировать функцию обратного вызова OnCompletion для каждого меньшего запроса. При каждом вызове функции обратного вызова OnCompletion она может вызывать IWDFObject::D eleteWdfObject для удаления созданного драйвером объекта запроса. После того как целевой объект ввода-вывода завершит все запросы меньшего размера, драйвер может вызвать IWDFIoRequest::Complete для завершения исходного запроса.
Получение сведений о завершении
Чтобы получить сведения о запросе ввода-вывода, выполненном другим драйвером, драйвер на основе UMDF может:
Используйте интерфейс IWDFRequestCompletionParams , чтобы получить состояние выполнения запроса ввода-вывода и другие сведения.
Используйте интерфейс IWDFIoRequestCompletionParams для получения буферов памяти запроса ввода-вывода.
Используйте интерфейс IWDFUsbRequestCompletionParams для получения буферов памяти и других сведений, связанных с запросом, отправленным в целевой объект USB-канала.
Кроме того, драйвер на основе UMDF может использовать метод IWDFIoRequest2::GetStatus для получения текущего состояния запроса ввода-вывода до или после завершения запроса.