I/O 要求の完了

すべてのフレームワークベースのドライバーは、最終的に、フレームワークから受け取ったすべての I/O 要求を完了する必要があります。ドライバーは、要求オブジェクトの WdfRequestCompleteWdfRequestCompleteWithInformation、または WdfRequestCompleteWithPriorityBoost の各メソッドを呼び出すことで要求を完了します。

要求を完了する状況

ドライバーは、次のいずれかの場合に該当すると判断したときに要求を完了する必要があります。

  • 要求された I/O 操作が正常に完了した場合。

  • 要求された I/O 操作が開始されたが、完了前に失敗した場合。

  • 要求された I/O 操作がサポートされていないか受け取った時点で有効でなかったために、開始できなかった場合。

  • 要求された I/O 操作が取り消された場合。

ドライバーがデバイス上に I/O アクティビティを作成することで I/O 要求にサービスを提供する場合、ドライバーは通常、その EvtInterruptDpc コールバック関数または EvtDpcFunc コールバック関数から WdfRequestComplete を呼び出します。

ドライバーがサポート外またはそれ以外の無効な要求を受け取った場合、ドライバーは通常、要求を受け取った要求ハンドラーから WdfRequestComplete を呼び出します。

I/O 操作が取り消された場合、ドライバーは通常、その EvtRequestCancel コールバック関数から WdfRequestComplete を呼び出します。

ドライバーが I/O 要求を I/O ターゲット転送する場合、ドライバーは次のように I/O ターゲットが要求を完了した後で要求を完了します。

  • ドライバーが I/O 要求を I/O ターゲットに同期的に転送する場合、ドライバーの I/O ターゲットへの呼び出しは、(エラーが発生しない限り) 下位レベルのドライバーが要求を完了してから返されます。I/O ターゲットから制御が戻った後で、ドライバーは WdfRequestComplete を呼び出す必要があります。

  • ドライバーが I/O 要求を非同期的に転送する場合、下位レベルのドライバーが要求を完了したときにドライバーが通知を受ける必要が生じることがあります。ドライバーが CompletionRoutine コールバック関数を登録した場合、フレームワークは、I/O ターゲットが要求を完了した後にこのコールバック関数を呼び出します。CompletionRoutine コールバック関数は、通常、WdfRequestComplete を呼び出します。

ドライバーは、CompletionRoutine コールバック関数を登録するために、I/O ターゲットに I/O 要求を転送する前に WdfRequestSetCompletionRoutine を呼び出す必要があります。

I/O ターゲットが非同期的に転送された I/O 要求を完了したときにドライバーが通知を受ける必要がない場合は、ドライバーが CompletionRoutine コールバック関数を登録する必要はありません。代わりに、ドライバーは WdfRequestSend の呼び出し時に WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET フラグを設定できます。その場合、ドライバーは WdfRequestComplete を呼び出しません。

ドライバーは、WdfRequestCreate または WdfRequestCreateFromIrp の呼び出しによって作成した I/O 要求を完了しません。代わりに、ドライバーは (通常は I/O ターゲットが要求を完了した後で) WdfObjectDelete を呼び出して要求オブジェクトを削除する必要があります。

たとえば、ドライバーが、その I/O ターゲットが一度に処理できる量を超えるデータの読み取りまたは書き込み要求を受け取ったとします。ドライバーはデータをいくつかの小さい要求に分割して、それらの小さい要求を 1 つ以上の I/O ターゲットに送信する必要があります。この状況に対処するには、下記の方法があります。

  • WdfRequestComplete を呼び出して、小さい要求を表す追加の要求オブジェクトを 1 つ作成します。

    ドライバーは、この要求を I/O ターゲットに同期的に送信できます。小さい要求の CompletionRoutine コールバック関数は、WdfRequestReuse を呼び出し、ドライバーが要求を再利用して再度 I/O ターゲットに送信できるようにします。I/O ターゲットが最後の小さい要求を完了すると、CompletionRoutine コールバック関数は WdfObjectDelete を呼び出してドライバー作成の要求オブジェクトを削除でき、ドライバーは WdfRequestComplete を呼び出して元の要求を完了できます。

  • WdfRequestComplete を呼び出して、小さい要求を表す追加の要求オブジェクトを複数作成します。

    ドライバーの I/O ターゲットは、これらの複数の要求を非同期的に処理できます。ドライバーは、小さい要求のそれぞれに対して CompletionRoutine コールバック関数を登録できます。CompletionRoutine コールバック関数が呼び出されるたびに、このコールバック関数は WdfObjectDelete を呼び出してドライバー作成の要求オブジェクトを削除できます。I/O ターゲットが小さい要求をすべて完了したら、ドライバーは WdfRequestComplete を呼び出して元の要求を完了できます。

完了情報の提供

ドライバーは、要求を完了する際に、他のドライバーがアクセスできるいくつかの追加情報を必要に応じて提供できます。たとえば、読み取りまたは書き込み要求のために転送されたバイト数を提供できます。この情報を提供するために、ドライバーは次のいずれかの処理を実行できます。

完了情報の取得

他のドライバーが完了した I/O 要求に関する情報を取得するために、ドライバーは次の処理を実行できます。

  • WdfRequestGetStatus を呼び出して、下位レベルのドライバーが WdfRequestComplete を呼び出した際に指定した完了状態の値を取得します。

  • WdfRequestGetCompletionParams を呼び出して、WDF_REQUEST_COMPLETION_PARAMS 構造体を取得します。この構造体には、完了した要求に関する追加情報 (要求のバッファーを表すメモリー オブジェクトへのハンドルなど) またはバス固有の情報が含まれます。

    ドライバーは、WdfRequestSend を呼び出して I/O ターゲットに I/O 要求を同期的または非同期的に送信した後にのみ、WdfRequestGetCompletionParams を呼び出すことができます。ドライバーは、I/O ターゲットに I/O 要求を同期的にのみ送信するメソッド (WdfIoTargetSendReadSynchronously など) を呼び出した後に WdfRequestGetCompletionParams を呼び出すことはできません。

  • WdfRequestGetInformation を呼び出して、下位レベルのドライバーが WdfRequestSetInformation または WdfRequestCompleteWithInformation を呼び出した際に指定した追加の I/O 完了情報を取得します (ドライバー スタック内のドライバーがそのような情報を提供している場合)。

ドライバーが I/O 要求を同期的に送信する場合、ドライバーは通常、同期呼び出しが戻された後で WdfRequestGetStatusWdfRequestGetCompletionParams、 および WdfRequestGetInformation を呼び出します。ドライバーが I/O 要求を非同期的に送信する場合、ドライバーは通常、これらのメソッドを CompletionRoutine コールバック関数から呼び出します。

I/O 要求の完了の詳細については、「取り消しと完了のコードの同期化」を参照してください。