カーネル モードのクライアントのサポート
Version 1.9 以降の UMDF では、UMDF ベースのドライバーで "カーネル モードのクライアント" をサポートできます。カーネル モードのクライアントには次の 2 種類があります。
デバイスのドライバー スタックで UMDF ベースのドライバーの上位に存在するカーネル モード ドライバー。
ドライバー スタックに UMDF ベースのドライバーを含むデバイスへのハンドルを開く、そのデバイスとは別のデバイスをサポートするデバイス スタックのカーネル モード ドライバー。
つまり、カーネル モードのクライアントをサポートする UMDF ベースのユーザー モード ドライバーは、カーネル モード ドライバーから I/O 要求を受信できます。カーネル モード ドライバーでは、ユーザー モード アプリケーションから受信した I/O 要求をユーザー モード ドライバーに転送したり、新しい I/O 要求を作成してユーザー モード ドライバーに送信したりできます。
UMDF ベースのドライバーでカーネル モードのクライアントをサポートする必要があるかどうかを判定するには、そのドライバーが追加されるドライバー スタックと、そのドライバーのスタック内での位置を把握する必要があります。また、別のスタックのドライバーからそのドライバーのデバイスに I/O 要求が送信されるかどうかを確認する必要もあります。
次のような場合は、ドライバーでカーネル モードのクライアントをサポートする必要があります。
ドライバー スタックでその UMDF ベース ドライバーのすぐ上にカーネル モード ドライバーが配置される可能性がある場合。たとえば、カーネル モードのフィルター ドライバーは UMDF ベースの関数ドライバーのすぐ上に配置される可能性があります。
そのドライバーのデバイスに別のスタックのカーネル モード ドライバーから I/O 要求が送信される可能性がある場合。たとえば、ドライバーで、別のスタックのカーネル モード ドライバーがドライバーのデバイスへのハンドルを開くために使用できるシンボリック リンクを作成した場合、そのカーネル モード ドライバーはドライバーのデバイスに I/O 要求を送信できます。
UMDF ベースのドライバーでカーネル モードのクライアントをサポートする方法
UMDF ベースのドライバーがカーネル モード ドライバーから I/O 要求を受信できるのは、その UMDF ベースのドライバーでカーネル モードのクライアントのサポートが有効になっている場合だけです。さらに、デバイスのインストール時にカーネル モード ドライバーがデバイスのドライバー スタックで UMDF ベースのドライバーの上位に読み込まれるのが許可されるのも、その UMDF ベースのドライバーでカーネル モードのクライアントのサポートが有効になっている場合だけです。
UMDF ベースのドライバーでカーネル モードのクライアントのサポートを有効にするには、その UMDF ベースのドライバーの INF ファイルの INF DDInstall.WDF セクションに UmdfKernelModeClientPolicy ディレクティブを含める必要があります。UMDF ベースのドライバーの INF ファイルにこのディレクティブが含まれていないと、UMDF ベースのドライバーの上位にインストールされるカーネル モード ドライバーの実行が UMDF で許可されません。
フレームワークには、カーネル モードのクライアントをサポートするドライバーで役に立つ 2 つのインターフェイス メソッドが用意されています。ドライバーで IWDFIoRequest2::GetRequestorMode メソッドを呼び出すと、I/O 要求の送信元がカーネル モードかユーザー モードかを確認できます。要求の送信元がユーザー モードだった場合は、IWDFIoRequest2::IsFromUserModeDriver を呼び出して、送信元がアプリケーションか別のユーザー モード ドライバーかを確認できます。
カーネル モード ドライバーに関する制約
UMDF ベースのドライバーでカーネル モード ドライバーからの I/O 要求を処理できるのは、そのカーネル モード ドライバーが以下の要件を満たしている場合だけです。
I/O 要求の送信時にカーネル モード ドライバーが IRQL = PASSIVE_LEVEL で実行されている必要があります。
カーネル モード ドライバーがユーザー モード ドライバーに送信する各 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 ベースのドライバーによってユーザー モードで変更される可能性があるため、ユーザー モード ドライバーから受信した出力データをカーネル モード ドライバーで検証する必要があります。
カーネル モードのクライアントでは、通常、UMDF ベースのドライバーが IWDFIoRequest::CompleteWithInformation に渡す Information の値を検証する必要があります (KMDF ベースのドライバーでこの情報を取得するには、WdfRequestGetCompletionParams を呼び出して IO_STATUS_BLOCK 構造体に取得します)。
通常は、UMDF ベースのドライバーが IWDFIoRequest::CompleteWithInformation に渡す information の値はフレームワークで検証されません (このパラメーターは、通常、転送されるバイト数を指定します)。information の値は、バッファー付き I/O データ アクセス方式が使用されている場合に出力バッファーに対してのみ検証されます (たとえば、アクセス方式がバッファー付き I/O の場合は、転送されるバイト数が読み取り操作の出力バッファーのサイズを超えていないかどうかが確認されます)。
状態の戻り値の処理
ユーザー モードからカーネル モードに状態の戻り値を渡す際には、以下の点に注意する必要があります。
UMDF ベースのドライバーが受け取る一般的な戻り値は HRESULT 型ですが、KMDF ベースおよび WDM ベースのカーネル モード ドライバーが受け取る一般的な戻り値は NTSTATUS 型です。カーネル モードのクライアントをサポートする UMDF ベースのドライバーで I/O 要求を完了するには、IWDFIoRequest::Complete または IWDFIoRequest::CompleteWithInformation の呼び出しで、NTSTATUS 型の値から生成した HRESULT 型の値を指定する必要があります。
HRESULT 型の値を作成するには、次のように、HRESULT_FROM_NT マクロ (Winerror.h で定義されています) を使用します。
request->Complete(HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW);
このマクロによって生成される戻り値は、ユーザー モードでは HRESULT 型の値として、カーネル モードでは NTSTATUS 型の値として使用できます。
このマクロを使用して STATUS_SUCCESS を NTSTATUS 値から HRESULT 値に変換しないでください。次のように、単純に S_OK を返します。
request->Complete(S_OK);
I/O 要求の中には、UMDF ベースのドライバーに代わってフレームワークが完了するものもあります。フレームワークでは、HRESULT 型の戻り値が対応する NTSTATUS 値に変換されない場合があるため、カーネル モードのクライアントに HRESULT 型の完了状態が渡される可能性があります。
そのため、カーネル モードのクライアントで I/O 要求の完了状態をテストする際には NT_ERROR マクロを使用しないでください。NT_ERROR マクロでは、HRESULT のエラー値に対して TRUE が返されません。カーネル モード ドライバーで I/O 要求の完了状態をテストする際には NT_SUCCESS マクロを使用してください。
以前のバージョンの UMDF でのカーネル モードのクライアントのサポート
Version 1.9 より前のバージョンの UMDF では、ドライバーの INF ファイルに INF AddReg ディレクティブを含めて、デバイスのハードウェア キーの WUDF サブキーの下に REG_DWORD 型の UpperDriverOk レジストリ値を作成することができます。
UpperDriverOk レジストリ値が 0 以外の数値に設定されている場合は、カーネル モード ドライバーがユーザー モード ドライバーの上位に読み込まれるのがフレームワークで許可されます。この場合、カーネル モード ドライバーは、ユーザー モード アプリケーションから UMDF ベースのドライバーに I/O 要求を転送することはできますが、カーネル モードで作成された I/O 要求を UMDF ベースのドライバーに送信することはできません。
Version 1.9 以降の UMDF では、UpperDriverOk レジストリ値は廃止されており、既存のドライバーに対してのみサポートされています。新しいドライバーでは UmdfKernelModeClientPolicy ディレクティブを使用する必要があります。