ドライバー パッケージの分離

ドライバー パッケージの分離は、外部の変更に対するドライバー パッケージの回復性を高め、更新を容易にし、インストールをよりわかりやすいものにする、Windows ドライバーの要件です。

Note

ドライバー パッケージの分離は Windows ドライバーで必須ですが、Windows デスクトップ ドライバーでも回復性とサービス性の向上を通じてメリットが得られます。

次の表では、Windows ドライバーで使用できなくなった従来のドライバー パッケージ手法のいくつかの例を左の列に、Windows ドライバーで必須の動作を右の列に示します。

分離されていないドライバー 分離されているドライバー
INF により、ファイルが %windir%\System32 または %windir%\System32\drivers にコピーされる ドライバー ファイルはドライバー ストアから実行される
ハードコーディングされたパスを使用してデバイスのスタック/ドライバーと対話する システム提供の関数またはデバイス インターフェイスを使用してデバイスのスタック/ドライバーと対話する
パスをグローバルなレジストリの場所にハードコーディングする レジストリの相対的な場所とファイルの状態を指定するために、HKR とシステムが提供する関数を使用する
ランタイム ファイルは任意の場所に書き込まれる ファイルは、オペレーティング システムによって提供される場所を基準にして書き込まれる

お使いのドライバー パッケージがドライバー パッケージの分離要件を満たしているかどうかを判断する方法については、「Windows ドライバーの検証」を参照してください。 ドライバー パッケージの分離要件を満たすように INF を更新する方法の例については、「ドライバー パッケージの分離に従うように INF を移植する」をご覧ください。

ドライバー ストアから実行する

分離されているすべてのドライバー パッケージでは、ドライバー パッケージ ファイルがドライバー ストアに配置されます。 つまり、インストール時のドライバー パッケージ ファイルの場所を指定するため、INF に DIRID 13 と指定されるということです。 ドライバー パッケージでこれを使用する方法の詳細については、「ドライバー ストアから実行する」を参照してください。

状態の読み取りと書き込み

Note

コンポーネントがデバイスまたはデバイス インターフェイスのプロパティを使用して状態を保存している場合、引き続きその方法および適切な OS API を使用して、状態を保存し、アクセスしてください。 レジストリとファイルの状態についての次のガイダンスは、コンポーネントが保存する必要があるその他の状態のためのものです。

様々なレジストリとファイルの状態にアクセスするには、状態の場所を呼び出し元に示す関数を実行します。次いで、その場所から見た相対位置で、読み書きを行います。 ハードコーディングされた絶対レジストリ パスとファイル パスを使用すべきではありません。

このセクションには、次のサブセクションが含まれています。

レジストリの状態

このセクションには、次のサブセクションが含まれています。

PnP デバイス レジストリの状態

分離されているドライバー パッケージとユーザーモード コンポーネントは、通常 2 つの場所のうちいずれかを使用してデバイスの状態をレジストリ内に保存します。 デバイスのハードウェア キー (デバイス キー) と、デバイスのソフトウェア キー (ドライバーキー) です。 通常、"ハードウェア キー" は、個々のデバイス インスタンスがハードウェアとどのようにやり取りするかに関連する設定用です。 たとえば、ハードウェアの機能を有効にしたり、ハードウェアを特定のモードにしたりします。 通常、"ソフトウェア キー" は、個々のデバイス インスタンスがシステムや他のソフトウェアとどのようにやり取りするかに関しての設定用です。 たとえば、データ ファイルの場所を構成したり、フレームワークと相互運用したり、デバイスのアプリ設定にアクセスしたりします。 これらのレジストリの場所へのハンドルを取得するには、次のいずれかのオプションを使用します。

[ExampleDDInstall.HW]
AddReg = Example_DDInstall.AddReg

[Example_DDInstall.AddReg] 
HKR,,ExampleValue,,%13%\ExampleFile.dll

デバイス インターフェイス レジストリの状態

デバイス インターフェイス レジストリの状態の読み取りと書き込みを行うには、次のいずれかのオプションを使用します。

サービス レジストリの状態

サービスの状態は、3 つのカテゴリのいずれかに分類する必要があります。

不変サービス レジストリの状態

不変サービスの状態は、サービスをインストールするドライバー パッケージによって提供される状態です。 ドライバーおよび Win32 サービスの INF により設定されるこれらのレジストリの値は、AddReg セクション内に HKR 行を追加して、INF のサービス インストール セクション内でそのセクションを参照することにより、サービスの "Parameters" サブキーの下に保存する必要があります。 次に例を示します。

[ExampleDDInstall.Services]
Addservice = ExampleService, 0x2, Example_Service_Inst

[Example_Service_Inst]
DisplayName    = %ExampleService.SvcDesc%
ServiceType    = 1
StartType      = 3
ErrorControl   = 1
ServiceBinary  = %13%\ExampleService.sys
AddReg=Example_Service_Inst.AddReg

[Example_Service_Inst.AddReg]
HKR, Parameters, ExampleValue, 0x00010001, 1

実行時にサービスからこの状態の場所にアクセスするには、次のいずれかの関数を使用します。

サービスの "Parameters" サブキーで INF によって指定されたこれらのレジストリ値は、実行時にのみ読み取る必要があり、変更することはできません。 これらは、読み取り専用として扱う必要があります。

INF によって指定されたレジストリ値が、実行時に上書きできる既定の設定である場合は、サービスの内部サービス レジストリの状態または共有サービス レジストリの状態にオーバーライド値を書き込む必要があります。 設定を取得するときに、変更可能な状態の最初で設定を検索できます。 存在しない場合は、不変の状態で設定を検索できます。 RtlQueryRegistryValueWithFallback は、オーバーライドおよび既定値を持つ設定などのクエリを実行するために使用できます。

内部サービス レジストリの状態

内部サービスの状態は、実行時に書き込まれ、サービス自体によってのみ所有および管理される状態であり、そのサービスにのみアクセスできます。 内部サービスの状態の場所にアクセスするには、サービスの次のいずれかの関数を使用します。

サービスで他のコンポーネントによるこれらの設定の変更を許可する場合、サービスは、他のコンポーネントが呼び出すことができるインターフェイスを公開する必要があります。これにより、サービスにこれらの設定を変更する方法が示されます。 たとえば、Win32 サービスは COM または RPC インターフェイスを公開でき、ドライバー サービスはデバイス インターフェイスを介して IOCTL インターフェイスを公開できます。

共有サービス レジストリの状態

共有サービスの状態は、実行時に書き込まれる状態であり、他のユーザー モード コンポーネントと共有できます (十分な特権がある場合)。 この共有サービスの状態の場所にアクセスするには、次のいずれかの関数を使用します。

ファイルの状態

このセクションには、次のサブセクションが含まれています。

デバイス ファイルの状態

実行時にデバイスと関連するファイルに書き込む必要がある場合、これらのファイルは、OS API を介して提供されるハンドルまたはファイル パスに対する相対的な位置に保存される必要があります。 そのデバイスに特有の構成ファイルは、そこに保存すべきファイルの種類の一例です。 この状態の場所にアクセスするには、サービスの次のいずれかの関数を使用します。

サービス ファイルの状態

サービス ファイルの状態は、3 つのカテゴリのいずれかに分類できます。

不変サービス ファイルの状態

不変サービス ファイルの状態は、ドライバー パッケージの一部であるファイルです。 これらのファイルへのアクセスの詳細については、「ドライバー ストアから実行する」を参照してください。

内部サービス ファイルの状態

内部サービス ファイルの状態は、実行時に書き込まれ、サービス自体によってのみ所有および管理される状態であり、そのサービスにのみアクセスできます。 内部サービスの状態の場所にアクセスするには、サービスの次のいずれかの関数を使用します。

サービスで他のコンポーネントによるこれらの設定の変更を許可する場合、サービスは、他のコンポーネントが呼び出すことができるインターフェイスを公開する必要があります。これにより、サービスにこれらの設定を変更する方法が示されます。 たとえば、Win32 サービスは COM または RPC インターフェイスを公開でき、ドライバー サービスはデバイス インターフェイスを介して IOCTL インターフェイスを公開できます。

共有サービス ファイルの状態

共有サービス ファイルの状態は、実行時に書き込まれる状態であり、他のユーザー モード コンポーネントと共有できます (十分な特権がある場合)。 この共有サービスの状態の場所にアクセスするには、次のいずれかの関数を使用します。

DriverData と ProgramData

他のコンポーネントと共有できるが、共有サービスのファイル状態カテゴリに当てはまらないファイルは、 いずれかDriverDataまたはProgramData場所に書き込むことができます。

これらの場所は、コンポーネントに対し、一時的な状態、つまり他のコンポーネントによって使用されることになる状態を書き込む場所を提供します。こうした状態は、あるシステムから収集およびコピーされ、別のシステムによって処理される可能性があります。 たとえば、カスタム ログ ファイルやクラッシュ ダンプがこの説明にあてはまります。

DriverData または ProgramData ディレクトリのルートにファイルを書き込まないでください。 代わりに、会社名でサブディレクトリを作成し、そのディレクトリ内にファイルを書き込んだり、サブディレクトリをさらに作成したりしてください。

たとえば、会社名が Contoso だとすると、カーネルモード ドライバーはカスタム ログを \DriverData\Contoso\Logs に書き込み、ユーザーモード アプリケーションは %DriverData%\Contoso\Logs からログ ファイルを収集して分析することができます。

DriverData

DriverData ディレクトリは、Windows 10 バージョン 1803 およびそれ以降で使用でき、管理者および UMDF ドライバーからアクセスできます。

カーネル モード ドライバーでは、DriverData というシステム提供のシンボリック リンクを使用して \DriverData ディレクトリにアクセスします。

ユーザー モード プログラムからは、環境変数 DriverData を使用して %DriverData% ディレクトリにアクセスします。

ProgramData

ユーザーモード コンポーネントは、データを保存する際に %ProgramData% ユーザーモード環境変数を使用できます。

一時ファイル

一時ファイルは通常、中間操作で使用されます。 これらは、%TEMP%または%TMP%環境変数の下のサブパスに書き込むことができます。 これらの場所は環境変数を通じてアクセスされるため、この機能はユーザーモードコンポーネントに限定されます。 これらの一時ファイルへのハンドルが閉じられた後の、一時ファイルの存続期間や永続性については保証されません。 オペレーティングシステムまたはユーザーはいつでもこれらを削除する可能性があり、再起動すると保持されなくなる可能性があります。

%TEMP% または %TMP% ディレクトリのルートにファイルを書き込まないでください。 代わりに、会社名でサブディレクトリを作成し、そのディレクトリ内にファイルを書き込んだり、サブディレクトリをさらに作成したりしてください。

プロパティの状態

デバイスとデバイス インターフェイスの両方で、PnP プロパティ モデルによる状態の格納がサポートされています。 プロパティ モデルを使用すると、構造化されたプロパティ データをデバイスまたはデバイス インターフェイスに対して格納できます。 これは、プロパティ モデルでサポートされるプロパティの型に適度に適合する小さなデータを対象としています。

デバイスのプロパティにアクセスするには、これらの API を使用できます。

デバイス インターフェースのプロパティにアクセスするには、これらの API を使用できます。

デバイス インターフェイスの使用

ドライバーがドライバーの内部状態の読み取りまたは変更を他のコンポーネントに許可する場合、ドライバーは、別のコンポーネントが呼び出すことができるインターフェイスを公開する必要があります。これにより、どの設定を返すか、または特定の設定を変更するかどうかがドライバーに伝えられます。 たとえば、ドライバー サービスは、デバイス インターフェイスを介して IOCTL インターフェイスを公開できます。

通常、状態を所有するドライバーはカスタムのデバイス インターフェイス クラス内でデバイス インターフェイスを公開します。 そのドライバーの準備が整い、他のコンポ―ネントから状態にアクセスできるようになると、インターフェイスが有効になります。 デバイス インターフェイスが有効になったときに通知を受け取るために、ユーザー モード コンポーネントはデバイス インターフェイスの到着通知に登録でき、カーネル モード コンポーネントは IoRegisterPlugPlayNotification を使用できます。 これらのコンポーネントが状態にアクセスするには、インターフェイスを有効にするドライバーで、そのカスタム デバイス インターフェイス クラスのコントラクトを定義する必要があります。 通常、このコントラクトは次の 2 種類のうちの 1 つです。

  • I/O コントラクト は、状態へのアクセスの仕組みを提供する、そのデバイス インターフェイス クラスと関連付けることができます。 他のコンポーネントは、有効化されたデバイス インターフェイスを使用して、コントラクトに適合する I/O リクエストを送信します。

  • クエリ インターフェイス経由で返される直接呼び出しインターフェイス。 他のドライバーは、IRP_MN_QUERY_INTERFACE を送信して、呼び出すドライバーから関数ポインターを取得できます。

または、状態を所有するドライバーによって状態への直接アクセスが許可される場合、他のドライバーは、デバイス インターフェイスの状態にプログラムでアクセスできるようにするためにシステムによって提供されている関数を使用して、状態にアクセスすることができます。 詳細については、「デバイス インターフェイス レジストリの状態」を参照してください。

これらのインターフェイスまたは状態 (使用する共有方法による) は、適切にバージョン管理される必要があります。これは、状態を所有するドライバーが、状態にアクセスする他のコンポーネントから独立してサービスの提供を受けられるようにするためです。 ドライバー ベンダーは、他のコンポーネントがドライバーと同時にサービスを受け、同じバージョンを保つと見なすことはできません。

インターフェイスを制御するデバイスとドライバーは頻繁に切り替わるので、ドライバーとアプリケーションは、コンポーネントの起動時に IoGetDeviceInterfaces を呼び出して有効なインターフェイスのリストを取得すべきではありません。 ベスト プラクティスは、デバイス インターフェイスの到着と削除の通知に登録してから適切な関数を呼び出し、マシン上の既存の有効なインターフェイスのリストを取得することです。

デバイス インターフェイスの詳細については、次を参照してください。

状態管理 API のオペレーティング システム サポートのクイック リファレンス

ほとんどのドライバー パッケージでは、さまざまなバージョンのオペレーティング システムをサポートする必要があります。 ドライバー パッケージでこれを実現する方法の詳細については、「オペレーティング システムの複数バージョンのサポート」を参照してください。 次の表は、さまざまな状態管理 API に対してオペレーティング システムのサポートが追加されたときのクイック リファレンスを示しています。

WDM ドライバー

オペレーティング システム サポートが追加されました
Windows 2000 IoOpenDeviceRegistryKey
IoOpenDeviceInterfaceRegistryKey
Windows Vista IoGetDevicePropertyData
IoSetDevicePropertyData
Windows 8 IoGetDeviceInterfacePropertyData
IoSetDeviceInterfacePropertyData
Windows 8.1 IoQueryFullDriverPath
Windows 10 1803 DriverRegKeyParameters および DriverRegKeyPersistentStateRegKeyTypeIoOpenDriverRegistryKey
IoGetDeviceDirectory
DriverDirectoryImageDriverDirectoryDataDirectoryTypeIoGetDriverDirectory
Windows 10 1809 RtlQueryRegistryValueWithFallback
Windows 11 21H2 DriverRegKeySharedPersistentStateRegKeyTypeIoOpenDriverRegistryKey
DriverDirectorySharedDataDirectoryTypeIoGetDriverDirectory

KMDF ドライバー

KMDF バージョン サポートが追加されました
1.0 WdfDeviceOpenRegistryKey
WdfFdoInitOpenRegistryKey
WdfDriverOpenParametersRegistryKey
WdfDeviceQueryProperty
WdfDeviceAllocAndQueryProperty
WdfFdoInitQueryProperty
WdfFdoInitAllocAndQueryProperty
1.13 WdfDeviceQueryPropertyEx
WdfDeviceAllocAndQueryPropertyEx
WdfDeviceAssignProperty
WdfFdoInitQueryPropertyEx
WdfFdoInitAllocAndQueryPropertyEx
1.25 WdfDriverOpenPersistentStateRegistryKey (Windows 10 1803)

UMDF ドライバー

UMDF バージョン サポートが追加されました
2.0 WdfDeviceOpenRegistryKey
WdfFdoInitOpenRegistryKey
WdfDriverOpenParametersRegistryKey
WdfDeviceQueryProperty
WdfDeviceAllocAndQueryProperty
WdfDeviceQueryPropertyEx
WdfDeviceAllocAndQueryPropertyEx
WdfDeviceAssignProperty
WdfFdoInitQueryProperty
WdfFdoInitAllocAndQueryProperty
WdfFdoInitQueryPropertyEx
WdfFdoInitAllocAndQueryPropertyEx
WdfDeviceQueryInterfaceProperty (Windows 8.1)
WdfDeviceAllocAndQueryInterfaceProperty (Windows 8.1)
WdfDeviceAssignInterfaceProperty (Windows 8.1)
2.25 WdfDeviceRetrieveDeviceDirectoryString
WdfDriverOpenPersistentStateRegistryKey (Windows 10 1803)
2.27 WdfDriverRetrieveDriverDataDirectoryString

ユーザー モード コード

オペレーティング システム サポートが追加されました
Windows 2000 CM_Open_DevNode_Key
Windows Vista CM_Open_Device_Interface_Key
CM_Get_DevNode_Property
CM_Set_DevNode_Property
CM_Get_Device_Interface_Property
CM_Set_Device_Interface_Property
Windows 10 2004 GetServiceRegistryStateKey
GetServiceDirectory
Windows 11 21H2 GetSharedServiceRegistryStateKey
GetSharedServiceDirectory