制御デバイス オブジェクトの使用

コントロール デバイス オブジェクトは、プラグ アンド プレイ (PnP) または電源管理操作をサポートしないフレームワーク デバイス オブジェクトです。 ドライバーは、コントロール デバイス オブジェクトを使用して、ソフトウェアのみの仮想デバイスまたは レガシ ハードウェア デバイス (つまり、PnP または電源管理機能を提供しないデバイス) を表すことができます。

コントロール デバイス オブジェクトを作成するドライバーは、通常、デバイス オブジェクトのシンボリック リンクも作成します。 アプリケーションは、Microsoft Win32 CreateFile 関数などの API 要素にシンボリック リンク名を渡すことによって、コントロール デバイス オブジェクトに I/O 要求を送信できます。

フレームワークは、コントロール デバイス オブジェクトをデバイス スタックにアタッチしません。 そのため、アプリケーションがコントロール デバイス オブジェクトに I/O 要求を送信すると、I/O マネージャーは、スタックの上部にあるドライバーではなく、コントロール デバイス オブジェクトを作成したドライバーに直接要求を配信します。 (ただし、追加のドライバーが コントロール デバイス オブジェクトの上にデバイス オブジェクトをアタッチするために IoAttachDevice を呼び出すことがあります。この場合、追加のドライバーが最初に I/O 要求を受け取ります)。

コントロール デバイス オブジェクトの使用

コントロール デバイスの一般的な用途は次の 2 つです。

  1. PnP デバイスのフィルター ドライバー (ドライバーがアプリケーションで使用するカスタム I/O コントロール コードのセットをサポートしている場合)。

    アプリケーションが、(たとえばデバイス インターフェイスのシンボリック リンク名を使用して) カスタム I/O コントロール コードをドライバー スタックの先頭に送信しようとした場合、ドライバーがカスタム I/O コントロール コードを認識しなかった場合、フィルター ドライバーの上のドライバーは I/O 要求に失敗する可能性があります。 この問題を回避するために、フィルター ドライバーは、コントロール デバイス オブジェクトを作成できます。 アプリケーションでは、コントロール デバイス オブジェクトのシンボリック リンク名を使用して、フィルター ドライバーに直接 I/O コントロール コードを送信できます。

    (フィルター ドライバーが問題を回避するためのより良い方法は、バス ドライバーとして機能し、raw モードで動作する子デバイスを列挙することです。 つまり、フィルター ドライバーがサポートするデバイスごとに、ドライバーは、ファンクション ドライバーを必要としない物理デバイス オブジェクト (PDO) を作成できます。 ドライバーは、これらの各デバイスの WdfPdoInitAssignRawDeviceWdfDeviceInitAssignName を呼び出します。アプリケーションは、カスタム I/O コントロール コードを送信するときに、名前でデバイスを識別できます)。

  2. PnP をサポートしていないデバイスのドライバー。

    このようなデバイスのデバイス オブジェクトはデバイス スタック内に存在せず、PnP 機能を提供しないため、このようなドライバーは、コントロール デバイス オブジェクトを使用する必要があります。 非 PnP デバイスのサポートの詳細については、「非 PnP ドライバーでのカーネルモード ドライバー フレームワークの使用」を参照してください。

コントロール デバイス オブジェクトの作成

コントロール デバイス オブジェクトを作成するには、ドライバーで次の操作を行う必要があります。

  1. WdfControlDeviceInitAllocate を呼び出して、WDFDEVICE_INIT 構造体を取得します。

  2. 必要に応じてオブジェクト初期化メソッドを呼び出して、WDFDEVICE_INIT 構造体を初期化します。 ドライバーは、次の初期化メソッドのみを呼び出すことができます。

  3. WdfDeviceCreate を呼び出します。このメソッドは、WDFDEVICE_INIT 構造体の内容を使用してフレームワーク デバイス オブジェクトを作成します。

  4. 次の初期化操作を完了します。

  5. WdfControlFinishInitializing を呼び出します。

コントロールデバイスオブジェクトの使用に関するルール

コントロール デバイス オブジェクトを作成するドライバーは、次の規則に従う必要があります。

  • ドライバーは、子デバイスを列挙するフレームワーク メソッドに、コントロール デバイス オブジェクトのハンドルを渡すことはできません。

  • ドライバーは、デバイス インターフェイスをサポートするフレームワーク メソッドにコントロール デバイス オブジェクトのハンドルを渡すことはできません。

  • ドライバーは、I/O キューを作成して、キューの要求ハンドラーを登録できますが、フレームワークではキューを電源管理キューにはできません。

  • ドライバーは、コントロール デバイス オブジェクトのファイル オブジェクトを作成できます。

コントロール デバイス オブジェクトの名前付け

すべてのコントロール デバイス オブジェクトに名前を付ける必要があります。 通常、ドライバーは WdfDeviceInitAssignName を呼び出してデバイス名を割り当てた後、WdfDeviceCreateSymbolicLink を呼び出して、アプリケーションがオブジェクトへのアクセスに使用できるシンボリック リンク名を作成します。

ドライバーがデバイス名を割り当てるために WdfDeviceInitAssignName を呼び出さなかった場合、フレームワークはコントロール デバイスの名前を自動的に生成しますが、ドライバーは WdfDeviceCreateSymbolicLink を呼び出すことができません。

ドライバーは、WdfDeviceInitSetDeviceClass を呼び出して、コントロール デバイスのデバイス セットアップ クラスを指定できます。 デバイス セットアップ クラスは、セットアップ クラスに属するデバイスに関する、管理者が指定した情報を含むレジストリのセクションを特定します。 WdfDeviceInitSetDeviceClass の呼び出しの詳細については、「フレームワークベースのドライバーでのデバイス アクセスの制御」を参照してください。

システムシャットダウンの通知の受信

コントロール デバイス オブジェクトは PnP をサポートしていないため、ドライバーは、デバイスの電源状態が変化したときにドライバーに通知するコールバック関数を登録できません。 ただし、ドライバーは WdfControlDeviceInitSetShutdownNotification を呼び出して EvtDeviceShutdownNotification コールバック関数を登録できます。 このコールバック関数は、システムの電源が失われるときにドライバーに通知します。

コントロール デバイス オブジェクトの削除

一部のドライバーは、次のように、ドライバーがアンロードされる前に、コントロール デバイス オブジェクトを削除する必要があります。

  • ドライバーが (PnP も電源管理もサポートしていない) コントロール デバイス オブジェクトを作成し、ドライバーが PnP と電源管理をサポートするフレームワーク デバイス オブジェクトも作成する場合、ドライバーは最終的に WdfObjectDelete を IRQL = PASSIVE_LEVEL で呼び出して、コントロール デバイス オブジェクトを削除する必要があります。

    ドライバーが両方の種類のデバイス オブジェクトを作成する場合、ドライバーがコントロール デバイス オブジェクトを削除するまで、オペレーティング システムはドライバーをアンロードできません。

    ただし、フレームワークが他のデバイス オブジェクトを削除するまで、ドライバーはコントロール デバイス オブジェクトを削除しないでください。 フレームワークが他のデバイス オブジェクトを削除したタイミングを判断するには、ドライバーは、これらのオブジェクトの EvtCleanupCallback 関数を提供する必要があります。

  • ドライバーがコントロール デバイス オブジェクトを作成しても、PnP と電源管理をサポートするフレームワーク デバイス オブジェクトを作成しない場合、ドライバーはコントロール デバイス オブジェクトを削除する必要はありません。

    この場合、フレームワークは、ドライバーの EvtDriverUnload コールバック関数が返された後、コントロール デバイス オブジェクトを削除します。