UMDFでの I/O 要求の完了
警告
UMDF 2 は UMDF の最新バージョンであり、UMDF 1 に取って代わるものです。 すべての新しい UMDF ドライバーは、UMDF 2 を使用して記述する必要があります。 UMDF 1 には新機能が追加されておらず、Windows 10 の新しいバージョンでは UMDF 1 のサポートが制限されています。 ユニバーサル Windows ドライバーでは、UMDF 2 を使用する必要があります。
アーカイブされた UMDF 1 サンプルは、Windows 11, バージョン 22H2 - 2022 年 5 月 ドライバー サンプル アップデートでご確認いただけます。
詳しくは、UMDFの概要をご覧ください。
すべての I/O 要求は、最終的に UMDF ドライバーによって完了する必要があります。 要求を完了するには、ドライバーが IWDFIoRequest::Complete または IWDFIoRequest::CompleteWithInformation メソッドを呼び出す必要があります。 ドライバーが要求を完了すると、次のいずれかのシナリオが示されます。
要求された I/O 操作が正常に完了しました。
要求された I/O 操作は開始されましたが、完了する前に失敗しました。
要求された I/O 操作はサポートされていないか、受信した時点では無効であるため、デバイスと通信できません。
要求された I/O 操作が 取り消されました。
ドライバーは IWDFIoRequest ::CompleteWithInformation メソッドを呼び出して、要求操作に関する追加情報を渡します。 たとえば、読み取り操作の場合、ドライバーは読み取ったバイト数を指定する必要があります。
I/O 要求を完了するには、ドライバーは IWDFIoRequest::Complete または IWDFIoRequest::CompleteWithInformation の呼び出しで、CompletionStatus パラメーターに適切な完了状態を渡す必要があります。 ドライバーは、HRESULT コードを使用して、完了した要求の状態を伝えます。
UMDF ドライバー ホスト プロセスは、完了した要求をリフレクター (Wudfrd.sys) に渡す前に、HRESULT コードを NTSTATUS コードに変換します。 リフレクタは 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;
}
---------------------
}
ドライバーは、要求が正常に完了すると、HRESULT 値であるS_OKを返します。 S_OKは Winerror.h の NO_ERROR と Ntstatus.h の STATUS_SUCCESS に相当するため、変換マクロは必要ありません。
リフレクターに対してドライバー検証ツールが有効になっている場合は、無効な状態コードが識別され、システム バグチェックが発生します。
注: Windows XP のドライバー検証ツールでは、値が 10 進数の 1024 (1024L) を超える Win32 エラー コードに対して、誤ってシステム バグチェックが発生します。 ドライバーが Windows XP で実行されている場合は、リフレクターのドライバー検証ツールを有効にした場合、この問題に注意してください。
ドライバーが以前に下位レベルのドライバーに要求を送信した場合、ドライバーは、下位レベルのドライバーが要求を完了したときに通知を必要とします。 通知を登録するために、ドライバーは IWDFIoRequest::SetCompletionCallback メソッドを呼び出して、下位レベルのドライバーが要求を完了したときにフレームワークが呼び出すメソッドのインターフェイスを登録します。 ドライバーは、要求を完了するために必要な操作を実行する IRequestCallbackRequestCompletion::OnCompletion コールバック関数を実装します。
ドライバーは、IWDFDevice::CreateRequest を呼び出して作成した I/O 要求を完了しません。 代わりにドライバーは、通常 I/O ターゲットが要求を完了した後に、IWDFObject::D eleteWdfObject を呼び出して要求オブジェクトを削除する必要があります。です。
たとえば、ドライバーは、ドライバーの I/O ターゲットが一度に処理できるよりも大きい量のデータの読み取りまたは書き込み要求を受け取る場合があります。 ドライバーは、データを複数の小さな要求に分割し、これらの小さな要求を 1 つ以上の I/O ターゲットに送信する必要があります。 この状況を処理する手法は次のとおりです。
IWDFDevice::CreateRequest を呼び出して、より小さな要求を表す 1 つの追加要求オブジェクトを作成します。
ドライバーは、I/O ターゲットに同期的にこの要求を送信できます。 小さい要求の IRequestCallbackRequestCompletion::OnCompletion コールバック関数は、IWDFIoRequest2::Reuse を呼び出して、ドライバーが要求を再利用して I/O ターゲットに再度送信できるようにします。 I/O ターゲットが最後の小さい要求を完了すると、OnCompletion コールバック関数は IWDFObject::D eleteWdfObject を呼び出してドライバーが作成した要求オブジェクトを削除し、ドライバーは IWDFIoRequest::Complete を呼び出して元の要求を完了できます。
IWDFDevice::CreateRequest を呼び出して、より小さな要求を表す複数の追加要求オブジェクトを作成します。
ドライバーの I/O ターゲットは、これらの複数の小さな要求を非同期的に処理できます。 ドライバーは、小さい要求ごとに OnCompletion コールバック関数を登録できます。 OnCompletion コールバック関数が呼び出されるたびに、IWDFObject::D eleteWdfObject を呼び出して、ドライバーによって作成された要求オブジェクトを削除できます。 I/O ターゲットがすべての小さい要求を完了すると、ドライバーは IWDFIoRequest::Complete を呼び出して元の要求を完了できます。
完了情報の取得
別のドライバーが完了した I/O 要求に関する情報を取得するには、UMDF ベースのドライバーは次のことができます。
IWDFRequestCompletionParams インターフェイスを使用して、I/O 要求の完了状態やその他の情報を取得します。
IWDFIoRequestCompletionParams インターフェイスを使用して、I/O 要求のメモリ バッファーを取得します。
IWDFUsbRequestCompletionParams インターフェイスを使用して、USB ターゲット パイプ オブジェクトに送信された要求に関連するメモリ バッファーやその他の情報を取得します。
さらに、UMDF ベースのドライバーは、IWDFIoRequest2::GetStatus メソッドを使用して、要求が完了する前または後に、I/O 要求の現在の状態を取得できます。