Driver package isolation
Driver package isolation is a requirement for Windows Drivers that makes driver packages more resilient to external changes, easier to update, and more straightforward to install.
Note
While driver package isolation is required for Windows Drivers, Windows Desktop Drivers still benefit from it through improved resiliency and serviceability.
The following table shows some example legacy driver package practices that are no longer allowed for Windows Drivers in the left column along with the required behavior for Windows Drivers in the right column.
Non-isolated driver | Isolated driver |
---|---|
INF copies files to %windir%\System32 or %windir%\System32\drivers | Driver files are run from the driver store |
Interacts with device stacks/drivers using hardcoded paths | Interacts with device stacks/drivers using system-supplied functions or device interfaces |
Hardcodes path to global registry locations | Uses HKR and system-supplied functions for relative location of registry and file state |
Runtime file writes to any location | Files are written relative to locations supplied by the operating system |
For help in determining if your driver package meets driver package isolation requirements, see Validating Windows Drivers. For examples of how to update an INF to meet driver package isolation requirements, see Porting an INF to follow driver package isolation.
Run from driver store
All isolated driver packages leave their driver package files in the driver store. This means that they specify DIRID 13 in their INF to specify the location for driver package files on install. For more information on how to use this in a driver package, see Run from driver store.
Reading and writing state
Note
If your component is using device or device interface properties to store state, continue to use that method and the appropriate OS API's to store and access state. The following guidance for registry and file state is for other state that needs to be stored by a component.
Access to various registry and file state should be done by calling functions that provide a caller with the location of the state and then the state is read/written relative to that location. Do not use hardcoded absolute registry paths and file paths.
This section contains the following subsections:
Registry state
This section contains the following subsections:
PnP device registry state
Isolated driver packages and user-mode components typically use one of two locations to store device state in the registry. These are the hardware key (device key) for the device and the software key (driver key) for the device. The hardware key is typically for settings related to how an individual device instance interacts with the hardware. For example, to enable a hardware feature or put the hardware into a specific mode. The software key is typically for settings related to how an individual device instance interacts with the system and other software. For example, to configure the location of a data file, to inter operate with a framework, or to access app settings for a device. To retrieve a handle to these registry locations, use one of the following options:
IoOpenDeviceRegistryKey (WDM)
CM_Open_DevNode_Key (user-mode code)
INF AddReg directive using HKR reg-root entries in an add-registry-section referenced from an INF DDInstall section or DDInstall.HW section, as shown below:
[ExampleDDInstall.HW]
AddReg = Example_DDInstall.AddReg
[Example_DDInstall.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll
Device interface registry state
To read and write device interface registry state, use one of the following options:
CM_Open_Device_Interface_Key (user-mode code)
INF AddReg directive using HKR reg-root entries in an add-registry-section referenced from an add-interface-section section
Service registry state
Service state should be classified into one of 3 categories
Immutable service registry state
Immutable service state is state that is provided by the driver package that installs the service. These registry values that are set by the INF for driver and Win32 services must be stored under the "Parameters" subkey of the service by providing an HKR line in an AddReg section, and then referencing that section in the service install section in the INF. For example:
[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
To access the location of this state from the service at runtime, use one of these functions:
IoOpenDriverRegistryKey (WDM) with a DRIVER_REGKEY_TYPE of DriverRegKeyParameters
GetServiceRegistryStateKey (Win32 Services) with a SERVICE_REGISTRY_STATE_TYPE of ServiceRegistryStateParameters
These registry values supplied by the INF in the "Parameters" subkey for the service should only be read at runtime and not modified. They should be treated as read only.
If the registry values supplied by the INF are default settings that can be overwritten at runtime, the override values should be written into the Internal service registry state or Shared service registry state for the service. When retrieving the settings, the setting can be looked for first in the mutable state. If it does not exist there, then the setting can be looked for in the immutable state. RtlQueryRegistryValueWithFallback can be used to help query settings such as these that have an override and a default value.
Internal service registry state
Internal service state is state that is written at runtime and owned and managed by only the service itself and is only accessible to that service. To access the location for internal service state, use one of these functions from the service:
IoOpenDriverRegistryKey (WDM) with a DRIVER_REGKEY_TYPE of DriverRegKeyPersistentState
GetServiceRegistryStateKey (Win32 Services) with a SERVICE_REGISTRY_STATE_TYPE of ServiceRegistryStatePersistent
If the service wants to allow other components to modify these settings, the service must expose an interface that another component can call into that tells the service how to alter these settings. For example, a Win32 service could expose a COM or RPC interface and a driver service could expose an IOCTL interface via a device interface.
Shared service registry state
Shared service state is state that is written at runtime and can be shared with other user mode components if they are sufficiently privileged. To access the location for this shared service state, use one of these functions:
IoOpenDriverRegistryKey (WDM) with a DRIVER_REGKEY_TYPE of DriverRegKeySharedPersistentState
GetSharedServiceRegistryStateKey (Win32 Services) with a SERVICE_SHARED_REGISTRY_STATE_TYPE of ServiceSharedRegistryPersistentState
File state
This section contains the following subsections:
Device file state
If files related to a device need to be written at runtime, those files should be stored relative to a handle or file path provided via OS API's. Configuration files specific to that device is one example of what types of files to be stored here. To access the location of this state, use one of these functions from the service:
IoGetDeviceDirectory (WDM) with the DirectoryType parameter set to DeviceDirectoryData
Service file state
Service file state can be classified into one of 3 categories
Immutable service file state
Immutable service file state are files that are part of the driver package. For more information on accessing those files, see Run from Driver Store.
Internal service file state
Internal service file state is state that is written at runtime and owned and managed by only the service itself and is only accessible to that service. To access the location for internal service state, use one of these functions from the service:
IoGetDriverDirectory (WDM, KMDF) with the DirectoryType parameter set to DriverDirectoryData
GetServiceDirectory (Win32 Services) with the eDirectoryType parameter set to ServiceDirectoryPersistentState
If the service wants to allow other components to modify these settings, the service must expose an interface that another component can call into that tells the service how to alter these settings. For example, a Win32 service could expose a COM or RPC interface and a driver service could expose an IOCTL interface via a device interface.
Shared service file state
Shared service file state is state that is written at runtime and can be shared with other user mode components if they are sufficiently privileged. To access the location for this shared service state, use one of these functions:
IoGetDriverDirectory (WDM, KMDF) with the DirectoryType parameter set to DriverDirectorySharedData
GetSharedServiceDirectory (Win32 Services) with the DirectoryType parameter set to ServiceSharedDirectoryPersistentState
DriverData and ProgramData
Files that can be shared with other components but that do not fit into the shared service file state category can be written to either DriverData
or ProgramData
locations.
These locations offer components a location to write temporary state or state that is meant to be consumed by other components and potentially collected and copied from a system to be processed by another system. For example, custom log files or crash dumps fit this description.
Avoid writing files in the root of the DriverData
or ProgramData
directories. Instead, create a subdirectory with your company name and then write files and further subdirectories within that directory.
For example, for a company name of Contoso, a kernel-mode driver could write a custom log to \DriverData\Contoso\Logs
and a user-mode application could collect or analyze the log files from %DriverData%\Contoso\Logs
.
DriverData
The DriverData
directory is available in Windows 10, version 1803 and later, and is accessible to administrators and UMDF drivers.
Kernel-mode drivers access the DriverData
directory by using a system-supplied symbolic link called \DriverData
.
User-mode programs access the DriverData
directory by using the environment variable %DriverData%
.
ProgramData
The %ProgramData%
user-mode environment variable is available for user-mode components to use when storing data.
Temporary files
Temporary files are typically used in intermediate operations. These can be written to a sub-path under the %TEMP%
or %TMP%
environment variables. Since these locations are accessed through environment variables, this ability is limited to user mode components. There are no guarantees on the lifetime or persistence of these temporary files after handles to them are closed. The operating system or user may remove them at any time and they may not persist across a reboot.
Avoid writing files in the root of the %TEMP%
or %TMP%
directories. Instead, create a subdirectory with your company name and then write files and further subdirectories within that directory.
Property state
Both devices and device interfaces support storing state via the PnP property model. The property model allows for structured property data to be stored against a device or device interface. This is meant for smaller data that reasonably fits into the property types supported by the property model.
To access device properties, these APIs can be used:
WDM drivers
WDF drivers
User mode code
To access device interface properties, these APIs can be used:
WDM drivers
WDF drivers
User mode code
Using device interfaces
If a driver wants to allow other components to read or modify the driver's internal state, the driver should expose an interface that another component can call into that tells the driver what settings to return or how to modify particular settings. For example, the driver service could expose an IOCTL interface via a device interface.
Typically, the driver that owns the state exposes a device interface in a custom device interface class. When the driver is ready for other components to have access to the state, it enables the interface. To get notified when a device interface is enabled, user mode components can register for device interface arrival notifications and kernel mode components can use IoRegisterPlugPlayNotification. For these components to access the state, the driver enabling the interface must define a contract for its custom device interface class. This contract typically is one of two kinds:
An I/O contract can be associated with that device interface class that provides a mechanism for accessing the state. Other components use the enabled device interface to send I/O requests that conform to the contract.
A direct-call interface that gets returned via a query interface. Other drivers could send IRP_MN_QUERY_INTERFACE to retrieve function pointers from the driver to call.
Alternatively, if the driver that owns the state allows direct access to the state, other drivers could access state by using system-supplied functions for programmatic access to device interface state. See Device Interface Registry State for more information.
These interfaces or state (depending on sharing method used) need to be properly versioned so the driver owning the state can be serviced independently of other components that access that state. Driver vendors cannot rely on other components being serviced at the same time as the driver and staying at the same version.
Because devices and drivers controlling interfaces come and go, drivers and applications should avoid calling IoGetDeviceInterfaces at component start-up to get a list of enabled interfaces. Instead, the best practice is to register for notifications of device interface arrival or removal and then call the appropriate function to get the list of existing enabled interfaces on the machine.
For more information about device interfaces, see:
Quick reference of operating system support for state management APIs
Most driver packages need to support a range of operating system versions. See Supporting multiple operating system versions for more information on how to achieve this in a driver package. The following tables provide a quick reference of when operating system support was added for various state management APIs.
WDM drivers
Operating system | Support added |
---|---|
Windows 2000 | IoOpenDeviceRegistryKey IoOpenDeviceInterfaceRegistryKey |
Windows Vista | IoGetDevicePropertyData IoSetDevicePropertyData |
Windows 8 | IoGetDeviceInterfacePropertyData IoSetDeviceInterfacePropertyData |
Windows 8.1 | IoQueryFullDriverPath |
Windows 10 1803 | IoOpenDriverRegistryKey for RegKeyType of DriverRegKeyParameters and DriverRegKeyPersistentState IoGetDeviceDirectory IoGetDriverDirectory for DirectoryType of DriverDirectoryImage and DriverDirectoryData |
Windows 10 1809 | RtlQueryRegistryValueWithFallback |
Windows 11 21H2 | IoOpenDriverRegistryKey for RegKeyType of DriverRegKeySharedPersistentState IoGetDriverDirectory for DirectoryType of DriverDirectorySharedData |
KMDF drivers
UMDF drivers
User mode code
Operating system | Support added |
---|---|
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 |