UMDF 1.x ドライバーでのカーネルモード クライアントのサポート
警告
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 の概要」をご覧ください。
警告
「UMDF 2.x でのカーネルモード クライアントのサポート」も参照してください。
UMDF バージョン 1.9 以降では、UMDF ドライバーでカーネルモード クライアントをサポートできます。 カーネルモード クライアントには、次のいずれかを指定できます。
デバイスのドライバー スタック内の UMDF ドライバーの上に存在するカーネルモード ドライバー。
1 つのデバイスをサポートするデバイス スタックのカーネルモード ドライバーは、別のデバイスへのハンドルを開き、もう 1 つのデバイスのドライバー スタックには UMDF ドライバーが含まれています。
つまり、カーネルモード クライアントをサポートする UMDF ドライバーは、カーネルモード ドライバーから I/O 要求を受信できます。 カーネルモード ドライバーは、ユーザーモード アプリケーションから受信した I/O 要求を転送したり、新しい I/O 要求を作成してユーザーモード ドライバーに送信したりできます。
UMDF ドライバーがカーネルモード クライアントをサポートする必要があるかどうかを判断するには、ドライバーが追加されるドライバー スタックと、そのスタック内のどこにドライバーが存在かを理解する必要があります。 また、別のスタックのドライバーがドライバーのデバイスに I/O 要求を送信する可能性があるかどうかを判断する必要もあります。
ドライバーは、次の場合にカーネルモード クライアントをサポートする必要があります。
カーネルモード ドライバーは、ドライバー スタック内の UMDF ドライバーのすぐ上に位置する場合があります。 たとえば、カーネルモード フィルター ドライバーは、UMDF ベースの関数ドライバーのすぐ上に存在する可能性があります。
別のスタックのカーネルモード ドライバーは、ドライバーのデバイスに I/O 要求を送信できます。 たとえば、ドライバーは、別のスタック内のカーネルモード ドライバーがドライバーのデバイスへのハンドルを開くために使用できるシンボリック リンクを作成する場合があります。 カーネルモード ドライバーは、デバイスに I/O 要求を送信できます。
UMDF ドライバーでカーネルモード クライアントをサポートする方法
UMDF ドライバーは、UMDF ドライバーがカーネルモード クライアントのサポートを有効にしている場合にのみ、カーネルモード ドライバーから I/O 要求を受信できます。 さらに、デバイスのインストールがデバイスのドライバー スタック内の UMDF ドライバーの上にカーネルモード ドライバーを読み込もうとすると、フレームワークは、UMDF ドライバーがカーネルモード クライアントのサポートを有効にしている場合にのみ、ドライバーを読み込むことができます。
UMDF ドライバーによるカーネルモード クライアントのサポートを有効にするには、UMDF ドライバーの INF ファイルに、その INF の DDInstall WDF セクションに UmdfKernelModeClientPolicy ディレクティブを含める必要があります。 UMDF ドライバーの INF ファイルにこのディレクティブが含まれていない場合、UMDF は UMDF ドライバーの上にインストールされているカーネルモード ドライバーの実行を許可しません。
フレームワークには、カーネルモード クライアントをサポートするドライバーに役立つ 2 つのメソッドが用意されています。 ドライバーは、IWDFIoRequest2::GetRequestorMode メソッドを呼び出して、I/O 要求がカーネルモードまたはユーザーモードから送信されたかどうかを判断できます。 I/O 要求がユーザーモードから送信された場合、ドライバーは IWDFIoRequest2::IsFromUserModeDriver を呼び出して、要求がアプリケーションまたは別のユーザーモード ドライバーから送信されたかどうかを判断できます。
カーネルモード ドライバーに関する制限事項
UMDF ドライバーは、カーネルモード ドライバーが次の要件を満たしている場合にのみ、カーネルモード ドライバーからの I/O 要求を処理できます。
カーネルモード ドライバーは、I/O 要求を送信するときに IRQL = PASSIVE_LEVEL で実行されている必要があります。
ドライバーが UmdfFileObjectPolicy INF ディレクティブを AllowNullAndUnknownFileObjects に設定していない限り、カーネルモード ドライバーがユーザーモード ドライバーに送信する各 I/O 要求には、関連付けられているファイル オブジェクトが必要です。 I/O マネージャーがファイル オブジェクトを作成したことをフレームワークに事前に通知しておく必要があります。 (このような通知により、フレームワークはユーザーモード ドライバー を呼び出します。IQueueCallbackCreate::OnCreateFile コールバック関数ですが、そのコールバック関数は省略可能です。)
I/O 要求に IRP_MJ_INTERNAL_DEVICE_CONTROL 関数コードを含めることはできません。
ユーザーモード ドライバーはポインターを逆参照できないため、I/O 要求のバッファーには追加情報へのポインターを含めることはできません。
I/O 要求に "どちらでもない" バッファー アクセス メソッドを指定する I/O 制御コードが含まれている場合、カーネルモード ドライバーは、I/O 要求を作成したアプリケーションのプロセス コンテキストで I/O 要求を送信する必要があります。 UMDF ベース ドライバーで "どちらでもない" メソッドをサポートする方法の詳細については、「UMDF ドライバーでバッファー I/O もダイレクト I/O も使用しない」を参照してください。
UMDF ドライバーは、ユーザーモードで I/O 要求の出力データを変更する場合があります。 したがって、カーネルモード ドライバーは、ユーザーモード ドライバーから受信するすべての出力データを検証する必要があります。
通常、カーネルモード クライアントは、UMDF ドライバーが IWDFIoRequest::CompleteWithInformation に渡す情報値を検証する必要があります。 クライアントが KMDF ドライバーの場合は、WdfRequestGetCompletionParams を呼び出して、IO_STATUS_BLOCK 構造体でこの情報を取得できます。
通常、フレームワークは、UMDF ドライバーが IWDFIoRequest::CompleteWithInformation に渡す情報値を検証しません。 (このパラメーターは通常、転送されたバイト数を指定します)。フレームワークは、出力バッファーに対してのみ情報値を検証し、バッファー I/O データ アクセス メソッドに対してのみ検証します。 (たとえば、フレームワークは、アクセス メソッドがバッファー I/O である場合、転送されたバイト数が読み取り操作の出力バッファー サイズを超えていないことを確認します。)
UMDF 1.x ドライバーでの戻り値の処理
戻り値をユーザーモードからカーネルモードに渡すには、以下のように特に注意が必要です。
UMDF バージョン 1 ドライバーは通常、HRESULT 型の戻り値を受け取りますが、KMDF および WDM ベースのカーネルモード ドライバーは通常、NTSTATUS 型の値を受け取ります。 UMDF 1.x ドライバーが I/O 要求を完了し、ドライバーにカーネルモード クライアントがある場合、ドライバーの呼び出し IWDFIoRequest::Complete または IWDFIoRequest::CompleteWithInformation は、ドライバーが NTSTATUS 値から生成する HRESULT 値を指定する必要があります。 一般には、UMDF 1.x ドライバーは、HRESULT_FROM_NT マクロ (Winerror.h で定義) を使用して、カーネルモード クライアントに状態を返す必要があります。 次の例は、要求を完了するときにこのマクロを使用する方法を示しています。
hr = HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW) request->Complete(HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW); return hr;
特定の HRESULT 値をカーネルモード クライアントに返すには、次のコールバックで HRESULT_FROM_NT マクロを使用する必要があります。
- IPnpCallback::OnQueryRemove
- IPnpCallback::OnQueryStop
- IPnpCallbackHardware::OnPrepareHardware
- IPnpCallbackHardware::OnReleaseHardware
ntstatus.h で定義されている NTSTATUS 値を使用するには、UMDF 1.x ドライバーは、追加のヘッダーを含める前に、これら 2 つの行を含める必要があります。
#define UMDF_USING_NTSTATUS #include <ntstatus.h>
HRESULT_FROM_NT マクロを使用して、STATUS_SUCCESS を NTSTATUS 値から HRESULT 値に変換しないでください。 次の例に示すように、S_OK を返すだけです。
request->Complete(S_OK);
フレームワークは、UMDF ドライバーに代わって一部の I/O 要求を完了します。 フレームワークが HRESULT 型の戻り値を同等の NTSTATUS 値に変換しないことがあるため、フレームワークは HRESULT 型の完了状態をカーネルモード クライアントに渡す場合があります。
このような状況のため、NT_ERROR マクロは HRESULT エラー値に対して TRUE を返さないため、I/O 要求の完了状態をテストするときにカーネルモード クライアントは NT_ERROR マクロを使用しないでください。 カーネルモード ドライバーは、I/O 要求の完了状態をテストするときに、NT_SUCCESS マクロを使用する必要があります。
以前の UMDF バージョンでのカーネルモード クライアントのサポート
バージョン 1.9 より前の UMDF バージョンの場合、ドライバーの INF ファイルに INF AddReg ディレクティブを含めて、デバイスのハードウェア キーの WUDF サブキーの下に REG_DWORD サイズの UpperDriverOk レジストリ値を作成できます。
UpperDriverOk レジストリ値が 0 以外の数値に設定されている場合、フレームワークでは、カーネルモード ドライバーがユーザーモード ドライバーの上に読み込むことができます。 カーネルモード ドライバーは、ユーザーモード アプリケーションから UMDF ドライバーに I/O 要求を転送できますが、カーネルモード ドライバーは、UMDF ドライバーにカーネルモードで作成された I/O 要求を送信できません。
UMDF バージョン 1.9 以降では、UpperDriverOk レジストリ値は廃止され、既存のドライバーでのみサポートされています。 新しいドライバーでは、UmdfKernelModeClientPolicy ディレクティブを使用する必要があります。