WDK Doc

Download as pdf or txt
Download as pdf or txt
You are on page 1of 611

Contents

What's New for WDF Drivers


Overview
Getting Started with UMDF
User-Mode Driver Framework Frequently Asked Questions
Advantages of Writing UMDF Drivers
Overview of UMDF
UMDF Driver Host Process
Architecture of UMDF
Comparing UMDF 2.0 Functionality to KMDF
How to convert a KMDF driver to a UMDF 2.0 driver (and vice-versa)
Porting a Driver from UMDF 1 to UMDF 2
Framework Library Versioning
KMDF Version History
UMDF Version History
Concepts
Using WDF to Develop a Driver
WDF Architecture
Writing a Simple WDF Driver
DriverEntry for WDF Drivers routine
WDFDEVICE_INIT
Sample KMDF Drivers
Sample UMDF Drivers
Sample Toaster Driver Programming Tour
Developing Drivers with the Windows Driver Foundation: Reference Book
Creating a Framework Device Object
Creating Device Objects in a Function Driver
Creating Device Objects in a Filter Driver
Creating Device Objects in a Bus Driver
Building, Installing, and Testing
Building and Loading a WDF Driver
Building a WDF driver for multiple versions of Windows
Redistributable Framework Components
Specifying the KMDF Co-installer in an INF File
Using the UMDF Co-installer
Using INX Files to Create INF Files
Testing a WDF Driver (KMDF or UMDF)
Troubleshooting KMDF and UMDF Driver Installation
Installing a UMDF Filter Driver
Specifying the Reflector in an INF File
Specifying WDF Directives in INF Files
Using Device Pooling in UMDF Drivers
Session Zero Guidelines for UMDF Drivers
Restricting the Loading Location of UMDF Drivers
Controlling Device Access
Using the Framework's Event Logger
Using KMDF Verifier
Using UMDF Verifier
How UMDF Handles Driver Failures
How UMDF Handles Application Failures
How UMDF Reports Errors
Reporting Device Failures
Creating WDF HID Minidrivers
Framework File Objects
Handling Client Impersonation in UMDF Drivers
Host Process Timeouts in UMDF
Supporting Kernel-Mode Clients in UMDF Drivers
Using Activity Identifiers
Controlling Device Access in KMDF Drivers
Debugging
Accessing UMDF Metadata in WER Reports
Attaching a User-Mode Debugger
Avoiding Reboot when Updating a UMDF Driver
Breaking into a Debugger from KMDF Drivers
VERIFY_IS_IRQL_PASSIVE_LEVEL
WDFVERIFY
Bug Checks from KMDF Drivers
Debugging Power Reference Leaks in WDF
Determining If a Driver Leaks Framework Objects
Determining the State of a UMDF Device
Determining Why an Application Request Does Not Complete
Determining Why the Reflector Terminated the Host Process
Determining Why the UMDF Driver Fails to Load or the UMDF Device Fails to Start
Determining Why UMDF Indicates Outstanding Files at Device Removal Time
How to Enable Debugging of a UMDF Driver
Registry Values for Debugging WDF Drivers
Summary of Debugger Extensions in Wdfkd.dll
Troubleshooting UMDF 2.0 Driver Crashes
Using Inflight Trace Recorder (IFR) in KMDF and UMDF 2 Drivers
Using the Windows Performance Toolkit (WPT) with WDF
Using WPP Software Tracing in KMDF Drivers
Using WPP Software Tracing in UMDF Drivers
Video: Debugging your driver with WDF source code
Video: Accessing driver IFR logs without a debugger
Videos: Debugging KMDF Drivers
Videos: Debugging UMDF Drivers
DMA
Introduction to DMA in Windows Driver Framework
Framework DMA Objects
DMA Transactions and DMA Transfers
Sample Drivers That Use Framework DMA
Handling I/O Requests in a KMDF Driver for a Bus-Master DMA Device
Enabling DMA Transactions
Creating and Initializing a DMA Transaction
Starting a DMA Transaction
Programming DMA Hardware
Completing a DMA Transfer
Completing a DMA Transaction
Reusing DMA Transaction Objects
Supporting Power Management for DMA Devices
Using Common Buffers
Supporting System-Mode DMA
Canceling DMA Transactions
Using Single Transfer DMA
Reserving DMA Resources
Testing DMA in KMDF Drivers
Accessing Hardware
Handling Hardware Resources
Introduction to Hardware Resources
Framework Objects for Hardware Resources
Creating a Resource Requirements List
Modifying a Resource Requirements List
Creating a Resource List for a Boot Configuration
Modifying a Resource List
Raw and Translated Resources
Finding and Mapping Hardware Resources
Reading and Writing to Device Registers
Driver Access to Hardware
Interrupts
Creating an Interrupt Object
Enabling and Disabling Interrupts
Servicing an Interrupt
Synchronizing Interrupt Code
Supporting Passive-Level Interrupts
Using an Interrupt to Wake a Device
Handling Active-Both Interrupts
I/O Targets
Using I/O Targets
Introduction to I/O Targets
General I/O Targets
Initializing a General I/O Target
Sending I/O Requests to General I/O Targets
Sending I/O Requests Synchronously
Sending I/O Requests Asynchronously
Controlling a General I/O Target's State
Obtaining Information About a General I/O Target
USB I/O Targets
Working with USB Devices
Working with USB Interfaces
Working with USB Pipes
Objects
Introduction to Framework Objects
Framework Object Methods
Framework Object Events
Framework Object Properties
Framework Object Life Cycle
Framework Object Context Space
Framework Object Custom Types
Using General Framework Objects
Framework Object Collections
Summary of Framework Objects
Using Memory Buffers
Memory Buffer Life Cycle
Using Timers
Using String Objects
Using Framework Work Items
Using Device Interfaces
WDF General Object Macros
WDF_DECLARE_CONTEXT_TYPE
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME
WDF_DECLARE_CUSTOM_TYPE
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE
WDF_PTR_ADD_OFFSET
WDF_PTR_ADD_OFFSET_TYPE
WDF_PTR_GET_OFFSET
WdfObjectAddCustomType
WdfObjectAddCustomTypeWithData
WdfObjectDereference
WdfObjectDereferenceWithTag
WdfObjectGetCustomTypeData
WdfObjectGetTypedContext
WdfObjectIsCustomType
WdfObjectReference
WdfObjectReferenceWithTag
Framework Object Creation Errors
PnP and Power Management
Supporting PnP and Power Management in Your Driver
Supporting PnP and Power Management in Software-only Drivers
Supporting PnP and Power Management in Function Drivers
PnP and Power Management Scenarios
A User Plugs in a Device
A User Unplugs a Device
A Device Enters a Low-Power State
A Device Returns to Its Working State
The PnP Manager Redistributes System Resources
PnP and Power Management Callback Sequences
Power-Up Sequence for a Function or Filter Driver
Power-Up Sequence for a Bus Driver
Power-Down and Removal Sequence for a Function or Filter Driver
Power-Down and Removal Sequence for a Bus Driver
Surprise-Removal Sequence
Power Management for I/O Queues
Using Self-Managed I/O
Handling Requests to Stop a Device
Power Policy
Power Policy Ownership
Supporting Idle Power-Down
Supporting System Wake-Up
User Control of Device Idle and Wake Behavior
Supporting Functional Power States
Supporting Single-Component Devices with Single or Multiple Functional Power
States
Supporting Multiple-Component Devices with Single or Multiple Functional Power
States
Coordinating I/O Requests with Component Power State
Reporting Device Powered On When System Returns to S0
Supporting Idle Power-Down on Multiple-Component Devices
Porting
Porting a Driver from WDM to WDF
Which Drivers Can Be Ported and Where
WDM Concepts for WDF Drivers
Differences Between WDM and WDF
Preparing for Porting
Steps in Porting
Porting DriverEntry
Porting AddDevice to EvtDriverDeviceAdd
Porting Interrupts
Porting PnP and Power Management
Porting I/O
Porting I/O Queues
Porting I/O Dispatch Routines to I/O Event Callback Functions
Revise Code That Handles Completed Requests
Revise Canceled Request Logic
Revise Forward Request Logic
Revise Code That Issues I/O Requests
Porting DMA
Porting WMI
Requests That KMDF Does Not Support
Summary of KMDF and WDM Equivalents
WDM Equivalents for WDF Buffer Pointers
WDM IRPs and WDF Event Callback Functions
Queues
Framework Queue Objects
Creating I/O Queues
Dispatching Methods for I/O Requests
Request Handlers
Deleting I/O Queues
Managing I/O Queues
Using Power-Managed I/O Queues
I/O Queue States
Example Uses of I/O Queues
Registry
Introduction to Registry Keys for Drivers
Using Framework Registry-Key Objects
Accessing the Unified Device Property Model
Requests
Framework Request Objects
Creating Framework Request Objects
Using Request Object Context
Request Ownership
Processing I/O Requests
Receiving I/O Requests
Requeuing I/O Requests
Completing I/O Requests
Canceling I/O Requests
Synchronizing Cancel and Completion Code
Synchronizing Cancellation of Sent Requests
Forwarding I/O Requests
Obtaining Information About an I/O Request
Accessing Data Buffers in WDF Drivers (KMDF or UMDF)
Managing Buffer Access Methods in UMDF Drivers
Reusing Framework Request Objects
Synchronization
Using Automatic Synchronization
Using Framework Locks
KMDF specific
Using Kernel-Mode Driver Framework with Non-PnP Drivers
Installing a Non-PnP Driver
Guaranteeing Forward Progress of I/O Operations
Specifying Priority Boosts When Completing I/O Requests
Supporting PnP and Power Management in Bus Drivers
Enumerating the Devices on a Bus
Static Enumeration
Dynamic Enumeration
Handling Enumeration Requests
Supporting Ejectable Devices
State Machines in the Framework
Using Driver-Defined Interfaces
Supporting Special Files
Using Control Device Objects
Creating KMDF Miniport Drivers
Creating Pageable Code in a KMDF Driver
Introduction to WMI for KMDF Drivers
Initializing WMI Support in Your Driver
Supporting WMI Data Blocks and Events in Your Driver
Accessing WDM Interfaces in KMDF Drivers
Obtaining WDM Information
Handling WDM IRPs Outside of the Framework
Handling an IRP that the Framework Does Not Support
Preprocessing and Postprocessing IRPs
Dispatching IRPs to I/O Queues
WDM Interface Restrictions
UMDF 1
UMDF 1.x Design Guide
UMDF Objects and Interfaces
Framework Objects
Framework Base Object
Framework Driver Object
Framework Device Object
Framework File Object
Framework I/O Queue Object
Framework I/O Request Object
Framework I/O Target Object
Framework Interrupt Object
Framework Memory Object
Framework Object Hierarchy
UMDF Based on COM Subset
UMDF DDI Programming Model
Managing the Lifetime of Objects
Initializing UMDF Drivers
Adding a Device Overview
Adding a Device
PnP and Power Management in UMDF Drivers
PnP and Power Management Interfaces
Power Policy Ownership in UMDF
Supporting Idle Power-Down in UMDF Drivers
Supporting System Wake-Up in UMDF Drivers
User Control of Device Idle and Wake Behavior in UMDF
PnP and Power Management Scenarios in UMDF
A User Plugs in a Device
A User Unplugs a Device
A Device Enters a Low-Power State
A Device Returns to Its Working State
The PnP Manager Redistributes System Resources
Processing I/O Requests
I/O Request Processing Operation Flow
Operation Flow with Single Device Stack
Operation Flow with Double Device Stack
Sending I/O Requests to Lower Drivers
Obtaining Parameters for I/O Requests
Canceling I/O Requests
Completing I/O Requests
Accessing Data Buffers in UMDF Drivers
Reusing Framework Request Objects
Handling Client Impersonation in UMDF 1.x Drivers
Preventing an Imbalance of Create and Close Notifications to a Driver
Using I/O Targets in UMDF
General I/O Targets in UMDF
Initializing a General I/O Target in UMDF
Sending I/O Requests to a General I/O Target in UMDF
Controlling a General I/O Target's State in UMDF
Obtaining Information About a General I/O Target in UMDF
USB I/O Targets in UMDF
Choosing a Driver Model for a USB Device
USB-Specific UMDF 1.x Interfaces
Working with USB Devices in UMDF 1.x Drivers
Working with USB Interfaces in UMDF 1.x Drivers
Working with USB Pipes in UMDF 1.x Drivers
File Creation by a USB I/O Target
Calling WinUSB from UMDF
Accessing Hardware and Handling Interrupts
Enabling Hardware Access
Finding and Mapping Hardware Resources in UMDF 1.x Drivers
Reading and Writing to Device Registers in UMDF 1.x Drivers
Handling Interrupts
Creating an Interrupt Object
Enabling and Disabling Interrupts
Servicing an Interrupt
Using Work Items
Synchronizing Interrupt Code
Deleting an Interrupt Object
UMDF Driver Tasks
Using Device Interfaces in UMDF Drivers
Creating Callback Objects
Creating Callback Objects Example
Defining Callback Objects Example
Associating Callback Interfaces Example
Specifying a Callback Synchronization Mode
I/O Queue Event Callback Functions
Configuring Dispatch Mode for an I/O Queue
Combining Dispatch and Synchronization Modes
Creating a File Object to Handle I/O
Driver-Created Versus Application-Created File Objects
Creating and Using Driver-Created File Objects
Using the Registry in UMDF 1.x Drivers
Supporting Kernel-Mode Clients in UMDF 1.x Drivers
Viewing UMDF Objects
Determining Why a UMDF Driver Consumes an Excessive Amount of Memory
Summary of Debugger Extensions in Wudfext.dll
What's New for WDF Drivers in Windows 10
11/2/2020 • 6 minutes to read • Edit Online

This topic summarizes the new features and improvements for Windows Driver Frameworks (WDF) drivers in
Windows 10.
Windows 10, version 1903 (March 2019 Update, 19H1) includes Kernel-Mode Driver Framework (KMDF)
version 1.29 and User-Mode Driver Framework (UMDF) version 2.29.
You can use these framework versions to build drivers for:
Windows 10 (all SKUs)
Windows Server, version 1809
For version history, see KMDF Version History and UMDF Version History. Except where noted, UMDF references
on this page describe version 2 functionality that is not available in UMDF version 1.

New in WDF for Windows 10, version 2004


See KMDF Version History and UMDF Version History.

New in WDF for Windows 10, version 1903


No functionality added or changed.

New in WDF for Windows 10, version 1809


Added new API WdfDriverRetrieveDriverDataDirector yString

New in WDF for Windows 10, version 1803


Building a WDF driver for multiple versions of Windows.
WdfDeviceRetrieveDeviceDirector yString

New in WDF for Windows 10, version 1709


See KMDF Version History and UMDF Version History.

New in WDF for Windows 10, version 1703


In Windows 10, version 1703, WDF includes the following enhancements:
New WDF Verifier settings to detect excessive object creation
In some cases, framework objects are incorrectly parented and not deleted after use. With this feature,
you can specify a maximum number of objects and what should happen when this threshold is exceeded.
To start monitoring, add the following registry values under:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\<driver service>\Parameters\wdf

1. Add a DWORD value named ObjectLeakDetectionLimit with the threshold value. This is the
maximum number of objects of the types described in the ObjectsForLeakDetection key.
2. Add a new REG_MULTI_SZ value named ObjectsForLeakDetection that lists each type name to
verify. For example, you could specify WDFDMATRANSACTION WDFDEVICE . To specify all handle types, use
* as the string.

3. To control whether exceeding this threshold should cause a debug break or a bugcheck, set the
DbgBreakOnError key.
By default, if the ObjectsForLeakDetection key is not specified, the framework monitors
WDFREQUEST, WDFWORKITEM, WDFKEY, WDFSTRING, WDFOBJECT, and WDFDEVICE.
The limit scales with the number of devices installed, so if the driver creates three WDFDEVICE
objects, the WDF Verifier limit is three times the value specified in ObjectLeakDetectionLimit .
If you specify WDFREQUEST, the verifier only counts WDFREQUEST objects that the driver creates.
This feature does not currently support tracking the WDFMEMORY object type.
SleepStudy tool provides info on KMDF drivers
The SleepStudy software tool reports the number of power references that a KMDF driver has that are
preventing the system from going to sleep. For more info, see Modern standby SleepStudy.
The rest of this page describes functionality that was added in Windows 10, version 1507.

WDF source code is publicly available


The WDF source code is now available as open source on GitHub. This is the same source code from
which the WDF runtime library that ships in Windows 10 is built. You can debug your driver more
effectively when you can follow the interactions between the driver and WDF. Download it from
https://github.com/Microsoft/Windows-Driver-Frameworks.
The private symbol files for WDF on Windows 10 are now available through the Microsoft Symbol Server.
The Windows Driver Kit (WDK) 10 samples are also now published to GitHub. Download them from
https://github.com/Microsoft/Windows-Driver-Samples.

Automatic Source Level Debugging of Framework Code


When you use WinDbg to debug a WDF driver on Windows 10, WinDbg automatically retrieves the framework
source code from Microsoft's public GitHub repository. You can use this feature to step through the WDF source
code while debugging, and to learn about framework internals without downloading the source code to a local
machine. For more information, see Debugging with WDF Source and Video: Debugging your driver with WDF
source code.

Universal Driver Compliance


All WDF driver samples and Visual Studio driver templates are Universal Windows driver compliant.
All KMDF and UMDF 2 functionality is Universal Windows driver compliant.
Note that UMDF 1 drivers run only on Windows 10 for desktop editions and earlier versions of desktop
Windows. Want to benefit from the universal capabilities of UMDF 2? To learn how to port your old UMDF 1
driver, see Porting a Driver from UMDF 1 to UMDF 2.

Debugging and Diagnosability


All KMDF and UMDF 2 drivers can use an always on, always available Inflight Trace Recorder (IFR). When
a driver provides a custom trace, the driver IFR log contains the trace messages. Note that the new driver
IFR log is separate from the framework IFR log that WDF creates for each driver.
It's easy to turn on the IFR. See Inflight Trace Recorder (IFR) for logging traces and Using Inflight Trace
Recorder in KMDF and UMDF Drivers.
The IFR maintains a circular buffer of WPP traces in non-pageable memory. If a driver crashes, the logs
are frequently included in the crash dump file.
If you turn on the IFR in your driver binary, the IFR is present and running during the lifetime of your
driver. You don't need to start an explicit trace collection session.
IFR logs are included in minidump files except when the responsible driver is undetermined or if
the crash was a host timeout.
If you have a debugger connected, you can access both the driver and framework IFR logs by
issuing !wdfkd.wdflogdump .
If you do not have a debugger connected, you can still access both logs. To learn how, see Video:
Accessing driver IFR logs without a debugger.
When debugging a UMDF driver, you can merge framework logs with driver logs by issuing:
!wdfkd.wdflogdump <drivername.dll> -m
UMDF logs (WudfTrace.etl) and dumps are now located in %ProgramData%\Microsoft\WDF instead of
%systemDrive%\LogFiles\Wudf.
New debugger command: !wdfkd.wdfumtriage provides a kernel-centric view of all UMDF devices on
the system.
You can run !analyze to investigate UMDF verifier failures or UMDF unhandled exceptions. This works
for live kernel debugging as well as debugging user crash dump files from
%ProgramData%\Microsoft\WDF.
In KMDF and UMDF 2, you can monitor power reference usage in the debugger. For info, see Debugging
Power Reference Leaks in WDF.
You can use !wdfkd.wdfcrashdump to display error information about UMDF 2 drivers. For more
information, see !wdfkd.wdfcrashdump .

Performance Tracing tool for WDF drivers


You can use the Windows Performance Toolkit (WPT) to view performance data for a given KMDF or UMDF 2
driver. When tracing is enabled, the framework generates ETW events for I/O, PnP, and Power callback paths. You
can then view graphs in the Windows Performance Analyzer (WPA) that show I/O throughput rates, CPU
utilization, and callback performance. The WPT is included in the Windows Assessment and Deployment Kit
(ADK).
For more information, see Using the Windows Performance Toolkit (WPT) with WDF.

Additional support for HID drivers in UMDF


UMDF now fully supports HID filters (enumerated by HIDClass) and minidrivers. Simply port your
existing KMDF driver or write a new UMDF 2 filter; the functionality is automatically enabled.
UMDF HID minidrivers that are enumerated by ACPI can perform selective suspend. For more
information, see Creating WDF HID Minidrivers.
UMDF drivers can now be installed in the HID stack for low latency input devices such as touch and
mouse. A driver for an input device should specify the UmdfHostPriority INF directive. For information,
see Specifying WDF Directives in INF Files.

Support for interrupts for GPIO-backed devices


UMDF 2 supports interrupts for GPIO-backed devices like hardware push-buttons. KMDF supports these
devices natively, without the workaround described in Handling Active-Both Interrupts. For more
information, see Creating an Interrupt Object.

UMDF no longer requires WinUSB


New support has been added for USB drivers in UMDF. A UMDF 2 USB driver no longer uses WinUSB. To use the
new functionality, the driver sets the UmdfDispatcher directive to NativeUSB , instead of WinUSB . See
Specifying WDF Directives in INF Files.

Improved Performance
UMDF system components consume less disk space.
KMDF and UMDF drivers use less non-paged memory.
Improved framework version checking reduces header/library mismatches.
UMDF provides improved buffer mapping for HID transfers.
Getting Started with UMDF
2/5/2021 • 2 minutes to read • Edit Online

This section describes User-Mode Driver Framework (UMDF) and details the differences between UMDF
versions 1 and 2. It also provides high-level architectural information about UMDF. Use this section to determine
if a UMDF driver is the right choice for your needs, and to decide which UMDF version to use.
Windows Driver Frameworks (WDF) contains UMDF, a framework for the creation of user-mode drivers. Like
Kernel-Mode Driver Framework (KMDF), UMDF provides an abstraction layer from WDM, handling much of the
Plug and Play (PnP) and power management functionality, and allowing the driver to opt in for specific
functionality and event handling.
In Windows 8.1 onward, there are two major versions of UMDF, versions 1 and 2. UMDF version 1.11 (one dot
eleven) is the most recent version of UMDF version 1, and is the final version before the advent of UMDF 2. For
a table showing full version info and operating system relevance, see UMDF Version History.
Writing a driver using UMDF version 1 requires using the COM programming model to write C++ code. While
UMDF version 1 is based on the same conceptual driver programming model as KMDF, UMDF 1 implements the
model with different components, device driver interfaces (DDIs), and data structures.
In contrast, starting in UMDF version 2, you can write a UMDF driver in the C programming language that calls
many of the methods that are available to KMDF drivers. All of the interfaces that are shared between UMDF
version 2 and KMDF have the same names, parameters, and structure definitions. If your driver uses only shared
functionality, or uses conditional macros around calls that are only supported in one framework, you can write a
single driver that you can compile with either UMDF or KMDF. For more information, see How to generate a
UMDF driver from a KMDF driver.
While there is significant commonality between UMDF 2 and KMDF, there is still a small amount of functionality
that is available only in one framework or the other. For specifics, see Comparing UMDF 2 Functionality to
KMDF. For a list of all UMDF 2 and KMDF callbacks and methods and which framework(s) they apply to, see
Summary of WDF Callbacks and Methods. In a few cases, a structure member or parameter of a method applies
only to one framework or the other. The documentation describes these differences on the corresponding
reference pages.
You must choose one or the other; you cannot write a UMDF driver that calls methods from both UMDF
versions 1 and 2.
UMDF version 2 drivers run only on Windows 8.1 or later. If you need to write a UMDF driver that runs on
operating systems earlier than Windows 8.1, you need to write a UMDF 1.x driver. You can use version 1.11 to
build drivers that run on Windows Vista and later. For more info on version 1, see UMDF 1.x Design Guide. This
section describes UMDF version 2.
User-Mode Driver Framework Frequently Asked
Questions
2/5/2021 • 4 minutes to read • Edit Online

Windows Driver Frameworks (WDF) is a set of libraries that you can use to write device drivers that run on the
Windows operating system. WDF defines a single driver model that is supported by two frameworks: Kernel-
Mode Driver Framework (KMDF) and User-Mode Driver Framework (UMDF). This topic provides answers to
frequently asked questions about UMDF.

Which operating systems can run UMDF drivers?


You can run UMDF drivers on the following operating systems:
Windows 10
Windows 8.1
Windows 8
Windows 7
Windows Vista
Windows XP

What is the most recent version of UMDF?


UMDF version 2 (both 2.0 and 2.1) is included in Windows 10 and later.

What is the difference between UMDF version 2 and the previous


version, 1.11 (one dot eleven)?
A driver written in UMDF version 2 is written in the C programming language. This same driver can then be
easily compiled for KMDF. Additionally, a UMDF version 1 driver must be written according to the COM
programming model.
For more info, see Getting Started with UMDF.

Which operating systems support UMDF 2?


UMDF version 2 drivers run on Windows 8.1 and later.

Which UMDF versions can I build against in Windows Driver Kit


(WDK) 10?
You can build UMDF 2.1, 2.0, 1.11, and 1.9 drivers using Windows Driver Kit (WDK) 10 and Microsoft Visual
Studio. For information about which versions of Windows can run drivers built using these UMDF versions, see
UMDF Version History.

Can I write part of my driver to run in user mode and part in kernel
mode?
Yes. Even if your driver requires access to some kernel-mode resources or features, you might be able to split
your driver into two parts. This approach enables you to benefit from some of the advantages of developing and
running drivers in user mode.
A UMDF driver can receive I/O requests from a kernel-mode driver. For more info about kernel-mode clients,
see Supporting Kernel-Mode Clients in UMDF 2 Drivers.
As a result of increased parity between KMDF and UMDF, however, you will rarely need to split a driver.

Which framework should I start with?


If your driver requires any of the less common features listed in Comparing UMDF 2 Functionality to KMDF, you
must use KMDF. For all other drivers, your first choice should be UMDF.
If you start with UMDF and decide later to transition to KMDF, you can do so with minimal effort, as described in
How to convert a KMDF driver to a UMDF 2 driver (and vice-versa).

How do user-mode drivers handle security?


UMDF drivers run in a driver host process, which runs in the security credentials of a LocalService account,
although the host process itself is not a Windows service. Thus, user-mode drivers are as secure as any other
user-mode service. When a UMDF driver issues I/O requests, it can optionally impersonate its client process.
Impersonation enables the driver thread to run in the security context of the client so that the system performs
access checks against the client's identity rather than that of the driver host process.
A user-mode driver can impersonate its client process only for I/O requests, and not for Plug and Play or other
system messages.
At driver installation, the INF file sets a maximum impersonation level for the driver. Impersonation should be
set at the lowest level possible to prevent "elevation-of-privilege" attacks. When a client application calls the
CreateFile function, it specifies an impersonation level. The driver then requests this level of impersonation for
each individual I/O request.

Will a user-mode driver be fast enough?


Performance is a high priority in developing UMDF. Although latency and CPU usage both increase somewhat,
bus capacity is the primary gating factor for the types of devices that UMDF supports.

What is the difference between a user-mode driver and an


application?
A user-mode driver is started by the Driver Manager and runs in a driver host process. A single instance of the
driver can service simultaneous requests from multiple applications. To communicate with the driver,
applications issue I/O requests to the driver's device through the Win32 API. The primary entry point in a user-
mode driver is the IDriverEntr y interface (UMDF 1.11 and earlier) or the DriverEntr y routine (starting in
UMDF 2.0), rather than a main() function.
A driver also includes additional interfaces or callbacks that are invoked in response to I/O requests and Plug
and Play and power notifications. A device that is managed by a UMDF driver is integrated into the system and
participates in Plug and Play and power management.

How do I debug a UMDF driver?


You can debug a UMDF driver by using user-mode debuggers or kernel-mode debuggers. For more info, see
Debugging WDF Drivers.
Starting in UMDF version 2.0, you can use many of the commands in the Wdfkd.dll debugger extension library
to debug your UMDF driver. For a list of commands, see Debugger Extensions. In addition, UMDF stores the
UMDF trace log (or UMDF IFR ) in kernel non-paged memory. For info about the IFR, see Using the Framework's
Event Logger.

Is there a newsgroup for UMDF?


You can find discussion of all aspects of Windows drivers on the following forums:
Microsoft maintains the Windows Hardware WDK and Driver Development forum.
Open Systems Resources (OSR) moderates the OSR Online NTDEV List forum.
Advantages of Writing UMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

This topic describes the advantages of writing a User-Mode Driver Framework (UMDF) driver instead of a
kernel-mode driver.
When you write a UMDF driver, you benefit from the following:
UMDF drivers contribute to greater operating system stability because they have access only to the
address space of the process in which they run.
Because UMDF drivers run under the LocalSer vice account, they have limited access to a user's data or
to system files.
User-mode drivers operate in a much simpler environment than kernel-mode drivers. For example,
kernel-mode drivers must take into account IRQL, page faults, and thread context. In user mode, however,
these issues do not exist. User-mode drivers always run in a different thread from the requesting process
and can always take page faults.
UMDF version 2 offers feature parity with KMDF in most areas. For a full comparison, see Comparing
UMDF 2 Functionality to KMDF.
UMDF version 2 facilitates converting between KMDF and UMDF. See How to convert a KMDF driver to a
UMDF 2 driver (and vice-versa).
You can debug UMDF drivers by using either a user-mode debugger or, starting with UMDF version 2, a
kernel-mode debugger.
You can use the Wdfkd.dll debugger extension commands with KMDF and starting with UMDF version 2.
For more info, see Debugger Extensions.
A fundamental goal of the overall WDF model is to provide intelligent defaults, so that you can focus on your
device hardware and avoid writing code to perform tasks that are common to most drivers.
To achieve this goal, the framework is designed to work with drivers on an "opt-in" basis. When you write a
UMDF driver, you provide callback routines for only the events that affect your device. For example, some
devices require intervention immediately after they are turned on and just before they are turned off. The driver
for such a device can implement callback functions that the framework calls at those times.
The driver includes code to handle only those events for which its device requires device-specific support. All
other events can be handled by framework defaults.
In addition, a driver can configure its I/O request queues so that the framework stops dispatching requests while
the device is in a low-power state and resumes dispatching after the device has returned to the operational
state. Similarly, if an I/O request arrives while the device is in a low-power state, the framework can
automatically turn on the device.
Overview of UMDF
2/5/2021 • 2 minutes to read • Edit Online

This topic provides a high-level overview of User-Mode Driver Framework (UMDF) components and describes
how your driver interacts with system-supplied components. It applies to both UMDF versions 1 and 2.
UMDF drivers abstract hardware functionality, run in the user-mode environment, and can access various
services. UMDF drivers operate as part of a stack of drivers that manage a device. File system drivers, display
drivers (for full display devices, not display-only display devices), and print drivers cannot be UMDF drivers.
A UMDF driver interacts with the following system-supplied components:
Driver host process
The driver host process loads vendor-supplied UMDF drivers and framework DLLs, provides an execution
environment for user-mode drivers, and routes messages between drivers in a user-mode stack. For
more information, see UMDF Driver Host Process.
Driver manager
The driver manager is a Windows service that manages all instances of the Wudfhost driver host process.
The driver manager launches and tracks information about each driver host process. Each host is a child
process of the driver manager. Only one driver manager exists per system. The driver manager starts
during installation of the first UMDF device and runs on the system thereafter.
Reflector
The reflector is a kernel-mode driver that permits an application and a driver host process (and user-
mode device stacks) to communicate. The reflector creates a separate device object for each device
instance and handles Plug and Play (PnP) and power I/O requests associated with each device instance.
All communication between the application and the driver host process happens through the reflector.
For more information, see Architecture of UMDF.
All function and filter drivers for a given device must run in the same driver host process, but multiple host
processes can be running concurrently.
The following diagram shows how driver host processes, driver manager, and reflector communicate across the
user mode/kernel mode boundary.
UMDF Driver Host Process
2/5/2021 • 2 minutes to read • Edit Online

This topic describes the User-Mode Driver Framework (UMDF) driver host process and how it works with other
UMDF components. It applies to both UMDF versions 1 and 2.
The driver host process (Wudfhost.exe) is a child process of the driver manager service. Wudfhost.exe usually
runs in the LocalService account, which has minimum privileges on the local computer. An instance of
Wudfhost.exe loads one or more UMDF driver DLLs, in addition to the framework DLLs. The driver host process
provides a runtime environment that handles interprocess communication (IPC) between the driver manager
and the reflector, as well as I/O dispatching, driver loading, driver layering, and thread pool management.
The driver manager can create multiple concurrent instances of Wudfhost.exe, as follows:
If your UMDF driver was built with version 1.11 and is running on Windows 8, by default the driver
manager creates a single instance of Wudfhost that can host multiple device stacks. This technique is
called device pooling.
If your UMDF driver was built with version 2 and is running on Windows 8.1 or Windows 10, pooling is
also on by default.
If your driver was built with UMDF version 1.9 or earlier, the framework creates a separate instance of the
host process (Wudfhost) for each device stack.
For more about device pooling, see Using Device Pooling in UMDF Drivers.
Within Wudfhost.exe, each UMDF driver runs in its own address space, and is therefore isolated from the
application process and other instances of the driver host.
You can load drivers built with UMDF versions 1 and 2 concurrently, either in the same host process or in
different host processes. For example, by default, the driver manager would load a UMDF 1.11 driver and a
UMDF 2 driver in the same host process on a computer running Windows 8.1 or later.
However, you cannot load UMDF version 1 and 2 drivers in the same device stack. For example, you cannot load
a UMDF version 1 filter driver above a UMDF version 2 function driver.
For a diagram that shows how the driver host relates to other UMDF components, see Overview of UMDF.
Architecture of UMDF
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how the driver manager builds a user-mode device stack, and how the host process,
reflector, and driver manager process an I/O request that an application sends to a User-Mode Driver
Framework (UMDF) driver.
Similar to a kernel-mode stack, the construction and tear down of a user-mode stack is driven by Plug and Play
(PnP) events. After the kernel-mode stack has been built, the reflector notifies the driver manager to start
construction of the user-mode stack. The driver manager launches the driver host process and provides
sufficient information to the launched process to build the user-mode stack. In this way, the user-mode stack can
be considered an extension of the kernel-mode stack.
The driver host process provides the execution environment for user-mode drivers and routes messages
between drivers in the user-mode stack. The reflector uses a message-based interprocess communication
mechanism to communicate with the driver manager and host process.

To send an I/O request to a UMDF driver, an application calls a Win32 file I/O function, such as CreateFile ,
ReadFileEx , CancelIoEx , or DeviceIoControl . When the reflector receives a request from the client
application, it sends the request to the appropriate driver host process. The driver host process then routes the
request to the top of the correct user-mode device stack.
The request is either completed by one of the drivers in the user-mode stack or forwarded by one of the drivers
back to the reflector. When the reflector receives a request from the user-mode driver stack, it sends the request
down the kernel-mode stack for completion.
Comparing UMDF 2 Functionality to KMDF
2/5/2021 • 2 minutes to read • Edit Online

This topic compares the functionality available to a Kernel-Mode Driver Framework (KMDF) driver with that
available to a User-Mode Driver Framework (UMDF) 2 driver. It is designed to help you decide whether you
should write a UMDF 2 driver or a KMDF driver.
While UMDF version 2 offers a significant subset of functionality that was previously available only to KMDF
drivers, the following features are available only to KMDF drivers. If your driver requires one of these features,
you must write a KMDF driver.

F EAT URE REL AT ED IN F O RM AT IO N

Direct memory access (DMA) Handling DMA Operations in KMDF Drivers

Bus enumeration Enumerating the Devices on a Bus

Functional power states (limited support is available in Supporting Functional Power States
UMDF)

Access to WDM objects and IRPs Obtaining WDM Information

Neither Buffered Nor Direct I/O Accessing Data Buffers in WDF Drivers
Intercepting an I/O Request before it is Queued
EvtIoInCallerContext

Internal device control requests (IOCTLs) Sending I/O Requests Synchronously


WdfIoTargetSendInternalIoctlSynchronously
WdfIoTargetSendInternalIoctlOthersSynchrono
usly
Sending I/O Requests Asynchronously
WdfIoTargetFormatRequestForInternalIoctl
WdfIoTargetFormatRequestForInternalIoctlOth
ers

Remove lock opt-in for I/O requests WdfDeviceInitSetRemoveLockOptions

WMI Introduction to WMI for KMDF Drivers

If your driver does not require any of the above, you can write a UMDF 2 driver instead of using KMDF. Because
the two frameworks share many interfaces, you can convert your driver to KMDF later if the need arises. For
information about why you might want to choose UMDF, see Advantages of Writing UMDF Drivers.
For more information about the framework objects and which are supported by KMDF and UMDF, see
Summary of Framework Objects.
For a table showing all Windows Driver Frameworks (WDF) callbacks and methods and their framework
applicability, see Summary of WDF Callbacks and Methods.
How to convert a KMDF driver to a UMDF 2 driver
(and vice-versa)
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how to convert a Kernel-Mode Driver Framework (KMDF) driver into a User-Mode Driver
Framework (UMDF) version 2 driver, and vice-versa.

Driver Conversion using Visual Studio


1. When switching from KMDF to UMDF, create an empty UMDF project in Visual Studio using the User
Mode Driver, Empty (UMDF V2) project template. When switching from UMDF to KMDF, create an
empty KMDF project in Visual Studio using the Kernel Mode Driver, Empty (KMDF) project template.
Visual Studio creates an empty driver project with the appropriate settings, along with an INF file targeted
to the specified framework.
2. Copy the source code and header files from the previous driver into the new project.
3. Update your header files. For UMDF, include Windows.h. For KMDF, include Ntddk.h. Wdf.h is common to
both KMDF and UMDF, so include it in both types of drivers.
Optionally, use the _KERNEL_MODE preprocessor macro to add the right system header conditionally:

#ifndef _KERNEL_MODE
// This is a user-mode driver
#include <windows.h>

#else
// This is a kernel-mode driver
#include <ntddk.h>
#define NTSTRSAFE_LIB
#include <ntstrsafe.h>
#endif

// This is a common WDF header (for both KMDF and UMDF)


#include <wdf.h>

4. Update the source code to either remove or conditionally compile (using the _KERNEL_MODE macro)
any functionality that is not supported in the target driver model. For example:
If your driver uses WPP tracing, update the WPP_INIT_TRACING macro. This macro takes different
parameters in user mode and kernel mode.

WPP_INIT_TRACING ( DriverObject, RegistryPath ); // KMDF


WPP_INIT_TRACING ( “<MyDriverNameString>” ); // UMDF

If you are converting a KMDF driver that calls WDM routines such as ExAllocatePoolWithTag ,
replace these with the corresponding WDF methods, such as WdfMemor yCreate . Similarly, if
you are converting a UMDF driver that calls user-mode functions, replace these with equivalent
kernel-mode routines.
Some methods are supported only in KMDF, while others are supported only in UMDF. For a list of
all Windows Driver Frameworks (WDF) methods and their framework applicability, see Summary
of WDF Callbacks and Methods.
Porting a Driver from UMDF 1 to UMDF 2
2/5/2021 • 4 minutes to read • Edit Online

This topic describes how to port a User-Mode Driver Framework (UMDF) 1 driver to UMDF 2. You can start with
a UMDF 1 driver that uses Sources/Dirs files (not a Visual Studio project), or you can convert a UMDF 1 driver
that is contained in a Visual Studio project. The result will be a UMDF 2 driver project in Visual Studio. UMDF 2
drivers run on both Windows 10 for desktop editions (Home, Pro, Enterprise, and Education) and Windows 10
Mobile.
The Echo driver sample is an example of a driver that has been ported from UMDF 1 to UMDF 2.
Echo Sample (UMDF Version 1)
Echo Sample (UMDF Version 2)

Getting Started
To start, open a new driver project in Visual Studio. Select the Visual C++->Windows Driver->WDF->User
Mode Driver (UMDF 2) template. Visual Studio opens a partially populated template that includes stubs for
the callback functions that your driver must implement. This new driver project will be the foundation of your
UMDF 2 driver. Use the UMDF 2 Echo sample as a guide to the type of code you should introduce.
Next, review your existing UMDF 1 driver code and determine object mappings. Each COM object in UMDF 1
has a corresponding WDF object in UMDF 2. For example, the IWDFDevice interface maps to the WDF device
object, which is represented by a WDFDEVICE handle. Nearly all framework-supplied interface methods in
UMDF 1 have corresponding methods in UMDF 2. For example, IWDFDevice::GetDefaultIoQueue maps to
WdfDeviceGetDefaultQueue .
Similarly, driver-supplied callback functions have equivalents in the two versions. In UMDF 1, the naming
convention for driver-supplied interfaces (except for IDriverEntr y ) is IObjectCallbackXxx, while in UMDF 2
the naming convention for driver-supplied routines is Evt ObjectXxx . For example, the
IDriverEntr y::OnDeviceAdd callback method maps to EvtDriverDeviceAdd.
Your driver implements callback functions in both UMDF 1 and 2, but the way that the driver supplies pointers
to its callbacks differs. In UMDF 1, the driver implements callback methods as members of driver-supplied
interfaces. The driver registers these interfaces with the framework when it creates framework objects, for
example by calling IWDFDriver ::CreateDevice .
In UMDF 2, the driver provides pointers to driver-supplied callback functions in configuration structures such as
WDF_DRIVER_CONFIG and WDF_IO_QUEUE_CONFIG .

Managing Object Lifetime


Drivers that use UMDF 1 must implement reference counting in order to determine when it is safe to delete
objects. Because the framework tracks object references on the driver's behalf, a UMDF 2 driver does not need to
count references.
In UMDF 2, each framework object has a default parent object. When a parent object is deleted, the framework
deletes associated child objects. When your driver calls an object creation method such as WdfDeviceCreate , it
can accept the default parent, or it can specify a custom parent in a WDF_OBJECT_ATTRIBUTES structure. For
a list of framework objects and their default parent objects, see Summary of Framework Objects.
Driver Initialization
A UMDF 1 driver implements the IDriverEntr y interface. In its IDriverEntr y::OnDeviceAdd callback method,
the driver typically:
Creates and initializes an instance of the device callback object.
Creates the new framework device object by calling IWDFDriver ::CreateDevice .
Sets up the device's queues and their corresponding callback objects.
Creates an instance of a device interface class by calling IWDFDevice::CreateDeviceInterface .
A UMDF 2 driver implements DriverEntr y and EvtDriverDeviceAdd. In its DriverEntr y routine, a UMDF 2
driver typically calls WDF_DRIVER_CONFIG_INIT to initialize the driver's WDF_DRIVER_CONFIG structure.
Then it passes this structure to WdfDriverCreate .
In its EvtDriverDeviceAdd function, the driver might do some of the following:
Fill in the WDFDEVICE_INIT structure, which supplies information that is used to create the device object. For
more information about using WDFDEVICE_INIT, see Creating a Framework Device Object.
Set up the device object’s context area. For information about allocating and accessing context space for
framework objects, see Framework Object Context Space.
Create the device object.
Specify request handlers for the device object.
Create I/O queues.
Create device interfaces.
Set device idle policy and wake settings, if the device object owns power policy.
Create interrupt objects, if the hardware supports interrupts.

Installing your driver


When you create a new driver project in Visual Studio, the new project contains an .inx file. When you build your
driver, Visual Studio compiles your .inx file into an INF file that can be used as part of a driver package.
While an INF file for a UMDF 1 driver must include a driver class ID, a DriverCLSID is not required in an INF file
for a UMDF 2 driver.
Also, although a UMDF 1 driver must reference the co-installer in its INF file, no constaller reference is required
in a UMDF 2 INF file. Though a coinstaller reference can appear in an INF file for a UMDF 2 driver, one is not
required.

Storing Device Context


In UMDF 1, the driver usually stores device context in a driver-created callback object, for example by specifying
private members of the device callback object class. Alternatively, a UMDF 1 driver can call the
IWDFObject::AssignContext method to register context on a framework object.
In UMDF 2, the framework allocates context space based on the optional WDF_OBJECT_ATTRIBUTES structure
that the driver provides when it calls an object creation method. After calling an object's create method, a driver
can call WdfObjectAllocateContext one or more times to allocate additional context space to a specific object.
For the steps a UMDF 2 driver should use to define a context structure and accessor method, see Framework
Object Context Space.

Debugging your driver


To debug a UMDF 2 driver, you'll use extensions in Wdfkd.dll instead of Wudfext.dll. For more info about
extensions in Wudfext.dll, see Summary of Debugger Extensions in Wdfkd.dll.
In UMDF 2, you can also get additional driver debugging information through the Inflight Trace Recorder (IFR),
as described in Using Inflight Trace Recorder in KMDF and UMDF 2 Drivers. Also, you can use the framework's
own In-flight Recorder (IFR). See Using the Framework's Event Logger.

Related topics
Getting Started with UMDF
Framework Object Context Space
UMDF Version History
Framework Objects
Framework Library Versioning
2/5/2021 • 2 minutes to read • Edit Online

In this topic, you'll learn about the naming conventions for the file names of the Kernel-Mode Driver Framework
(KMDF) library and the User-Mode Driver Framework (UMDF) library.

KMDF
A major version number and a minor version number are assigned to each version of the KMDF library. The
library's file name contains the major version number. The file name's format is:
Wdf <MajorVersionNumber>000.sys
The major version number uses two characters. For example, the file name for version 1.0 of the library is
Wdf01000.sys. Versions 1.9, 1.11, and so on are also named Wdf01000.sys, and each new minor version of the
library file overwrites the previous version of the file.
If you built your driver using a version of the KMDF library that is more recent than the version of the
framework that is on the system, then the latter must be updated. For information about updating the
framework library, see Redistributable Framework Components.
(Note that the framework co-installer's file name includes both the major and minor version numbers. For more
information about co-installer file names, see Using the KMDF Co-installer.)
When you build your driver, the MSBuild utility links the driver with a stub file that contains the version number
of the library that the MSBuild utility used. When the operating system loads your driver, the framework's loader
checks the version information in your driver's stub to determine if the driver will run with the version of the
framework library that is on the system.
To determine the version of the library that your driver is running with, the driver can call
WdfDriverIsVersionAvailable or WdfDriverRetrieveVersionString .
WDF allows you to build a driver using a different version of Windows than the one that the driver will run on.
For more info, see Building a WDF driver for multiple versions of Windows.
For information about the release history of the KMDF library, see KMDF Version History.

UMDF
As with KMDF, the major version number of the UMDF library uses two characters. However, the major version
number only appears in the UMDF library file name starting with UMDF version 2.0.
For UMDF version 2.0, the file name of the UMDF library is Wudfx02000.dll.
For UMDF version 1.x, the file name of the UMDF library is Wudfx.dll.
For information about the release history of the KMDF library, see UMDF Version History.
KMDF Version History
2/5/2021 • 4 minutes to read • Edit Online

This topic lists versions of Kernel-Mode Driver Framework (KMDF), the corresponding versions of the Windows
operating system, and the changes made in each release.
The following table shows the release history of the KMDF library:

IN C L UDED IN T H IS
K M DF VERSIO N REL EA SE M ET H O D VERSIO N O F W IN DO W S DRIVERS USIN G IT RUN O N

1.31 Windows 10, version 2004 Windows 10, version 2004 Windows 10, version 2004
WDK (May 2020 Update, and later
Vibranium)

1.29 Not released in WDK Windows 10, version 1903 Windows 10, version 1903
(March 2019 Update, and later
19H1)

1.27 Windows 10, version 1809 Windows 10, version 1809 Windows 10, version 1809
WDK (October 2018 Update, and later
Redstone 5)

1.25 Windows 10, version 1803 Windows 10, version 1803 Windows 10, version 1803
WDK (April 2018 Update, and later
Redstone 4)

1.23 Windows 10, version 1709 Windows 10, version 1709 Windows 10, version 1709
WDK (Fall Creators Update, and later
Redstone 3)

1.21 Windows 10, version 1703 Windows 10, version 1703 Windows 10, version 1703
WDK (Creators Update, Redstone and later
2)

1.19 Windows 10, version 1607 Windows 10, version 1607 Windows 10 version 1607,
WDK (Anniversary Update, Windows Server 2016 and
Redstone 1) later

1.17 Windows 10, version 1511 Windows 10, version 1511 Windows 10 version 1511,
WDK (November Update, Windows Server 2016 and
Threshold 2) later

1.15 Windows 10 WDK Windows 10, version 1507 Windows 10, version 1507,
(Threshold 1) Windows Server 2016 and
later

1.13 Windows 8.1 WDK Windows 8.1 Windows 8.1 and later

1.11 Windows 8 WDK Windows 8 Windows Vista and later

1.9 Windows 7 WDK Windows 7 Windows XP and later


IN C L UDED IN T H IS
K M DF VERSIO N REL EA SE M ET H O D VERSIO N O F W IN DO W S DRIVERS USIN G IT RUN O N

1.7 Windows Server 2008 WDK Windows Vista with Service Windows 2000 and later
Pack 1 (SP1), Windows
Server 2008

1.5 Windows Vista WDK Windows Vista Windows 2000 and later

1.1 Download only None Windows 2000 and later

1.0 Download only None Windows XP and later

You can use the Windows Driver Kit (WDK) with Microsoft Visual Studio 2017 to build drivers that run on
Windows 7 and later.
For help determining what version of WDF to use, see Which framework version should I use?.
For a complete list of callbacks and methods, and which frameworks and versions they apply to, see Summary
of WDF Callbacks and Methods.
For information about the new features for KMDF drivers in Windows 10, see What's New for WDF Drivers.

KMDF Version 1.31


Added new API WdfDeviceSetDeviceInterfaceStateEx
Improved existing API WdfDeviceGetSystemPowerAction
Added new API WdfPdoInitRemovePowerDependencyOnParent
Introduction to the Directed Power Management Framework

KMDF Version 1.29


Unchanged from version 1.25.

KMDF Version 1.27


Unchanged from version 1.25.

KMDF Version 1.25


Building a WDF driver for multiple versions of Windows

KMDF Version 1.23


Companion functionality added for internal use only. For the new DDIs, see Summary of WDF Callbacks and
Methods.

KMDF Version 1.21


WdfFileObjectGetInitiatorProcessId was previously UMDF-only, now available in KMDF.
WdfRequestGetRequestorProcessId was previously UMDF-only, now available in KMDF.
WdfObjectDereferenceActual : Type of File parameter changed from PCHAR to PCCH.
WdfObjectReferenceActual : Type of File parameter changed from PCHAR to PCCH.
KMDF Version 1.19
Added WdfDmaTransactionSetSingleTransferRequirement
Added WDF_DMA_ENABLER_CONFIG_REQUIRE_SINGLE_TRANSFER flag in
WDF_DMA_ENABLER_CONFIG_FL AGS
Added STATUS_WDF_TOO_MANY_TRANSFERS return value for WdfDmaTransactionInitialize and
WdfDmaTransactionDmaCompleted
Added output messages for single transfer output to !wdfkd.wdfdmatransaction and
!wdfkd.wdfdmaenabler
For more info about single transfer DMA, see Using Single Transfer DMA.

KMDF Version 1.15


The new WdfDeviceOpenDevicemapKey method allows a driver to access subkeys and values under
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP .

KMDF Version 1.13


KMDF version 1.13 adds the following functionality:
Added CanWakeDevice member to WDF_INTERRUPT_CONFIG structure to support interrupts that can
be used to bring a device from a low-power Dx state back to its fully on D0 state. For more information, see
Using an Interrupt to Wake a Device.
Support for high resolution timers. For more information, see Using Timers.
Support for timers that do not wake the system if they expire when the system is in a low-power state. For
more information, see Using Timers.
The following KMDF/UMDF methods described in Accessing the Unified Device Property Model:
WdfDeviceAllocAndQuer yProper tyEx
WdfDeviceAssignProper ty
WdfDeviceInitSetIoTypeEx
WdfDeviceQuer yProper tyEx
WdfFdoInitAllocAndQuer yProper tyEx
WdfFdoInitQuer yProper tyEx
For information about UMDF versions, see UMDF Version History.

KMDF Version 1.11


Version 1.11 adds the following functionality:
System-mode DMA
Support for passive-level interrupts
Functional power states for multiple components within a single device
Dispatching IRPs to I/O Queues
The following methods:
WdfDeviceConfigureWdmIrpDispatchCallback
WdfDeviceInitSetReleaseHardwareOrderOnFailure
WdfDeviceInitSetRemoveLockOptions
WdfDeviceWdmDispatchIrp
WdfDmaEnablerConfigureSystemProfile
WdfDmaTransactionAllocateResources
WdfDmaTransactionCancel
WdfDmaTransactionFreeResources
WdfDmaTransactionGetTransferInfo
WdfDmaTransactionInitializeUsingOffset
WdfDmaTransactionSetChannelConfigurationCallback
WdfDmaTransactionSetDeviceAddressOffset
WdfDmaTransactionSetImmediateExecution
WdfDmaTransactionSetTransferCompleteCallback
WdfDmaTransactionWdmGetTransferContext
WdfInterruptQueueWorkItemForIsr
WdfInterruptRepor tActive
WdfInterruptRepor tInactive
WdfInterruptTr yToAcquireLock
WdfIoQueueStopAndPurge
WdfIoQueueStopAndPurgeSynchronously
WdfIoTargetPurge
WdfUsbTargetDeviceCreateIsochUrb
WdfUsbTargetDeviceCreateUrb
WdfUsbTargetDeviceCreateWithParameters
WdfUsbTargetDeviceQuer yUsbCapability
Added EvtDeviceUsageNotificationEx.
Added IdleTimeoutType and ExcludeD3Cold members to
WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS .
Added Repor tInactiveOnPowerDown member to WDF_INTERRUPT_CONFIG .
Added WdfIoTargetPurged value to WDF_IO_TARGET_STATE .
Added WdfSpecialFileBoot value to WDF_SPECIAL_FILE_TYPE .
Added DbgWaitForSignalTimeoutInSec to Registry Values for Debugging Framework-based Drivers.
Added InstallWdf, MultiComp, and SingleComp samples.

KMDF Version 1.9


Version 1.9 adds the following functionality:
Guaranteed forward progress for I/O queues
Support for requeuing I/O requests from a child device's I/O queue to a parent device's I/O queue
Ability to specify queue-level synchronization for individual queue objects.
The following methods:
WdfDeviceGetSystemPowerAction
WdfDeviceRemoveDependentUsageDeviceObject
WdfInterruptSetExtendedPolicy
WdfPdoInitAllowFor wardingRequestToParent
WdfPdoInitAssignContainerID
WdfPreDeviceInstallEx
WdfRequestFor wardToParentDeviceIoQueue
WdfRequestMarkCancelableEx
Added the NumberOfPresentedRequests member to the WDF_IO_QUEUE_CONFIG structure so
drivers can limit the number of I/O requests that the framework delivers to the driver from a parallel I/O
queue.
Added the WdfFileObjectCanBeOptional flag to the WDF_FILEOBJECT_CL ASS structure.
Added the TolerableDelay member to the WDF_TIMER_CONFIG structure.
Added WdfDefaultIdleInWorkingState and WdfDefaultWakeFromSleepState registry values.

KMDF Version 1.7


The WdfDeviceEnqueueRequest method can be called at IRQL<=DISPATCH_LEVEL.
The WdfWorkItemEnqueue method can be called if the specified work item is already on the work-item
queue.
Added the EvtDeviceArmWakeFromSxWithReason event callback function.
Added ArmForWakeIfChildrenAreArmedForWake and IndicateChildWakeOnParentWake
members to the WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS structure.

KMDF Version 1.5


WdfUsbInterfaceGetNumSettings
Added the DriverPoolTag member to WDF_DRIVER_CONFIG .

KMDF Version 1.1


The following methods:
WdfCommonBufferCreateWithConfig
WdfDmaEnablerGetFragmentLength
WdfDmaEnablerWdmGetDmaAdapter

KMDF Version 1.0


Initial release.
UMDF Version History
2/5/2021 • 5 minutes to read • Edit Online

This topic lists versions of User-Mode Driver Framework (UMDF), the corresponding versions of the Windows
operating system, and the changes made in each release.
The following table shows the release history of the UMDF library:

IN C L UDED IN T H IS DRIVERS USIN G IT C A N


UM DF VERSIO N REL EA SE M ET H O D VERSIO N O F W IN DO W S RUN O N

2.31 Windows 10, version 2004 Windows 10, version 2004 Windows 10, version 2004
WDK (May 2020 Update, and later
Vibranium)

2.29 Not released in WDK Windows 10, version 1903 Windows 10, version 1903
(March 2019 Update, and later
19H1)

2.27 Windows 10, version 1809 Windows 10, version 1809 Windows 10, version 1809
WDK (October 2018 Update, and later
Redstone 5)

2.25 Windows 10, version 1803 Windows 10, version 1803 Windows 10, version 1803
WDK (April 2018 Update, and later
Redstone 4)

2.23 Windows 10, version 1709 Windows 10, version 1709 Windows 10, version 1709
WDK (Fall Creators Update, and later
Redstone 3)

2.21 Windows 10, version 1703 Windows 10, version 1703 Windows 10, version 1703
WDK (Creators Update, Redstone and later
2)

2.19 Windows 10, version 1607 Windows 10, version 1607 Windows 10, version 1607,
WDK (Anniversary Update, Windows Server 2016 and
Redstone 1) later

2.17 Windows 10, version 1511 Windows 10, version 1511 Windows 10, version 1511,
WDK (November Update, Windows Server 2016 and
Threshold 2) later

2.15 Windows 10 WDK Windows 10, version 1507 Windows 10, version 1507,
(Threshold 1) Windows Server 2016 and
later

2.0 Windows Driver Kit Windows 8.1 Windows 8.1 and later
(WDK) 8.1

1.11 Windows Driver Kit (WDK) 8 Windows 8 Windows Vista and later

1.9 Windows 7 WDK Windows 7 Windows XP and later


IN C L UDED IN T H IS DRIVERS USIN G IT C A N
UM DF VERSIO N REL EA SE M ET H O D VERSIO N O F W IN DO W S RUN O N

1.7 Windows Server 2008 WDK Windows Vista with Service Windows XP and later
Pack 1 (SP1), Windows
Server 2008

1.5 Windows Vista WDK Windows Vista Windows XP and later

You can use the Windows Driver Kit (WDK) with Microsoft Visual Studio 2017 to build drivers that run on
Windows 7 and later.
For help determining what version of WDF to use, see Which framework version should I use?.
For information about the new features for UMDF drivers in Windows 10, see What's New for WDF Drivers.

UMDF Version 2.31


Added new API WdfDeviceSetDeviceInterfaceStateEx
Improved existing API WdfDeviceGetSystemPowerAction
Added per-driver HostProcessDbgBreakOnDriverLoad registry value. For info, see Registry Values for
Debugging WDF Drivers.
Introduction to the Directed Power Management Framework

UMDF Version 2.29


Unchanged from version 2.27.

UMDF Version 2.27


Added new API WdfDriverRetrieveDriverDataDirector yString

UMDF Version 2.25


Building a WDF driver for multiple versions of Windows
WdfDeviceRetrieveDeviceDirector yString

UMDF Version 2.23


Companion functionality added for internal use only. For the new DDIs, see Summary of WDF Callbacks and
Methods.

UMDF Version 2.21


WdfObjectDereferenceActual : Type of File parameter changed from PCHAR to PCCH.
WdfObjectReferenceActual : Type of File parameter changed from PCHAR to PCCH.

UMDF Version 2.19


There are no changes or additions for UMDF Version 2.19.

UMDF Version 2.17


This version adds UMDF support for the following existing interfaces:
WdfDeviceConfigureWdmIrpDispatchCallback
EvtDeviceWdmIrpDispatch
WdfDeviceWdmDispatchIrp
WdfDeviceWdmDispatchIrpToIoQueue
For more information, see Dispatching IRPs to I/O Queues.

UMDF Version 2.15


Here is the list of updated DDIs for version 2.15:
The new WdfDeviceOpenDevicemapKey method allows a driver to access subkeys and values under
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP .
A UMDF driver can call WdfIoTargetWdmGetTargetFileHandle to obtain a file handle to the next-
lower kernel-mode driver in its stack. The driver can write data to that handle, bypassing the framework's
abstractions for sending I/O to the local I/O target.
A UMDF driver can request that the underlying bus driver re-enumerate it. See WdfDeviceSetFailed .
Setting the UmdfDirectHardwareAccess directive is no longer always necessary for devices that have
connection resources. See Specifying WDF Directives in INF Files.

UMDF Version 2.0


In addition to the shared functionality described in Getting Started with UMDF, UMDF version 2.0 adds:
Support for timers that do not wake the system if they expire when the system is in a low-power state.
For more information, see Using Timers.
Added CanWakeDevice member to WDF_INTERRUPT_CONFIG structure to support interrupts that
can be used to bring a device from a low-power Dx state back to its fully on D0 state. For more
information, see Using an Interrupt to Wake a Device.
Single-component, single-state (F0) power management for UMDF drivers. For more information, see
WdfDeviceAssignS0IdleSettings .
Several debugger extension commands in Wdfkd.dll can now be used for UMDF 2.0 drivers as well. The
extension library also contains the following new extension commands designed specifically for
debugging UMDF 2.0 drivers:
!wdfkd.wdfumdevstack
!wdfkd.wdfumdevstacks
!wdfkd.wdfumdownirp
!wdfkd.wdfumfile
!wdfkd.wdfumirp
!wdfkd.wdfumirps
!wdfkd.wdfdeviceinterrupts
For a list of extension commands and framework applicability, see Debugger Extensions.
The framework's event logger, or In-flight Recorder (IFR) has been updated to work for UMDF 2.0 drivers.
Other WDF debugger extensions have been updated to work with UMDF 2.0 drivers. For a full list of
extension commands, including information about which ones apply to which framework, see Debugger
Extensions for WDF Drivers.
Added WdfIoTargetOpenLocalTargetByFile to WDF_IO_TARGET_OPEN_TYPE to allow UMDF
drivers to send driver-created requests to lower targets that require an associated file object. For more
information, see the Remarks of WDF_IO_TARGET_OPEN_TYPE .
The following UMDF-only routines:
EvtRequestImpersonate
WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_FILE
WdfDeviceAllocAndQuer yInterfaceProper ty
WdfDeviceAssignInterfaceProper ty
WdfDeviceGetDeviceStackIoType
WdfDeviceGetHardwareRegisterMappedAddress
WdfDeviceMapIoSpace
WdfDevicePostEvent
WdfDeviceQuer yInterfaceProper ty
WdfDeviceUnmapIoSpace
WdfFileObjectGetInitiatorProcessId (added to KMDF 1.21)
WdfFileObjectGetRelatedFileObject
WdfRequestGetEffectiveIoType
WdfRequestGetRequestorProcessId (added to KMDF 1.21)
WdfRequestGetUserModeInitiatedIo
WdfRequestImpersonate
WdfRequestIsFromUserModeDriver
WdfRequestRetrieveActivityId
WdfRequestSetActivityId
WdfRequestSetUserModeDriverInitiatedIo
The following KMDF/UMDF methods described in Accessing the Unified Device Property Model:
WdfDeviceAllocAndQuer yProper tyEx
WdfDeviceAssignProper ty
WdfDeviceInitSetIoTypeEx
WdfDeviceQuer yProper tyEx
WdfFdoInitAllocAndQuer yProper tyEx
WdfFdoInitQuer yProper tyEx
For more information, see Accessing the Unified Device Property Model.
Support for the following USB configuration types in WdfUsbTargetDeviceSelectConfigType :
WdfUsbTargetDeviceSelectConfigTypeSingleInterface
WdfUsbTargetDeviceSelectConfigTypeMultiInterface
WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs
Support for querying the following capability types in WdfUsbTargetDeviceQuer yUsbCapability :
GUID_USB_CAPABILITY_DEVICE_CONNECTION_HIGH_SPEED_COMPATIBLE
GUID_USB_CAPABILITY_DEVICE_CONNECTION_SUPER_SPEED_COMPATIBLE
Added WDF Register/Port Access Functions

UMDF Version 1.11


Version 1.11 adds the following driver-supplied callback interfaces and event callback functions:
IPnpCallbackHardware2
IPnpCallbackHardwareInterrupt
Version 1.11 adds the following framework-supplied interfaces:
IWDFCmResourceList
IWDFDevice3
IWDFFile3
IWDFInterrupt
IWDFIoRequest3
IWDFUnifiedProper tyStore
IWDFUnifiedProper tyStoreFactor y
IWDFWorkItem
Version 1.11 adds the following capabilities to UMDF-based drivers:
Accessing Hardware and Handling Interrupts
Using Device Pooling in UMDF Drivers
Added UmdfHostProcessSharing , UmdfDirectHardwareAccess , UmdfRegisterAccessMode ,
UmdfFileObjectPolicy , and UmdfFsContextUsePolicy directives, described in Specifying WDF
Directives in INF Files
Well-known security identifiers (SID) for UMDF drivers
Unified property store support, described in Using the Registry in UMDF-based Drivers
IoGetDeviceObjectPointer is integrated to work with UMDF. In prior versions, this routine closes the
handle to the device object after taking a reference on the device’s handle. This behavior was
incompatible with UMDF’s expectation that the cleanup request on the device object won’t occur until
after all the I/O is complete.
Creating UMDF-based HID Minidrivers
Enhanced support for Supporting Idle Power-Down in UMDF-based Drivers. The framework can now put
the device in the D3cold power state when the idle timeout period expires. The framework can also cause
the device to return to its working (D0) state when the system returns to its working (S0) state.
The following samples are new in UMDF 1.11: WudfVhidmini, NetNfpProvider.

UMDF Version 1.9


Version 1.9 adds the following driver-supplied callback interfaces:
IPnpCallbackRemoteInterfaceNotification
IPowerPolicyCallbackWakeFromS0
IPowerPolicyCallbackWakeFromSx
IQueueCallbackIoCanceledOnQueue
IRemoteInterfaceCallbackEvent
IRemoteInterfaceCallbackRemoval
IRemoteTargetCallbackRemoval
IWDFRemoteInterfaceInitialize
Version 1.9 adds the following framework-supplied interfaces:
IWDFDevice2
IWDFDeviceInitialize2
IWDFFile2
IWDFIoRequest2
IWDFIoTarget2
IWDFNamedPropertyStore2
IWDFPropertyStoreFactory
IWDFRemoteTarget
IWDFUsbTargetPipe2
These interfaces add the following capabilities to UMDF-based drivers:
Remote I/O targets
Power policy ownership
The direct I/O buffer access method
Continuous readers for USB devices
Enhanced support for device interfaces
Enhanced ability to cancel I/O requests
Enhanced access to the registry
Using WDF to Develop a Driver
2/5/2021 • 3 minutes to read • Edit Online

This topic provides a high-level overview of the framework objects you'll use to develop a Kernel-Mode Driver
Framework (KMDF) driver. Except where indicated, you'll use the same objects to develop a User-Mode Driver
Framework (UMDF) driver starting in UMDF version 2.
Windows Driver Frameworks (WDF) drivers consist of a DriverEntr y routine and a set of event callback
functions that are defined by the Windows Driver Framework objects that framework-based drivers use. The
callback functions call object methods that the framework exports. The Windows Driver Kit (WDK) contains
sample WDF drivers that demonstrate how to implement a driver's event callback functions. You can download
these samples from the Windows Dev Center - Hardware. For information about what samples are available, see
Sample KMDF Drivers and Sample UMDF Drivers.
When you create a WDF driver, you will typically do the following:
Use a framework driver object to represent your driver.
The driver's DriverEntr y routine must call WdfDriverCreate to create a framework driver object that
represents the driver. The WdfDriverCreate method also registers the driver's EvtDriverDeviceAdd
callback function, which the framework calls each time that the Plug and Play (PnP) manager reports the
existence of a device that the driver supports.
Use framework device objects to support PnP and power management in your driver.
All drivers must call WdfDeviceCreate to create a framework device object for each device that a driver
supports. A device can be a piece of hardware that is plugged into the computer, or it can be a software-
only device. Framework device objects support PnP and power management operations, and drivers can
register event callback functions that notify the driver when a device enters or leaves its working state.
For more information about framework device objects, see Supporting PnP and Power Management in
Your Driver.
Use framework queue objects and framework request objects to support I/O operations in your driver.
All drivers that receive read, write, or device I/O control requests from applications or other drivers must
call WdfIoQueueCreate to create framework queue objects that represent I/O queues. Typically, drivers
register one or more request handlers for each I/O queue. When the I/O manager sends an I/O request to
the driver, the framework creates a framework request object for the request, places the request object in
an I/O queue, and calls one of the driver's request handlers to inform the driver that a request is available.
The driver obtains the I/O request and can requeue, complete, cancel, or forward the request.
For more information about using the framework's queue objects and request objects, see Framework
Queue Objects and Framework Request Objects.
Use framework interrupt objects to handle device interrupts.
Drivers that handle device interrupts must call WdfInterruptCreate to create a framework interrupt
object for each interrupt and to register callback functions. These callback functions enable and disable
the interrupt and serve as the interrupt service routine (ISR) and deferred procedure call (DPC) for the
interrupt.
For more information about framework interrupt objects, see Handling Hardware Interrupts.
KMDF drivers can use the framework's DMA enabler objects and DMA transaction objects to handle a
device's direct memory access (DMA) operations.
If your KMDF driver's device supports DMA operations, the driver should call WdfDmaEnablerCreate
to create a DMA enabler object and WdfDmaTransactionCreate to create one or more DMA
transaction objects. The DMA transaction object defines an EvtProgramDma callback function that
programs device hardware to perform a DMA operation.
For more information about supporting DMA operations, see Handling DMA Operations in Framework-
based Drivers.
Use the framework's I/O target objects to send I/O requests to other drivers.
To pass I/O requests to other drivers (typically the next lower driver in the driver stack), your driver sends
the request to a I/O target object.
For more information about I/O target objects, see Using I/O Targets.
A KMDF driver can use the framework's WMI provider objects and WMI instance objects to support
Windows Management Instrumentation (WMI) capabilities.
Most KMDF drivers should support WMI and should call WdfWmiInstanceCreate to register callback
functions that send or receive WMI data.
For more information about WMI, see Supporting WMI in Framework-based Drivers.
Use the framework's synchronization capabilities.
All drivers must be aware of multiprocessor synchronization issues and should use synchronization
techniques that the framework provides.
Use additional objects and features that the framework provides.
The framework provides additional objects that your driver can use. For more information about these
objects, see WDF Support Objects.
WDF Architecture
2/5/2021 • 2 minutes to read • Edit Online

WDF provides object-based interfaces for drivers. Framework-defined object interfaces consist of:
Object methods
Methods are functions that a driver can call to perform an operation on the object or to get or set an object
property. Methods are named Wdf ObjectAction, where Object describes the object and Action indicates what
the function does. For example, WdfDeviceCreate creates a device object.
Object event callback functions
Event callback functions are functions that a driver provides. Each event callback function is associated with a
specific event that can occur on an object. The framework calls the event callback function when the associated
event occurs. By convention, the placeholders for event callback functions are called EvtObjectEvent, although
you can name these callbacks anything you choose in your driver. For example, a driver registers the
EvtDeviceD0Entry event callback to be notified when its device enters the working state.
Object properties
Properties are values that are stored within an object and that a driver can get (that is, obtain) and set (that is,
change). In many cases, properties map directly to the fields in the corresponding WDM objects. Properties that
cannot fail are named Wdf ObjectGet Value and Wdf ObjectSet Value, and properties that can fail are named
Wdf ObjectRetrieve Value and Wdf ObjectAssign Value. Object describes the object, and Value identifies the data
that the function sets or returns. For example, WdfDeviceGetDriver returns a handle to the driver object that is
associated with the device object.
Object handles
A framework-based driver never directly accesses framework objects. Instead, the driver receives object handles,
which it can pass to an object's methods.
The framework defines several object types that framework-based drivers use:
A framework driver object represents each driver.
A framework device object represents each device that a driver supports.
Framework queue objects represent I/O queues that receive a device's I/O requests.
Framework request objects represent I/O requests that each I/O queue receives.
For a list of all of the objects that the framework defines, see Summary of Framework Objects.
Writing a Simple WDF Driver
2/5/2021 • 2 minutes to read • Edit Online

This topic describes the minimal functionality you need to write a Kernel-Mode Driver Framework (KMDF) driver.
You need the same minimal functionality to write a User-Mode Driver Framework (UMDF) driver starting in
UMDF version 2.
When you create a new KMDF or UMDF driver, you must select a driver name that has 32 characters or less. This
length limit is defined in wdfglobals.h. If your driver name exceeds the maximum length, your driver will fail to
load.
Each framework-based driver consists of a DriverEntr y routine and a set of event callback functions that the
framework calls when object-specific events occur. For example, a simple framework-based driver might consist
of:
A DriverEntr y routine, which is called when the driver is loaded and which calls WdfDriverCreate .
An EvtDriverDeviceAdd event callback function, which the framework calls when the Plug and Play (PnP)
manager reports the detection of a device with a hardware identifier (ID) that matches a hardware ID that
the driver supports.
You specify the hardware IDs that your driver supports by providing an INF file, which the operating
system uses to install drivers the first time that one of your devices is connected to the computer. For
more information about how the system uses INF files and hardware IDs, see How Setup Selects Drivers.
The driver's EvtDriverDeviceAdd callback function calls WdfDeviceCreate to create a framework device
object for the device that was detected.
A request handler, such as the EvtIoDefault callback function, that the framework calls when the I/O
manager sends an I/O request to the driver.
When the I/O manager sends I/O requests to your driver, the framework places the requests in an I/O
queue and then notifies your driver by calling a request handler.
The driver must create at least one I/O queue for each device, so that the driver can receive I/O requests
for the device. To create an I/O queue, the driver calls WdfIoQueueCreate , which creates a framework
queue object and registers the device's request handlers.
For more information about writing a framework-based driver, see Using the Framework to Develop a Driver.
DriverEntry for WDF Drivers routine
2/5/2021 • 3 minutes to read • Edit Online

[Applies to KMDF and UMDF]


DriverEntr y is the first driver-supplied routine that is called after a driver is loaded. It is responsible for
initializing the driver.

Syntax
NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
);

Parameters
DriverObject [in]
A pointer to a DRIVER_OBJECT structure that represents the driver's WDM driver object.
RegistryPath [in]
A pointer to a UNICODE_STRING structure that specifies the path to the driver's Parameters key in the registry.

Return value
If the routine succeeds, it must return STATUS_SUCCESS. Otherwise, it must return one of the error status values
that are defined in ntstatus.h.

Remarks
Like all WDM drivers, framework-based drivers must have a DriverEntr y routine, which is called after the
driver is loaded. A framework-based driver's DriverEntr y routine must:
Activate WPP software tracing.
DriverEntr y should include a WPP_INIT_TRACING macro to activate software tracing.
Call WdfDriverCreate .
The call to WdfDriverCreate enables the driver to use Windows Driver Framework interfaces. (The
driver cannot call other framework routines before calling WdfDriverCreate .)
Allocate any non-device-specific system resources and global variables that it might need.
Typically, drivers associate system resources with individual devices. Therefore, framework-based drivers
allocate most resources in an EvtDriverDeviceAdd callback, which is called when individual devices are
detected.
Because multiple instances of a UMDF driver might be hosted by separate instances of Wudfhost, a
global variable might not be available across all instances of a UMDF driver.
Obtain driver-specific parameters from the registry.
Some drivers obtain parameters from the registry. These drivers can call
WdfDriverOpenParametersRegistr yKey to open the registry key that contains these parameters.
Provide a DriverEntry return value.
Note A UMDF driver runs in a user-mode host process, while a KMDF driver runs in kernel mode in a system
process. The framework might load multiple instances of a UMDF driver into separate instances of the host
process. As a result:
The framework might call a UMDF driver’s DriverEntry routine multiple times if it loads instances of the
driver in different host processes. In contrast, the framework calls a KMDF driver's DriverEntry routine only
once.
If a UMDF driver creates a global variable in its DriverEntry routine, the variable might may not be available
to all instances of the driver. However, a global variable that a KMDF driver creates in its DriverEntry routine
is available to all instances of the driver.
For more information about when a framework-based driver's DriverEntr y routine is called, see Building and
Loading a WDF Driver.
The DriverEntr y routine is not declared in WDK headers. Static Driver Verifier (SDV) and other verification tools
may require a declaration such as the following:

DRIVER_INITIALIZE MyDriverEntry;

NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
// Function body
}

Examples
The following code example shows the Serial (KMDF) sample driver's DriverEntr y routine.

NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
WDF_DRIVER_CONFIG config;
WDFDRIVER hDriver;
NTSTATUS status;
WDF_OBJECT_ATTRIBUTES attributes;
SERIAL_FIRMWARE_DATA driverDefaults;

//
// Initialize WPP tracing.
//
WPP_INIT_TRACING(
DriverObject,
RegistryPath
);

SerialDbgPrintEx(
TRACE_LEVEL_INFORMATION,
DBG_INIT,
"Serial Sample (WDF Version) - Built %s %s\n",
__DATE__, __TIME__
);
//
// Register a cleanup callback function (which calls WPP_CLEANUP)
// for the framework driver object. The framework will call
// the cleanup callback function when it deletes the driver object,
// before the driver is unloaded.
//
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.EvtCleanupCallback = SerialEvtDriverContextCleanup;

WDF_DRIVER_CONFIG_INIT(
&config,
SerialEvtDeviceAdd
);

status = WdfDriverCreate(
DriverObject,
RegistryPath,
&attributes,
&config,
&hDriver
);
if (!NT_SUCCESS(status)) {
SerialDbgPrintEx(
TRACE_LEVEL_ERROR,
DBG_INIT,
"WdfDriverCreate failed with status 0x%x\n",
status
);
//
// Clean up tracing here because WdfDriverCreate failed.
//
WPP_CLEANUP(DriverObject);
return status;
}

//
// Call an internal routine to obtain registry values
// to use for all the devices that the driver
// controls, including whether or not to break on entry.
//
SerialGetConfigDefaults(
&driverDefaults,
hDriver
);

//
// Break on entry if requested bt registry value.
//
if (driverDefaults.ShouldBreakOnEntry) {
DbgBreakPoint();
}

return status;
}

See also
WdfDriverCreate
EvtDriverDeviceAdd
WDFDEVICE_INIT structure
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WDFDEVICE_INIT structure is an opaque structure that is defined and allocated by the framework.

Syntax
struct WDFDEVICE_INIT {
; // Reserved.
};

Members
Function and filter drivers receive a pointer to this structure as input to a EvtDriverDeviceAdd callback function
or as a return value from WdfControlDeviceInitAllocate .
Bus drivers receive a structure pointer as input to a EvtChildListCreateDevice callback function or as the return
value from WdfPdoInitAllocate .
After a driver receives a WDFDEVICE_INIT structure, it passes the structure pointer to initialization functions.
These functions use the WDFDEVICE_INIT structure to store information that the framework uses to create a
framework device object.
To find documentation for device initialization methods, see wdfdevice.h header.
After calling initialization functions, the driver must call WdfDeviceCreate to create the framework device
object.
If your driver received the WDFDEVICE_INIT structure from a call to WdfPdoInitAllocate or
WdfControlDeviceInitAllocate , and if the driver receives an error from calling an initialization function, the
driver must call WdfDeviceInitFree instead of WdfDeviceCreate .
Your driver must not call WdfDeviceInitFree after a successful call to WdfDeviceCreate .
The WDFDEVICE_INIT structure is available in version 1.0 and later versions of KMDF.

Requirements
Header Wdftypes.h (include Wdftypes.h)
Sample KMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

This topic lists the Kernel-Mode Driver Framework (KMDF) sample drivers that you can browse and download
on the Microsoft Samples portal. You can also clone, fork, or download the Windows-driver-samples repo on
GitHub.
For information on building the samples, see Building a Driver.
ECHO Demonstrates how to use the framework's queue and request objects and automatic synchronization.
For more information about this sample, see the KMDF Echo Sample.
FakeModem Demonstrates a simple controllerless modem driver that sends and receives AT commands.
For more information about this sample, see the Fakemodem Driver.
FIREFLY Demonstrates programming a human input device (HID) device by using I/O control codes (IOCTLs),
and provides a Windows Management Instrumentation (WMI) interface.
For more information about this sample, see the FIREFLY - WDF filter driver for HID device.
HIDUSBFX2 Demonstrates how to write a minidriver for a HID device and how to map a non-HID USB device to
a HID device. The device is contained in the OSR USB-FX2 Learning Kit.
For more information about this sample, see HIDUSBFX2.
KbFiltr Demonstrates an upper device filter driver for a PS/2 keyboard.
For more information about this sample, see the Keyboard Input WDF Filter Driver (Kbfiltr).
NDISProt Demonstrates a connection-less NDIS 5.0/5.1 and NDIS 6.0 protocol driver.
For more information about this sample, see NDISProt Connection-less WDF Protocol.
NONPNP Demonstrates a non-Plug and Play (PnP) driver that uses the framework.
For more information about this sample, see NONPNP.
KMDF_FX2 Demonstrates how to perform bulk and interrupt data transfers to the USB device that is contained
in the OSR USB-FX2 Learning Kit.
For more information about this sample, see kmdf_fx2.
PCIDRV A fully functional framework-based driver for Intel 82557/82558-based PCI Ethernet adapters (10/100)
and Intel compatibles.
For more information about this sample, see the PCIDRV - WDF Driver for PCI Device.
PLX9x5x Demonstrates how to write a driver for a generic PCI device that supports DMA and uses the
PLX9656/9653RDK-LITE board.
For more information about this sample, see the PLX9x5x PCI Driver.
Serial A framework-based serial driver that is based on the WDM serial sample driver.
For more information about this sample, see the Serial sample.
Toaster Framework-based versions of the WDM toaster sample drivers. The toaster sample includes a filter
driver, a function driver, and a bus driver that create a single driver stack. The sample also includes an additional
kernel-mode driver that uses a remote I/O target to communicate with the driver stack.
For more information about this sample, see Toaster.
UsbSamp Demonstrates how to use the framework to perform bulk and isochronous data transfers to a USB
device.
For more information about this sample, see the Usbsamp Sample.
WmiSamp Demonstrates how to register WMI providers and create provider instances for framework device
objects and how to handle WMI queries that applications send to the device.
For more information about this sample, see the WmiSamp WMI Provider.
Sample UMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

This topic lists available User-Mode Driver Framework (UMDF) sample drivers that you can browse and
download on the Microsoft Samples portal. You can also clone, fork, or download the Windows-driver-samples
repo on GitHub.
Earlier versions of driver samples are archived at Windows 8.1 driver samples

UMDF 2 Samples
Sample Function Driver for OSR USB-FX2 (UMDF Version 2)
Toaster Sample (UMDF Version 2)
Echo Sample (UMDF Version 2)
Power Framework (PoFx) Sample (UMDF Version 2)

UMDF 1 Samples
GPIO Sample Drivers
The HID client sample driver (Fx2Hid) sample was removed in Windows 8.1. If you are writing a Universal
Windows app that communicates with a HID device, you'll use the Windows.Devices.Custom namespace to
access the device's HID collections directly. For more information, see the Custom driver access sample app
and the HidUsbFx2 sample driver. If you are writing a Win32 application that accesses a HID collection, refer
to the HClient sample application.
Near-Field Proximity Sample Driver
Sample UMDF Filter Driver above KMDF Function Driver for OSR USB-FX2
Sample UMDF Function Driver for OSR USB-FX2
SkeletonI2C Sample Driver
Toaster
UMDF Driver Skeleton Sample
UMDF Echo Sample
UMDF SocketEcho Sample
Virtual serial driver sample
Windows Biometric Driver Samples
WPD basic-hardware sample driver
WPD multi-transport sample driver
WPD service sample driver
WPD WUDF sample driver
WPDHelloWorld sample driver for portable devices
Sample Toaster Driver Programming Tour
2/5/2021 • 8 minutes to read • Edit Online

This topic provides a code walkthrough of the Toaster sample, which contains Kernel-Mode Driver Framework
(KMDF) and User-Mode Driver Framework (UMDF) drivers designed for learning purposes.

Class installer and Coinstaller


The tostrcls project demonstrates how to write a class installer DLL. This DLL provides a custom icon for the
Toaster class and a custom property sheet in Device Manager to change the friendly name of the device. This
DLL is referenced in the INF file for the toaster.
The tostrco1 project demonstrates how to write a coinstaller DLL. This DLL shows how to create a friendly name
based on the instance number of the device and also how to parse a custom section in an INF file. This DLL is
referenced in the INF file for the toaster.

Applications
The sample includes applications that interact with the toaster bus driver and function driver. These applications
work with both KMDF and UMDF toaster versions.
Enum.exe is a user-mode enumerator, a simple console application. Because the toaster bus is not a physical
bus, you can use this application to cause the bus driver to plug in, unplug, and eject devices from the
system. Type Enum.exe for usage tips.
Toast.exe: This is a user-mode console application to control the toaster. This application enumerates toaster
devices, opens the last enumerated device, and sends a read request to it.
Notify.exe: This GUI application combines the functionality of Enum.exe and toast.exe and also shows how to
handle PnP notifications in user mode. For example, install the toaster's coinstaller using toastco.inf and use
this app to view PnP notifications. You can also use Notify.exe to specify a different hardware ID (other than
the default toaster device ID) to cause a different driver to be loaded as a function driver.

KMDF Bus Driver


The KMDF bus driver services the toaster bus controller, enumerates devices that are plugged in, and performs
bus-level power management. The bus driver supports D0 and D3 power states. It also has a WMI interface. This
directory contains two subdirectories that show two different implementation of the Toaster bus driver.
Static
The static version of the bus driver shows how to enumerate child devices using a static child list, one per
device, provided by the framework.
Static enumeration enables a driver to detect and report the existence of devices during initialization, with
a limited ability to report subsequent changes to the system's configuration.
Bus drivers can use static enumeration if the number and type of devices or functional subunits is
predetermined and permanent, and does not depend on the configuration of the system on which the
driver is running.
For example, a sound card's driver might act as a bus driver and create separate physical device objects
(PDOs) for each of the card's capabilities, such as MIDI, audio, and joystick.
To enumerate a child, the bus driver:
1. Calls WdfPdoInitAllocate to obtain a WDFDEVICE_INIT structure.
2. Initializes the WDFDEVICE_INIT structure.
3. Call WdfDeviceCreate to create a framework device object that represents a PDO.
After calling WdfDeviceCreate , the driver calls WdfFdoAddStaticChild to add the child device to the
child list.
Because drivers should only use static child lists for device configurations that are predetermined and
permanent, a driver does not typically modify a static child list after creating it. If the driver determines
that a child device has become inaccessible, the driver can call WdfPdoMarkMissing . (If a child device is
accessible but unresponsive, the driver should set the Failed member of the WDF_DEVICE_STATE
structure to WdfTrue and then call WdfDeviceSetDeviceState .)
In order to statically enumerate child devices every time the bus driver starts, you can set a registry value
in the Toaster Bus driver's device parameter key.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\SYSTEM\
<InstanceNumber>\Device Parameters
NumberOfToasters: REG_DWORD: 2
The maximum number of child devices that can be enumerated using this registry setting is 10. You can
also configure this value through the Toaster Bus Inf file.
Dynamic
The dynamic version of the bus driver shows how to enumerate child devices using child list objects.
Dynamic enumeration enables a driver to detect and report changes to the number and type of devices
that are connected to the system while the system is running.
Bus drivers must use dynamic enumeration if the number or types of devices that are connected to the
parent device depend on a system's configuration. Some of these devices might be always connected to
the system, and some might be plugged in and unplugged while the system is running.
For example, the number and type of devices that are plugged into a system's PCI bus are system-
dependent, but they are permanent unless a user turns off power, opens the case, and adds or removes a
device by using a screwdriver. On the other hand, a user can add or remove USB devices by plugging in
or unplugging a cable while the system is running.
Each time a bus driver identifies a child device, it must add the child device's description to a child list.
Driver can either use framework provided device's default child list by calling
WdfFdoGetDefaultChildList , or can create additional child lists, for grouping children, by calling
WdfChildListCreate . This sample uses the default child list. A child description consists of a required
identification description and an optional address description.

T ERM DESC RIP T IO N

Identification Description An identification description is a structure that


contains information that uniquely identifies each
device that the driver enumerates. The driver defines
this structure, but its first member must be a
WDF_CHILD_IDENTIFICATION_DESCRIPTION_
HEADER structure.
T ERM DESC RIP T IO N

Address Description An address description is a structure that contains


information that the driver requires so that it can
access the device on its bus, if the information can
change while the device is plugged in. The driver
defines this structure, but its first member must be a
WDF_CHILD_IDENTIFICATION_DESCRIPTION_
HEADER structure. Address descriptions are
optional. This sample does not use address
descriptions.

To add children to a child list, the driver calls WdfChildListAddOrUpdateChildDescriptionAsPresent for


each child device that it finds. This call informs the framework that a driver has discovered a child device that is
connected to a parent device. When your driver calls
WdfChildListAddOrUpdateChildDescriptionAsPresent , it supplies an identification description and,
optionally, an address description.
After the driver calls WdfChildListAddOrUpdateChildDescriptionAsPresent to report a new device, the
framework informs the PnP manager that the new device exists. The PnP manager then builds a device stack
and driver stack for the new device. As part of this process, the framework calls the bus driver's
EvtChildListCreateDevice callback function. This callback function must call WdfDeviceCreate to create a PDO
for the new device.
To report a child device missing, this driver calls WdfChildListUpdateChildDescriptionAsMissing. For further
details on dynamic enumeration, please refer to the framework documentation.

KMDF Function Driver


The function driver has two different versions: wdfsimple and wdffeatured. The two versions of the function
driver share a common header file in the shared directory.
WdfSimple
In this version, the driver doesn't handle any PnP and Power events, and relies instead on the framework's
default support for these events. An application, such as notify.exe, can use this driver to open the device
interface registered by the driver and send read, write or IOCTL requests.
WdfFeatured
This version shows how to register for PNP and Power events, handle create and close file requests,
handle WMI set and query events, and trigger WMI notification events. By being a power policy owner, it
also registers for idle notification so it can put the device to low power state when there is no I/O activity.

KMDF Filter Driver


This directory contains source code for two filter drivers. The Generic sample is a simple passthru filter driver.
The SideBand shows how to provide a sideband ioctl interface to an application by using control-device object.
This private interface enables application to talk to the filter driver directly; bypassing the functional device stack
that filter is attached to. The SideBand sample also demonstrates how to implement a collection of device
objects if the driver will handle requests for more than one device. You can install these filters on an existing
toaster device by using the filter.inf.

KMDF Toastmon
This sample demonstrates how to open a device and perform I/O in kernel mode using remote I/O target
interfaces. This sample registers a PnP notification callback routine for the toaster interface class by calling
IoRegisterPlugPlayNotification . When a toaster device is plugged in, the PnP manager invokes the callback.
In the callback, this sample creates a remote target and opens the device by using the symbolic link provided in
the callback data.
Also, this sample uses a passive timer to demonstrate asynchronous read and write to the target device. It also
shows how to respond to a device change notification by registering
EvtIoTargetQueryRemove/EvtIoTargetRemoveCanceled/EvtIoTargetRemoveComplete on the I/O target object.
You can use this technique if your driver talks to another device that your driver is not controlling. You install this
driver as a root-enumerated device using Wdftoastmon.inf. Use the same steps for installation as the toaster bus
driver.

UMDF Function Driver


The WUDFToaster driver enables a user application (toast/notify.exe) to open the device interface that is
registered by the driver and send read, write or IOCTL requests. This driver sample also shows how to register
for PnP and Power events, set power policy ownership, and handle I/O requests. This is a minimal driver sample
that is not intended for use in a production environment.
You can use the WUDF Toaster in conjunction with the KMDF Toastmon sample to demonstrates kernel-mode
client access to a user-mode driver using remote I/O targets.
To do so, add the following line to the .WDF section of the INF for this UMDF driver:
UmdfKernelModeClientPolicy = AllowKernelModeClients
Testing UMDF Toaster
1. Use Toast.exe, Notify.exe or Enum.exe applications.
2. Install KMDF Toastmon driver. Allow kernel mode clients to user mode drivers as described previously. Install
WUDFToaster.dll. Use Traceview.exe to see the requests sent from Toastmon to the UMDF Toaster.
UMDF Toastmon Overview
This sample is a UMDF version of the KMDF ToastMon sample.
UMDF Toastmon demonstrates how to use UMDF to write a minimal driver with the User-Mode Driver
Framework and shows best practices. The driver will successfully load on a device (either root enumerated or a
real hardware device) but has the minimum PnP functionality and does not support receiving any I/O
operations.
Toastmon is intended to serve as a learning tool for other UMDF drivers that you may write.
Developing Drivers with the Windows Driver
Foundation: Reference Book
2/5/2021 • 2 minutes to read • Edit Online

The Developing Drivers with Windows Driver Foundation book is also available to help you learn the concepts
and fundamentals of Windows Driver Frameworks (WDF). This book introduces Windows drivers and basic
kernel-mode programming, and then describes the WDF architecture and programming model. It provides a
practical, sample-oriented guide to using the frameworks to develop Windows drivers.

Orwick, Penny and Guy Smith. Developing Drivers with Windows Driver Foundation. Redmond, WA: Microsoft
Press, 2007.

Where can I find the book?


You can purchase the book from O'Reilly using the following link:
Preview or read entire content with a Safari subscription
Creating a Framework Device Object
2/5/2021 • 2 minutes to read • Edit Online

Every function driver, filter driver, and bus driver must create a framework device object for each instance of a
supported device that is connected to the system.
Creating a framework device object involves three steps:
1. Obtaining a pointer to a WDFDEVICE_INIT structure.
This is an opaque, system-allocated structure, into which the driver stores information about a device.
2. Initializing the WDFDEVICE_INIT structure.
The driver calls a set of framework-supplied functions that add information to the structure.
3. Calling WdfDeviceCreate .
The driver passes the WDFDEVICE_INIT structure's pointer to the WdfDeviceCreate method. The
method creates a framework device object and uses information in the WDFDEVICE_INIT structure to
initialize the object.
For more information about creating framework device objects, see the following topics:
Creating Device Objects in a Function Driver
Creating Device Objects in a Filter Driver
Creating Device Objects in a Bus Driver
Creating Device Objects in a Function Driver
2/5/2021 • 3 minutes to read • Edit Online

Each function driver creates a framework device object for each of its supported devices that exists on the
system. Because these device objects are created by function drivers, they are called functional device objects
(FDOs). Each FDO is a function driver's representation of a device.
A function driver must create a framework device object each time the framework calls the driver's
EvtDriverDeviceAdd callback function. The framework calls this callback function to inform the driver that one of
its supported devices exists on the system.
The driver's EvtDriverDeviceAdd callback function receives a pointer to a WDFDEVICE_INIT structure. The
driver can call a set of framework device object initialization methods, which store information in the
WDFDEVICE_INIT structure. Additionally, function drivers can call framework FDO initialization methods.
Creating a framework device object in a function driver typically includes the following steps:
Registering PnP, power, and power policy callback functions.
Most function drivers call WdfDeviceInitSetPnpPowerEventCallbacks to register PnP and power
callback functions. For more information about these callback functions, see Supporting PnP and Power
Management in Function Drivers.
If the device supports low-power idle or has wake-up capabilities, the function driver typically also calls
WdfDeviceInitSetPowerPolicyEventCallbacks to register power policy callback functions. For more
information about these callback functions, see Power Policy Ownership.
Registering function driver-specific callback functions.
Some function drivers call WdfFdoInitSetEventCallbacks , if they must participate in specifying the
system hardware resources that a device requires. For more information about hardware resources, see
Hardware Resources for Framework-Based Drivers.
Registering file event callback functions.
If your driver must respond when an application opens or closes a file on a device, the driver must call
WdfDeviceInitSetFileObjectConfig to register callback functions for the framework file object. For
more information, see Using Framework File Objects.
Setting I/O request attributes.
If your driver will receive I/O requests from framework queue objects, the driver can call
WdfDeviceInitSetRequestAttributes to set up context memory that the framework will assign to a
device's request objects. For more information, see Using Request Object Context.
Setting device characteristics.
Typically, a function driver calls some of the following methods to specify a device's characteristics:
WdfDeviceInitSetDeviceType , to identify the type of hardware that the driver supports.
WdfDeviceInitSetIoType , to identify a method for accessing data buffers, if the driver handles I/O
requests from applications.
WdfDeviceInitSetCharacteristics , to set device characteristics, such as whether the device is read-
only or supports removable media.
WdfDeviceInitSetExclusive , if the device requires exclusive access by one application at a time.
WdfDeviceInitSetPowerInrush , if the device requires an inrush of current when it transitions from
a low-power state to its working (D0) state.
WdfDeviceInitSetPowerPageable or WdfDeviceInitSetPowerNotPageable , to indicate whether
the driver must access pageable data while the system is transitioning between a sleeping state and
the working (S0) state.
WdfDeviceInitAssignName , to assign a name to the device object.
WdfDeviceInitAssignSDDLString , to assign a security descriptor to the device object.
WdfDeviceInitSetDeviceClass , to identify the device's setup class.
Obtaining device properties.
Sometimes function drivers must obtain information about the device properties that the driver for the
device's bus, or other lower-level driver, has set. The driver can call WdfFdoInitQuer yProper ty or
WdfFdoInitAllocAndQuer yProper ty to obtain this information. New drivers targeting Windows 8.1
and later can call WdfFdoInitQuer yProper tyEx and WdfFdoInitAllocAndQuer yProper tyEx .
Accessing the device's registry key.
Some function drivers must obtain information about the device or driver that another driver, a user, or
an installation package has placed in the registry. The driver can call WdfFdoInitOpenRegistr yKey to
open the device or driver's registry key. For more information, see Using the Registry in Framework-
Based Drivers.
Creating a default child list configuration to use for dynamic enumeration.
If you are writing a function driver for a bus, and if your driver will perform dynamic enumeration of child
devices that are connected to the bus, the driver must call WdfFdoInitSetDefaultChildListConfig . For
more information, see Enumerating the Devices on a Bus.
Creating the device object.
The final step in creating a device object is to call WdfDeviceCreate .
Creating Device Objects in a Filter Driver
2/5/2021 • 2 minutes to read • Edit Online

Each filter driver creates a framework device object for each of its supported devices that exists on the system.
Because these device objects are created by filter drivers, they are called filter device objects (Filter DOs). Each
Filter DO is a filter driver's representation of a device.
Filter drivers, like function drivers, provide an EvtDriverDeviceAdd callback function that receives a handle to a
WDFDEVICE_INIT structure. The driver can call the same set of framework device object initialization methods
that function drivers call to store information in the WDFDEVICE_INIT structure. Like function drivers, filter
drivers can also call framework FDO initialization methods.
A small number of filter drivers enumerate child software-only devices. Such filter drivers can call framework
PDO initialization methods.
Filter drivers must call WdfFdoInitSetFilter .
The final step in creating a device object is to call WdfDeviceCreate .
Creating Device Objects in a Bus Driver
2/5/2021 • 2 minutes to read • Edit Online

Each bus driver must create a framework device object when it discovers that a child device is connected to a
parent device. The parent device is typically a bus, but it can also be a multifunction device for which each
function requires a separate set of drivers (such as a sound card that supports digital audio and MIDI). The
device objects that bus drivers create are called physical device objects (PDOs) because each represents an
actual connection of one piece of hardware (the child) to another (the parent).
The process of identifying and reporting the devices that are connected to a bus is called bus enumeration.
If a bus driver performs dynamic bus enumeration, its EvtChildListCreateDevice callback function receives
a handle to a WDFDEVICE_INIT structure.
If a bus driver performs static bus enumeration, it must call WdfPdoInitAllocate to obtain a handle to a
WDFDEVICE_INIT structure.
For more information about bus enumeration, see Enumerating the Devices on a Bus.
A bus driver can call a set of framework device object initialization methods, which store information in the
WDFDEVICE_INIT structure. Additionally, bus drivers can call framework PDO initialization methods.
Creating a framework device object for an enumerated child device typically includes the following steps:
Registering bus driver-specific callback functions.
Most bus drivers call WdfPdoInitSetEventCallbacks , because they must specify the system hardware
resources that a device requires. For more information about specifying hardware resources, see
Hardware Resources for Framework-Based Drivers. Additional callback functions can be registered if the
device and driver support ejection.
Reporting device identification strings.
Bus drivers must report the device's identification strings by calling WdfPdoInitAssignDeviceID ,
WdfPdoInitAssignInstanceID , WdfPdoInitAddCompatibleID , and WdfPdoInitAddHardwareID for
each type of string that the device supports. In addition, bus drivers that use version 1.9 or later of the
framework can call WdfPdoInitAssignContainerID .
Reporting whether the bus driver can support the device in raw mode.
If the bus driver supports raw mode for the device, it must call WdfPdoInitAssignRawDevice .
Providing displayable text that describes the device.
Bus drivers call WdfPdoInitAddDeviceText and WdfPdoInitSetDefaultLocale to provide text that
describes the device to users, in multiple languages.
Creating the device object.
The final step in creating a device object is to call WdfDeviceCreate .
If the driver encounters an error while initializing the WDFDEVICE_INIT structure that it obtained from
WdfPdoInitAllocate , the driver must call WdfDeviceInitFree instead of WdfDeviceCreate .
After the bus driver has created the device object, it typically calls WdfDeviceSetPnpCapabilities and
WdfDeviceSetPowerCapabilities to report the device's Plug and Play and power capabilities.
Each bus driver is also the function driver for the bus adapter. Therefore, the driver must also provide an
EvtDriverDeviceAdd callback function. This callback function creates a functional device object (FDO) for each
bus adapter on the system. For more information about creating FDOs, see Creating Device Objects in a
Function Driver.
Building, Installing, and Testing
2/5/2021 • 2 minutes to read • Edit Online

This section describes how you build a Windows Driver Frameworks (WDF) driver in Microsoft Visual Studio,
whether you need to provide a co-installer, and how you test your driver using the WDF Verifier and built-in
event logging.

In this section
Building and Loading a WDF Driver
Building a WDF driver for multiple versions of Windows
Redistributable Framework Components
Specifying the KMDF Co-installer in an INF File
Using the UMDF Co-installer
Using INX Files to Create INF Files
Testing a WDF Driver (KMDF or UMDF)
Troubleshooting KMDF and UMDF Driver Installation
Installing a UMDF Filter Driver
Specifying the Reflector in an INF File
Specifying WDF Directives in INF Files
Using Device Pooling in UMDF Drivers
Session Zero Guidelines for UMDF Drivers
Restricting the Loading Location of UMDF Drivers
Controlling Device Access
Using the Framework's Event Logger
Using KMDF Verifier
Using UMDF Verifier
How UMDF Handles Driver Failures
How UMDF Handles Application Failures
How UMDF Reports Errors
Building and Loading a WDF Driver
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how to select a target operating system and framework version for a driver project in Visual
Studio.
To determine if you need to include redistributable framework components in your driver package, see
Redistributable Framework Components.

Which framework version should I use?


To target Windows XP, use WDF 1.9 or earlier.
To target Windows Vista, Windows 7, or Windows 8, use WDF 1.11 or earlier.
To target Windows 8.1, use KMDF 1.13 or earlier, or UMDF 1.x, or UMDF 2.0.
To target Windows 10 version 1507, use KMDF 1.15 or earlier, or UMDF 1.x, or UMDF 2.15 or earlier.
For detailed information about KMDF and UMDF versions, see KMDF Version History and UMDF Version
History.
KMDF Version History
UMDF Version History

How do I set the versions in Visual Studio?


If you're building your driver project for the latest version of Windows and the most recent KMDF or UMDF
version, you can keep the defaults and skip this step.
Otherwise, follow these steps:
Right-click the solution and select Configuration Manager . Set Project Configuration to the desired
value (for example Debug ).
Right-click the driver project and select Proper ties . Open Configuration Proper ties->Driver Settings-
>Driver Model . Change the KMDF Version Minor (Target Version) or UMDF Version Minor (Target
Version) value in the Driver Model Settings to the desired value. For info about KMDF Version Minor
(Minimum Required) and UMDF Version Minor (Minimum Required) , see Specifying Minimum
Required.
You can use the Windows Driver Kit (WDK) that ships with Windows 10 to build KMDF 1.9-1.29 drivers, as well
as UMDF 1.9-2.29 drivers.
For detailed information about KMDF and UMDF versions, see KMDF Version History and UMDF Version
History.
KMDF Version History
UMDF Version History

Linking and loading


When you build a Windows Driver Frameworks (WDF) project in Microsoft Visual Studio, MSBuild links your
driver to the appropriate framework library, the library's loader, and a stub file, all of which are included in the
WDK. (The library and loader are also included in the framework's co-installer so that if necessary, you can
distribute them with your driver package.)
The stub file contains a special entry point routine: FxDriverEntr y . MSBuild sets the stub's FxDriverEntr y
routine as the initial entry point for framework-based drivers.
When the operating system loads a framework-based driver, it also loads the stub file and the library's loader.
Next, the system calls the stub file's FxDriverEntr y routine. This routine then calls the loader. The loader
determines the version of the framework library that the driver requires and then loads the correct version of
the library as a kernel-mode service (if it is not already loaded). Finally, the library calls the driver's DriverEntr y
routine.
Building a WDF driver for multiple versions of
Windows
12/5/2018 • 3 minutes to read • Edit Online

WDF has always allowed you to build a driver once and use the resulting binary on multiple versions of
Windows, but before Windows 10 version 1803 (Redstone 4), this was limited to "build on older, run on newer."
Starting in Windows 10 version 1803, WDF adds "build on newer, run on older," with the additional benefit of
conditional execution. To summarize:
Existing : Binaries built with older versions of the framework run on versions of Windows that include newer
versions of the framework, provided major versions match. For example, a driver built with KMDF 1.9
(Windows 7) runs on a Windows 8 system (KMDF 1.11). In the example, the driver is limited to functionality
of KMDF 1.9.
Added : Starting in KMDF version 1.25 and UMDF version 2.25 on Windows 10 version 1803, you can build a
driver with a newer framework version and the resulting driver binary runs on earlier versions of Windows
(at minimum Windows 10 version 1803). In addition, the driver can conditionally use functionality that is
only available in newer framework versions.
This means that not only does your driver run on future versions of Windows, as it always has, but it also runs
on past versions, back to Windows 10 version 1803.
There are two steps to doing this: specifying build settings in Visual Studio, and performing a runtime check
before invoking an API or accessing a structure or field that may or may not be present.
Note : This feature is optional and a driver should only enable it to build a driver that uses the latest WDF
functionality while remaining loadable on earlier versions of Windows that do not have the latest WDF
functionality.
If you do not set Version Minor (Target Version) or Version Minor (Minimum Required) , versioning
remains the same as before.

Specifying Minimum Required


The new configuration settings in Visual Studio are:
KMDF Version Minor (Minimum Required)
UMDF Version Minor (Minimum Required)
In accordance with this change, the names of two existing settings were updated:
KMDF Version Minor -> KMDF Version Minor (Target Version)
UMDF Version Minor -> UMDF Version Minor (Target Version)
If you don't set Minimum Required , Visual Studio builds for Target Version and up, and does not provide
downlevel support. This matches the behavior of the old Version Minor properties.
If you do set Minimum Required , the following requirements apply:
25 <= Minimum Required <= Target Version
In Configuration Proper ties->Driver Settings->General , set _NT_TARGET_VERSION to 0x0A000005 (RS4)
or later.
Checking if functionality is present
Prior to every use of an API, structure, or member that may or may not be present, you must call one of the
following macros, which are defined in WdfFuncEnum.h:

BOOLEAN
WDF_IS_FUNCTION_AVAILABLE (
FunctionName
);

BOOLEAN
WDF_IS_STRUCTURE_AVAILABLE (
StructName
);

BOOLEAN
WDF_IS_FIELD_AVAILABLE (
StructName,
FieldName
);

Consider the following example. When WDF v29 is released, it adds a new API: WdfSomeNewFeature . If you
set Target Version to 29 and Minimum Required to 25, the resulting driver loads on any framework version
from 25 through 29 (and beyond, as long as major version doesn't change), calls version 25 APIs like before,
and makes the following check before each call of any v29 API:

if (WDF_IS_FUNCTION_AVAILABLE(WdfSomeNewFeature)) {
WdfSomeNewFeature();
}

If you don't do the conditional check, you might see the following:
If the API returns NTSTATUS, the call returns a failure code.
If the API returns anything other than NTSTATUS:
KMDF: The machine bug checks.
UMDF: The WudfHost process crashes with a DriverStop error.
If Driver Verifier is enabled, the driver crashes as well. This helps to identify the problem in a test
environment.
Silent memory corruption (when accessing a structure or field).
A driver crash contains the failed driver name, the framework name, and the failed API index. You can retrieve
the name of API by looking up the value of WDFFUNCENUM in WdfFuncEnum.h.
For more info about Visual Studio properties for WDF, see Driver Model Settings Properties for Driver Projects.
Redistributable Framework Components
2/5/2021 • 2 minutes to read • Edit Online

This topic describes the Microsoft-supplied redistributable framework updates that are included as part of the
Windows Driver Kit (WDK), and how to determine which ones to add to your driver package.
The redistributable framework updates make it possible to run a driver built with a later framework version than
the one included in an operating system. For example, KMDF 1.11 is included in Windows 8. But you can run a
KMDF 1.11 driver on Windows Vista or Windows 7. Before you can do so, however, you must ensure that the
KMDF 1.11 framework library replaces the framework library included in the earlier operating system (in this
case, KMDF 1.7 and KMDF 1.9 respectively). You do this by redistributing a Microsoft-supplied co-installer or
.msu file with your driver package.

When do I need to include a co-installer or .msu in my driver


package?
First, decide which versions of Windows your driver will support. Based on that, determine which framework
version to use.
If the chosen WDF version is more recent than the version that shipped with the target OS, include the co-
installer or .msu file in your driver package.
For example, you want your driver to run on Windows 7. You can choose to build your driver using either WDF
1.11 or WDF 1.9. If you choose 1.9, which is provided with Windows 7, there is no need to update the system.
On the other hand, if you choose 1.11, you would need to include a WDF 1.11 update package with your driver.

Should I include the co-installer or the .msu file?


If your driver installation is triggered by plugging in a new hardware device to a system and you are installing
only the driver, include the co-installer in your driver package. Then reference the co-installer in your INF file, as
described in Specifying the KMDF Co-installer in an INF File.
If you need to install an application in addition to your driver, you should instead redistribute the relevant MSU
package (for example kmdf-1.11-Win.6.0.msu) along with a setup application that calls it. In this case, no INF
entries are needed.
You never need both the co-installer and the .msu file.

Where can I find these files, and what's included?


The co-installers are located in %program files%\Windows Kits\<version>\redist\wdf .
This directory contains the following files, for x86 and x64:
WdfCoinstaller01007.dll, WdfCoinstaller01009.dll, WdfCoinstaller01011.dll (co-installers for KMDF
1.7/1.9/1.11).
WUDFUpdate_01007.dll, WUDFUpdate_01009.dll, WUDFUpdate_01011.dll (co-installers for UMDF).
winusbcoinstaller.dll, winusbcoinstaller2.dll (co-installers for WinUSB 1.5/1.9).
If you would like the MSU file, please download and install the package (in MSI format) from WDK 8
redistributable components. After installation, the MSU and co-installers can be found in
%program files%\Windows Kits\8.0\redist\wdf .
Co-installer Naming and Versioning
The co-installer is named WdfCoInstaller MMmmm.dll .
MM is the major version number.
mmm is the minor version number.
For example, the filename for version 1.0 of the co-installer is WdfCoInstaller01000.dll, and the filename for
version 1.11 is WdfCoInstaller01011.dll.
The version of the co-installer that you include with your driver package must match the version of the
framework library that you use to develop your driver.
Note that the framework library's file name includes only the major version number. For more information
about library file names, see Framework Library Versioning.
Specifying the KMDF Co-installer in an INF File
2/5/2021 • 2 minutes to read • Edit Online

If you include a co-installer in your driver package, read this topic for information about sections you must
provide in your driver's INF file. This information does not apply if you provide your own setup application that
calls Microsoft-supplied .msu redistributables.

INF File Sections for the Co-installer


Your driver's INF file must contain an INF DDInstall.CoInstallers section that installs the co-installer. For
example this section might be named MyDevice.ntx86.CoInstallers . For more information about specifying a
co-installer in an INF file, see INF DDInstall.CoInstallers Section .
In addition, your driver's INF file must contain an INF DDInstall.Wdf section that the co-installer reads after it
has been installed. For example, this section might be named MyDevice.ntx86.Wdf . After the framework's co-
installer has been installed, it reads this section while it is installing your driver.
The INF DDInstall.Wdf section contains the following directive:
KmdfSer vice = DriverService,Wdf-install-section
DriverService represents the name that the operating system will assign to your driver's kernel-mode service,
and Wdf-install-section represents the name of an INF section that the co-installer reads to obtain information
about your driver.
The INF section that Wdf-install-section identifies must contain the following directive:
KmdfLibrar yVersion = WdfLibraryVersion
WdfLibraryVersion represents a library version number, such as "1.0" or "1.11".
For example, the following INF DDInstall.Wdf section specifies Echo_wdfsect as the Wdf-install-section name.

[ECHO_Device.NT.Wdf]
KmdfService = Echo, Echo_wdfsect
[Echo_wdfsect]
KmdfLibraryVersion = 1.0

You can avoid creating multiple INF files for multiple versions of the framework by using INX files and the
Stampinf tool. For more information about INX files, see Using INX Files to Create INF Files.
Sample INF DDInstall.CoInstallers and DDInstall.Wdf Sections
The following code example shows how to create the INF DDInstall.CoInstallers section and INF DDInstall.Wdf
section of an INF file for a PnP driver. The example shows how to create an INF file that is called MyDevice.inf
and is based on the ECHO sample driver's Echo.inf file. The Echo sample driver is located in the samples
directory of the WDK.
To create MyDevice.inf, you must change all ECHO_Device substrings in Echo.inf to a name that is appropriate
for your product. The following code example uses MyDevice .
You should attempt to match the section layout that the Echo.inf sample uses. In other words, if possible, keep
the co-installer-related sections together to more easily spot cut-and-paste errors.
Before you have modified echo.inf, the sections that install the co-installer are as follows:
=============== Top of Echo.inf ====================
....
....
[DestinationDirs]
DefaultDestDir = 12
ECHO_Device_CoInstaller_CopyFiles = 11
....
....
;
;--- ECHO_Device Co-installer installation ------
;
[ECHO_Device.NT.CoInstallers]
AddReg=ECHO_Device_CoInstaller_AddReg
CopyFiles=ECHO_Device_CoInstaller_CopyFiles

[ECHO_Device_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller01000.dll,WdfCoInstaller"

[ECHO_Device_CoInstaller_CopyFiles]
WdfCoInstaller01000.dll

[ECHO_Device.NT.Wdf]
KmdfService = Echo, Echo_wdfsect
[Echo_wdfsect]
KmdfLibraryVersion = 1.0

=============== End of Echo.inf ===============

After you have changed all ECHO_Device substrings, your MyDevice.inf file should appear as follows:

=============== Top of MyDevice.inf ===============


....
....
[DestinationDirs]
DefaultDestDir = 12
MyDevice_CoInstaller_CopyFiles = 11
....
....
;
;--- MyDevice Co-installer installation ------
;
[MyDevice.NT.CoInstallers]
AddReg=MyDevice_CoInstaller_AddReg
CopyFiles=MyDevice_CoInstaller_CopyFiles

[MyDevice_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller01000.dll,WdfCoInstaller"

[MyDevice_CoInstaller_CopyFiles]
WdfCoInstaller01000.dll

[MyDevice.NT.Wdf]
KmdfService = MyDevice, MyDevice_wdfsect
[MyDevice_wdfsect]
KmdfLibraryVersion = 1.0
....
....
=============== End of MyDevice.inf ===============
Using the UMDF Co-installer
2/5/2021 • 3 minutes to read • Edit Online

A co-installer updates the framework version stored on the machine and processes framework-specific INF file
sections. This topic describes the two UMDF co-installers and when you need to include one with your driver
installation package or reference a co-installer in your INF file.

Getting the Co-installer Package


In Windows 8.1, the Microsoft-supplied redistributable framework updates are included as part of the Windows
Driver Kit (WDK).
For a complete list of the contents of the co-installer directory, see Installation Components for KMDF Drivers.
Among other components, the co-installer directory contains an update co-installer, called
WUDFUpdate_MMmmm.dll, where MM is the major version number, and mmm is the minor version number.
The update co-installer updates the UMDF framework version that is on the computer. For example, if the
computer has UMDF version 1.9 and the co-installer contains version 1.11, the co-installer updates the
computer's framework version to 1.11.
The operating system includes another co-installer, called the configuration co-installer, or WudfCoinstaller.dll.
The configuration co-installer processes the UMDF-specific sections of the driver's INF file and makes any
necessary updates to the registry.

Referencing Co-installers from your INF File


If you are writing a UMDF 2.0 driver for Windows 8.1, your INF file must reference the configuration co-installer.
Because the configuration co-installer is included in the operating system, you do not need to redistribute it.
If you are writing a UMDF 1.11 driver that targets operating systems prior to Windows 8.1, you must ensure that
version 1.11 of the framework is installed on machines that use your driver. Here are three ways to do this:
Reference the update co-installer in your INF file, and include the update co-installer in your driver
installation package. When the operating system installs your driver, it runs the co-installer. If your driver
will be distributed via Windows Update, you must choose this option.
Redistribute the relevant MSU package (for example umdf-1.11-Win-6.0.msu) along with a setup
application that calls it. You can find a sample of such an application in the src\general\wdkinstall
subdirectory of your WDK installation. You might choose this option if you are writing a setup program
that ships with the device and must be run before the device can be used. If you choose this option, your
INF file must reference the configuration co-installer.
Rely on Windows Update to install the required framework version on machines that use your driver.
Starting with version 1.11 of the framework, new versions of UMDF are distributed via Windows Update.
If you choose this option, your INF file must reference the configuration co-installer.
In your INF file, you must always reference either the update co-installer or the configuration co-installer.
However, referencing both co-installers in the INF will lead to installation errors.

INF File Sections for the Co-installer


Your driver's INF file must include an INF DDInstall.CoInstallers section . If you redistribute the update co-
installer, your DDInstall.CoInstallers section must include both an INF AddReg directive and an INF
CopyFiles directive , as the following example shows.

[MyDriver_Install.CoInstallers]
AddReg = MyDriver_Install.CoInstallers_AddReg
CopyFiles = MyDriver_CoInstallers_CopyFiles

The INF AddReg directive identifies an INF section that creates a CoInstallers32 registry entry.

[MyDriver_Install.CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WudfUpdate_01011.dll"

The INF CopyFiles directive identifies an INF section that copies the co-installer from the installation device to
the system device.

[MyDriver_CoInstallers_CopyFiles]
WudfUpdate_01011.dll

If you redistribute an MSU package, your DDInstall.CoInstallers section must specify an AddReg directive
that references the configuration co-installer.

[Echo_Install.NT.CoInstallers]
AddReg=CoInstallers_AddReg
[CoInstaller.AddReg]
HKR,,CoInstallers32,0x00010000,WudfCoinstaller.dll

Your driver's INF file must always contain a DDInstall.Wdf section that the co-installer reads after it has been
installed. For information about directives that your driver can specify in DDInstall.Wdf , see Specifying WDF
Directives in INF Files.
You can avoid creating multiple INF files for multiple versions of the framework by using INX files and the
Stampinf tool. For more information about INX files, see Using INX Files to Create INF Files.
Using INX Files to Create INF Files
2/5/2021 • 2 minutes to read • Edit Online

An INX file is an INF file that contains string variables that represent version information. When you build your
driver using Microsoft Visual Studio, the build process runs the Stampinf tool to replace the string variables in
INX files with text strings that represent a specific hardware architecture or a framework version. You can also
manually run the Stampinf tool, which is located in the bin subdirectory of the WDK.
If you create INX files for your drivers, you do not have to maintain multiple version-specific INF files. Instead,
you can create a single INX file and use Visual Studio or Stampinf to generate version-specific INF files when you
need them.
To modify Stampinf properties within Visual Studio, open the Property Pages for your driver package project.
Right-click the package project in Solution Explorer and select Proper ties . In the Property Pages for the
package, click Configuration Proper ties , and then StampInf .
The WDK includes INX files for all the KMDF and UMDF sample drivers.
INX files can contain the following string variables:
$ARCH$
Stampinf replaces this variable with an architecture-specific string. For example, if you are using an x86 build
environment, the tool replaces $ARCH$ with "x86". You can use the $ARCH$ string wherever you need to
specify a specific architecture within an INF file, such as within an INF Manufacturer section , as follows:

[Manufacturer]
%StdMfg%=Standard,NT$ARCH$

$KMDFCOINSTALLERVERSION$
If you use the Stampinf tool's -k option, Stampinf replaces this variable with a string that represents a specific
version of the KMDF co-installer. You can use the $KMDFCOINSTALLERVERSION$ variable when you specify the
framework's co-installer within an INF file, such as within an INF DDInstall.CoInstallers section , as follows:

[ECHO_Device.NT.CoInstallers]
AddReg=ECHO_Device_CoInstaller_AddReg
CopyFiles=ECHO_Device_CoInstaller_CopyFiles

[ECHO_Device_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"

[ECHO_Device_CoInstaller_CopyFiles]
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll

$KMDFVERSION$
If you set the KMDF Version Number property in Visual Studio (or use the Stampinf tool's -k option), Stampinf
replaces this variable with a string that represents a specific version of KMDF. You can use the $KMDFVERSION$
variable when you specify the framework's version within an INF file, such as when you specify the
KmdfLibraryVersion directive, as follows:

KmdfLibraryVersion = $KMDFVERSION$

$UMDFCOINSTALLERVERSION$
[SourceDisksFiles]
WudfUpdate_$UMDFCOINSTALLERVERSION$.dll=1

[CoInstallers_CopyFiles]
WudfUpdate_$UMDFCOINSTALLERVERSION$.dll

[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WUDFUpdate_$UMDFCOINSTALLERVERSION$.dll"

$UMDFVERSION$

[UMDFYourDriver_Install]
UmdfLibraryVersion=$UMDFVERSION$

Stampinf also supports a -u option to replace UMDF string variables in an INX file. If your driver package
includes both UMDF-based drivers and KMDF-based drivers, you can use the -k and -u options with a single
Stampinf command and a single INX file.
Testing a WDF Driver (KMDF or UMDF)
2/5/2021 • 2 minutes to read • Edit Online

This topic describes recommendations for testing a Kernel-Mode Driver Framework (KMDF) or User-Mode
Driver Framework (UMDF) version 2 driver.
When testing your driver, you should:
Set the VerifierOn registry value to enable the framework's driver verification features. For more
information about VerifierOn and other registry values that you can use when you are debugging and
testing your driver, see Using KMDF Verifier and Using UMDF Verifier. For information about an
application that helps you to use the framework's driver verification features, see WDF Verifier Control
Application.
For both UMDF versions 1 and 2, enable [Application Verifier (AppVerif.exe)] on Wudfhost.exe. You can
download the AppVerif tool as part of Download Debugging Tools for Windows. For example:

appverif -enable handles locks heaps memory exceptions TLS -for WudfHost.exe

Doing so automatically turns on the framework's built-in verification.


Use the driver verification tools that are described in this documentation. For more information about
these important tools, see:
WdfTester: WDF Driver Testing Toolset
Tools for Verifying Drivers
Tools for Testing Drivers
To thoroughly test your driver, you must use both the framework's driver verification features and the driver
verification tools.
Troubleshooting KMDF and UMDF Driver
Installation
2/5/2021 • 3 minutes to read • Edit Online

The framework's co-installer creates debugging messages. You can see these messages in a debugger.
Additionally, the co-installer writes its debugging messages to the Setup action log (%windir%\setupact.log) file.
The Setup action log contains the version of the co-installer and the driver specified in the driver's INF file. You
should verify that these are as expected.

Examining KMDF Installation


The following output in the Setup action log is from the successful installation of a KMDF driver:

WdfCoInstaller: DIF_INSTALLDEVICE: Pre-Processing


WdfCoInstaller: ReadComponents: WdfSection for Driver Service ECHO using KMDF lib version Major 0x1, minor
0x9
WdfCoInstaller: DIF_INSTALLDEVICE: Coinstaller version: 1.9.7100
WdfCoInstaller: DIF_INSTALLDEVICE: KMDF in-memory version: 1.9.7100
WdfCoInstaller: DIF_INSTALLDEVICE: KMDF on-disk version: 1.9.7100
WdfCoInstaller: Service Wdf01000 is running
WdfCoInstaller: DIF_INSTALLDEVICE: Update is not required. The on-disk KMDF version is newer than or same as
the version of the coinstaller
WdfCoInstaller: DIF_INSTALLDEVICE: Post-Processing

In the above scenario, no update was necessary because the on-disk version and in-memory framework version
is KMDF 1.9, which is the same version of the co-installer.
Consider the following output, which details an unsuccessful installation:

WdfCoInstaller: ReadComponents: WdfSection for Driver Service ECHO using KMDF lib version Major 0x1, minor
0x9
WdfCoInstaller: DIF_INSTALLDEVICE: Coinstaller version: 1.9.7100
WdfCoInstaller: DIF_INSTALLDEVICE: KMDF in-memory version: 1.7.6000
WdfCoInstaller: DIF_INSTALLDEVICE: KMDF on-disk version: 1.7.6000
WdfCoInstaller: Service Wdf01000 is running
WdfCoInstaller: DIF_INSTALLDEVICE: Reboot is required, because the in-memory KMDF version is older than the
coinstaller's version.
WdfCoInstaller: DIF_INSTALLDEVICE: Update is required, because the on-disk KMDF version is older than the
coinstaller
WdfCoInstaller: VerifyMSRoot: exit: error(0) The operation completed successfully.
WdfCoInstaller: Invoking "D:\Windows\system32\wusa.exe "D:\Windows\Temp\WdfTemp\Microsoft Kernel-Mode Driver
Framework Install-v1.9-Vista.msu" /quiet /norestart".
WdfCoInstaller: The update process returned error code :error(265) <no error text>.
WdfCoInstaller: For additional information please look at the log files %windir%\windowsupdate.log and
%windir%\Logs\CBS\CBS.log

In this scenario, both an update and a reboot were necessary because the in-memory version and the on-disk
version of the KMDF runtime were older than the version of the co-installer. However, the update was
unsuccessful. The co-installer points to additional log files where you can find more information about the
failure.
You can also check the system event log for errors related to the dynamic binding of the KMDF driver to the
runtime library. Such an error may generate an Wdf <MajorVersionNumber><MinorVersionNumber> entry in
the system event log. In this case, reboot the computer. You can also force a reinstallation of the KMDF runtime
by deleting Wdf <MajorVersionNumber><MinorVersionNumber>.sys from the %windir%\system32\drivers
folder.

Examining UMDF Installation


The following output in the Setup action log describes a successful UMDF driver installation.

WudfUpdate: installing version (1,9,0,7100).


WudfUpdate: Checking for presence of previous UMDF installation.
WudfUpdate: Found binary %WINDIR%\system32\drivers\wudfrd.sys version (1.9.0.7100)
WudfUpdate: Found binary %WINDIR%\system32\drivers\wudfpf.sys version (1.9.0.7100)
WudfUpdate: Found binary %WINDIR%\system32\wudfhost.exe version (1.9.0.7100)
WudfUpdate: Found binary %WINDIR%\system32\wudfsvc.dll version (1.9.0.7100)
WudfUpdate: Found binary %WINDIR%\system32\wudfx.dll version (1.9.0.7100)
WudfUpdate: Found binary %WINDIR%\system32\wudfplatform.dll version (1.9.0.7100)
WudfUpdate: Found binary %WINDIR%\system32\wudfcoinstaller.dll version (1.9.0.7100)
WudfUpdate: UMDF installation is same as update. WudfUpdate: Loading configuration coinstaller from
D:\Windows\system32\wudfcoinstaller.dll.
WudfCoInstaller: ReadWdfSection: Checking WdfSection [Echo_Install.NT.Wdf]
WudfCoInstaller: Configuring UMDF Service WUDFEchoDriver.
WudfCoInstaller: Service WudfSvc is already running.
WudfCoInstaller: Final status: error(0) The operation completed successfully.

In the above scenario, no update is necessary because the on-disk version of the runtime is UMDF 1.9, which is
the same as the version of the co-installer.
Consider the following output, which details an unsuccessful installation.

WudfUpdate: installing version (1,9,0,7100).


WudfUpdate: Checking for presence of previous UMDF installation.
WudfUpdate: Found binary %WINDIR%\system32\drivers\wudfrd.sys version (1.5.0.6000)
WudfUpdate: Found binary %WINDIR%\system32\drivers\wudfpf.sys version (1.5.0.6000)
WudfUpdate: Found binary %WINDIR%\system32\wudfhost.exe version (1.5.0.6000)
WudfUpdate: Found binary %WINDIR%\system32\wudfsvc.dll version (1.5.0.6000)
WudfUpdate: Found binary %WINDIR%\system32\wudfx.dll version (1.5.0.6000)
WudfUpdate: Found binary %WINDIR%\system32\wudfplatform.dll version (1.5.0.6000)
WudfUpdate: Found binary %WINDIR%\system32\wudfcoinstaller.dll version (1.5.0.6000)
WudfUpdate: UMDF installation is older than current.
WudfUpdate: Locating resource stream WUDF_UPDATE_VISTA-RTM.
WudfUpdate: unpacking update from resource to Microsoft User-Mode Driver Framework Install-v1.9-Vista.msu.
WudfUpdate: Temporary path is D:\Windows\Temp\WDF7625.tmp.
WudfUpdate: Invoking update "%SYSTEMROOT%\system32\wusa.exe" with command line
"D:\Windows\Temp\WDF7625.tmp\Microsoft User-Mode Driver Framework Install-v1.9-Vista.msu /quiet /norestart".
WudfUpdate: Waiting for update to terminate.
WudfUpdate: Update process returned 22.
WudfUpdate: update returned error 0x16 - error(22) The device does not recognize the command.
WudfUpdate: For additional information please look at the log files %windir%\windowsupdate.log and
%windir%\Logs\CBS\CBS.log
WudfUpdate: Cleaning up update.
WudfUpdate: Error updating UMDF - error(22) The device does not recognize the command. Aborting
installation.

In this scenario, the on-disk version of the UMDF runtime was older than the version of the co-installer. However,
in this case the update was unsuccessful. The co-installer points to additional log files where you can find more
information regarding the reason for the failure.
Installing a UMDF Filter Driver
2/5/2021 • 2 minutes to read • Edit Online

A filter driver can support a specific device or all devices in a setup class. A lower filter driver attaches below a
device's function driver, while an upper filter attaches above a device's function driver.
This topic describes how to install and configure a User-Mode Driver Framework (UMDF) device-specific (upper
or lower) filter driver. You cannot use UMDF to write a class filter driver. This topic applies to both UMDF
versions 1 and 2.
As you structure your device stack, keep in mind that the framework currently supports only one contiguous
block of UMDF drivers per stack. Also, you cannot install UMDF version 1 and version 2 drivers in the same
device stack.
How to install and configure your driver
1. A UMDF 1 filter driver should call IWDFDeviceInitialize::SetFilter from the its
IDriverEntr y::OnDeviceAdd callback function. Starting in UMDF version 2, your driver instead calls
WdfFdoInitSetFilter .
2. In addition to any UMDF-specific directives your driver may specify, you must specify the UmdfSer vice
and UmdfSer viceOrder directives. In this topic, we'll specify an upper filter driver:

[<mydriver>_Install.NT.Wdf]
UmdfService=UMDFFunction,WUDFFuncDriver_Install
UmdfService=UMDFFilter,UMDFFilter_Install
UmdfServiceOrder=UMDFFunction,UMDFFilter

The drivers are added to the device stack in the order that they are listed in the UmdfSer viceOrder
entry. The first parameter specifies the lowest UMDF driver in the device stack. To install a lower filter
driver, simply reverse the arguments for UmdfSer viceOrder .
For more info about these and other UMDF-specific INF directives, see Specifying WDF Directives in INF
Files.
3. If your driver's device stack contains only UMDF drivers, skip this step.
If your driver's device stack contains any drivers that are not UMDF, your INF file must include an
AddReg section that specifies the reflector as an upper filter driver:

[<mydriver>_Device_AddReg]
; Load the redirector as an upperfilter on this specific device.
; 0x00010008 - FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND
HKR,,"UpperFilters",0x00010008,"WUDFRd"

4. After your driver is loaded as an upper filter, it is responsible for forwarding I/O requests to the next
driver in the stack. To illustrate, consider a simple pass-through driver (UMDF version 1) that is above a
KMDF function driver.
First, retrieve the interface of the default I/O target (next driver in the stack). Then, format and send the
request. The simplest scenario would look like this:
IWDFIoTarget * kmdfIoTarget = NULL;

this->GetFxDevice()->GetDefaultIoTarget (&kmdfIoTarget);

Request->FormatUsingCurrentType();

hr = Request->Send (
kmdfIoTarget,
0, // 0 Submits Asynchronous else use WDF_REQUEST_SEND_OPTION_SYNCHRONOUS
0);
Specifying the Reflector in an INF File
2/5/2021 • 2 minutes to read • Edit Online

To add the reflector (WUDFRd.sys) to the kernel-mode device stack, the INF file of a UMDF driver must include
an AddSer vice directive in an INF DDInstall.Ser vices section . The reflector can be an upper filter, a lower
filter, or the service for the device, depending on the configuration of the user-mode stack.
The following code example shows how the INF file for a UMDF function driver might add the reflector.

[Skeleton_Install.Services]
AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall

In this example, the driver specifies the 0x2 (SPSVCINST_ASSOCSERVICE) flag (ORed into the flags parameter
above) to assign the reflector as the function driver in the kernel-mode device stack.
The AddSer vice directive also sets the 0x000001f8 flags to prevent overwriting any preexisting configuration
for the service. For more information about these flags, see the flags parameter of the AddSer vice directive .
The following code example, taken from the WUDFVhidmini sample, shows an AddSer vice directive for a
UMDF filter driver.

[hidumdf.win8.NT.Services]
AddService=WUDFRd,0x000001f8,WUDFRD_ServiceInstall
AddService=mshidumdf, 0x000001fa, mshidumdf.AddService

[WudfVhidmini_AddReg]
HKR,,"LowerFilters",0x00010008,"WUDFRd" ; FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND

In this case, the mshidumdf service is associated with the FDO for the device stack, and the reflector is a lower
filter.

Providing a service-install-section
The AddSer vice directive references an service-install-section similar to the following code example. The
Ser viceType entry specifies 1 or 0x00000001, which indicates that the INF installs support for one or more
devices. The Star tType entry specifies when to start the driver. The ErrorControl entry specifies the level of
error control that the driver provides. The Ser viceBinar y entry specifies the path to the binary (the reflector)
for the service.

[WUDFRD_ServiceInstall]
DisplayName = "Windows Driver Frameworks - User-mode Driver Framework Reflector"
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=%12%\WUDFRd.sys

Specifying a unique service name


Although it is not required to do so, a UMDF driver that runs only on Windows 8 and later operating systems
can specify a unique service name for the WUDFRd (reflector) service.
The following example shows how to specify a unique service name instead of WUDFRd.

[Echo_Install.NT.Services]
AddService=WudfEchoDriver,0x00000002,WUDFEchoDriver_ServiceInstall

[WUDFEchoDriver_ServiceInstall]
DisplayName = %WudfEchoDriverDisplayName%
ServiceType = 1
StartType = 3
ErrorControl = 1
ServiceBinary = %12%\WUDFRd.sys
StartName = \Driver\WudfRd

In the above example, the driver specifies a unique value for the service name in the AddSer vice directive. (In
this case, it's WudfEchoDriver, which is the name of the driver.) Next, the driver specifies a unique DisplayName
value for the service. Finally, the driver adds the Star tName entry and sets it to \Driver\WudfRd.
UMDF drivers cannot specify a unique service name for the reflector on operating systems earlier than
Windows 8. If your driver specifies a unique service name but must also work on operating systems earlier than
Windows 8, use operating system specific sections in the INF file, as shown in the following example.

[Manufacturer]
%MSFT% = Microsoft,NTx86.6.0,NTx86.6.2
[Microsoft.NTx86.6.0]
%Sensors.DeviceDesc% = Sensors_Install_VistaWin7,HID_DEVICE_UP:0020_U:0001
[Microsoft.NTx86.6.2]
%Sensors.DeviceDesc% = Sensors_Install_Win8,HID_DEVICE_UP:0020_U:0001
[Sensors_Install_VistaWin7]
--- Install the device this way on Vista/Win7 ---
[Sensors_Install_Win8]
--- Install the device in a different way on Win8 ---

If the reflector is not added, UMDF is never loaded. The device might start, but the host process is not present
and the device will not operate properly.
Specifying WDF Directives in INF Files
2/5/2021 • 9 minutes to read • Edit Online

This topic applies to both User-Mode Driver Framework (UMDF) versions 1 and 2.
An INF file that installs a UMDF driver must contain a Microsoft Windows Driver Frameworks (WDF)-specific
DDInstall section. The INF file can contain more than one WDF-specific DDInstall section if the INF file installs
more than one WDF driver. Each WDF-specific DDInstall section:
Corresponds to the DDInstall and DDInstall.Ser vices sections that are associated with a particular
WDF driver.
Is processed by all the loaded WDF co-installers, which run in arbitrary order.
Contains WDF installation directives for a device. UMDF-specific directives begin with the UMDF prefix,
and KMDF-specific directives begin with the KMDF prefix.
The following code example shows UMDF-specific directives in a WDF-specific DDInstall section.

[Skeleton_Install.Wdf]
UmdfService=UMDFSkeleton,UMDFSkeleton_Install
UmdfServiceOrder=UMDFSkeleton

Each UMDF-specific directive in the WDF-specific DDInstall section is described on this page. You can use the In
this article links on the right to navigate between directives.

UmdfService
`UmdfSer vice = <serviceName>, <sectionName>
Associates a UMDF driver with a UMDF-service-install section that contains information that is required to
install the UMDF driver. The serviceName parameter specifies the UMDF driver, and is limited to a maximum of
31 characters in length. The sectionName parameter references the UMDF-service-install section. A valid INF file
typically requires at least one UmdfSer vice directive. However, if a UMDF driver is part of the operating
system, a UmdfSer vice directive for the UMDF driver is not required. Therefore, a valid INF file might not have
any UmdfSer vice directives, although most INF files have one UmdfSer vice directive for each UMDF driver.

UmdfHostProcessSharing
This directive is supported in UMDF versions 1.11 and later.
UmdfHostProcessSharing = <ProcessSharingDisabled | ProcessSharingEnabled >
Determines whether a device stack is placed into a shared process pool (ProcessSharingEnabled ) or its own
individual process (ProcessSharingDisabled ). The default is ProcessSharingEnabled . This directive is
device-specific rather than driver-specific.
For more information about device pooling, see Using Device Pooling in UMDF Drivers.

UmdfDirectHardwareAccess
This directive is supported in UMDF versions 1.11 and later.
UmdfDirectHardwareAccess = <AllowDirectHardwareAccess | RejectDirectHardwareAccess >
Indicates whether the framework should allow the driver to use any of the direct hardware access features, such
as accessing device registers and ports, scanning hardware resources assigned to the device, handling hardware
interrupts, or acquiring connection resources.
If UmdfDirectHardwareAccess is set to AllowDirectHardwareAccess , the framework allows the driver to
use UMDF interfaces that perform direct hardware access.
You must specify AllowDirectHardwareAccess if your UMDF driver accesses hardware resources such as
registers or ports, interrupts, general-purpose I/O (GPIO) pins, or serial bus connections such as I2C, SPI, and
serial port. Your driver receives all of these resources through the ResourcesRaw and ResourcesTranslated
parameters of its EvtDevicePrepareHardware callback function.

NOTE
Starting with UMDF version 2.15, a UMDF driver does not need to specify AllowDirectHardwareAccess in order to
receive hardware resource lists in its EvtDevicePrepareHardware callback routine. If you don't specify it, the driver does not
have the access rights to use these resources, with one exception: If the device is assigned one or more connection
resources (CmResourceTypeConnection ) and one or more interrupt resources (CmResourceTypeInterrupt ), the
driver can call WdfInterruptCreate from its EvtDevicePrepareHardware callback routine (but not from
EvtDriverDeviceAdd).

For information about connecting a UMDF driver to particular types of resources, see:
Hardware Resources for User-Mode SPB Peripheral Drivers
Connection IDs for SPB-Connected Peripheral Devices
Connecting a UMDF Peripheral Driver to a Serial Port
If UmdfDirectHardwareAccess is set to RejectDirectHardwareAccess , the framework does not allow
drivers to use any direct hardware access features. The default value is RejectDirectHardwareAccess .
For information about how a UMDF driver accesses hardware resources, see Finding and Mapping Hardware
Resources.

UmdfHostPriority
This directive is supported in UMDF versions 2.15 and later.
UmdfHostPriority = <PriorityHigh >
A UMDF HID client driver can set UmdfHostPriority to PriorityHigh to increase its thread priority. This
directive should only be used for touch or input drivers that are sensitive to user response time. When a driver
specifies PriorityHigh , the system puts it in a separate device pool along with other drivers of similar priority.
Because the additional device pool uses more memory, you should use this setting with caution. For more
information about device pooling, see Using Device Pooling in UMDF Drivers.

UmdfRegisterAccessMode
This directive is supported in UMDF versions 1.11 and later.
UmdfRegisterAccessMode = <RegisterAccessUsingSystemCall |
RegisterAccessUsingUserModeMapping >
Indicates whether the framework should map the registers into user-mode address space (so that a system call
is not involved in accessing registers), or use a system call to access registers.
If UmdfRegisterAccessMode is set to RegisterAccessUsingSystemCall , the framework uses a system call
to access registers.
If UmdfRegisterAccessMode is set to RegisterAccessUsingUserModeMapping , the framework maps the
registers into user-mode address space so that a system call is not needed to access registers. The default value
is RegisterAccessUsingSystemCall .

UmdfServiceOrder
UmdfSer viceOrder = <serviceName1> [, <serviceName2> ...]
Lists the order that the co-installer installs the UMDF drivers on the device stack. Even if the co-installer installs
only one UMDF driver on the device stack, the INF file must contain this directive. The serviceNameXx
parameters correspond to the serviceName parameters for each UmdfSer vice directive. Because the UMDF
drivers are added to the device stack in the order that they are listed, the first parameter specifies the lowest
UMDF driver in the device stack.
To ensure that a UMDF co-installer installs the device, only one UmdfSer viceOrder directive must be present
in any given WDF-specific DDInstall section. That is, the UmdfSer viceOrder directive cannot be imported by
using the Include and Needs directives.

UmdfImpersonationLevel
UmdfImpersonationLevel = <level>
Informs the framework about the maximum impersonation level that the UMDF driver can have. A
UmdfImpersonationLevel directive is optional; if an impersonation level is not specified, the default is
Identification . When an application opens a file handle, the application can grant a greater impersonation level
to the driver. However, the driver cannot call the IWDFIoRequest::Impersonate method to request an
impersonation level that is greater than the level that UmdfImpersonationLevel specifies. The possible values
for this directive are:
Anonymous
Identification
Impersonation
Delegation
These values correspond to the values that are specified in the SECURITY_IMPERSONATION_LEVEL
enumeration.

UmdfMethodNeitherAction
UmdfMethodNeitherAction = <Copy | Reject >
Indicates whether the framework will accept (Copy ) or reject (Reject ) a device's I/O requests, if the request
objects contain I/O control codes that specify the METHOD_NEITHER buffer access method. A
UmdfMethodNeitherAction directive is optional. If the directive is not specified, the default value is Reject .
For more information about supporting the METHOD_NEITHER buffer access method in UMDF-based drivers,
see Using Neither Buffered I/O nor Direct I/O in UMDF Drivers.

UmdfDispatcher
UmdfDispatcher = <FileHandle | WinUsb | NativeUSB >
Informs the framework where to send I/O after the I/O goes through the user-mode portion of the device stack.
By default, I/O is sent to the reflector (WUDFRd.sys). By setting UmdfDispatcher to WinUsb , the driver
instructs UMDF to send I/O to the WinUsb architecture. Starting in UMDF 2.15, specifying NativeUSB causes
the reflector to handle USB I/O.
If any driver in the stack uses a file-handle-based target, set this directive to FileHandle .
If the driver uses UMDF 2.15 or later and uses USB I/O targets, set this directive to NativeUSB .
If the driver is pre-UMDF 2.15 and uses USB I/O targets, set this directive to WinUsb .
A UmdfDispatcher directive is optional.
The following code example shows the UmdfDispatcher directive in a WDF-specific DDInstall section.

[Xxx_Install.Wdf]
UmdfDispatcher=NativeUSB

UmdfKernelModeClientPolicy
This directive is supported in UMDF versions 1.9 and later.
UmdfKernelModeClientPolicy = <AllowKernelModeClients | RejectKernelModeClients >
To allow kernel-mode drivers to load above a user-mode driver in earlier UMDF versions, see Kernel-mode
Client Support in Earlier UMDF Versions.
Indicates whether the framework should allow the driver to receive I/O requests from kernel-mode drivers.
If UmdfKernelModeClientPolicy is set to AllowKernelModeClients , the framework allows kernel-mode
drivers to load above a user-mode driver, and it delivers I/O requests from kernel-mode drivers to the user-
mode driver.
If UmdfKernelModeClientPolicy is set to RejectKernelModeClients , the framework does not allow kernel-
mode drivers to load above a user-mode driver, and it does not deliver I/O requests from any kernel-mode
drivers to the user-mode driver. If a driver's INF file does not contain this directive, the default value is
RejectKernelModeClients . For more information, see Supporting Kernel-mode Clients.

UmdfFileObjectPolicy
This directive is supported in UMDF versions 1.11 and later.
UmdfFileObjectPolicy = <RejectNullAndUnknownFileObjects | AllowNullAndUnknownFileObjects >
Indicates whether the framework should allow processing of I/O requests (IWDFIoRequest) that are either not
associated with a file object (IWDFFile) or are associated with an unknown file object (a file object for which a
driver has not previously seen a create request).
If UmdfFileObjectPolicy is set to RejectNullAndUnknownFileObjects , the framework does not allow
processing of requests that are associated with a NULL or unknown file object.
If UmdfFileObjectPolicy is set to AllowNullAndUnknownFileObjects , the framework allows processing of
requests that are associated with a NULL or unknown file object.
The default value is RejectNullAndUnknownFileObjects .

UmdfFsContextUsePolicy
This directive is supported in UMDF versions 1.11 and later.
UmdfFsContextUsePolicy = <CanUseFsContext | CanUseFsContext2 | CannotUseFsContexts >
Indicates whether the framework can store internal information in specific context members of a WDM file
object. If a kernel-mode driver in the same stack uses a particular member of the file object, you can use this
directive to request that the framework not use the same location.
If UmdfFsContextUsePolicy is set to CanUseFsContext , the framework stores information in the FsContext
member of the WDM file object.
If UmdfFsContextUsePolicy is set to CanUseFsContext2 , the framework stores information in the
FsContext2 member of the WDM file object.
If UmdfFsContextUsePolicy is set to CannotUseFsContexts , the framework does not use either FsContext
or FsContext2 .
The default value is CanUseFsContext .
The following code example shows the required directives in a UMDF-service-install section.

[UMDFSkeleton_Install]
UmdfLibraryVersion=1.0.0
ServiceBinary=%12%\UMDF\UMDFSkeleton.dll
DriverCLSID={d4112073-d09b-458f-a5aa-35ef21eef5de}

Each directive in the UMDF-service-install section is described in the following list:

UmdfLibraryVersion
UmdfLibrar yVersion = <version>
Informs the co-installer about the version number of the framework that the UMDF driver will use. The format
of the version string is <major>.<minor>.<service>. When drivers on the device stack use more than one
version of the framework, the INF file copies multiple co-installers--one for each framework version--to the
same location on the hard disk drive. However, the INF file adds only the highest version co-installer to the
CoInstallers32 registry value. For more information about copying co-installers, see Using the UMDF Co-
installer.
The co-installer verifies the version string and uses it to locate the version-specific co-installer for the UMDF
driver. The co-installer then extracts the framework from the version-specific co-installer.

ServiceBinary
Ser viceBinar y = <binarypath>
Informs UMDF about where to place the UMDF driver binary on the hard disk drive.
UMDF drivers should be copied to, and run from, the Windows\System32\Drivers\UMDF directory.

DriverCLSID
Note This directive is only supported in 1.x versions of UMDF.
DriverCLSID = <{CLSID}>
Informs UMDF about the class identifier (CLSID) of the UMDF driver. When UMDF loads the UMDF driver, the
UMDF host uses the UMDF driver's CLSID to create an instance of the UMDF driver's IDriverEntry interface.

UmdfExtensions
UmdfExtensions = <cxServiceName>
Required for drivers that communicate with class extension drivers provided by Microsoft. The cxServiceName
parameter corresponds to the service associated with the class extension driver binary.
Service names for the class extension drivers could be located as a subkey under the following registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Ser vices
Using Device Pooling in UMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

User-Mode Driver Framework (UMDF) Versions 1.11 and 2.0


If your User-Mode Driver Framework (UMDF) driver was built with version 1.11 or 2.0 and is running on
Windows 8 or later, the framework creates a single instance of Wudfhost that can host multiple device stacks.
This technique is called device pooling. The main benefit of device pooling is reduced memory consumption in
an environment with multiple UMDF devices.
If a pooled device fails, the framework terminates the instance of Wudfhost and attempts to restart all of the
devices that were previously in the pool. If the device fails again while pooled, the framework creates a separate
Wudfhost process for the device and attempts to start the device again.
If the device fails in the separate host process, the framework attempts to restart it up to five times. The
framework resets the device error count to one when thirty minutes have elapsed since the last failure.
If the system is rebooted, the framework repools devices except for those that have failed while running in a
separate process.
To disable device pooling for a specific device, use the UmdfHostProcessSharing directive in the WDF-specific
DDInstall section of the INF. For information about UmdfHostProcessSharing , see Specifying WDF Directives
in INF Files.
If your driver uses direct I/O, you must set UmdfHostProcessSharing to ProcessSharingDisabled .
Otherwise your driver may fail to start. If WdfDeviceIoBufferedOrDirect is selected and the device is pooled,
the framework changes the buffer access method to buffered I/O. If WdfDeviceIoBufferedOrDirect is
selected and the device is not pooled, the framework changes the buffer access method to direct I/O.
To select a buffer access method, your driver must call the IWDFDeviceInitialize2::SetIoTypePreference
method from its IDriverEntr y::OnDeviceAdd callback function. For information about access methods, see
Accessing Data Buffers in UMDF-Based Drivers.

UMDF Versions 1.9 and earlier


If your driver was built with UMDF version 1.9 or earlier, the framework creates a separate instance of the host
process (Wudfhost) for each device stack.
If the device fails to start, the framework attempts to restart it up to five times. The framework resets the device
error count to one when thirty minutes have elapsed since the last failure.
In a non-pooled environment, if multiple device stacks share the same UMDF driver:
Each device stack loads in a separate WudfHost process.
The framework calls the driver’s IDriverEntr y::OnInitialize and IDriverEntr y::OnDeinitialize methods
once for each device stack.
The framework calls the driver’s IDriverEntr y::OnDeviceAdd method once for each device stack. Each
device object is associated with a separate driver object.
In a pooled environment, if multiple device stacks share the same user mode driver:
Each device stack loads in the same WudfHost process.
The framework calls the driver’s IDriverEntr y::OnInitialize and IDriverEntr y::OnDeinitialize methods
only once.
The framework calls the driver’s IDriverEntr y::OnDeviceAdd method once for each device stack. Each
device object is associated with the same driver object.
Because there is only one driver object in a pooled configuration, the driver must not store any per-device
context in global variables or in objects that are shared across the devices, such as the driver callback object.
Instead, the driver must store per-device context in an object that is not shared between the device stacks, such
as the driver’s device callback object.
Session Zero Guidelines for UMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

Starting in Windows Vista, the operating system isolates services and system processes in Session 0, while
applications run in subsequent, higher numbered sessions. Because the UMDF host process (WUDFHost.exe) is
one of the system processes that run in session 0, UMDF drivers are isolated from applications. As a result, you
must use the following guidelines when developing your driver:
Do not create a user interface (UI) element, such as a dialog box, or depend on user input. Because the
user is not running in Session 0, he or she never sees the UI and cannot respond to it.
Similarly, do not manipulate any UI elements. For example, a UMDF driver cannot enumerate windows in
the user's session.
If your driver must communicate with a service, use a client/server mechanism such as remote procedure
call (RPC) or named pipes.
Use caution when calling functions in the Windows API. Some functions may manipulate UI elements or
attempt to access named objects in a user's session. Do not call Windows functions that you would not
call from a user-mode service. As a general rule, a UMDF driver can safely call functions that are exported
in kernel32.dll, but not functions exported in user32.dll.
A UMDF driver might call Windows functions to perform the following tasks:
A driver might call SetupDi Xxx functions to retrieve a Plug and Play device property. For example,
the UMDF Sample Driver for OSR USB Fx2 Learning Kit calls
SetupDiGetDeviceRegistr yProper ty to retrieve the GUID for the device's bus type. Note A
UMDF driver cannot safely call many of the SetupDi Xxx functions, but it is safe to call functions
that retrieve device node properties.
A driver that retrieves I/O requests from a manual queue might create a periodic timer to poll the
queue. For example, the WudfVhidmini sample registers a timer callback routine by calling
CreateThreadpoolTimer , and then sets a periodic timer by calling SetThreadpoolTimer .
Note Starting in version 1.11, UMDF provides support for work items. For more information, see
Using Work Items.
For additional information about using system services outside the frameworks, see Chapter 14 ("Beyond the
Frameworks") of Orwick, Penny, and Guy Smith. Developing Drivers with the Windows Driver Foundation.
Redmond, WA: Microsoft Press, 2007.
For additional information about session zero isolation, see Impact of Session 0 Isolation on Services and
Drivers in Windows.
Restricting the Loading Location of UMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

The UMDF platform will fail to load the main UMDF driver binaries from any location other than the
%SystemRoot%\System32\Drivers\Umdf directory. Therefore, a UMDF INF file must restrict the location where
it installs UMDF drivers to that directory. Installing in this directory also ensures that unprivileged users cannot
tamper with the UMDF drivers.
To install UMDF driver binaries to %SystemRoot%\System32\Drivers\Umdf, the UMDF driver INF file must
include an INF DestinationDirs Section that is similar to the following code example.

[DestinationDirs]
UMDriverCopy=12,UMDF ; copies to drivers\umdf

"UMDriverCopy" represents an INF-writer-determined name of a section that lists the UMDF driver binaries as
shown in the following example.

[UMDriverCopy]
WUDFOsrUsbDriver.dll

The CopyFiles directive must also reference the UMDriverCopy section to indicate the list of UMDF driver
binaries for the operating system to copy from the source media to the destination as shown in the following
example.

[OsrUsb_Install.NT]
CopyFiles=UMDriverCopy
Controlling Device Access
2/5/2021 • 2 minutes to read • Edit Online

The UMDF driver host process runs in the context of the local service account. Your driver may need to access
other devices or components that do not permit generalized access to the local service account.
Starting in Windows 8, the operating system includes a security identifier (SID) that identifies UMDF drivers. By
including this SID in their device security requirements, devices or components can permit access to UMDF
drivers while preventing access from other requests from the local service account.
The SID for UMDF drivers is SDDL_USER_MODE_DRIVERS, and the definition is in sddl.h. The full representation
of this SID is:

S-1-5-84-0-0-0-0-0

The abbreviation for this SID is UD. This abbreviation is available starting in Windows 8.
A driver external to your UMDF driver can specify the SID either in its INF file or in the driver, before it creates
the device object.

Specifying device security in an INF file


In the INF file, you can use either the abbreviated form or the fully specified form of the SID.
The abbreviated form is available starting in Windows 8:

HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)(A;;GA;;;UD)"

On operating systems earlier than Windows 8, you must use the fully specified form:

HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)(A;;GA;;;S-1-5-84-0-0-0-0-0)"

Specifying device security in a KMDF driver


To specify security requirements in the driver, you must use the abbreviated form, which is only available
starting in Windows 8. For example, a KMDF driver could enable access to its device from UMDF drivers by
using the following:

RtlInitUnicodeString(&sddlString, L"D:P(A;;GA;;;BA)(A;;GA;;;SY)(A;;GA;;;UD)");
status = WdfDeviceInitAssignSDDLString(DeviceInit, &sddlString);
Using the Framework's Event Logger
2/5/2021 • 4 minutes to read • Edit Online

WDF includes an internal trace logger, sometimes called the framework's In-flight Recorder (IFR). The WDF
logger creates a trace log that contains a recent history of events for each WDF driver. The trace logs track the
progress of I/O request packets (IRPs) through the framework and the corresponding requests through a driver.
Each Kernel-Mode Driver Framework (KMDF) and User-Mode Driver Framework (UMDF) driver has its own log.
The WDF logger is always enabled. For each trace log, the logger stores event records in a circular memory
buffer. Optionally, you can turn on verbosity, which causes the event logger to record additional information that
can help you debug your driver, such as entries into or exits from internal code paths. By default, the size of the
buffer is one memory page and verbosity is turned off. You can change the buffer's size and verbosity by
adjusting these values within the WdfVerifier application. Note that turning on verbosity might degrade system
performance.
You can use WDF debugger extensions to view and save the WDF log during interactive debugging. To view the
WDF log during a debugging session:
1. Load the correct symbols. You can use the .symfix + debugger command to append the Microsoft public
symbol store to your existing symbol path. The public symbol store includes symbols for the WDF
binaries. You might also want to load symbols for your driver symbols.
For additional information about how to obtain Window symbols and how to set the debugger's symbol
path, see the documentation that is supplied with the Windows Debugging package.
2. Load the Wdfkd.dll extension library into your debugger. If you are using the kernel debugger, you can do
this by using the .load command. To load the correct version of Wdfkd.dll you need to specify the fully
qualified path to the DLL. For example, you would use the following path on an x86-based debugger host
machine:

.load "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\wdfkd.dll"

You can then confirm that the extension is loaded by using the !chain command to display all loaded
extensions.
For more information about the framework debugger extension, use the !wdfhelp extension. For more
information about the kernel debugger, see the documentation that is supplied with the Windows
Debugging package.
3. If your driver uses framework version 1.11 or later, and you are using the kernel debugger from
Windows 8 or later, you can skip this step.
If your driver uses a framework version that is earlier than 1.11, use !wdftmffile or !wdfsearchpath to
specify a platform-specific trace message format (.tmf) file, or a path to a .tmf file. The .tmf files are
located in platform-specific subdirectories in the WDK.
Because .tmf files are version specific, you must specify a .tmf file that corresponds to the version of the
framework's runtime library that is currently running. For example, if KMDF version 1.9 is running on the
host machine:

!wdftmffile c:\WinDDK\<version>\tools\tracing\x86\wdf01009.tmf
You can also set the search path by setting the TRACE_FORMAT_SEARCH_PATH environment variable. The
!wdftmffile command takes precedence over the search path that is set by the environment variable.
To verify the framework version number, you can run the !wdfldr debugger extension command from
the kernel debugger.
4. Use the !wdflogdump extension to display the event logger's records. For example, the following
screenshot of a WinDbg Command window shows a typical example of the output of !wdflogdump :

Each line in the framework's log is preceded by a string that is called the trace message prefix. The trace logger
prepends this prefix to each message that is written to the log. By default, the prefix includes a standard set of
data elements, but you can change the default elements to suit your particular requirements. You can change the
prefix string for a WDF driver by setting the TRACE_FORMAT_PREFIX environment variable or by using the
!wdfsettraceprefix debugger extension command.
To set the environment variable, use a command similar to the following:

Set TRACE_FORMAT_PREFIX=%2!s!: %!FUNC!: %8!04x!.%3!04x!: %4!s!:

This command sets the trace message prefix to the following:

SourceFile_LineNumber: FunctionName: ProcessID.ThreadID: SystemTime

You can also use the !wdflogsave extension command to save the event logger's records in an event trace log
(.etl) file that you can view by using TraceView.
You can sometimes use the !wdfcrashdump debugger extension on a crash dump to display log information
after the system bug checks. The log information is available in the crash dump only if the framework can
determine that your driver caused the bug check or if you have set the ForceLogsInMiniDump registry value for
the driver.
If a debugger is attached when the bug check occurs, you can either use !wdfcrashdump to view the log
information immediately, or you can view the information by loading the memory dump file. Due to size
limitations of a small memory dump file, the log for the driver that caused the crash might not appear in the
dump.
The framework can determine whether a particular driver caused the following bug check codes:
Bug Check 0xD1: DRIVER_IRQL_NOT_LESS_OR_EQUAL
Bug Check 0xA: IRQL_NOT_LESS_OR_EQUAL
Bug Check 0x20: KERNEL_APC_PENDING_DURING_EXIT
Bug Check 0x8E: KERNEL_MODE_EXCEPTION_NOT_HANDLED
Bug Check 0x1E: KMODE_EXCEPTION_NOT_HANDLED
Bug Check 0x50: PAGE_FAULT_IN_NONPAGED_AREA
Bug Check 0x7E: SYSTEM_THREAD_EXCEPTION_NOT_HANDLED
Starting in UMDF version 2, UMDF stores the UMDF trace log (or UMDF IFR ) in kernel non-paged memory. The
framework allocates one IFR per driver host (Wudfhost) instance.
For more information about the debugger extension commands, see Debugger Extensions for Framework-based
Drivers.
Using KMDF Verifier
2/5/2021 • 3 minutes to read • Edit Online

The framework provides built-in verification functionality that you can use to test a running KMDF driver. This
functionality, called KMDF Verifier, extensively validates your driver's state and the arguments that the driver
passes to framework object methods. You can use the framework's verifier by itself or together with the general-
purpose Driver Verifier (Verifier.exe) tool.
If KMDF Verifier is enabled, the framework checks lock acquisition and hierarchies, ensures that calls to the
framework occur at the correct IRQL, verifies correct I/O cancellation and queue usage, and ensures that the
driver and framework follow the documented contracts. It can also simulate out-of-memory conditions so that
the driver developer can test whether the driver responds properly without crashing, hanging, or failing to
unload.
When KMDF Verifier is enabled, the framework breaks into the debugger if a default time-out period of 60
seconds expires before some of the events described previously have completed. At this point, you can debug
the issue, or type "g" in the debugger to restart the time-out period. You can change the default time-out period
by using the DbgWaitForSignalTimeoutInSec registry value described in Controlling the Verifier's Behavior.
We recommend running Driver Verifier (Verifier.exe) during testing, and adding your own driver and
wdf01000.sys to the verify list.
If your driver was built with KMDF version 1.9 or later and you run Verifier.exe, KMDF Verifier is automatically
enabled.
You can also use the WDF Verifier Control Application (WdfVerifier.exe) to enable and disable KMDF Verifier.

Enabling and Disabling the Framework's Built-in Verification


You can manually enable KMDF Verifier using this procedure:
1. If your driver is already loaded, use Device Manager to disable the device. Disabling the device causes the
driver to be unloaded.
2. Use RegEdit to set VerifierOn to a nonzero value in the driver's Parameters\Wdf subkey of the
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Ser vices key in the Windows registry. A
nonzero value indicates that KMDF Verifier is enabled.
You may need to add VerifierOn manually to the subkey if it is not already present.
3. Use Device Manager to reenable the device, thereby loading the driver.
4. When the driver calls WdfDriverCreate , the framework examines the registry and enables the
framework's verifier if VerifierOn to a nonzero value.
To disable the framework's verifier, follow the same steps, but set the value of VerifierOn to zero.
To determine whether the framework's verifier is enabled, set a breakpoint at a location after your driver calls
WdfDriverCreate and use the !wdfdriverinfo debugger extension command:
!wdfkd.wdfdriverinfo <your drivername> **** 0x1
For more information about the debugger extension commands, see Debugger Extensions for Framework-based
Drivers.
Controlling the Verifier's Behavior
We recommend that you use the WDF Verifier control application to control the options below. However, you
can directly modify the following values in the registry.
The relevant values are located under the Parameters\Wdf subkey of the
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Ser vices key.
VerifyOn (REG_DWORD )
Set this value to a nonzero value to enable the WDFVERIFY macro.
DbgBreakOnError (REG_DWORD )
If this value is set to a nonzero value, the framework will break into the debugger (if available) each time that a
driver calls WdfVerifierDbgBreakPoint .
DbgWaitForSignalTimeoutInSec (REG_DWORD )
Starting in Windows 8, when VerifierOn and DbgBreakOnError are set to nonzero values, the driver can
change the default time-out period by setting DbgWaitForSignalTimeoutInSec .
VerifierAllocateFailCount (REG_DWORD )
If this value is set to a value n, the framework fails every attempt to allocate memory for the driver's objects
after the nth allocation.
TrackHandles (REG_MULTI_SZ )
If this value is set to a list of one or more type names of framework object handles, the framework tracks
references to all object handles that match the specified handle types.
EnhancedVerifierOptions (REG_DWORD )
KMDF only
Contains a bitmap that you can use to enable optional features of the framework's verifier.
VerifyDownLevel (REG_DWORD )
If set to a nonzero value, and if the driver was built with a version of the framework that is older than the current
version, the framework's verifier includes tests that were added after the driver was built.
As a general rule, if you set the above registry values, delete them when they are no longer needed.
For full descriptions of these registry values, see Registry Values for Debugging Framework-based Drivers.
Using UMDF Verifier
2/5/2021 • 4 minutes to read • Edit Online

The framework provides built-in verification functionality that you can use to test a running User-Mode Driver
Framework (UMDF) driver. This functionality, sometimes called UMDF Verifier, extensively validates your driver's
state and the arguments that the driver passes to framework object methods. You can use UMDF Verifier by
itself or together with the general-purpose Application Verifier (AppVerif.exe) tool.
UMDF Verifier checks lock acquisition and hierarchies, verifies correct I/O cancellation and queue usage, and
ensures that the driver and framework follow the documented contracts.
UMDF Verifier causes failures in UMDF driver code to bug check the host process. However, a UMDF bug check
does not cause a blue text screen to appear with information about the error. Instead, a UMDF bug check:
Creates a memory dump file and saves the file to the computer's log file directory (for example,
%windir%\System32\LogFiles\WUDF\Xxx.dmp).
Note Starting in UMDF 2.15, the log directory is %ProgramData%\Microsoft\WDF.
Creates an error report for Microsoft (opt-in).
Breaks into the debugger if one is attached to the computer.
Terminates the host process and disables the device.
Starting in UMDF 2.0, UMDF Verifier issues breakpoints in some cases, and causes a UMDF bug check in others.
This behavior is similar to that of KMDF Verifier.
We strongly recommend doing all development and testing of your driver after enabling Application Verifier
(AppVerif.exe) on WUDFHost.exe. Use the following command, attach a debugger and then reboot.

AppVerif –enable Heaps Exceptions Handles Locks Memory TLS Leak –for WudfHost.exe

Starting in version 2.0 of UMDF, if you run Application Verifier on the driver host process (Wudfhost), UMDF
Verifier is automatically enabled for all UMDF 2.0 drivers in that host, as well as all UMDF 2.0 drivers in future
driver host processes.
In UMDF 1.11 and earlier, the framework's verifier is always on and you cannot turn it off.

Enabling and Disabling UMDF Verifier


You can manually enable UMDF Verifier by setting VerifierOn to a nonzero value in the driver's
Parameters\Wdf subkey of the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\WUDF\Ser vices\<driver name> registry key.
Note The existence of a VerifierOn value at all, even set to zero, overrides the linkage with Application Verifier.
As a result, we recommend deleting the value if you're not forcing it on, rather than setting it to zero.
To determine whether UMDF Verifier is enabled, set a breakpoint at a location after your driver calls
WdfDriverCreate and use the !wdfdriverinfo debugger extension command:
!wdfkd.wdfdriverinfo <your drivername> **** 0x1
For more information about the debugger extension commands, see Debugger Extensions for Framework-based
Drivers.

Controlling the Verifier's Behavior


You can control the behavior of UMDF Verifier by modifying values in the registry. Alternatively, you can use the
WDF Verifier control application to set these values.
The following registry values can be used with UMDF 1.x drivers, as well as UMDF 2.0 and later drivers.
VerifyDownLevel (REG_DWORD )
If VerifyDownLevel is set to a nonzero value, and if the driver was built with a version of the framework that is
older than the current version, the framework's verifier includes tests that were added after the driver was built.
If this value does not exist or is set to zero, the framework's verifier includes only the tests that existed when the
driver was built.
For example, if your driver was built with version 1.7 of the framework, and if version 1.9 of the framework is
installed on the computer, setting VerifyDownLevel to nonzero causes the verifier to include tests that were
added to version 1.9 of the verifier when your driver runs.
This value is located in the Parameters\Wdf subkey of the
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\WUDF\Ser vices\ DriverName registry key.
TrackObjects (REG_DWORD )
If TrackObjects is set to a nonzero value, the framework enters the debugger when the driver is unloaded, if
any framework-based objects have leaked (not been deleted).
During regular testing, you should enable TrackObjects and not TrackRefCounts . If the verifier reports that
the driver is leaking framework objects, then use the control application to enable the TrackRefCounts verifier
option.
This value is located in the DefaultHostProcessGuid subkey of the
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Ser vices
registry key, where DefaultHostProcessGuid is a value that you can find in the
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF subkey.
TrackRefCounts (REG_DWORD )
If TrackRefCounts is set to a nonzero value, the framework maintains a count of the number of references to
each framework-based object. You can use the !wudfrefhist debugger extension to view the changes of an
object's reference count.
Setting TrackRefCounts to a nonzero value degrades the driver's performance, so you should leave the value at
zero unless you are debugging an object deletion bug.
This value is located in the DefaultHostProcessGuid subkey of the
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Ser vices
registry key, where DefaultHostProcessGuid is a value that you can find in the
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF subkey.
In addition to the registry values listed above, UMDF 2.0 and later drivers can also use many of the registry
values listed in Using KMDF Verifier.
How UMDF Handles Driver Failures
2/5/2021 • 2 minutes to read • Edit Online

This topic describes actions that User-Mode Driver Framework (UMDF) and the operating system take when a
UMDF driver fails. It applies to both UMDF versions 1 and 2.
The following events occur in the order presented:
The operating system notifies the reflector (WUDFRd.sys).
The reflector tracks outstanding I/O in the host process:
The reflector completes outstanding I/O with the STATUS_DRIVER_PROCESS_TERMINATED error code.
Microsoft Win32 applications receive the ERROR_DRIVER_PROCESS_TERMINATED error code for the
outstanding I/O.
Note The reflector that runs on Microsoft Windows XP completes outstanding I/O with
STATUS_DRIVER_INTERNAL_ERROR, and Win32 applications, in turn, receive the ERROR_IO_DEVICE error
code for the outstanding I/O. Therefore, applications that run on Windows XP should not use
ERROR_IO_DEVICE to detect a driver failure because they cannot determine any difference from the
status that is returned from a typical I/O request (for example, the status that is returned from a call to the
Win32 DeviceIoControl function).
The reflector sends the GUID_WUDF_DEVICE_HOST_PROBLEM custom Plug and Play (PnP) event to the
operating system after the operating system reports a problem with the host process.
If an application previously called the Win32 RegisterDeviceNotification function to register
GUID_WUDF_DEVICE_HOST_PROBLEM for the device, that application will receive a DBT_CUSTOMEVENT
notification when the host process fails. For more information about RegisterDeviceNotification and
DBT_CUSTOMEVENT, see the Windows SDK documentation.
The operating system writes an entry to the system event log that indicates that the driver failed. It also
indicates how many more times the operating system will restart the driver. The operating system writes
the following event numbers into the system event log to indicate the specified problems:
10110 if the host process was at fault
10111 if the device went offline and was restarted
10112 if the device went offline and was not restarted
The framework can attempt to restart a failing driver. The UMDF code verifier provides a registry value
that controls the number of restart attempts. If the user either disables and enables the device in the
Device Manager or unplugs and plugs in the device, the operating system creates a new instance of the
device and the framework resets the restart counter.
The operating system unloads the kernel drivers in the device stack.
Note The operating system will not tear down and restart the device stack until all handles to the old
stack have closed. An application will detect the device failure and a surprise removal notification for the
device (DBT_REMOVEDEVICEPENDING). However, if any handle to the old stack is kept open, the device is
not restarted.
The driver manager either restarts or disables the device. If the device is disabled, the operating system
displays a yellow exclamation point in Device Manager.
Note that after a UMDF driver fails, the following operations can occur in an arbitrary order:
The operating system tears down and restarts the device.
The reflector sends the GUID_WUDF_DEVICE_HOST_PROBLEM PnP event to the operating system.
The reflector completes outstanding I/O with STATUS_DRIVER_PROCESS_TERMINATED.
Therefore, an application might receive ERROR_DRIVER_PROCESS_TERMINATED for the outstanding I/O after
the operating system has restarted the device. After receiving ERROR_DRIVER_PROCESS_TERMINATED, the
application might also receive the DBT_CUSTOMEVENT notification that results from the
GUID_WUDF_DEVICE_HOST_PROBLEM event.
How UMDF Handles Application Failures
2/5/2021 • 2 minutes to read • Edit Online

This topic describes actions that User-Mode Driver Framework (UMDF) and the operating system take when an
application fails. It applies to both UMDF versions 1 and 2.
When an application fails, the following events occur:
The reflector receives IRP_MJ_CLEANUP .
The cleanup request is sent to the host process on the "cancel" IPC channel.
The host process and UMDF driver complete pending I/O requests.
How UMDF Reports Errors
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how User-Mode Driver Framework (UMDF) reports errors. It applies to both UMDF versions
1 and 2.
When a UMDF driver crashes, the framework creates a Windows Error Reporting (WER) report.
UMDF reports the following types of errors:
UMDF Verifier failures.
Unhandled exceptions in the host process.
Unexpected termination of the host process.
Failure or time-out of critical operations. For more information about timeouts, see Host Process
Timeouts in UMDF.
A UMDF error report can contain the following information. The contents of the report depend on the problem
that is detected.
A memory dump of the host process
A copy of the UMDF trace log
Configuration information about the device, which can include the device name, manufacturer, drivers
that are installed, and driver binary versions
Analysis of the problem, which can include the address of the last driver-to-framework call (or vice versa),
problem code, exception information, and so on
Reporting Device Failures
2/5/2021 • 2 minutes to read • Edit Online

There are three ways to report device failures:


When returning from device object callback functions, the driver can supply a return value for which
NT_SUCCESS(status) equals FALSE .
The driver can call WdfDeviceSetFailed .
When returning from its EvtDriverDeviceAdd callback routine, a function driver can supply a return value
for which NT_SUCCESS(status) equals FALSE . If a driver that is installed as a filter fails
EvtDriverDeviceAdd, the operating system skips the filter device object and does not indicate a PnP error.
Each of the above methods results in the framework effectively removing the device. If the device's drivers are
not supporting other devices on the system, the I/O manager unloads the drivers.
If a driver's device object callback function returns a value for which NT_SUCCESS(status) equals FALSE , the
framework notifies the PnP manager, which then attempts to restart the device by requesting the bus driver to
reenumerate its devices. Your driver will be reloaded, if it was unloaded.
If your driver calls WdfDeviceSetFailed , it supplies an input argument that determines whether the device will
be restarted. The argument values are WdfDeviceFailedAttemptRestar t and WdfDeviceFailedNoRestar t .
UMDF Before UMDF 2.15 a UMDF driver must set this value to WdfDeviceFailedNoRestar t . Starting in UMDF
version 2.15, a UMDF driver can request that the underlying bus driver re-enumerate it by calling
WdfDeviceSetFailed with FailedAction set to WdfDeviceFailedAttemptRestar t . For more information, see
WdfDeviceSetFailed .
For more information about these argument values, see WDF_DEVICE_FAILED_ACTION . Before a driver's
device object callback function returns with a value for which NT_SUCCESS(status) equals FALSE , the callback
function can prevent restarts by calling WdfDeviceSetFailed with an input argument of
WdfDeviceFailedNoRestar t . Otherwise, these callback functions do not have to call WdfDeviceSetFailed .
If, within a short period of time, several consecutive restart attempts fail (because the restarted driver again
reports an error), the framework stops trying to restart the device.
If a bus driver's EvtDeviceD0Entry function returns a value for which NT_SUCCESS(status) equals FALSE , the
framework might still call the EvtDeviceD0Entry functions of drivers associated with the bus driver's child
devices.
Creating WDF HID Minidrivers
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how to create a Human Interface Device (HID) minidriver using Windows Driver
Frameworks (WDF).
You can write a HID minidriver using either KMDF or UMDF. We recommend starting with the vhidmini2
minidriver sample. You can compile this sample driver using either KMDF or UMDF 2.x.
What to provide
1. You'll write a lower filter driver under MsHidUmdf.sys (for UMDF) or MsHidKmdf.sys (for KMDF), both of
which are included as part of the operating system.
2. Download and review the vhidmini2 sample.
3. Call WdfFdoInitSetFilter from the driver's EvtDriverDeviceAdd callback function.
4. Create I/O queues to receive I/O requests that MsHidUmdf.sys or MsHidKmdf.sys pass from the class
driver to your driver.
5. Provide an EvtIoDeviceControl callback function that branches to IOCTL-specific method handlers. Review
the IOCTLs described in WDF HID Minidriver IOCTLs and ensure that your driver handles the relevant
ones for your device.
6. For UMDF, if your driver is enumerated by ACPI, optionally enable selective suspend. In the device's
hardware key, add a EnableDefaultIdleNotificationHandler subkey and set it to 1.
7. For UMDF, set the following INF directives in a WDF-specific DDInstall section of your INF file:
UmdfKernelModeClientPolicy to AllowKernelModeClients so that the kernel-mode pass-
through driver can be loaded in the stack.
UmdfMethodNeitherAction to Copy to allow UMDF to process IOCTLs of METHOD_NEITHER type.
UmdfFileObjectPolicy to AllowNullAndUnknownFileObjects
UmdfFsContextUsePolicy to CanUseFsContext2
For example:

[hidumdf.NT.Wdf]
UmdfKernelModeClientPolicy = AllowKernelModeClients
UmdfMethodNeitherAction=Copy
UmdfFileObjectPolicy=AllowNullAndUnknownFileObjects
UmdfFsContextUsePolicy = CanUseFsContext2

If you are writing a UMDF HID minidriver for Windows 7, download Windows Driver Kit (WDK) 8.1 to obtain
source code for HidUmdf.sys. Then, write a UMDF 1.11 driver and include HidUmdf.sys and UMDF 1.11 in your
driver package.

Architecture
The HID class driver (HidClass.sys) and the framework provide conflicting WDM dispatch routines to handle
some I/O requests (such as Plug and Play and power management requests) for minidrivers. As a result, a HID
minidriver cannot link to both the class driver and the framework. Therefore, Microsoft provides MsHidUmdf.sys
and MsHidKmdf.sys, which are WDM drivers that reside between the class driver and the minidriver.
Both MsHidUmdf.sys and MsHidKmdf.sys call the HID class driver's HidRegisterMinidriver routine to register
as the actual HID minidriver. Although these drivers act as the device's function driver, they just pass I/O requests
from the class driver to your driver (and are thus sometimes called pass-through drivers). For both KMDF and
UMDF, the only component that you supply is the HID minidriver, which is a lower filter driver that sits under the
pass-through driver.
UMDF architecture : KMDF architecture

:
Framework File Objects
2/5/2021 • 6 minutes to read • Edit Online

When an application or a driver attempts to access a device, typically by creating or opening a file, the operating
system sends a file creation request to the driver stack. When the application or driver has finished using the
device, the system sends file cleanup and close requests to the driver stack. The request types of these three
requests are WdfRequestTypeCreate , WdfRequestTypeCleanup , and WdfRequestTypeClose , respectively.
Typically, unless your driver has called WdfDeviceInitSetExclusive , the driver must perform file-specific or
other access-specific operations when it receives file creation, cleanup, and close requests, because multiple files
can be open simultaneously or multiple applications can access the device simultaneously. The driver must
therefore keep track of the I/O requests that are associated with each file or application.
The framework defines framework file objects, which represent an application or driver's means for accessing a
device, such as a file, directory, volume, mail slot, named pipe, or the entire device. A file name can be associated
with a file object, but the meaning of a file name is driver-specific. For more information about file names, see
Controlling Device Namespace Access.
If your driver must handle file operations, it must call WdfDeviceInitSetFileObjectConfig from within its
EvtDriverDeviceAdd callback function. The WdfDeviceInitSetFileObjectConfig method receives a
WDF_FILEOBJECT_CONFIG structure as input. The driver uses this structure to register its
EvtDeviceFileCreate, EvtFileCleanup, and EvtFileClose callback functions and, optionally, to indicate whether the
framework should create a framework file object each time that the driver receives a file creation request.
Most drivers that handle file operations store file-specific information in the framework file object's context
space. If your driver handles file operations but does not need to store information in a file object's context
space, the framework does not have to create framework file objects for the driver.
Creating or Opening a File
When the framework receives a file creation request for your function driver, it:
1. Creates a framework file object that represents the file, unless the driver previously indicated that it does
not need to use framework file objects.
2. Calls your driver's EvtDeviceFileCreate callback function, if the driver has registered the callback function.
The EvtDeviceFileCreate callback function typically obtains information about the file, such as its name and file
object flags. The driver typically stores this information in the context space of the framework file object.
Instead of providing an EvtDeviceFileCreate callback function, the driver can call
WdfDeviceConfigureRequestDispatching to set an I/O queue to receive all file creation requests
(WdfRequestTypeCreate request type). The driver will subsequently receive file creation requests in the
queue's EvtIoDefault request handler. (An I/O queue cannot receive file creation requests if the DefaultQueue
member of the queue's WDF_IO_QUEUE_CONFIG structure is set to TRUE .)
If your driver does not provide an EvtDeviceFileCreate callback function and does not set up an I/O queue to
handle WdfRequestTypeCreate -typed I/O requests, the framework:
Completes all file creation requests for the driver with a status value of STATUS_SUCCESS, if your driver is
a function driver.
Forwards all file creation requests to the next-lower driver, if your driver is a filter driver.
(To see how you can change this behavior, see the AutoFor wardCleanupClose member of the
WDF_FILEOBJECT_CONFIG structure.)
Note If your function driver does not provide any device interfaces that applications can use to access the
driver's devices, the driver must provide an EvtDeviceFileCreate callback function that completes all file creation
requests with a status value for which NT_SUCCESS(status) equals FALSE . Otherwise, a malicious application
might attempt to access a device by using the name of the device's physical device object (PDO). (All PDOs have
names.)
If a driver forwards a creation request to an I/O target, the driver must not subsequently complete the request
with a failure status value unless the driver receives a failure status value from the I/O target. Otherwise, the
lower drivers will not be notified that the creation request failed and might attempt to operate as if the file is
open.
If a driver forwards a creation request to an I/O target, the driver cannot set the
WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET flag if the framework has created a framework file
object for the creation request. Therefore, the driver cannot set the
WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET flag for a creation request unless it also sets the
WdfFileObjectNotRequired flag as the driver won't be able to clean up the WDFFILEOBJECT in the event that
a driver lower in the stack fails the creation request. Instead, the driver can use any other send-options, for
example, send asynchronously with a completion routine or send synchronously. In both cases, the driver must
call WdfRequestComplete when it regains control.
Note that if a driver completes a creation request with an error status, the framework deletes the framework file
object but does not call the driver's EvtFileCleanup or EvtFileClose callback functions. Therefore, if the driver
allocates extra object-specific memory outside of the file object's context space it must provide an
EvtCleanupCallback or EvtDestroyCallback callback function that deletes the allocated memory.
For Windows Vista and later, file creation requests can be canceled. Earlier versions of the Windows operating
system do not support canceling file creation requests.
The system always creates a Windows Driver Model (WDM) file object for each creation request that comes
from a user application. If a driver sends a creation request, it might not create a WDM file object for the request.
Typically, the framework does not create a framework file object if a WDM file object is not present. However, if
your driver has called WdfDeviceInitSetExclusive and if the driver has set
WdfFileObjectWdfCannotUseFsContexts in the FileObjectClass member of the
WDF_FILEOBJECT_CONFIG structure, the framework will create a framework file object even if a WDM file
object does not exist.
Obtaining File Information
The driver's EvtDeviceFileCreate callback function can call one or more of the following object methods to obtain
information about an application or driver's access to a device:
WdfFileObjectGetFileName
Returns the file name that is contained in a framework file object.
WdfFileObjectGetFlags
Returns the flags that are contained within a framework file object.
WdfFileObjectWdmGetFileObject
Returns the WDM file object that is associated with a framework file object.
WdfRequestGetParameters
Retrieves the parameters that are associated with a framework request object. If the request type is
WdfRequestTypeCreate , the Parameters.Create member of the WDF_REQUEST_PARAMETERS structure
contains information about the file creation request.
Typically, the driver stores file information in the framework file object's context space. When your driver obtains
an I/O request from one if its I/O queues, the driver can call WdfRequestGetFileObject to obtain a handle to
the framework file object that is associated with the request. The driver can then retrieve the file information
that it stored in the framework file object's context space.
Your driver can search an I/O queue for requests that are associated with a particular file by calling
WdfIoQueueRetrieveRequestByFileObject .
If your driver has a pointer to a WDM DEVICE_OBJECT structure, the driver can call WdfDeviceGetFileObject
to obtain a handle to the framework file object that is associated with the WDM device object.
Closing a File
When an application or another driver closes a file, the framework receives a cleanup request and a close
request for your driver. The framework:
1. Calls your driver's EvtFileCleanup and EvtFileClose callback functions, if the driver has registered these
callback functions.
2. Deletes the framework file object that represents the file.
The driver's EvtFileCleanup and EvtFileClose callback functions receive a handle to the framework file object. The
driver can call WdfFileObjectGetDevice to determine which framework device object is associated with the
framework file object.
Handling Client Impersonation in UMDF Drivers
2/5/2021 • 4 minutes to read • Edit Online

This topic describes how a User-Mode Driver Framework (UMDF) driver accesses protected resources, starting
in UMDF version 2.
UMDF drivers typically run under the LocalService account and cannot access files or resources that require user
credentials, such as protected files or other protected resources. A UMDF driver typically operates on commands
and data that flow between a client application and a device. Therefore, most UMDF drivers do not access
protected resources.
However, some drivers might require access to a protected resource. For example, a UMDF driver might load
firmware into a device from a file that a client application provides. The file might have an access control list
(ACL) that prevents unauthorized users from modifying the file and taking control of the device. Unfortunately,
this ACL also prevents the UMDF driver from accessing the file.
The framework provides an impersonation capability that allows drivers to impersonate the driver's client and
obtain the client's access rights to protected resources.
Enabling Impersonation
Both the UMDF driver's installation package and the client application must enable the framework's
impersonation capability, as follows:
The INF file of the UMDF driver's installation package must include the UmdfImpersonationLevel
directive and set the maximum allowable impersonation level. Impersonation is enabled only if the INF
file includes the UmdfImpersonationLevel directive. For more information about setting the
impersonation level, see Specifying WDF Directives in INF Files.
The client application must set the allowed impersonation level for each file handle. The application uses
the quality of service (QoS) settings in the Microsoft Win32 CreateFile function to set the allowed
impersonation level. For more information about these settings, see the dwFlagsAndAttributes parameter
of CreateFile in the Windows SDK documentation.
Handling Impersonation for an I/O Request
The UMDF driver and framework handle impersonation for an I/O request in the following sequence:
1. The driver calls the WdfRequestImpersonate method to specify the required impersonation level and
an EvtRequestImpersonate callback function.
2. The framework checks the requested impersonation level. If the requested level is greater than the level
that the UMDF driver's installation package and the client application allow, the impersonation request
fails. Otherwise, the framework impersonates the client and immediately calls the EvtRequestImpersonate
callback function.
The EvtRequestImpersonate callback function must perform only the operations that require the requested
impersonation level, such as opening a protected file.
The framework does not allow a driver's EvtRequestImpersonate callback function to call any of the framework's
object methods. This ensures that the driver does not expose the impersonation level to other driver callback
functions or other drivers.
As a best practice, your driver should not enable cancellation of an I/O request before calling
WdfRequestImpersonate for that request.
The WdfRequestImpersonate method grants only the impersonation level that the driver requests.
Passing Credentials down the Driver Stack
When your driver receives a WdfRequestTypeCreate -typed I/O request, the driver might forward the I/O
request down the driver stack to a kernel-mode driver. Kernel-mode drivers do not have the impersonation
capability that WdfRequestImpersonate provides to UMDF drivers.
Therefore, if you want a kernel-mode driver to receive the client's user credentials (rather the credentials of the
driver host process), the driver must set the WDF_REQUEST_SEND_OPTION_IMPERSONATE_CLIENT flag
when it calls WdfRequestSend to send the create request to the I/O target. The Send method returns an error
code if the impersonation attempt fails, unless the driver also sets the
WDF_REQUEST_SEND_OPTION_IMPERSONATION_IGNORE_FAILURE flag.
The following example shows how a UMDF driver might use the
WDF_REQUEST_SEND_OPTION_IMPERSONATE_CLIENT flag to send a file creation request to an I/O
target. The driver's INF file must also include the UmdfImpersonationLevel directive as described above.

WDFIOTARGET iotarget;
WDF_REQUEST_SEND_OPTIONS options;
NTSTATUS status;
WDF_REQUEST_PARAMETERS params;
ULONG sendFlags;

WDF_REQUEST_PARAMETERS_INIT(&params);
WdfRequestGetParameters(Request, &params);

sendFlags = WDF_REQUEST_SEND_OPTION_SYNCHRONOUS;
if (params.Type == WdfRequestTypeCreate) {
sendFlags |= WDF_REQUEST_SEND_OPTION_IMPERSONATE_CLIENT;
}

WDF_REQUEST_SEND_OPTIONS_INIT(&options, sendFlags);
if (WdfRequestSend(Request,
iotarget,
&options
) == FALSE) {
status = WdfRequestGetStatus(Request);
}

The driver does not have to call WdfRequestImpersonate before it sends the request to the I/O target.
If lower-level drivers also forward the request, the client's impersonation level travels down the driver stack.
Reducing Security Threats
To reduce the chance of an "elevation of privilege" attack, you should:
Try to avoid using impersonation.
For example, to avoid using impersonation to open a file that the driver must use, the client application
can open the file and use I/O operations to send file contents to the driver.
Use the lowest impersonation level that your driver requires.
Set the impersonation level in your driver's INF file as low as possible. If your driver does not require any
impersonation, do not include the UmdfImpersonationLevel directive in the INF file.
Minimize the opportunities for an attacker to exploit your driver.
Your EvtRequestImpersonate callback function should contain a small section of code that performs only
the operation that requires impersonation. For example, if your driver accesses a protected file, it requires
impersonation only when it opens the file handle. It does not require impersonation to read from or write
to the file.
Host Process Timeouts in UMDF
2/5/2021 • 2 minutes to read • Edit Online

When the reflector sends a critical request to the driver host process, the host starts an internal timer. The
default timeout interval is 60 seconds. Critical requests include Plug and Play, power, and I/O cancellation.
As long as the User-Mode Driver Framework (UMDF) driver performs operations on a regular basis toward
completing the request, the reflector extends the timeout period. For example, for a remove request, the driver
needs to return from the remove callbacks at regular intervals.
If the timeout period expires, the reflector generates a WER error report, terminates the host process, and
attempts to restart the device. For info about automatic restart, see Using Device Pooling in UMDF Drivers.
For info about the fields in this report, see Accessing UMDF Metadata in WER Reports.
Timeout expiration is the most common reason for the reflector to terminate the host process.
You can extend the timeout period by using the WDF Verifier Control Application.
Supporting Kernel-Mode Clients in UMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how a User-Mode Driver Framework (UMDF) driver supports kernel-mode clients, starting
in UMDF version 2.
A kernel-mode client is a kernel-mode driver that sends I/O requests to your UMDF driver. The kernel-mode
driver might be above the UMDF driver, in the same device stack, or it might be in a different device stack.
The kernel-mode driver can forward I/O requests that it has received from a user-mode application, or can
create new I/O requests and send them to the user-mode driver.
How to support kernel-mode clients in a UMDF driver
To enable a UMDF driver's support for kernel-mode clients, the INF file of the UMDF driver must include a
UmdfKernelModeClientPolicy directive in its INF DDInstall.WDF section.
The framework provides two methods that are useful to drivers that support kernel-mode clients. A driver can
call the WdfRequestGetRequestorMode method to determine whether an I/O request came from kernel
mode or user mode. If the I/O request came from user mode, the driver can call
WdfRequestIsFromUserModeDriver to determine whether the request came from an application or another
user-mode driver.
Restrictions on kernel-mode drivers
A UMDF driver can process I/O requests from a kernel-mode driver only if the kernel-mode driver meets the
following requirements:
The kernel-mode driver must be running at IRQL = PASSIVE_LEVEL when it sends the I/O request.
Unless the driver has set the UmdfFileObjectPolicy INF directive to
AllowNullAndUnknownFileObjects , each I/O request that a kernel-mode driver sends to a user-mode
driver must have an associated file object. The framework must have previously been notified that the I/O
manager created the file object. (Such notification causes the framework to call the user-mode driver's
EvtDeviceFileCreate callback function, but that callback function is optional.)
The I/O request cannot contain an IRP_MJ_INTERNAL_DEVICE_CONTROL function code.
The I/O request's buffers must not contain pointers to additional information, because the user-mode
driver cannot dereference the pointers.
If the I/O request contains an I/O control code that specifies the "neither" buffer access method, the
kernel-mode driver must send the I/O request in the process context of the application that created the
I/O request. For more information about how to support the "neither" method in a UMDF driver, see
Managing Buffer Access Methods in UMDF Drivers.
The UMDF driver might modify an I/O request's output data, in user mode. Therefore, the kernel-mode
driver must validate any output data that it receives from the user-mode driver.
The kernel-mode client should typically validate the Information value that a UMDF driver passes to
WdfRequestCompleteWithInformation . If the client is a KMDF driver, it can call
WdfRequestGetCompletionParams to obtain this information in an IO_STATUS_BLOCK structure.
Typically, the framework does not validate the information value that a UMDF driver passes to
WdfRequestCompleteWithInformation . (This parameter usually specifies the number of transferred
bytes.) The framework validates the information value only for output buffers, and only for the buffered
I/O data access method. (For example, the framework verifies that the number of transferred bytes does
not exceed the output buffer size of a read operation, if the access method is buffered I/O.)
Using Activity Identifiers
2/5/2021 • 2 minutes to read • Edit Online

In framework versions 1.11 and later, UMDF drivers can set and retrieve activity identifiers (IDs). Activity IDs
allow you to associate multiple I/O requests, so that you can track them using Event Tracing for Windows (ETW)
tracing. This topic describes some possible scenarios in which the driver might use activity IDs.

Associating New Requests with an Existing Request


In your driver's I/O dispatch callback function, you might create multiple framework I/O requests as a result of
an incoming request. The driver obtains the activity ID from the original request and sets it in the new requests
by calling WdfRequestRetrieveActivityId and WdfRequestSetActivityId .
For a code example, see WdfRequestRetrieveActivityId .

Associating New Requests with an Existing Thread


A driver might create a new I/O request in a thread other than the I/O dispatch thread, or in a work item. You can
set the activity ID for such a request from any corresponding request, or by using the activity ID associated with
the I/O dispatch thread. The driver can retrieve the activity ID associated with the current thread by calling
EventActivityIdControl and then calling WdfRequestSetActivityId to set the identifier for each new I/O
request.
If the driver calls the Win32 API to send an I/O request, it can retrieve the activity ID from the original request
and propagate it to the thread. The I/O manager then applies the activity ID that is associated with the thread to
any I/O request packets (IRPs) that it generates in response to the request.
Controlling Device Access in KMDF Drivers
2/5/2021 • 3 minutes to read • Edit Online

Drivers must help to prevent users from inappropriately accessing a computer's devices and files. To prevent
unauthorized access to devices and files, you must:
Name device objects only when necessary.
Provide security descriptors for device objects and interfaces.
Naming Device Objects Only When Necessary
Like most Windows Driver Model (WDM) drivers, framework-based drivers typically do not name their device
objects. Applications can access a device by specifying a device object name, so each additional device object
name represents an additional path that an application can use to access the device.
To prevent unauthorized access to a device, each driver can specify a security descriptor when it names a device
object. However, the file name that the operating system provides to a driver (see
WdfFileObjectGetFileName ) does not include the device object name that the application used. Therefore, if
several drivers in your driver's stack provide names for their device objects, your driver cannot determine which
object name the application used to open the device. As a result, an application might open the device with a
less restrictive security descriptor than your driver expects.
Physical device objects (PDOs) must have names. Typically, framework-based bus drivers do not specify a name
for a PDO, because the framework (by default) instructs the operating system to generate a name.
On the other hand, a framework-based driver can assign a device name to a device object by calling
WdfDeviceInitAssignName . A driver should name a functional device object (FDO), filter device object (filter
DO), or PDO only if the driver must support an older application that expects a specific device name, or if the
driver belongs to an older driver stack whose architecture requires object names.
Instead of naming FDOs and filter DOs, WDM drivers and framework-based drivers should provide device
interfaces that applications can access. The operating system obtains a device interface's security descriptor from
the device's PDO and from registry entries that a driver package's INF file specifies. A bus driver can provide
device interfaces for a PDO if the driver's devices operate in raw mode, without a function driver.
Some drivers must call WdfDeviceCreateSymbolicLink to create symbolic link names for their devices. For
example, a driver might create an MS-DOS device name if applications expect to see an MS-DOS name for the
device. If your driver creates a symbolic link name for an unnamed FDO or filter DO, the framework associates
the symbolic link name with the PDO's name. (Control devices are not associated with a PDO, so your driver
cannot create a symbolic link name for an unnamed control device.)
Providing Security Descriptors for Device Objects and Interfaces
Every named device object must have a security descriptor. The operating system uses the device object's
security descriptor to determine the types of users that are allowed to access a device and its device interfaces.
Security descriptors can be assigned to device objects by:
The operating system, which provides a default security descriptor for device objects (see Controlling
Device Access).
The framework, which provides a default security descriptor (by using the
SDDL_DEVOBJ_SYS_ALL_ADM_ALL value) if your driver calls WdfDeviceInitAssignName to assign a
name to a device object (see SDDL for Device Objects).
Your driver, which can override the framework's default security descriptor by calling
WdfDeviceInitAssignSDDLString .
By default, the operating system also uses the device PDO's security descriptor to determine access rights to the
device interfaces that a driver provides.
A driver package can provide an INF file that specifies a device's security descriptors with an INF AddReg
directive within an INF DDInstall.HW section .
For more information about specifying security descriptors in INF files, see Creating Secure Device Installations.
If your driver creates PDOs for devices that operate in raw mode, the driver must specify a device setup class
when it calls WdfPdoInitAssignRawDevice . Additionally, if your driver creates control devices, it can call
WdfDeviceInitSetDeviceClass to specify a device setup class. In both of these cases, system administrators
can use the registry key of the specified setup class to store security descriptors for the device.
For information about how the operating system determines which security descriptor to use for a device, see
Controlling Device Access.
When the framework creates a device object, it always sets the FILE_DEVICE_SECURE_OPEN flag so that the
operating system will check a device's security descriptor before allowing an application to access any names
within the device's namespace. For more information about the FILE_DEVICE_SECURE_OPEN flag and device
namespace, see Controlling Device Namespace Access.
Accessing UMDF Metadata in WER Reports
2/5/2021 • 4 minutes to read • Edit Online

This topic describes the location and contents of the Windows Error Reporting (WER) reports that the operating
system creates when a User-Mode Driver Framework (UMDF) crashes.
The system generates WER reports for three different UMDF event types: WUDFHostProblem ,
WUDFUnhandledException , and WUDFVerifierFailure .
When the reflector terminates the driver host process, sometimes due to the host timeout threshold being
exceeded, the system generates a file called Report.wer, which contains the WER information. Specifically,
Report.wer contains UMDF metadata that may be helpful if you are trying to debug a UMDF driver with no
access to a live debugging target.
In Windows 8.1, you can find the Report.wer file in the C:\ProgramData\Microsoft\Windows\WER\ReportQueue
directory. In this directory, open the most recent NonCritical_HostProblem_* folder and locate Report.wer.
You can also access WER reports for UMDF using the following PowerShell command:

get-winevent -providername "Windows Error Reporting" | where-object {$_.Message -like "*wudf*"} | format-
list | out-file UmdfReports.txt

WUDFHostProblem sample report


The following is a sample UMDF WER report of type WUDFHostProblem . It was obtained from the
ReportQueue directory described above. If you use PowerShell to retrieve the reports, the fields may be labeled
P0, P1, P2 instead of Sig[0], Sig[1], Sig[2]. Otherwise, the fields are the same and contain the same possible
values. This sample was generated from one of the WDK samples that use the OSR USB-FX2 hardware reference
board.

Sig[0].Name=EventClass
Sig[0].Value=HostProblem
Sig[1].Name=Problem
Sig[1].Value=HostTimeout
Sig[2].Name=DetectedBy
Sig[2].Value=2
Sig[3].Name=UMDFVersion
Sig[3].Value=6.3.9600
Sig[4].Name=ExitCode
Sig[4].Value=103
Sig[5].Name=Operation
Sig[5].Value=3
Sig[6].Name=Message
Sig[6].Value=11b00
Sig[7].Name=Status
Sig[7].Value=ffffffff
Sig[8].Name=HardwareId
Sig[8].Value=USB\VID_0547&PID_1002&REV_0000

WUDFHostProblem fields
The following table describes the possible values for the fields in a report of type WUDFHostProblem.
IN DEX NAME VA L UES

0 EventClass The framework sets this value to


HostProblem .

1 Problem This field contains one of the


following values:
HostFailure
SendFailure
HostTimeout
BadRequest
BadReply
HostFailure
Other
HostDisconnect
LeakedHandle
InvalidInterruptState
IsrTimedOut

2 DetectedBy Contains one of the following


enumeration values:
cpp WdfComponentInvalid = 0,
WdfComponentPlatform,
WdfComponentReflector,
WdfComponentDriverManager,
WdfComponentHost,
WdfComponentFramework,
WdfComponentTest,
WdfComponentMax

3 UMDFVersion Specifies the version of the UMDF


libraries currently in use. Note that
this may be a later version than
came with the operating system if
the user took action to update the
framework libraries.

4 ExitCode Contains one of the following


enumeration values:
cpp WdfHostExit_StillActive = 0x103,
WdfHostExit_CodeUnknown = 0x70000000,
WdfHostExit_InternalDriverStopReported,
WdfHostExit_InternalDriverStopReportFailed,
WdfHostExit_ExternalTermination
WdfHostExit_StillActive
indicates that the host process
was running at the time the
framework created the error
report.
IN DEX NAME VA L UES

5 Operation Contains one of the following


enumeration values:
cpp WudfOperation_Invalid,
WudfOperation_Init,
WudfOperation_HostShutdown,
WudfOperation_Pnp,
WudfOperation_Cleanup,
WudfOperation_Close,
WudfOperation_Cancel,
WudfOperation_IO,
WudfOperation_Interrupt,
WudfOperation_PoFx,
WudfOperation_Other,
WudfOperation_Max

6 Message The first digit is of this field is


always 1, which indicates that an
IRP is involved in the operation.
Subsequent pairs of digits indicate
the MajorFunction and
MinorFunction of the IRP,
respectively.
In the sample report above, for
example, this field contains the
value 11b00. This means that the
operation was an IRP that the
reflector handled on behalf of the
driver host process with a major
function value of IRP_MJ_PNP and
minor function value of
IRP_MN_START_DEVICE (1 = IRP
message, 1b = IRP_MJ_PNP, 00 =
IRP_MN_START_DEVICE).

7 Status The framework always sets to this


value to 0xffffffff.

8 HardwareId This field contains the hardware ID


of the device associated with the
driver that had a problem.

WUDFUnhandledException fields
The following table describes the possible values for the fields in a report of type WUDFUnhandledException .

IN DEX NAME VA L UES

0 EventClass The framework sets this value to


UnhandledException .
IN DEX NAME VA L UES

1 Component This field contains one of the


following values:
Invalid
Platform
Reflector
DriverManager
Host
Framework
Test

2 ExceptionCode The reason the exception occurred.


For a list of values, see
EXCEPTION_RECORD .

3 RelativeFaultingAddress The address where the exception


occurred.

4 CrashingModuleName Name of the driver that raised the


exception.

5 CrashingFileVersion Framework version of the driver.

6 LastDriverName Name of the first non-UMDF driver


component in the driver stack.

7 LastDriverVersion Version number of the first non-UMDF


driver component in the driver stack.

8 UMDFVersion Specifies the version of the UMDF


libraries currently in use. Note that
this may be a later version than
came with the operating system if
the user took action to update the
framework libraries.

9 HardwareId Starting in Windows 8, the


hardware ID is provided in a
separate file. In this case, the
framework sets this value to
Dumped Separately .

WUDFVerifierFailure fields
The following table describes the possible values for the fields in a report of type WUDFVerifierFailure .

IN DEX NAME VA L UES

0 EventClass The framework sets this value to


VerifierFailure .
IN DEX NAME VA L UES

1 FoundBy The framework sets this value to


Framework .

2 Category This field contains one of the


following values:
Internal
Driver
Caller
External
UnhandledException

3 ErrorNumber Internal use only.

4 Location Internal use only.

5 Driver The name of the driver module that


failed.

6 CallerAddress The address of the routine that


initiated generation of the report.

7 UMDFVersion Specifies the version of the UMDF


libraries currently in use. Note that
this may be a later version than
came with the operating system if
the user took action to update the
framework libraries.

8 HardwareId Starting in Windows 8, the


hardware ID is provided in a
separate file. In this case, the
framework sets this value to
Dumped Separately .
Attaching a User-Mode Debugger
2/5/2021 • 2 minutes to read • Edit Online

After the driver manager starts the driver host process for the device, you can attach a user-mode debugger.
How you attach the debugger depends on how many devices are attached to the computer:
If a single device is attached, run the following command:

windbg -pn WUDFHost.exe

Run this command repeatedly until a host process to debug is discovered.


If multiple devices are attached, determine the process identifier (PID) of a particular host and run the
following command:

windbg -p PID

You can use the operating system-supplied Tasklist.exe to determine the PID of a host process.
(Tasklist.exe is a command-line application that provides a user with a list of processes that are running
on the operating system.)
Avoiding Reboot when Updating a UMDF Driver
2/5/2021 • 2 minutes to read • Edit Online

To avoid a required reboot when you update a UMDF driver, specify the COPYFLG_IN_USE_RENAME flag in
the CopyFiles Directive in your driver's INF file, as shown in this example:

[VirtualSerial_Install.NT]
CopyFiles=UMDriverCopy

[UMDriverCopy]
Virtualserial.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME
Breaking into a Debugger from KMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

If you want your framework-based driver to break into a kernel-mode debugger, you can use the following:
The WdfVerifierDbgBreakPoint function breaks into the debugger if the DbgBreakOnError value is set
in the registry.
The WDFVERIFY macro tests a logical expression and breaks into the kernel debugger if the expression
evaluates to FALSE and if the VerifyOn value is set in the registry.
The VERIFY_IS_IRQL_PASSIVE_LEVEL macro breaks into the kernel debugger if the driver is not
executing at IRQL = PASSIVE_LEVEL and if the VerifyOn value is set in the registry.
The ASSERT macro tests a logical expression and breaks into the kernel debugger if the expression
evaluates to FALSE .
The ASSERTMSG macro tests an expression and, if the expression evaluates to FALSE , breaks into the
kernel debugger and supplies a displayable text message to the debugger.
The DbgPrintEx and KdPrintEx functions supply a displayable text message to the debugger.
The code for the WDFVERIFY and VERIFY_IS_IRQL_PASSIVE_LEVEL macros is included in your driver when you
build your driver in a release or debug configuration. The code for the ASSERT and ASSERTMSG macros is
included in your driver only when you build your driver in a debug configuration.
For more information about project configurations, see Building a Driver.
VERIFY_IS_IRQL_PASSIVE_LEVEL macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


The VERIFY_IS_IRQL_PASSIVE_LEVEL macro breaks into the kernel debugger if the driver is not executing at
IRQL = PASSIVE_LEVEL.

Syntax
VOID VERIFY_IS_IRQL_PASSIVE_LEVEL(void);

Parameters
This macro has no parameters.

Return value
None

Remarks
The code for the VERIFY_IS_IRQL_PASSIVE_LEVEL macro is included in your driver's binary when you build
your driver in a release configuration or a debug configuration.
The VERIFY_IS_IRQL_PASSIVE_LEVEL code breaks into a kernel debugger if one of the following is true:
DbgBreakOnError is set to a non-zero value in the registry.
VerifierOn is set to a non-zero value and DbgBreakOnError is not set.
Driver Verifier is enabled, the driver was built with framework version 1.9 or later, and neither VerifierOn
nor DbgBreakOnError is set.
For more information about registry entries that you can use to debug your driver, see Registry Entries for
Debugging Framework-Based Drivers.
For more information about debugging your driver, see Debugging a KMDF Driver.

Examples
The following code example breaks into the kernel debugger if the driver is not executing at IRQL =
PASSIVE_LEVEL.

VERIFY_IS_IRQL_PASSIVE_LEVEL();

Requirements
Target platform Universal
Minimum KMDF version 1.0

Header Wdfassert.h (include Wdf.h)

See also
WDFVERIFY
WDFVERIFY macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


The WDFVERIFY macro tests a logical expression and, if the expression evaluates to FALSE , breaks into the
kernel debugger.

Syntax
VOID WDFVERIFY(
exp
);

Parameters
exp
A logical expression that WDFVERIFY tests.

Return value
None

Remarks
The code for the WDFVERIFY macro is included in your driver's binary when you build your driver in a release
configuration or a debug configuration.
The WDFVERIFY code breaks into a kernel debugger only if the VerifyOn value is set in the registry. For more
information about registry entries that you can use to debug your driver, see Registry Entries for Debugging
Framework-Based Drivers.
For more information about debugging your driver, see Debugging a KMDF Driver.

Examples
The following code example breaks into the debugger if an attempt to reuse a request object fails.

status = WdfRequestReuse(Request, &params);


WDFVERIFY(NT_SUCCESS(status));

Requirements
Target platform Universal

Minimum KMDF version 1.0


Header Wdfassert.h (include Wdf.h)

See also
VERIFY_IS_IRQL_PASSIVE_LEVEL
Bug Checks from KMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

The framework checks for several types of errors from framework-based drivers. If one of these errors occurs,
the framework creates a WDF_VIOLATION bug check.
For information about the types of driver errors that the framework checks for, see WDF_VIOL ATION .
Your driver can create a bug check by calling WdfVerifierKeBugCheck .
Debugging Power Reference Leaks in WDF
2/5/2021 • 2 minutes to read • Edit Online

When a Windows Driver Frameworks (WDF) driver calls WdfDeviceStopIdle , the framework increments the
device's power reference count. Every successful call to WdfDeviceStopIdle must be matched by a call to
WdfDeviceResumeIdle to decrement the power reference count.
Starting in Kernel-Mode Driver Framework (KMDF) 1.15 and User-Mode Driver Framework (UMDF) 2.15, you
can monitor power reference usage by using the !wdfkd.wdfdevice and !wdfkd.wdftagtracker debugger
extensions. This functionality is disabled by default for performance reasons, so you need to turn it on with the
WdfVerifier application or by manually editing the driver’s service key.

WdfVerifier
Open the settings list for your driver and right-click the TrackPower setting. Choose the option appropriate for
your scenario.
Tip Avoid capturing stack traces in performance-critical code paths.

Editing the Registry


You can also turn on Verifier support and power reference tracking by editing your driver’s service key.
For a KMDF driver:
HKLM\SYSTEM\ControlSet001\Ser vices\<Driver Ser vice Name>\Parameters\Wdf
For a UMDF driver:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Ser vices\<Driver Ser vice
Name>\Parameters\Wdf

(REG_DWORD) VerifierOn = 0x1


(REG_DWORD) TrackPower = 0x0 (disabled)
= 0x1 (capture tick count, file name, line number)
= 0x2 (capture tick count, file name, line number, and stack traces)

Driver Code
Drivers call WdfDeviceStopIdle and WdfDeviceResumeIdle to manage the device’s working power state as
follows:
//
// Take power reference
//
status = WdfDeviceStopIdle(device, FALSE);
if (NT_SUCCESS(status)) {
//
// Release power reference
//
WdfDeviceResumeIdle(device);
}

Debugging with WdfKd


To display the power references taken on the device, as well as a tag tracker that shows the reference history,
use !wdfkd.wdfdevice with verbose flags:

kd> !wdfkd.wdfdevice 0x6d939790 ff


Power references: 0 !wdftagtracker 0x9ea030a8

Calling the !wdfkd.wdftagtracker shows the device’s power reference history:

kd> !wdftagtracker 0x9ea030a8


Reference and Release History:
# (showing most recent first; refcount is approximate in multi-threaded scenarios)

## 3 entries, history depth is 25

(--) 0 ref: Tag '....' at Time 0x1331e ticks


## path\to\your\driver\code.c @ 374

(++) 1 refs: Tag '....' at Time 0x1331e ticks


## path\to\your\driver\code.c @ 372

(++) Initial Tag '....' at Time 0x12c9a ticks

Specifying a Tag
Optionally, specify a tag name to facilitate identification of specific power references. To do so, use
WdfDeviceStopIdleWithTag and WdfDeviceResumeIdleWithTag :

status = WdfDeviceStopIdleWithTag(device, FALSE, (PVOID)'oyeH');


if (NT_SUCCESS(status)) {
WdfDeviceResumeIdleWithTag(device, (PVOID)'oyeH');
}

Corresponding !wdftagtracker sample output:

(--) 0 ref: Tag 'Heyo' at Time 0x24e40 ticks


## path\to\your\driver\code.c @ 374

(++) 1 refs: Tag 'Heyo' at Time 0x24e40 ticks


## path\to\your\driver\code.c @ 372

(++) Initial Tag '....' at Time 0x12c9a ticks


Determining If a Driver Leaks Framework Objects
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how you can find driver memory leaks caused by unreleased references. It applies to User-
Mode Driver Framework (UMDF) version 1 and 2 drivers.

UMDF 1
In UMDF version 1, a call stack can cause a memory leak if each call to AddRef does not have a matching
Release call.
To test if your UMDF version 1 driver leaks framework objects, use the following steps:
1. Use the WDF Verifier control application to set the verifier options that you want. During regular testing,
start by setting TrackObjects and not TrackRefCounts .
When the driver is unloaded, the framework's code verifier enters the debugger if a framework object
was not deleted, and it prompts you to use the !wudfdumpobjects debugger extension. This debugger
extension displays a list of undeleted objects.
2. If the code verifier indicates that the driver is leaking framework objects, then use the control application
to set the TrackRefCounts option.
If this option is set, the verifier keeps track of references to framework objects while the driver runs. You
can use the !wudfrefhist debugger extension to display each call stack (set of function calls) that
increments or decrements an object's reference count. By examining the AddRef and Release calls in
these call stacks, you should be able to find a stack that does not decrement the object's reference count
and thus causes the leak.
For information about additional verifier options, see Using UMDF Verifier.
For information about when to delete framework objects, see Managing the Lifetime of Objects.

UMDF 2
In UMDF version 2, unreleased references are rare, but can occur due to call mismatches when using
WdfObjectReference and WdfObjectDereference .
To test if your UMDF version 2 driver leaks framework objects, use the following procedure:
1. Follow the steps outlined in Best Practices to configure your computer for UMDF debugging.
2. To use tag tracking, enable both the UMDF Verifier and handle tracking in the registry. Both of these
settings are stored in the driver's Parameters\Wdf subkey of the
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\WUDF\Ser vices\<driver name> key.
To enable the UMDF Verifier, set a nonzero value for VerifierOn.
To enable handle tracking, set the value of TrackHandles to the name of one or more object types, or
specify an asterisk (*) to track all object types.
You can also modify UMDF Verifier settings by using the WdfVerifier.exe application.
3. Reboot, establish a debugger connection, and then use the following debugger commands:
!wdfkd.wdfdriverinfo 0x10 to display the handle hierarchy
!wdfkd.wdftagtracker to display tag information
If UMDF Verifier is on, memory leaks are detected at driver unload, just as in KMDF.
For additional information about using reference counts in KMDF and UMDF version 2 drivers, see Framework
Object Life Cycle.
Determining the State of a UMDF Device
2/5/2021 • 3 minutes to read • Edit Online

This topic describes how you can use debugger extensions in conjunction with a User-Mode Driver Framework
(UMDF) version 1 or 2 driver to determine what state your UMDF device is in.
For UMDF version 1, you'll use extension commands implemented in wudfext.dll. Starting in UMDF version 2,
you'll use extension commands implemented in wdfkd.dll.
To determine device state, use the following steps:
1. Break into a driver host process by using one of the following debugger types:
User-mode debugger:
a. Locate the appropriate driver host process for the device (that is, WUDFHost.exe). If there
are multiple instances of the host process, you can use the operating system-supplied
Tasklist.exe application to determine which process is hosting your driver.
Use this command from an elevated Command Prompt.
tasklist -m <yourdriver.dll>
b. Start the debugger with elevated privilege and attach to the appropriate process.
c. Reload symbols by using the .reload debugger command.
d. You can view all the threads by using the ~*k debugger command.
Kernel-mode debugger:
a. Locate the appropriate driver host process for the device (that is, WUDFHost.exe). Use the
!process kernel-mode debugger extension as shown in the following example to obtain a
list of all WUDFHost.exe instances:
!process 0 0 WUDFHost.exe
The process address and Process Environment Block (PEB) address from the !process 0 0
output are used in the next steps.
b. Attach to the host process in one of the following ways:
Use the .process debugger command for a non-invasive attach as shown in the
following example:
.process /p /r <process-addr>
You should use non-invasive attach when you cannot let the execution continue. For
example, you should use non-invasive attach when you receive a break in your
application and you want to see what the driver did to cause that break or when the
reflector prepares to terminate your host process.
Use the .process debugger command in an invasive attach as shown in the
following example:
.process /i <process-addr>
The debugger will request that you continue by using the g debugger command;
shortly after you execute the g debugger command, the debugger will break into the
active process. Reload user symbols by using the .reload debugger command as
shown in the followingexample:
.reload /user
c. If there are multiple instances of host process, you can use the !peb general debugger
extension as shown in the following example to obtain the list of modules that are loaded in
the process:
!peb <PEB-Address>
You need to attach to the process for this command to work. You can attach non-invasively
as shown in the previous step.
Locate the process in which your driver DLL is loaded.
d. Use the !process kernel-mode debugger extension as shown in the following example to
obtain information about the process. The information includes the threads that run in the
process and the addresses of those threads:
!process <process-addr>
e. Use the !thread kernel-mode debugger extension as shown in the following example to
obtain information about each thread:
!thread <thread-addr>
2. In the debugger, use the .chain command to see if the wudfext.dll (UMDF 1) or wdfkd.dll (UMDF 2)
debugger extension library is loaded.
3. If the library you need is not present, use the .load command to load the extension DLL into the
debugger. Then enter .reload to reload symbol information.
4. Use !wudfext.umdevstacks (UMDF 1) or !wdfkd.wdfumdevstacks (UMDF 2) to see all device stacks
loaded in the host process.
Then use !wudfext.umdevstack (UMDF 1) or !wdfkd.wdfumdevstack (UMDF 2) to get detailed
information about the device stack.
5. Use !wudfext.wudfdevice (UMDF 1) or !wdfkd.wdfdevice (UMDF 2) to obtain information about the
Plug and Play (PnP) and power-management state of the device.
6. Use !wudfext.wudfdriverinfo (UMDF 1) or !wdfkd.wdfdriverinfo (UMDF 2) to display additional
information about the driver, including its device tree.
Determining Why an Application Request Does Not
Complete
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how you can use the Wudfext.dll debugger extensions in conjunction with a User-Mode
Driver Framework (UMDF) version 1 or 2 driver to determine why an application request does not complete.
For UMDF version 1, you'll use extension commands implemented in wudfext.dll. Starting in UMDF version 2,
you'll use extension commands implemented in wdfkd.dll.
You can perform the following steps to determine why an application request does not complete:
1. Use !wudfext.umirps (UMDF 1) or !wdfkd.wdfumirps (UMDF 2) to display all the outstanding user-
mode I/O request packets (IRPs) in the host process. The information for each user-mode IRP includes the
original kernel-mode IRP for which the user-mode IRP was created.
Determine the user-mode IRP that corresponds to the kernel-mode IRP that the application originated.
2. Use !wudfext.umirp (UMDF 1) or !wdfkd.wdfumirp (UMDF 2) to obtain information about a particular
user-mode IRP.
The information for the user-mode IRP includes the stack locations. If you know the stack locations, you
can determine where the IRP is being processed. Stack location 0 represents the stack below UMDF (that
is, the kernel-mode stack or some other sub-system, such as Microsoft Win32 or Winsock).
3. If the IRP is at your driver's layer (that is, the layer in which your driver processes the IRP), perform the
following steps:
a. View the I/O queues that are set up at your driver's layer. You can use
!wudfext.wudfdevicequeues (UMDF 1) or !wdfkd.wdfdevicequeues (UMDF 2) to view all the
I/O queues that are set up at your driver's layer. You can also use !wudfext.wudfqueue (UMDF 1)
or !wdfkd.wdfqueue (UMDF 2) to obtain information about a particular queue.
b. If there are multiple requests outstanding, you can use !wudfext.wudfrequest (UMDF 1) or
!wdfkd.wdfrequest (UMDF 2) to obtain information about a request, which includes the
underlying user-mode IRP. From the user-mode IRP information, you can determine the request
that you are interested in.
c. Verify whether the request is owned by a queue or by the driver. This information is displayed as
part of the output from !wudfext.wudfqueue or !wdfkd.wdfqueue . Perform one of the
following verifications depending on whether the queue or the driver owns the request:
If the request is owned by the queue, check the state of the queue to determine why the queue
did not deliver the request to the driver.
If the request is owned by the driver, check the threads in the host process to determine if a
thread became stuck or deadlocked while processing the request.
4. If the IRP is at another UMDF driver layer, you can repeat the preceding steps for that layer. Remember
that you can use !wudfext.umdevstack (UMDF 1) or !wdfkd.wdfumdevstack (UMDF 2) to view
information about all stack layers.
5. If the IRP is beyond the UMDF stack (for example, if stack location 0 is where the IRP is currently being
processed), determine why the corresponding kernel-mode IRP did not complete.
Determining Why the Reflector Terminated the Host
Process
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how you can analyze why the reflector terminated the driver host process (WUDFHost.exe)
or why the driver host process crashed.
The most common reason for the reflector to terminate the host process is the expiration of UMDF host process
timeouts.
We strongly recommend doing all development and testing of your UMDF driver with a kernel debugger
attached to the test system and enabling Application Verifier (AppVerif.exe) on WUDFHost.exe. Use the following
command, attach a kernel debugger and then reboot.

AppVerif –enable Heaps Exceptions Handles Locks Memory TLS Leak –for WudfHost.exe

Using Dump Files


When your UMDF driver crashes or encounters a problem, a break will be reported in the kernel debugger.
These problems should be debugged when user-mode exceptions are reported in the kernel debugger. Kernel
debugger breaks are also reported by WudfRd.sys before it terminates a driver host process because of a
problematic (non-responsive) UMDF driver. You will also find logs and heap dumps reported at the following
location. To review dump files captured by UMDF, follow these steps:
1. Locate the latest .dmp file in the %ProgramData%\Microsoft\WDF directory. Before UMDF 2.15 that
shipped with Windows 10 1507, the log directory is under %windir%\system32\LogFiles\WUDF.
2. Load the latest .dmp file into the debugger by using the following command:

WinDbg -z <path to the .dmp file>

3. Look at the state of the threads at the time of termination.


If you need heap dumps captured, at the time of testing set the following registry values and re-boot your test
system before running tests. You can also examine Windows Error Reporting history from the system's
application event log at %SystemRoot%\System32\Winevt\Logs\Application.evtx

reg add "HKLM\Software\Microsoft\windows NT\CurrentVersion\Wudf" /v LogMinidumpType /t REG_DWORD /d 0x1122


reg add "HKLM\Software\Microsoft\windows NT\CurrentVersion\Wudf" /v LogEnable /t REG_DWORD /d 1

Using the Debugger


In other cases, you might need to attach to a live kernel-mode target to determine why the reflector terminated
the host process. To set up your debugging session, follow the steps described in How to Enable Debugging of a
UMDF Driver.
Once you have established a connection, use !wdfkd.wdfumtriage to examine the UMDF drivers, display the
outstanding IRPs by using the !wdfkd.wdfumirps UMDF debugger extension (!wudfext.umirps for UMDF
version 1).
If a PnP IRP or a power IRP is pending, determine why the driver causes the IRP to hang by examining
threads in the host process.
You can use the !process extension to examine the threads running in the host process. The 0x1f flags
value shows you the stack trace for each thread.
!process <process addr> 0x1f
If your driver has not completed a canceled IRP quickly, determine which IRP was canceled and why it has
not completed.
If a cleanup or close IRP is pending, determine why the IRP is taking a long time to process.
Determining Why the UMDF Driver Fails to Load or
the UMDF Device Fails to Start
2/5/2021 • 2 minutes to read • Edit Online

This topic describes troubleshooting steps you can use when a UMDF driver fails to load or an associated device
fails to start.
You can use the following technique with both UMDF version 1 and 2 drivers.
1. Check setup by ensuring that the following files are correct:
Driver's INF file.
Use the InfVerif tool to validate the driver's INF file.
%windir%\inf\setupapi.dev.log (setupapi.log on Windows XP), %windir%\setupact.log, and
%windir%\temp\wudf_update.log files.
2. If you did not find any setup issues, enable the HostProcessDbgBreakOnStar t registry entry by using
the WDF Verifier control application (WdfVerifier.exe). By enabling HostProcessDbgBreakOnStar t , you
will make the driver host process for the device (WUDFHost.exe) break into the debugger shortly after
WUDFHost.exe starts but before your driver DLL loads.
You should enable HostProcessDbgBreakOnStar t with a user-mode debugger and not a kernel-mode
debugger. A kernel-mode debugger, by default, does not receive user-mode module load and unload
notifications. Therefore, you will not be able to set deferred breakpoints.
3. If you do not see a host start, perform the following steps to correctly configure the device:
a. Ensure that all the drivers that you install through your INF exist and are copied to the operating
system.
b. If the reflector (also known as WUDFRd.sys) is not the service on the device, ensure that the driver,
which would then be the service, has a service entry (for example, 'sc qc foo') and is set to start
automatically.
4. Ensure that your driver's symbols are in the symbol path (that is, .sympath).
5. Verify the following items one at a time. In the following steps, assume that your driver is foo.dll:
a. Verify that your driver's DllMain routine is called (for example, bu Foo!DllMain).
b. If your driver DLL does load, for subsequent steps, you can also use the
HostProcessDbgBreakOnDriverLoad registry entry. Having
HostProcessDbgBreakOnDriverLoad set causes WUDFHost.exe to break into the debugger
after your driver DLL is loaded. HostProcessDbgBreakOnDriverLoad can also be used with the
kernel-mode debugger because at this point in the driver loading and device starting process you
can set breakpoints in your driver code.
c. This step applies to UMDF version 1 drivers only. Verify that your driver's DllGetClassObject
routine is called. Verify that the class identifier (ID) for your driver is correct. Verify that
DllGetClassObject runs successfully and returns a driver object (for example, bu
Foo!DllGetClassObject).
d. For UMDF version 1, verify that your driver's IDriverEntr y::OnDeviceAdd method is called.
Verify that the method creates a device and returns successfully (for example, bu
Foo!CMyDriver::OnDeviceAdd).
For UMDF version 2, verify that your driver's EvtDriverDeviceAdd function is called. Verify that the
function creates a device and returns successfully (for example, bu Foo!MyDriverDeviceAdd).
e. For UMDF version 1, verify that your driver's IPnpCallbackHardware::OnPrepareHardware or
IPnpCallback ::OnD0Entr y method is called. Verify that the method returns successfully (for
example, bu Foo!CMyDevice::OnPrepareHardware or Foo!CMyDevice::OnD0Entry).
For UMDF version 2, verify that your driver's EvtDevicePrepareHardware or EvtDeviceD0Entry
function is called. Verify that the function returns successfully (for example, bu
Foo!MyDevicePrepareHardware or Foo!MyDeviceD0Entry).
f. If each of the previous operations run successfully but the operation that follows does not run, you
should check the following items:
a. Verify that every driver above and below your driver in the user-mode stack also successfully
performs these operations.
b. Verify that the kernel stack below your driver successfully completes the IRP_MJ_PNP and
IRP_MN_START_DEVICE IRPs.
Determining Why UMDF Indicates Outstanding
Files at Device Removal Time
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how you can use the Wudfext.dll debugger extensions in conjunction with a User-Mode
Driver Framework (UMDF) version 1 or 2 driver to determine why UMDF indicates that there are outstanding
files when you remove a device.
For UMDF version 1, you'll use extension commands implemented in wudfext.dll. Starting in UMDF version 2,
you'll use extension commands implemented in wdfkd.dll.
To determine why UMDF indicates outstanding files, use the following steps:
1. Use !wudfext.umdevstack (UMDF 1) or !wdfkd.wdfumdevstack (UMDF 2) to dump the device stack.
The dump includes outstanding UMDF intra-stack files (that is, file objects that a driver in the stack
created as opposed to file objects that were created by an application or by a driver in another stack).
2. For each intra-stack file, run !wudfext.umfile (UMDF 1) or !wdfkd.wdfumfile (UMDF 2) to obtain
information about the file.
The output includes the list of IRPs that are pending.
3. Determine why each IRP is outstanding by using !wudfext.umirp (UMDF 1) or !wdfkd.wdfumirp
(UMDF 2) to obtain information about the IRP.
From the output of each !wudfext.umirp or !wdfkd.wdfumirp :
Determine if the IRP completed.
Determine if a driver-created request was not deleted either explicitly by the driver or implicitly by the
object tree.
How to Enable Debugging of a UMDF Driver
2/5/2021 • 3 minutes to read • Edit Online

You can use the following configurations to debug a User-Mode Driver Framework (UMDF) driver during
development. All configurations involve two machines, a host and a target.
Manually copy the driver to the target. Perform user-mode debugging on the target. In this scenario, you
attach manually to an instance of the driver host process running on the target.
Manually copy the driver to the target and then perform kernel-mode debugging from the host.
We recommend doing all UMDF driver testing and development with a kernel debugger attached.

Best Practices
We recommend doing all UMDF driver testing with a kernel debugger attached.
The following are recommended settings. You can set these manually, or use the WDF Verifier Control
Application (WDFVerifier.exe) tool in the WDK to view or change these settings.
Enable Application Verifier on WUDFHost.exe:

AppVerif –enable Heaps Exceptions Handles Locks Memory TLS Leak –for WudfHost.exe

If exceptions occur, Application Verifier sends diagnostic messages to the debugger and breaks in.
If you are using a kernel-mode debugging session, set HostFailKdDebugBreak so that the reflector
breaks into the kernel-mode debugger before terminating the driver host process. This setting is enabled
by default starting in Windows 8.
Disable pooling by setting UmdfHostProcessSharing to ProcessSharingDisabled . For info, see
Specifying WDF Directives in INF Files.
By default, when a UMDF device fails, the framework attempts to restart it up to five times. You can turn
off automatic restart by setting DebugModeFlags to 0x01. For more info, see Registry Values for
Debugging WDF Drivers.
Reboot your computer.
For debugging UMDF driver problems review Determining Why the Reflector Terminated the Host
Process and Debugging UMDF driver crashes

Using WinDbg to attach manually (user-mode debugging)


On the target machine, you can manually attach WinDbg to the instance of WUDFHost that hosts the driver.
When you attach, you break into the debugger and you can set breakpoints in your driver.
Because driver initialization occurs shortly after WUDFHost loads, it is not feasible to attach manually in time to
debug initialization code. Instead, you can set a registry value to cause the host process to wait some number of
seconds at host initialization or driver load time. This delay gives you time to attach WinDbg to the correct
instance of the WUDFHost process.
Follow these steps:
1. In the registry on the target computer, set HostProcessDbgBreakOnStar t or
HostProcessDbgBreakOnDriverLoad to some number of seconds and reboot.
2. On the target computer, open WinDbg as Administrator.
3. On the File menu, choose Attach to Process . Select By Executable , and locate all processes that are
named WUDFHost.exe (there might not be any). If there are any processes named WUDFHost.exe, write
down their process identifiers for future reference.
4. In Device Manager, enable the driver.
5. Repeat step 2 and locate a new instance of WUDFHost.exe. If you don't see a new instance of WUDFHost.exe,
click Cancel , and choose Attach to Process again. When you find the new instance of WUDFHost.exe,
select it, and click OK .
If device pooling is in use and you set the HostProcessDbgBreakOnDriverLoad registry value, you may see
debugger breaks due to other drivers loading. You can turn off device pooling by using UMDF debug mode.
To use debug mode, either use the F5 option in Visual Studio, or set the DebugModeFlags and
DebugModeBinaries values in the registry.
For detailed information about UMDF registry values, see Registry Values for Debugging WDF Drivers (KMDF
and UMDF).

Using WinDbg to remotely debug from a host machine (kernel-mode


debugging)
From a remote host, establish a kernel-mode debugging session and then set current process to the instance of
Wudfhost that is hosting your driver. If you are debugging from a remote kernel debugger, you can set
HostProcessDbgBreakOnDriverStar t or HostProcessDbgBreakOnDriverLoad to 0x80000000 to specify
no timeout, but break into the kernel debugger.
Use these steps:
1. Disable pooling. turn on DebugModeFlags and list your driver in DebugModeBinaries
2. If your driver uses UMDF 1.11 or later, HostFailKdDebugBreak is enabled by default. Skip this step.
If your driver uses UMDF 1.9 or earlier, set HostFailKdDebugBreak to 1.
3. If you are debugging problems related to timeouts, turn off HostProcessDbgBreakOnDriverStar t and
HostProcessDbgBreakOnDriverLoad . (When HostProcessDbgBreakOnDriverStar t or
HostProcessDbgBreakOnDriverLoad is non-zero, the framework disables timeouts so that the
reflector does not terminate the host while a user-mode debugger is attached to the host process.) If you
need to debug driver initialization code, instead of using these two values, try issuing the following
command in WinDbg before your driver loads: sxe ld:MyDriver.dll (break on module load)
4. Reboot if you made any registry changes.
5. Depending on the selections you made above, your remote kernel debugger should break in when the
driver loads or unloads on the target.
Registry Values for Debugging WDF Drivers
2/5/2021 • 8 minutes to read • Edit Online

This article describes the registry values that a WDF driver can set. It applies to KMDF drivers and UMDF drivers
starting with UMDF version 2.
Unless otherwise specified in sections below, the following registry values are located under a driver's
Parameters\Wdf subkey.

For a KMDF driver, this subkey is located in HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services , under the


driver's service name.
For a UMDF driver, this subkey is located in
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services , under the driver's service name.
The subkey for the driver always uses the driver's service name, even if the driver binary's file name differs from
the service name.

DbgBreakOnError
REG_DWORD
If set to a nonzero value, the framework breaks into the debugger when a driver calls
WdfVerifierDbgBreakPoint . (If the VerifierOn value is set, the framework breaks into the debugger even if
the DbgBreakOnError value does not exist.) See the code example in the VerifierOn section.

DbgPrintOn
REG_DWORD
For a KMDF driver, set this value under the HKLM\SYSTEM\CurrentControlSet\Control\Wdf\Kmdf\Diagnostics
registry key.
For a UMDF driver, set this value under the HKLM\System\CurrentControlSet\Control\Wdf\Umdf\Diagnostics
registry key.
The driver might need to create the optional Diagnostics subkey.
If set to a nonzero value, the framework's loader sends a variety of messages to the kernel debugger while it is
loading a driver and binding it to a version of the framework library, or while it is unloading a driver.

DbgWaitForSignalTimeoutInSec
REG_DWORD, framework versions 1.11 and later
Starting in Windows 8, when VerifierOn and DbgBreakOnError are set to nonzero values, the driver can
change the default timeout period for breaking into the debugger by setting
DbgWaitForSignalTimeoutInSec .

DebugModeBinaries
REG_MULTI_SZ, UMDF-only
This registry value is located in HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\DebugMode .
This value specifies the names of the driver binaries to be loaded in debug mode. To enable debug mode for
driver binaries X.DLL, Y.DLL and Z.DLL, for example, this value would be set to X.DLL\0Y.DLL\0Z.DLL\0\0 .

DebugModeFlags
REG_DWORD, UMDF-only
This registry value is located in HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\DebugMode .

VA L UE DESC RIP T IO N

0x01 Enable debug mode. This setting turns off the automatic
restart functionality described in Using Device Pooling in
UMDF Drivers.

0x02 Disable device pooling. For more information about device


pooling, see Using Device Pooling in UMDF Drivers.

0x04 Disable timeouts.

When you use the F5 option in Microsoft Visual Studio, all three flags are set for the deployed driver.

EnhancedVerifierOptions
REG_DWORD, framework versions 1.9 and later
This value contains a bitmap. Each bit represents an additional verifier option that users can enable by setting
the bit.
Bit values:
0x1 : If set, the verifier checks whether each of the driver's event callback functions does the following:
Returns at the same IRQL at which it was called. If the values are different, a WDF_VIOL ATION bug
check occurs with an error code of 0xE.
Before returning, exits all critical regions that it enters. If the callback function returns within a critical
region that it entered, a WDF_VIOL ATION bug check occurs with an error code of 0xF.
0x10000 : If set, and if the driver has enabled guaranteed forward progress for an I/O queue, the framework
simulates a low-memory situation for each of the queue's I/O requests.
0x20000 : If set, and if the driver has enabled guaranteed forward progress for an I/O queue, the framework
simulates a low-memory situation for some randomly selected I/O requests.

ForceLogsInMiniDump
REG_DWORD
Set to a nonzero value to cause the framework to include information from its event logger in crash dump files.

HostFailKdDebugBreak
REG_DWORD, UMDF-only
This registry value is located in HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF .
If this value is non-zero and a kernel debugger is connected to the machine, the reflector breaks into the kernel
debugger before terminating the host process. HostFailKdDebugBreak is disabled by default in Windows 7
and earlier operating systems. Starting in Windows 8, HostFailKdDebugBreak is enabled by default.
The reflector also breaks into the kernel debugger if there is an unexpected termination of the host process (e.g.
by a non-UMDF component or due to an unhandled exception). If there are multiple device stacks pooled in the
host process that is being terminated, the reflector breaks into the debugger multiple times, once for each
device stack loaded in the host process.

HostProcessDbgBreakOnDriverLoad (driver-specific)
REG_DWORD, UMDF-only, works with any UMDF 1.x/2.x driver running on a target computer with UMDF
version 2.31 or later
This registry value is located in
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services\<service name>\Parameters\Wdf .
This value affects only the specified UMDF driver.
Contains a delay value in seconds. Causes WUDFHost to try to connect to a debugger for the specified number
of seconds after the driver has been loaded.
During the specified delay period, the host process looks for the user-mode debugger once a second and breaks
in if one is connected. If a user-mode debugger is not attached within this period and the high bit in is set
(0x80000000), the framework makes a single attempt to break into the kernel-mode debugger. See the section
on HostProcessDbgBreakOnStar t above for examples.
For changes to UMDF registry values to take effect, you must reboot the computer.

HostProcessDbgBreakOnDriverLoad (global)
REG_DWORD, UMDF-only
This registry value is located in
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services\{193a1820-d9ac-4997-8c55-be817523f6aa} . You
can set it by using the WDF Verifier tool (WdfVerifier.exe) in the WDK. This value affects all UMDF drivers on the
system.
Contains a delay value in seconds. Causes WUDFHost to delay the specified number of seconds after the driver
has been loaded. The behavior for HostProcessDbgBreakOnDriverLoad is otherwise the same as that
described for HostProcessDbgBreakOnStar t .
Specifying HostProcessDbgBreakOnStar t or HostProcessDbgBreakOnDriverLoad causes the framework
to disable other UMDF timeouts (for example, Plug and Play operations). This means that if your driver causes
excessive timeouts, using these values might result in your driver causing a fatal crash on the target.

HostProcessDbgBreakOnStart
REG_DWORD, UMDF-only
This registry value is located in
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services\{193a1820-d9ac-4997-8c55-be817523f6aa} . You
can set it by using the WDF Verifier tool (WdfVerifier.exe) in the WDK. This value affects all UMDF drivers on the
system.
Contains a delay value in seconds. During the specified delay period, the host process looks for the user-mode
debugger once a second and breaks in if one is connected. If a user-mode debugger is not attached within this
period and the high bit in HostProcessDbgBreakOnStar t is set (0x80000000), the framework makes a single
attempt to break into the kernel-mode debugger. For example:

VA L UE RESULT

0x00000004 The framework attempts to connect to the user-mode


debugger once a second for 4 seconds. The framework never
tries to connect to the kernel-mode debugger.

0x80000000 The framework makes a single attempt to connect to the


user-mode debugger. If the user-mode debugger is not
attached, the framework tries to connect to the kernel-mode
debugger.

0x80000004 The framework attempts to connect to the user-mode


debugger once a second for 4 seconds. If the user-mode
debugger is not attached within 4 seconds, the framework
tries to connect to the kernel-mode debugger.

You can also set this registry value by using the WDF Verifier tool (WdfVerifier.exe) that is included in the WDK.

LogPages
REG_DWORD
Set to the number of memory pages that the framework assigns to its event logger. If the value is undefined, the
framework uses a default value of one page. The maximum value that you can set is 16 for computers that have
4-kilobyte-sized memory pages (x86 and amd64 processors) and 8 for computers that have 8-kilobyte-sized
memory pages (ia64 processors). (The operating system might not write the log contents to a crash dump file if
a large number of pages is specified.) Use the AddService directive and the AddReg directive to set this value in
your INF file, as follows:

[xxx.NT.Services]
AddService = yyy, 2, zzz.AddService

[zzz.AddService]
DisplayName = %aaa\bbb%
ServiceType = 1
StartType = 3
ErrorControl = 1
ServiceBinary = %12%\ddd.SYS
AddReg = eee.AddReg

[eee.AddReg]
HKR, Parameters\Wdf, LogPages, 0x00010001, 3 ; KMDF IFR size

TrackHandles
REG_MULTI_SZ
If set to a list of one or more type names of framework object handles, and if VerifierOn is set, the framework
tracks references to all object handles that match the specified handle types. For example, if the handle type list
consists of the "WDFREQUEST WDFQUEUE" string, the framework tracks references to all request objects and
queue objects. If the list contains an asterisk ("*"), the framework tracks all object handles.

VerboseOn
REG_DWORD
If set to a nonzero value, the framework's event logger records additional information that can help you debug
your driver, such as entries into or exits from internal code paths. You should set this value only while you are
developing your driver. See the code example in VerifierOn .

VerifierAllocateFailCount
REG_DWORD
If set to a value n, and if VerifierOn is set, the framework fails every attempt to allocate memory for the driver's
objects after the nth allocation. This failure helps you test your driver's handling of low-memory conditions. For
example, if you set VerifierAllocateFailCount to 2, every memory allocation after the second allocation will
fail. The default value for VerifierAllocateFailCount is 0xffffffff. After setting VerifierAllocateFailCount , you
can turn it off by setting it to (DWORD) -1 or removing the value altogether.
Note that the verifier counts both the allocations that your driver requests and the allocations that the
framework requests on behalf of your driver. Also note that the number of allocations that might occur for your
driver can change from one release of the framework to the next.

VerifierOn
REG_DWORD
Set to a nonzero value to enable KMDF Verifier, which extensively validates a driver's state and function
parameters. You should set VerifierOn and DbgBreakOnError when you are developing your driver. Use the
AddService directive and the AddReg directive to set these values in the Services section of the INF file, for
example:

[xxx_Inst.NT.Services]
AddService = xxx,%SPSVCINST_ASSOCSERVICE%,xxx_Service_Inst

[xxx_Service_Inst]
ServiceType = %SERVICE_KERNEL_DRIVER%
StartType = %SERVICE_BOOT_START%
ErrorControl = %SERVICE_ERROR_NORMAL%
LoadOrderGroup = "Base"
ServiceBinary = %12%\xxx.sys
AddReg = KMDFVerifierAddReg

[KMDFVerifierAddReg]
HKR, Parameters\Wdf,VerifierOn,0x00010001,1
HKR, Parameters\Wdf,VerboseOn,0x00010001,1
HKR, Parameters\Wdf,DbgBreakOnError,0x00010001,1

VerifyDownLevel
REG_DWORD, framework versions 1.9 and later
If set to a nonzero value, and if the driver was built with a version of the framework that is older than the current
version, the framework's verifier includes tests that were added after the driver was built. If this value does not
exist or is set to zero, the framework's verifier includes only the tests that existed when the driver was built.
For example, if your driver was built with version 1.7 of the framework, and if version 1.9 of the framework is
installed on the computer, setting VerifyDownLevel to nonzero causes the verifier to include tests that were
added to version 1.9 of the verifier when your driver runs.

VerifyOn
REG_DWORD
Set to a nonzero value to enable the WDFVERIFY macro that is defined in Wdfassert.h, or set to zero to disable
the macro. If the VerifierOn value is set, VerifyOn is implicitly set to nonzero.
Summary of Debugger Extensions in Wdfkd.dll
2/5/2021 • 4 minutes to read • Edit Online

The Windows Driver Kit (WDK) includes a debugger extension library, named Wdfkd.dll. This library contains
debugger extension commands that you can use to debug both Kernel-Mode Driver Framework (KMDF) and
User-Mode Driver Framework (UMDF) drivers starting with version 2.
For a complete description of each command, see Windows Driver Framework Extensions (Wdfkd.dll) . For
more information about all available debugger extension libraries, see the documentation that is supplied with
the Windows Debugging package.
You can find a video series that demonstrates how to debug a KMDF driver at Videos: Debugging KMDF Drivers.
To debug a driver that uses UMDF version 1.11 or earlier, you must instead use the Wudfext.dll debugger
extension library. For more info, see User-Mode Driver Framework Extensions (Wudfext.dll).
The extension commands that the Wdfkd.dll extension library provides include:

EXT EN SIO N DESC RIP T IO N F RA M EW O RK S

!wdfkd.wdfhelp Displays this list of debugger


extensions.

!wdfkd.wdfchildlist Displays a child list's state and KMDF


information about all of the device
identification descriptions that are
in the child list.

!wdfkd.wdfcollection Displays the objects that are KMDF


contained in a collection.
UMDF 2

!wdfkd.wdfcommonbuffer Displays information about a KMDF


common buffer object.
UMDF 2

!wdfkd.wdfcrashdump Displays the framework's event log KMDF


records, if available, from a small
memory dump. The framework's
event log records are available if
ForceLogsInMiniDump is set in the
registry, or if the framework can
determine that your driver caused
the bug check.

!wdfkd.wdfdevext Displays the WDFDEVICE-typed KMDF


object handle that is associated
with the DeviceExtension UMDF 1
member of a Microsoft Windows UMDF 2
Driver Model (WDM)
DEVICE_OBJECT structure.
EXT EN SIO N DESC RIP T IO N F RA M EW O RK S

!wdfkd.wdfdevice Displays information that is KMDF


associated with a WDFDEVICE-
typed handle. UMDF 2

!wdfkd.wdfdeviceinterrupts Displays all the interrupt objects KMDF


for a specified device handle
UMDF 2

!wdfkd.wdfdevicequeues Displays information about all of KMDF


the queue objects that belong to a
specified device. UMDF 2

!wdfkd.wdfdmaenabler Displays information about a DMA KMDF


enabler object, along with its
associated DMA transaction
objects and common buffer
objects.

!wdfkd.wdfdmaenablers Displays a summary of all DMA KMDF


enabler objects, DMA transaction
objects, and common buffer
objects that are associated with a
specified device object.

!wdfkd.wdfdmatransaction Displays information about a WDF KMDF


direct memory access (DMA)
transaction object.

!wdfkd.wdfdriverinfo Displays information about a KMDF


framework-based driver, such as its
library version and hierarchy of UMDF 2
object handles.

!wdfkd.wdfextendwatchdog Extends the time-out period (from KMDF


10 minutes to 24 hours) of the
framework's watchdog timer
during power transitions.

!wdfkd.wdffindobjects Finds and displays framework KMDF


objects.
UMDF 2

!wdfkd.wdffor wardprogress Displays information about the KMDF


guaranteed forward progress
capabilities of an I/O queue.

!wdfkd.wdfgetdriver Displays the driver name. KMDF


UMDF 2
EXT EN SIO N DESC RIP T IO N F RA M EW O RK S

!wdfkd.wdfhandle Displays information about a KMDF


framework object handle.
UMDF 2

!wdfkd.wdfinterrupt Displays information about a KMDF


framework interrupt object handle.
UMDF 2

!wdfkd.wdfiotarget Displays information about a KMDF


WDFIOTARGET-typed object
handle. UMDF 2

!wdfkd.wdfldr Displays information about all of KMDF


the drivers that are using the
framework library. UMDF 1
UMDF 2

!wdfkd.wdflogdump Displays the framework's event log KMDF


records, if available, from a
complete memory dump, a kernel UMDF 2
memory dump, or a live kernel-
mode target.

!wdfkd.wdflogsave Saves the framework's event log KMDF


records in an event trace log (.etl)
file that you can view by using UMDF 2
TraceView.

!wdfkd.wdfmemor y Displays a memory object's buffer KMDF


address and size.
UMDF 2

!wdfkd.wdfobject Displays information about a KMDF


framework object.
UMDF 2

!wdfkd.wdfopenhandles Displays information about all the KMDF


handles that are open on the
specified WDF device. UMDF 2

!wdfkd.wdfpoolusage Displays a driver's memory pool KMDF


usage.
UMDF 2

!wdfkd.wdfqueue Displays information about a KMDF


WDFQUEUE-typed object handle.
UMDF 2
EXT EN SIO N DESC RIP T IO N F RA M EW O RK S

!wdfkd.wdfrequest Displays information about a KMDF


WDFREQUEST-typed object
handle. UMDF 2

!wdfkd.wdfsearchpath Sets the search path for locating KMDF


the framework log's format files.
UMDF 2

!wdfkd.wdfsettraceprefix Sets a prefix string for tracing KMDF


messages in the framework's event
log. UMDF 2

!wdfkd.wdfsetdriver Sets a driver name that is used as KMDF


a default name for other
commands that require a driver UMDF 2
name.

!wdfkd.wdfspinlock Displays information about a KMDF


framework spin-lock object. This
information includes the spin lock's UMDF 2
acquisition history and the length
of time that the lock was held.

!wdfkd.wdftagtracker Displays tag information (including KMDF


the tag value, line, file, and time)
for a specified object tag. UMDF 2

!wdfkd.wdftmffile Specifies the trace message format KMDF


(.tmf) files that the !wdflogdump
extension will use to display event UMDF 2
log records.

!wdfkd.wdftracepr tdebug Turns on the TracePrt diagnostic KMDF


mode.
UMDF 2

!wdfkd.wdfumdevstack Displays detailed information UMDF 2


about a UMDF device stack in the
implicit process.

!wdfkd.wdfumdevstacks Displays information about all UMDF 2


UMDF device stacks in the implicit
process.

!wdfkd.wdfumdownirp Displays the kernel-mode I/O UMDF 2


request packet (IRP) that is
associated with a specified user-
mode IRP.
EXT EN SIO N DESC RIP T IO N F RA M EW O RK S

!wdfkd.wdfumfile Displays information about a UMDF 2


UMDF intra-stack file.

!wdfkd.wdfumirp Displays information about a user- UMDF 2


mode I/O request packet (UM
IRP).

!wdfkd.wdfumirps Displays the list of pending user- UMDF 2


mode I/O request packets (UM
IRPs) in the implicit process.

!wdfkd.wdfusbdevice Displays information about a KMDF


WDFUSBDEVICE-typed object
handle. UMDF 2

!wdfkd.wdfusbinterface Displays information about a KMDF


WDFUSBINTERFACE-typed object
handle. UMDF 2

!wdfkd.wdfusbpipe Displays information about a KMDF


WDFUSBPIPE-typed object handle.
UMDF 2

!wdfkd.wdfwmi Displays a device's Windows KMDF


Management Instrumentation
(WMI) information.
Troubleshooting UMDF 2.0 Driver Crashes
2/5/2021 • 2 minutes to read • Edit Online

Starting in User-Mode Driver Framework (UMDF) version 2, you can use a subset of the debugger extension
commands implemented in Wdfkd.dll to debug a UMDF driver. This topic describes which commands you might
start with to troubleshoot UMDF driver problems.

Determining Why a UMDF 2.0 Driver Crashed


If the driver host process is terminated, your driver might have a problem in a callback that results in the host
timeout threshold being exceeded. In this case, the reflector terminates the driver host process.
To investigate, first set up a kernel-mode debugging session as described in How to Enable Debugging of a
UMDF Driver. We strongly recommend doing all development and testing of your UMDF driver with a kernel
debugger attached to the test system and enabling Application Verifier (AppVerif.exe) on WUDFHost.exe. Use the
following command, attach a kernel debugger and then reboot.

AppVerif –enable Heaps Exceptions Handles Locks Memory TLS Leak –for WudfHost.exe

If HostFailKdDebugBreak is set (this should be enabled by default starting Windows 8), the reflector
breaks into the kernel-mode debugger when the timeout threshold is exceeded. In the debugger output,
you will see several suggestions on how to begin, including links you can click on. For example:

**** Problem detected in UMDF driver "WUDFOsrUsbFx2". !process 0xFFFFE0000495B080 0x1f, !devstack
0xFFFFE000032BFA10, Problem code 3 ****
**** Dump UMDF driver image name and stack: !wdfkd.wdfumdevstack 0x000000BEBB49AE20
**** Dump UM Irps for this stack: !wdfkd.wdfumirps 0x000000BEBB49AE20
**** Dump UMDF trace log: !wmitrace.logdump WUDFTrace
**** Helpful UMDF debugger extension commands: !wdfkd.wdfhelp
**** Note that driver host process may get terminated if you go past this break, making it difficult
to debug the problem!

Use !analyze to display information about the failure, and additional UMDF extension commands you
can try.
Use !process 0 0x1f wudfhost.exe to list all Wudfhost.exe driver host processes, including thread stack
information.
You can also use !wdfkd.wdfumtriage and !wdfkd.wdfldr to display all drivers that are currently bound
to WDF. When you click on the image name of a UMDF driver, the debugger displays the address of the
hosting process. You can then click on the process address to display information specific to that process.
If necessary, use .process /r /p Process to switch process context to that of the Wudfhost process that
is hosting your driver. Use .cache forcedecodeuser and lmu to verify that your driver is hosted in the
current process.
Examine thread call stacks (!thread Address ) to determine if a driver callback timed out. Look at the tick
count for the threads. In Windows 8.1, the reflector times out after one minute.
Use !wdfkd.wdfdriverinfo MyDriver.dll 0x10 to display the device tree in verbose form. Then click on
!wdfdevice . This command displays detailed power, power policy, and Plug and Play (PnP) state
information.
Use !wdfkd.wdfumirps to look for pending IRPs.
Use !wdfkd.wdfdevicequeues to check the status of the driver's queues.
In a kernel-mode debugging session, you can use !wmitrace.logdump WudfTrace to display the trace
log.

Displaying the UMDF 2.0 IFR Log


In a kernel-mode debugging session, you can use the !wdfkd.wdflogdump extension command to display the
Windows Driver Frameworks (WDF) In-flight Recorder (IFR) log records, if available.

Finding Memory Dump Files


See Determining Why the Reflector Terminated the Host Process for information on finding user-mode dump
files. See Using WPP Software Tracing in UMDF Drivers for information on how to set the LogMinidumpType
registry value to specify the type of information stored in the minidump file.
Using Inflight Trace Recorder (IFR) in KMDF and
UMDF 2 Drivers
2/5/2021 • 4 minutes to read • Edit Online

Starting in Windows 10, you can build your KMDF or UMDF driver so that it gets additional driver debugging
information through the Windows software trace preprocessing. This feature, called the Inflight Trace Recorder
(IFR), is available starting in KMDF version 1.15 and UMDF version 2.15.
Inflight Trace Recorder is an extension of WPP software tracing. Unlike WPP tracing, the Inflight Trace Recorder
continues to work without an attached trace consumer. The framework writes messages to a circular buffer, and
your driver can also add its own messages. Each driver has its own log, so multiple devices associated with a
driver share a single log.
The logs are stored in non-pageable memory, so they are recoverable after a system crash. In addition, Inflight
Trace Recorder logs are included in minidump files.
How to enable Inflight Trace Recorder and send messages from your driver
1. In Microsoft Visual Studio, do the following:
Open the Property Pages for your driver project. Right-click the driver project in Solution Explorer
and select Proper ties . In the Property Pages for the driver, click Configuration Proper ties , and
then Wpp Tracing . On the General menu, set Run WPP Tracing to Yes .
Navigate to Proper ties->Wpp Tracing->Function and Macro Options and choose Enable
WPP Recorder .
On the same menu, set Scan Configuration Data to the file containing your trace information,
for example Trace.h.
2. In each source file that calls a WPP macro, add an #include directive that identifies a trace message
header (TMH) file. The file name must have a format of <driver-source-file-name>.tmh .
For example, if your driver consists of two source files, called MyDriver1.c and MyDriver2.c, then
MyDriver1.c must contain:
#include "MyDriver1.tmh"
and MyDriver2.c must contain:
#include "MyDriver2.tmh"
When you build your driver in Visual Studio, the WPP preprocessor generates the .tmh files.
3. Define a WPP_CONTROL_GUIDS macro in a header file. This macro defines a GUID and trace flags for
your driver's tracing messages.
The Osrusbfx2 driver sample defines a single control GUID and seven trace flags in the Trace.h header file,
as shown in the following example:
#define WPP_CONTROL_GUIDS \
WPP_DEFINE_CONTROL_GUID(OsrUsbFxTraceGuid, \
(d23a0c5a,d307,4f0e,ae8e,E2A355AD5DAB), \
WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \
WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \
WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \
WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \
WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \
WPP_DEFINE_BIT(DBG_IOCTL) /* bit 5 = 0x00000020 */ \
WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \
WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \
)

In this example:
OsrUsbFxTraceGuid is the friendly name for the {d23a0c5a-d307-4f0e-ae8e-E2A355AD5DAB} GUID.
The trace flags are used to differentiate between trace messages that are generated as the driver
handles different types of I/O requests.
4. Your driver (both KMDF and UMDF 2) must call WPP_INIT_TRACING for Kernel-Mode Drivers with
the driver object and a registry path, typically from DriverEntr y :

WPP_INIT_TRACING( DriverObject, RegistryPath );

To deactivate tracing, both KMDF and UMDF 2 drivers call WPP_CLEANUP for Kernel-Mode Drivers
from EvtCleanupCallback or EvtDriverUnload:

WPP_CLEANUP( WdfDriverWdmGetDriverObject( Driver ));

The WPP_CLEANUP macro takes a parameter of type PDRIVER_OBJECT, so if your driver's DriverEntr y
fails, you can skip calling WdfDriverWdmGetDriverObject and instead call WPP_CLEANUP with a
pointer to the WDM driver object.
Starting in UMDF version 2.15, UMDF drivers use the kernel-mode signatures of these macros for
initializing and cleaning up tracing. This means that the calls look identical for KMDF and UMDF.
5. Use the DoTraceMessage macro, or a customized version of the macro, in your driver to create trace
messages.
The following example shows how the Osrusbfx2 driver uses its TraceEvents function in a portion of the
code devoted to handling read requests:

if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) {


TraceEvents(TRACE_LEVEL_ERROR,
DBG_READ,
"Transfer exceeds %d\n",
TEST_BOARD_TRANSFER_BUFFER_SIZE);

status = STATUS_INVALID_PARAMETER;
}

The call to TraceEvents generates a trace message if the trace controller enables the
TRACE_LEVEL_ERROR level and the DBG_READ trace flag. The message includes the value of the
driver-defined constant TEST_BOARD_TRANSFER_BUFFER_SIZE .
6. To change the size of the circular buffer that the driver log uses, modify the LogPages registry value in
the following registry location:
For UMDF:
SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Ser vices\
<YourDriver>\Parameters\Wdf
For KMDF:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Ser vices\<YourDriver>\Parameters\Wdf
This are values of type REG_DWORD that contain the size of the log buffer allocated, in pages. Valid
values are between 0x1 and 0x10.
For a KMDF driver
1. Load the RCDRKD commands by typing .load rcdrkd.dll in the debugger.
2. Use the !wdfkd.wdfldr extension to display information about the driver that are currently dynamically
bound to Windows Driver Frameworks (WDF).
3. Use !rcdrkd.rcdrlogdump and !rcdrkd.rcdrcrashdump to view messages that the driver provides.
4. Use !wdfkd.wdflogdump or !wdfkd.wdfcrashdump to see messages that the framework provides.
Live debugging of a UMDF driver
1. Use the !wdfkd.wdfldr extension to display information about the driver that are currently dynamically
bound to WDF. Find your user-mode driver. Enter the associated host process.
2. Type !wdfkd.wdflogdump <YourDriverName.dll> <Flag> , where <Flag> is:
0x1 – Merged framework and driver logs
0x2 – Driver logs
0x3 – Framework logs
If there is no driver log for the specified driver, the extension displays only the framework log.
Viewing Inflight Trace Recorder logs after a UMDF driver crash
1. From WinDbg, select File->Open Crash Dump , and specify the minidump file you would like to debug.
2. Type !wdfkd.wdfcrashdump <YourDriverName.dll> <process ID of driver host> <Option> ,
where <Option> is:
0x1 – Merged framework and driver logs
0x2 – Driver logs
0x3 – Framework logs
If you don't specify a driver, !wdfcrashdump displays information for all drivers. If you don't specify a
host process, and there is only one, the extension uses the single host process. If you don't specify a host
process and there is more than one, the extension lists the active host processes.
If the log information stored in the minidump does not match the entered name, the minidump does not
contain the driver's logs.
For more information about adding tracing messages to your driver, see Adding WPP Macros to a Driver.

Related topics
How to Enable Debugging of a UMDF Driver
RCDRKD Extensions
Using the Framework's Event Logger
Using WPP Software Tracing in UMDF Drivers
Using the Windows Performance Toolkit (WPT) with
WDF
2/5/2021 • 5 minutes to read • Edit Online

Starting in Windows 10, you can use the Windows Performance Toolkit (WPT) to view performance data for a
given Kernel-Mode Driver Framework (KMDF) or User-Mode Driver Framework (UMDF) 2 driver.

How can the Windows Driver Frameworks (WDF) extensions for WPT
help?
You can use WPT to obtain performance insights or troubleshoot performance issues. For example:
Examine the driver’s WDF I/O request completion rate, CPU utilization, and time spent in PnP and power
callbacks.
Compare a UMDF 2 driver against a similar KMDF driver and determine if UMDF meets your performance
requirements.
Identify performance glitches in the WDF I/O path.
Determine which instance of a given callback is taking a long time. Then examine sampled CPU usage to
understand why.
Check if the device is making power transitions in and out of the D0 power state too frequently.

Getting started
The WPT is part of the Windows Assessment and Deployment Kit (ADK). You can install the ADK from the
Windows hardware tools site.
The WPT consists of two separate tools: Windows Performance Recorder and Windows Performance Analyzer
(WPA). In this topic, we use WPR to record a trace, and then WPA to view the trace in a configurable GUI format.
To learn how to use the Windows Performance Toolkit to measure the performance of a WDF driver, either watch
the following video, or read the steps below the video. The video and the steps cover the same procedure.

Recording and viewing an event log for a WDF driver


1. Install your driver, if it's not already installed.
2. In an elevated command prompt, enter the following command.
WdfPerfEnhancedVerifier.cmd <ServiceName><UMDF or KMDF>
Note WdfPerfEnhancedVerifier.cmd should be copied from the location you installed WPT. If you installed
WPT on a development machine, you'll need to copy the script from the WPT installation directory to the
target machine.
This script sets registry entries for the specified driver so that the framework logs the events required to enable
performance analysis when the ETW provider is enabled in step 4.
3. Reboot the computer.
4. In an elevated command prompt, enter the following command.
Wpr.exe -Star t WdfTraceLoggingProvider -filemode
This command enables the ETW provider for WDF. The computer starts recording a trace.
Note As in step 2, Wpr.exe should be copied from the location you installed WPT. If you installed WPT on
a development machine, copy these files from the WPT installation directory to the target machine.
On Windows 10 for desktop editions (Home, Pro, Enterprise, and Education), you can also start the trace
with Wprui.exe, which provides a GUI for recording traces. Under more options, expand Resource
Analysis and select WDF Driver Activity .
5. Exercise your scenario of interest.
6. Stop the ETW trace session: Wpr.exe -Stop MyPerfTrace.etl
7. Open the event trace log in the Windows Performance Analyzer viewer:
Wpa.exe MyPerfTrace.etl
To capture another trace for the same driver, use Wpr.exe to start and stop a new trace. To capture a trace for a
different driver, first rerun WdfPerfEnhancedVerifier.cmd for the new driver.

Analyzing the trace


To start analyzing the driver's performance, find the Graph Explorer on the left, open the Computation
category, and then drag the UMDF or KMDF graph to the main work area, under the Analysis tab. This
screenshot shows the Graph Explorer pane:

There is a dedicated table for UMDF and another for KMDF drivers.

UMDF I/O Request Graph and summary table


WPT can display WDF I/O request completion throughput in two ways:
Number of I/O requests completing per second
Time duration of each I/O request (formatted as a Gantt chart)
The following screenshot shows sample summary graphs and tables for CPU and UMDF I/O request
performance. In the UMDF I/O Request Completion Rate graph, the number of requests per second is shown on
the y axis.

In the summary table, most columns are self-explanatory, but there are a couple things to note. The WdfDevice
column contains the WDFDEVICE handle associated with the I/O request. The ActivityID contains a unique
identifier for the I/O request. The framework creates this identifier when it delivers an I/O request to the driver. If
an activity identifier is already associated with the corresponding IRP, the framework uses that identifier. For
more information, see Using Activity Identifiers.
Entry time is the trace timestamp when the framework delivered the request to the driver, and exit time is the
timestamp when the driver called WdfRequestComplete or a related method to complete the request.

KMDF I/O Request Graph and summary table


Here's a similar screenshot showing I/O request info for a KMDF driver.
PnP Power callback graph and summary table
WPT can also display the processing time of each PnP and power callback. The following screenshot shows
EvtDeviceD0Entry, EvtDeviceD0Exit and EvtDevicePrepareHardware callback duration for a sample KMDF driver
and a sample UMDF driver.
The WdfDevice column contains the WDFDEVICE handle associated with the callback. The ActivityID contains a
unique identifier for the callback instance.

Which calls are instrumented?


This section describes which events are used to build the graphs and tables shown above.
After you run WdfPerfEnhancedVerifier.cmd for a specific driver, the framework records events in the ETL trace
log when the system calls some of the specified driver's callbacks, and also when the specified driver calls some
framework methods.
To determine when I/O requests start, the framework records events when it calls the following callbacks:
EvtIoDefault
EvtIoRead
EvtIoWrite
EvtIoDeviceControl
EvtIoInternalDeviceControl
The framework also records I/O request start events when the driver calls the following methods:
WdfIoQueueRetrieveNextRequest
WdfIoQueueRetrieveRequestByFileObject
WdfIoQueueRetrieveFoundRequest
To determine when I/O requests complete, the framework tracks when the driver calls:
WdfRequestComplete
WdfRequestCompleteWithInformation
WdfRequestCompleteWithPriorityBoost
Finally, to determine callback duration for PnP/Power callbacks, the framework records when it calls the
following driver-supplied callback routines, and when they finish:
EvtDeviceD0Entry
EvtDeviceD0Exit
EvtDevicePrepareHardware
EvtDeviceReleaseHardware
EvtIoStop

Resources and Troubleshooting


Be sure to reboot after you run the WdfPerfEnhancedVerifier.cmd script.
To determine if your driver is configured to record an event log, use the !WdfKd.wdfdriverinfo kernel
debugger command. If the driver is configured for performance tracing, you will see output like this:

!WdfKd.WdfDriverInfo Echo.sys


----------------------------------

WDF Verifier settings for echo.sys is ON


Enhanced verifier: performance analysis hooking ON
----------------------------------

For development and testing purposes only, enforcement of the driver code signing policy can be
temporarily disabled. For more information, see Installing an Unsigned Driver Package during
Development and Test.

Related topics
Windows Performance Analyzer
Using WPP Software Tracing in KMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

WPP software tracing enables you to add tracing messages that help you debug your driver. Additionally, the
framework's event logger provides hundreds of tracing messages that you can view.
You can view tracing messages by using TraceView or Tracelog. You can also send trace messages to a kernel
debugger.
Adding Tracing Messages to Your Driver
To add tracing messages to your framework-based driver, you must:
Add an #include directive to each of your driver's source files that contains any of the WPP macros. This
directive must identify a trace message header (TMH) file. The file name must have a format of <driver-
source-file-name>.tmh .
For example, if your driver consists of two source files, called MyDriver1.c and MyDriver2.c, then
MyDriver1.c must contain:
#include "MyDriver1.tmh"
and MyDriver2.c must contain:
#include "MyDriver2.tmh"
When you build your driver in Microsoft Visual Studio, the WPP preprocessor generates the .tmh files.
Define a WPP_CONTROL_GUIDS macro in a header file. This macro defines a GUID and trace flags for
your driver's tracing messages.
Include a WPP_INIT_TRACING macro in your driver's DriverEntr y routine . This macro activates
software tracing in your driver.
Include a WPP_CLEANUP macro in your driver's EvtDriverUnload callback function. This macro
deactivates software tracing in your driver.
Use the DoTraceMessage macro, or a customized version of the macro, in your driver to create trace
messages.
Open the Property Pages for your driver project. Right-click the driver project in Solution Explorer and
select Proper ties . In the Property Pages for the driver, click Configuration Proper ties , and then Wpp
Tracing . Under the General menu, set Run WPP Tracing to Yes. Under the File Options menu, you
should also specify the framework's WPP template file, for example:

{km-WdfDefault.tpl}*.tmh

To specify additional WPP trace settings for your driver project in Visual Studio, right-click on the driver
project in Solutions Explorer. Then follow the link to Properties->Configuration Properties->WPP Tracing.
To specify a trace configuration file use the 'Scan Configuration Data' setting. For more than one trace
configuration file add it under the 'Command Line'-> 'Additional Options' as follows

-scan:"$(KMDF_INC_PATH)\$(KMDF_VER_PATH)\wdftraceenums.h"
For more information about adding tracing messages to your driver, see Adding WPP Macros to a Driver.
Sample Drivers That Use WPP Software Tracing
The AMCC5933, NONPNP, KMDF_FX2, PCIDRV, PLX9x5x, and Serial sample drivers use WPP software tracing.
Using WPP Software Tracing in UMDF Drivers
2/5/2021 • 4 minutes to read • Edit Online

WPP software tracing enables you to add tracing messages that help you debug your driver. Additionally, the
framework's event logger provides hundreds of tracing messages that you can view.
You can view tracing messages by using TraceView or Tracelog. You can also send trace messages to a kernel
debugger.
Adding Tracing Messages to Your Driver
To add tracing messages to your framework-based driver, you must:
Add an #include directive to each of your driver's source files that contains any of the WPP macros. This
directive must identify a trace message header (TMH) file. The file name must have a format of <driver-
source-file-name>.tmh.
For example, if your driver consists of two source files, called MyDriver1.c and MyDriver2.c, then
MyDriver1.c must contain:
#include "MyDriver1.tmh"

and MyDriver2.c must contain:


#include "MyDriver2.tmh"

When you build your driver in Microsoft Visual Studio, the WPP preprocessor generates the .tmh files.
Define a WPP_CONTROL_GUIDS macro in a header file. This macro defines a GUID and trace flags for
your driver's tracing messages. (For each of the WDK's UMDF-based sample drivers, the Internal.h header
file includes this macro.)
Include a WPP_INIT_TRACING macro in your driver's DllMain routine. This macro activates software
tracing in your driver. (For each of the WDK's UMDF-based sample drivers, the DllSup.h header file
includes this macro.)
Include a WPP_CLEANUP macro in your driver's DllMain routine. This macro deactivates software tracing
in your driver. (For each of the WDK's UMDF-based sample drivers, the DllSup.h header file includes this
macro.)
Use the DoTraceMessage macro, or a customized version of the macro, in your driver to create trace
messages. (For each of the WDK's UMDF-based sample drivers, the Internal.h header file includes a
customized macro.)
Open the Property Pages for your driver project. Right-click the driver project in Solution Explorer and
select Proper ties . In the Property Pages for the driver, click Configuration Proper ties , and then Wpp .
Under the General menu, set Run WPP Tracing to Yes. Under the File Options menu, you should also
specify the framework's WPP template file, for example:

{km-WdfDefault.tpl}*.tmh

For more information about adding tracing messages to your driver, see Adding WPP Macros to a Driver.
Sample Drivers That Use WPP Software Tracing
All of the UMDF-based sample drivers in the WDK provide DllSup.h, Internal.h, and Sources files that enable
WPP software tracing. Most of these sample drivers also use a customized macro to create trace messages.
Viewing Your Driver's Trace Messages
If you have added trace messages to your driver, the driver is a trace provider. You can use a trace controller,
such as Tracelog, to control a trace session and create a trace log. You can use a trace consumer, such as
Tracefmt, to view the messages.
For more information about how to use the software tracing tools, see Survey of Software Tracing Tools.
Viewing the UMDF Trace Log
The UMDF log file is %windir%\system32\LogFiles\WUDF\WUDFTrace.etl.
Note Starting in UMDF 2.15, the log directory is %ProgramData%\Microsoft\WDF.
You can view the UMDF log file by using either TraceView or Tracelog. Both tools require trace message format
(TMF) files that format the trace log's messages. The TMF files are available in the WDK, under the \tools\tracing
subdirectory. (In TraceView, UMDF appears as a named provider with the name of "UMDF-Framework Trace" or
"Framework Trace", depending on the UMDF version.)
WDF Verifier enables you to send trace messages to both the UMDF trace log and your kernel debugger. (You
should not send trace messages to your kernel debugger by using the -kd option in Tracelog, because Tracelog
can disrupt trace logging within UMDF.)
You can also use the !wmitrace debugger extension to view the trace messages in the debugger:
1. In WinDbg, attach to the instance of WUDFHost that hosts the driver. For more information, see How to
Enable Debugging of a UMDF Driver.
2. If your driver uses version 1.11 or later, and you are using the kernel debugger from Windows 8 or later,
you can skip this step. If your driver uses a version of UMDF earlier than 1.11, use !wmitrace.tmffile or
!wmitrace.searchpath to specify a platform-specific trace message format (.tmf) file, or a path to a .tmf
file. The .tmf files are located in platform-specific subdirectories in the WDK.
3. Use the !wmitrace.logdump command to display the contents of the trace buffers:

!wmitrace.logdump WudfTrace

Controlling Trace Messages


You can control UMDF trace messages with the user interface that WDF Verifier provides, or by modifying
registry values. You should use the WDF Verifier interface when possible, because the registry values might
change in future versions of UMDF. In addition, you should not access these values within INF files or your
driver's code.
Currently, you can modify the following registry values, which are located under the
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF registry key:
The LogEnable value controls whether UMDF creates a trace log for your driver. If this value is set to 1,
UMDF creates a trace log.
The LogLevel value controls the amount of information that UMDF trace messages contain. The default
value for LogLevel is 3, which causes UMDF trace messages to contain error and warning messages. Set
this value to 7 to include error and warning messages, plus non-error informational messages. Set it to
15 to include all of the trace information that UMDF is capable of providing.
The LogKd value controls whether UMDF sends trace messages to your kernel debugger. If LogKd is set
to 1, UMDF sends its trace messages to your kernel debugger.
The LogFlushPeriodSeconds value specifies how often, in seconds, trace messages are written to the
trace log.
The LogMinidumpType value contains flags that specify the type of information that a mini-dump file, if
produced, will contain. For more information about these flags, see the MINIDUMP_TYPE enumeration.
You might find additional registry values under the HKLM\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\WUDF registry key. You should not modify those values.
Video: Debugging your driver with WDF source
code
2/5/2021 • 3 minutes to read • Edit Online

This topic contains a video tutorial that shows how to debug your Windows Driver Frameworks (WDF) driver
with full access to the WDF source code. Following the video is the step-by-step procedure followed in the video,
for convenient reference.

WDF source debugging allows you to step freely into framework code without needing to download WDF
source code. The debugger automatically downloads the correct version of WDF from GitHub.
For example, if you are using WinDbg to debug your WDF driver on a Windows 10 machine, and the debugger
is broken-in with framework code in the call stack, you can double-click on the WDF frame in the Call Stack view,
and WinDbg automatically downloads and opens the relevant WDF source file at the matching line. You can then
step through the code and set breakpoints.
This feature is available for target systems running public releases of Windows 10, Technical Preview build
10041 or later. These builds have private source indexed symbol files for KMDF (Wdf01000.sys) and UMDF
(Wudfx02000.dll) available on the Microsoft Public Symbol Server. Source-level debugging of WDF code is only
available in WinDbg, and not in the Visual Studio debugger.

Quick Start
Start a WinDbg kernel debug session to the target machine, break in, and follow these steps:
1. Set the default symbol path using .symfix. This sets the symbol path to point to the symbol server at
https://msdl.microsoft.com/download/symbols.
kd> .symfix

2. Set the default source path using .srcfix. This sets the source path to srv*, which tells the debugger to
retrieve source files from locations specified in the target modules' symbol files.

kd> .srcfix
Source search path is: SRV*

3. Reload symbols using .reload, and confirm that the Wdf01000.sys symbols (or Wudfx02000.dll for
UMDF) are source-indexed. As shown in the output of !lmi below, the Wdf01000.sys PDB is source
indexed. If yours is not, see the WinDbg Setup section below.

kd> .reload
...

kd> !lmi wdf01000.sys


Loaded Module Info: [wdf01000.sys]
...
Load Report: private symbols & lines, source indexed
C:\...\Wdf01000.pdb\...\Wdf01000.pdb

4. Now you're all set! An easy way to step through WDF source code is to set a break point on the
framework's IRP dispatch routine, and then step through the rest of the code. Since a Windows system
has many inbox KMDF drivers, WDF is always loaded and running, so this breakpoint will be hit right
away (without needing to load your own driver).

kd> bp Wdf01000!FxDevice::DispatchWithLock
kd> g
Breakpoint 0 hit
Wdf01000!FxDevice::DispatchWithLock:
87131670 8bff mov edi,edi

If this does not work, check out the WinDbg Setup steps below.

WinDbg Setup
If the above example did not work as expected, you may need to perform one or more of the instructions below.
Enable Source Mode Debugging
Make sure debugging in Source Mode is enabled. Open the Debug menu and confirm that Source Mode is
checked.
Clear Stale Symbols Cache
If you previously debugged WDF drivers for the same Windows target, then you may be using the locally cached
WDF symbols that were not source indexed. You can check this with the !lmi command:

kd> !lmi Wdf01000.sys


Loaded Module Info: [wdf01000.sys]
...
Load Report: private symbols & lines, not source indexed
C:\...\Wdf01000.pdb\...\Wdf01000.pdb

According to the Load Report above, Wdf01000.pdb is not source indexed. This means your local WinDbg
symbols cache is stale. To fix this, unload the PDB from WinDbg, clear the local cache (your path may differ
based on the !lmi output above), and reload the PDB:

kd> .reload /u Wdf01000.sys

CMD> del
C:\...\Wdf01000.pdb\...\Wdf01000.pdb

kd> .reload Wdf01000.sys

Now run !lmi to check again: the PDB should appear as source indexed and a source code window should pop
up.

kd> !lmi Wdf01000.sys


Loaded Module Info: [wdf01000.sys]
...
Load Report: private symbols & lines, source indexed
C:\...\Wdf01000.pdb\...\Wdf01000.pdb

You can use WDF source-level debugging not just for live debugging and analyzing crash dumps, but also for
learning more about the framework internals by setting breakpoints on core functions like the IRP dispatcher
and exploring the subsequent code paths.
Video: Accessing driver IFR logs without a
debugger
2/5/2021 • 2 minutes to read • Edit Online

This topic contains a video tutorial that shows how a driver can access IFR logs without a debugger attached.
To learn how to configure your driver to use Inflight Recorder (IFR), see Inflight Trace Recorder for logging traces.
You can find the GetIfr.ps1 script described in the video in the WDF GitHub repository.
Videos: Debugging KMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

This topic contains links to a three part video series by Kumar Rajeev that demonstrates how to debug Kernel-
Mode Driver Framework (KMDF) drivers.
After watching the videos, you'll be familiar with the KMDF debugger extensions and know how to use them in
basic debugging scenarios.

Prerequisites
This series of demonstrations is given at an advanced technical level. To get the most from this content you
should have working knowledge of the Windows kernel debugger (windbg.exe) and should be familiar with
creating and using code with KMDF. Because each session builds on the previous one, we recommend that you
view these demonstrations in the order listed.

Video Series: Debugging Kernel-Mode Driver Framework Drivers


Session 1: Dumping the KMDF Log (10 minutes) [media file]
The KMDF log is an important feature that helps quickly identify the root cause of a problem. This session
shows you how to dump the KMDF log in the kernel debugger. It also provides information on how to
change the size and verbosity of the log, and gives some tips on scanning the log.
Session 2: Getting Information about a KMDF Driver and Its Objects (15 minutes) [media file]
The KMDF provides several debugger commands that help you explore various types of information
about a driver. This session shows how to dump all the framework objects created by a KMDF driver,
including parent-child hierarchy, verifier state, and device hierarchy. These commands are usually the
starting point for a deeper investigation.
Session 3: Dumping Device and Queues (15 minutes) [media file]
This session shows you how to get detailed information about a KMDF device object including plug and
play (PnP) and power state, power policy ownership, power configuration, PnP and power callbacks, and
device properties. It also shows you how to get information on open handles, explore all the I/O queues
configured for the device, and dump individual requests.
Videos: Debugging UMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

This topic contains a series of videos by Abhishek Ram that demonstrate how to debug User-Mode Driver
Framework (UMDF) drivers.
After watching the videos, you'll be familiar with the UMDF debugger extensions and know how to use them in
basic debugging scenarios.
While the videos demonstrate debugging a UMDF version 1 driver on older versions of Windows, you can still
use the same techniques with a UMDF version 2 driver running on current versions of Windows.
Note This video describes the debugger extension commands in Wudfext.dll, which you can use to debug
UMDF version 1 drivers only. To debug UMDF drivers starting in UMDF version 2.0, you must instead use the
Wdfkd.dll debugger extension library. There are equivalents in Wdfkd.dll for all of the extensions in Wudfext.dll.
For more info, see Summary of Debugger Extensions in Wudfext.dll and Summary of Debugger Extensions in
Wdfkd.dll.
For more information about debugging UMDF, see the topics listed in Debugging WDF Drivers.

Prerequisites
To get the most from this content you should have working knowledge of UMDF and the Debugging Tools for
Windows. Because each session builds on the previous one, we recommend that you view these demonstrations
in the order listed.

Basics and setup


Discusses use of the WDK samples and the OSR USB-FX2 Learning Kit.

In this video, you'll learn about UMDF debugging basics, including preparing your test machine, using the
Devcon tool to install the UMDF Echo sample driver, using WdfVerifier to identify the host process hosting a
given UMDF driver, and using WdfVerifier to attach the host process to the debugger in time to debug
initialization code. This video also shows how you can list running host processes in Task Manager, and view
running drivers in Device Manager.

Examining the object hierarchy with debugger extensions


In this part, you'll learn how to start debugging a UMDF driver. The video describes how to set up the OSR USB-
FX2 driver sample and application sample so that three instances of the app send read, write, and device I/O
control requests to the driver. You'll see how the requests flow first to the reflector, and then to the user mode
driver host process. This video introduces the WDF object hierarchy for the FX2 driver sample, and discusses
how to use the following UMDF debugger extensions to traverse the UMDF object hierarchy:
!wudfext.umdevstacks
!wudfext.wudfdriverinfo
!wudfext.wudfdevice
!wudfext.wudfdevicequeues
For UMDF 2, see Summary of Debugger Extensions in Wdfkd.dll, for example !wdfkd.wdfumdevstacks .

Accessing framework USB objects


Here, you'll learn how to examine the driver's framework USB objects. To do so, you'll navigate through the WDF
object hiearchy to reach the USB pipe objects, USB interface objects, and USB I/O target objects.

I/O requests and queues


In this video, you'll use the debugger to examine the driver's framework I/O request objects and framework
queue objects.

File objects and callback objects


In this part, you'll learn how to examine framework file objects as well as the driver's callback objects.

Tracking I/O requests sent by a UMDF driver


Here, you'll learn how to use the App Verifier tool to help you debug. You'll also learn how to debug driver
initialization code, and how to track requests sent by a UMDF driver to the kernel stack below.

Driver does not complete an I/O request


In the final video, you'll investigate a case when a UMDF driver does not complete a request it received, and
you'll learn about the framework's object tracking and reference tracking capabilities.
Introduction to DMA in Windows Driver Framework
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


On Windows 7 and earlier, Kernel-Mode Driver Framework (KMDF) supports only bus-master direct memory
access (DMA) devices. Such devices contain their own DMA controllers.
On System on a Chip (SoC)–based platforms running Windows 8 and later, the framework also supports
system-mode DMA, in which multiple devices share a single multichannel DMA controller.
The framework's DMA support consists of:
A set of framework DMA objects and methods that drivers use to convert I/O requests into DMA
operations.
A set of driver-supplied event callback functions that configure the device's DMA behavior as different
events occur.
The framework supports both single packet and scatter/gather DMA transfers. It also supports the use of
common buffers.
On SoC-based platforms running Windows 8 and later, the framework supports single-packet system-mode
DMA transfers. For more information, see Supporting System-Mode DMA.
The framework does not support system-mode DMA transfers on PC-based platforms.

Related topics
Enabling DMA Remapping for device drivers
Framework DMA Objects
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


To handle bus-master and system-mode DMA operations in a framework-based driver, the framework provides
three objects:
DMA enabler object
The framework's DMA enabler object enables a driver to use the framework's DMA support for a particular
device. The driver must create a DMA enabler object for each of its devices that supports DMA operations.
DMA transaction object
The framework's DMA transaction object represents a single DMA I/O operation. A framework-based driver
typically creates a DMA transaction object for each I/O request that it receives, if the device uses DMA to
perform the requested operation.
Common buffer object
The framework's common buffer object represents an area of computer memory that is mapped for
simultaneous access by both the driver and a device. Some drivers use common buffers when they set up I/O
operations for DMA devices.
For information about the interfaces that these objects export, see:
Framework DMA Object Reference
Framework Common Buffer Object Reference
DMA Transactions and DMA Transfers
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


To understand how the framework handles bus-master and system-mode DMA operations, you must know the
following two terms:
DMA transaction
A DMA transaction is a complete I/O operation, such as a single read or write request from an application.
DMA transfer
A DMA transfer is a single hardware operation that transfers data from computer memory to a device or from
the device to computer memory.
A single DMA transaction always consists of at least one DMA transfer, but a transaction can consist of many
transfers.
When a framework-based driver receives an I/O request, the driver typically creates a single DMA transaction
object to represent the request. When the framework begins servicing the transaction, it determines if the device
can handle the entire transaction in a single transfer. If the transaction is too large, the framework breaks the
transaction into multiple transfers.
Sample Drivers That Use Framework DMA
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


The AMCC5933, PLX9x5x, and PCIDRV sample drivers use the framework's DMA capabilities.
Handling I/O Requests in a KMDF Driver for a Bus-
Master DMA Device
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


This topics in this section describe how a KMDF driver for a bus-master DMA device processes an I/O request. If
you are writing a KMDF driver that implements system-mode DMA, see Supporting System-Mode DMA.
Handling I/O requests in a KMDF driver for a bus-master DMA device requires code in several of the driver’s
event callback functions, as shown in the following figure:

As shown above, DMA-related processing takes place in four phases:


1. Your driver's EvtDriverDeviceAdd or EvtDevicePrepareHardware callback function must enable DMA
transactions for the device, so that your driver can use the framework's DMA capabilities. The same
callback function must also create a common buffer if your device and driver require access to a shared
memory buffer.
2. When your driver receives an I/O request that requires the device to perform a DMA operation, one of
the driver's request handlers must create and initialize a new DMA transaction. (Note that if your driver
reuses DMA transaction objects, your driver's EvtDriverDeviceAdd callback function can create the
transaction objects.) Then, the request handler must initiate the DMA transaction so that the framework
can begin breaking the transaction into smaller DMA transfers, if necessary, and call the driver's
EvtProgramDma callback function.
3. Your driver's EvtProgramDma callback function programs the DMA hardware for a single DMA transfer
and enables device interrupts.
4. When the device interrupts, the framework calls your driver's EvtInterruptIsr callback function, which
saves volatile device information and schedules execution of the driver's EvtInterruptDpc callback
function.
Your driver's EvtInterruptDpc callback function completes each DMA transfer after the hardware finishes
processing it. After a DMA transaction's final transfer is complete, the EvtInterruptDpc callback function
completes the DMA transaction.
Your driver might reuse its DMA transaction objects to ensure that they can operate when memory resources
are low.
Your driver can provide a set of callback functions that handle DMA-specific power management operations.
Some drivers use common buffers that both a device and the driver can access.
Enabling DMA Transactions
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


If your framework-based driver handles I/O operations for DMA devices, your driver must enable the
framework's DMA features for each DMA device. To enable these features, your driver's EvtDriverDeviceAdd or
EvtDevicePrepareHardware callback function must:
1. Call WdfDeviceSetAlignmentRequirement to specify the device's requirement for buffer alignment.
2. Call WdfDmaEnablerCreate to specify the type of DMA operations (single packet or scatter/gather) and
the maximum transfer size that the device supports. Starting in KMDF version 1.11, the framework
supports system-mode DMA on System on a Chip (SoC)–based systems running on Windows 8 or later
versions of the operating system.
3. Call WdfDmaEnablerSetMaximumScatterGatherElements to specify the maximum number of
elements that the device can support in a scatter/gather list, if the device supports scatter/gather
operations.
The following code example from the PLX9x5x sample illustrates how to enable the framework's DMA features.
This code appears in the Init.c file.

WDF_DMA_ENABLER_CONFIG dmaConfig;

WdfDeviceSetAlignmentRequirement( DevExt->Device, PCI9656_DTE_ALIGNMENT_16 );


WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,
WdfDmaProfileScatterGather64Duplex,
DevExt->MaximumTransferLength );
status = WdfDmaEnablerCreate( DevExt->Device,
&dmaConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&DevExt->DmaEnabler );

If your driver requires common buffers, the driver's EvtDriverDeviceAdd callback function typically sets them up.
For more information about these buffers, see Using Common Buffers.
After a driver has called WdfDmaEnablerCreate , it can call WdfDmaEnablerWdmGetDmaAdapter to
obtain pointers to WDM DMA_ADAPTER structures that the framework creates for the device's input and
output directions. However, most framework-based drivers do not need to access these structures.
Creating and Initializing a DMA Transaction
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


Before your driver can send an I/O request to a DMA device, the driver must:
1. Call WdfDmaTransactionCreate to create a DMA transaction object for the request.
2. Call WdfDmaTransactionInitializeUsingRequest , WdfDmaTransactionInitialize , or
WdfDmaTransactionInitializeUsingOffset to initialize the transaction object.
Typically, your driver creates a DMA transaction because a request handler has received a framework request
object and must pass the request to the hardware. In this case, the driver should call
WdfDmaTransactionInitializeUsingRequest , which accepts a request object handle as input and extracts the
request's address parameters from the request object.
If your driver must create a DMA transaction that is not based on a framework request object that the driver
received, the driver can call either WdfDmaTransactionInitialize or
WdfDmaTransactionInitializeUsingOffset . Both methods accept address parameters that the driver
provides.
All three initialization methods require the address of an EvtProgramDma event callback function as an input
parameter. This callback function programs the device, and the framework calls the callback function each time a
DMA transfer is available.
When your driver calls WdfDmaEnablerCreate to create a DMA enabler object, the driver supplies a
WDF_DMA_ENABLER_CONFIG structure that contains the device's maximum transfer length. The framework
uses this value as the default maximum length for all DMA transfers.
For some types of DMA transactions, you might need to specify a maximum transfer length that is different
from the device's default maximum length. You can use WdfDmaTransactionSetMaximumLength to set a
maximum transfer length for an individual transaction. The framework uses the specified maximum transfer
length only while it processes the specified transaction.
Note that the maximum transfer length is limited by the number of map registers that the operating system
makes available to the DMA enabler object. To determine the maximum transfer length that is available, your
driver can call WdfDmaEnablerGetFragmentLength . If the value that
WdfDmaEnablerGetFragmentLength returns is less than the maximum transfer length that the driver
supplied to WdfDmaEnablerCreate , the framework uses the smaller value.
After your driver creates and initializes a DMA transaction, the driver must start the transaction.
Starting a DMA Transaction
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


After your driver has created and initialized a DMA transaction, the driver can call the
WdfDmaTransactionExecute method to start the transaction. This method builds a scatter/gather list for the
first DMA transfer that is associated with the transaction. Next, the method calls the EvtProgramDma callback
function that the driver registered for the transaction. The callback function programs the DMA hardware to
start the transfer.
Before your driver calls WdfDmaTransactionExecute , the driver must store the DMA transaction handle so
that it can be retrieved later when the driver completes each DMA transfer that is associated with the
transaction. A good place to store the transaction handle is in the context memory of a framework object,
typically the device's framework device object. For more information about using object context memory, see
Framework Object Context Space.
The following code example from the PLX9x5x sample shows how to initialize and then execute a DMA
transaction. This code appears in the Read.c file.
VOID PLxEvtIoRead(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t Length
)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PDEVICE_EXTENSION devExt;
// Get the DevExt from the queue handle
devExt = PLxGetDeviceContext(WdfIoQueueGetDevice(Queue));
do {
// Validate the Length parameter.
if (Length > PCI9656_SRAM_SIZE) {
status = STATUS_INVALID_BUFFER_SIZE;
break;
}
// Initialize the DmaTransaction.
status =
WdfDmaTransactionInitializeUsingRequest(
devExt->ReadDmaTransaction,
Request,
PLxEvtProgramReadDma,
WdfDmaDirectionReadFromDevice
);
if(!NT_SUCCESS(status)) {
. . . //Error-handling code omitted
break;
}
// Execute this DmaTransaction.
status = WdfDmaTransactionExecute( devExt->ReadDmaTransaction,
WDF_NO_CONTEXT);
if(!NT_SUCCESS(status)) {
. . . //Error-handling code omitted
break;
}
// Indicate that the DMA transaction started successfully.
// The DPC routine will complete the request when the DMA
// transaction is complete.
status = STATUS_SUCCESS;
} while (0);
// If there are errors, clean up and complete the request.
if (!NT_SUCCESS(status )) {
WdfDmaTransactionRelease(devExt->ReadDmaTransaction);
WdfRequestComplete(Request, status);
}
return;
}
Programming DMA Hardware
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


This topic describes the functionality that a KMDF driver for a bus-master DMA device typically provides in its
EvtProgramDma event callback function. If your driver uses the framework's DMA support, the driver must
provide this callback. This information also applies to a KMDF driver for a system-mode DMA device that has a
hardware interrupt.
The EvtProgramDma callback function, which is called at IRQL = DISPATCH_LEVEL, programs the device to start
a DMA transfer. The input parameters for this callback function supply the transfer's direction (input or output)
and a scatter/gather list. If the transfer consists of a single packet, the scatter/gather list contains a single
element.
The EvtProgramDma callback function programs the device by using the hardware resources that the driver's
EvtDevicePrepareHardware callback function received. If the EvtProgramDma callback function successfully
programs the hardware, it returns TRUE .
After the hardware has completed the DMA transfer, typically the hardware issues an interrupt and the system
calls the driver's EvtInterruptIsr callback function. The driver's EvtInterruptIsr callback function usually:
Clears the hardware interrupt.
Saves the interrupt's context information if it is needed. This information might be lost after the callback
function returns and the system lowers the IRQL (because lowering the IRQL allows additional interrupts
to occur).
Calls WdfInterruptQueueDpcForIsr to schedule an EvtInterruptDpc callback function.
The EvtInterruptDpc callback function completes the DMA transfer by using context information that the
EvtInterruptIsr callback function saved.
If the EvtProgramDma callback function detects an error, the driver can stop the transaction.
To stop a transaction when the driver detects an error, the EvtProgramDma callback function must:
1. Call WdfDmaTransactionDmaCompletedFinal .
2. Call WdfObjectDelete to delete the DMA transaction object, or call WdfDmaTransactionRelease to
release and reuse the DMA transaction object.
3. Requeue the I/O request or complete the I/O request, if the transaction is associated with a framework
request object. To retrieve a handle to the request, the driver can call WdfDmaTransactionGetRequest .
4. Return FALSE .
Steps 1 and 4 are illustrated in the following code example, taken from the PLX9x5x sample’s EvtProgramDma
callback function for read requests in the Read.c file.
// If errors occur in the EvtProgramDma callback,
// release the DMA transaction object and complete the request.

if (errors) {
NTSTATUS status;

//
// Must abort the transaction before deleting.
//
(VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status);
ASSERT(NT_SUCCESS(status));

PLxReadRequestComplete( Transaction, STATUS_INVALID_DEVICE_STATE );


TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
"<-- PLxEvtProgramReadDma: errors ****");
return FALSE;
}

The example calls the PLxReadRequestComplete function to perform steps 2 and 3:

VOID
PLxReadRequestComplete(
IN WDFDMATRANSACTION DmaTransaction,
IN NTSTATUS Status
)
/*++

Routine Description:

Arguments:

Return Value:

--*/
{
WDFREQUEST request;
size_t bytesTransferred;

//
// Get the associated request from the transaction.
//
request = WdfDmaTransactionGetRequest(DmaTransaction);

ASSERT(request);

//
// Get the final bytes transferred count.
//
bytesTransferred = WdfDmaTransactionGetBytesTransferred( DmaTransaction );

TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,
"PLxReadRequestComplete: Request %p, Status %!STATUS!, "
"bytes transferred %d\n",
request, Status, (int) bytesTransferred );

WdfDmaTransactionRelease(DmaTransaction);

//
// Complete this Request.
//
WdfRequestCompleteWithInformation( request, Status, bytesTransferred);

}
Completing a DMA Transfer
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


Typically, your driver's EvtInterruptDpc callback function completes the processing of each DMA transfer.
First, because multiple DMA transactions can be in progress concurrently, the EvtInterruptDpc callback function
must determine which DMA transaction the completed transfer is associated with. The callback function can do
this by retrieving the transaction handle that the driver stored when it started the DMA transaction. To retrieve
the device extension, the PLX9x5x sample defines a function called PLxGetDeviceContext in its Private.h
header file:

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, PLxGetDeviceContext)

Then, in the driver's EvtInterruptDpc callback, it does the following:

WDFDMATRANSACTION dmaTransaction;
PDEVICE_EXTENSION devExt;
...
devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt));
...
dmaTransaction = devExt->WriteDmaTransaction;

Next, the EvtInterruptDpc callback function must inform the framework that a transfer is complete, by calling
one of the following transfer completion methods:
WdfDmaTransactionDmaCompleted , if the transfer completed successfully and the hardware does
not report a count of transferred bytes.
WdfDmaTransactionDmaCompletedWithLength , if the transfer completed successfully and the
hardware reports a count of transferred bytes (or a count of bytes not transferred), or if the driver
detected an error and specifies a transfer count of zero to retry the transfer. If the driver specifies a
transfer count of zero, the framework subtracts zero from the number of bytes that remain and thus
sends the same transfer to the EvtProgramDma callback function.
WdfDmaTransactionDmaCompletedFinal , if the hardware reports an underrun or failure condition.
Your driver can call WdfDmaTransactionGetCurrentDmaTransferLength to obtain the original length of the
completed transfer. This call is useful if your device reports a count of bytes that were not transferred, because
the driver can subtract the number of non-transferred bytes from the original transfer length and then call
WdfDmaTransactionGetCurrentDmaTransferLength to report the actual transfer size.
Each of the preceding transfer completion methods informs the framework that a single DMA transfer (not the
entire DMA transaction) is complete. After your driver calls one of these methods, the driver checks the
method's return value to see if the transaction requires more transfers:
If the completion method's return value is FALSE , the framework has determined that additional DMA
transfers are required to finish processing the DMA transaction.
Typically, the driver's EvtInterruptDpc callback function just returns. The framework calls the driver's
EvtProgramDma callback function again, and the callback function can program the hardware for the next
transfer.
The transfer completion methods provide a status value, which is always
STATUS_MORE_PROCESSING_REQUIRED in this case.
If the return value is TRUE , no more transfers will occur for the DMA transaction.
The transfer completion methods provide a status value. If the status value is STATUS_SUCCESS, all
transfers for the DMA transaction are complete and the driver must complete the DMA transaction. If the
status value is anything else, an error occurred and the DMA transaction might not have been completed.
If the EvtInterruptDpc callback function detects an error, typically due to a timer expiring or a hardware interrupt
signaling a transfer error, the driver can restart the transaction's current transfer.
To restart the transaction's current transfer, the driver's EvtInterruptDpc callback function can call
WdfDmaTransactionDmaCompletedWithLength with the TransferredLength parameter set to zero.
Completing a DMA Transaction
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


Each time that a driver's device completes a DMA transfer, the driver must call
WdfDmaTransactionDmaCompleted , WdfDmaTransactionDmaCompletedWithLength , or
WdfDmaTransactionDmaCompletedFinal and then check the return value.
When the return value is TRUE , no more transfers are needed for the DMA transaction and the driver must
complete the DMA transaction. Typically, the driver has not yet returned from its EvtInterruptDpc callback
function. Therefore, this callback function completes the DMA transaction by:
1. Calling WdfObjectDelete to delete the transaction object, or calling WdfDmaTransactionRelease if
the driver reuses DMA transaction objects.
2. Calling WdfRequestComplete or WdfRequestCompleteWithInformation , if the transaction is
associated with a framework request object.
If the driver calls WdfRequestCompleteWithInformation , it typically first calls
WdfDmaTransactionGetBytesTransferred to obtain the total length (number of bytes) of all of the
transaction's transfers.
These steps are illustrated in the following code example, taken from the PLX9x5x sample’s EvtInterruptDpc
callback function in the Isrdpc.c file:

if (readComplete) {
BOOLEAN transactionComplete;
WDFDMATRANSACTION dmaTransaction;
size_t bytesTransferred;

// Get the current Read DmaTransaction.


dmaTransaction = devExt->CurrentReadDmaTransaction;

// Indicate that this DMA operation has completed:


// This may start the transfer on the next packet if
// there is still data to be transferred.
transactionComplete =
WdfDmaTransactionDmaCompleted( dmaTransaction, &status );
if (transactionComplete) {
// Complete the DmaTransaction and the request.
devExt->CurrentReadDmaTransaction = NULL;
bytesTransferred =
((NT_SUCCESS(status)) ?
WdfDmaTransactionGetBytesTransferred(dmaTransaction): 0 );
WdfDmaTransactionRelease(dmaTransaction);
WdfRequestCompleteWithInformation(request, status, bytesTransferred);
}
}
Reusing DMA Transaction Objects
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


After a driver processes all of the DMA transfers that are associated with a DMA transaction, the driver can
delete or reuse the transaction object. Typically, the driver's EvtInterruptDpc callback function deletes the
transaction object (by calling WdfObjectDelete ). Subsequently, when the driver creates a new DMA
transaction, it calls WdfDmaTransactionCreate to create a new transaction object.
However, sometimes it is beneficial for the driver to reuse transaction objects. In such cases, the driver calls
WdfDmaTransactionRelease instead of WdfObjectDelete .
For example, suppose your driver and device must operate when computer memory resources are low. To
handle this memory issue, your driver can use the following procedure:
1. The driver's EvtDriverDeviceAdd callback function can call WdfDmaTransactionCreate to create one or
more transaction objects. The driver saves the handles to these transaction objects.
2. Each time the driver is ready to create and initialize a new transaction, it calls
WdfDmaTransactionCreate . If this method returns STATUS_INSUFFICIENT_RESOURCES, the driver can
use one of the stored transaction objects.
3. If the driver uses one of its stored transaction objects, it should reuse the transaction object, instead of
deleting it, when the transaction is completed. The driver sets up the transaction object for re-use by
calling WdfDmaTransactionRelease instead of WdfObjectDelete .
The PLX9x5x sample reuses DMA transaction objects.
Supporting Power Management for DMA Devices
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


The DMA enabler object defines a set of optional event callback functions that drivers for DMA devices can use
to manage transitions into and out of a device's working (D0) state.
Each time a DMA device enters its working state, and after the framework has called the driver's
EvtDeviceD0Entry callback function, the framework calls the following DMA callback functions, in the order that
they are listed:
EvtDmaEnablerFill
Allocates a device's DMA buffers.
EvtDmaEnablerEnable
Enables a device's DMA capability after the device enters its working (D0) state.
EvtDmaEnablerSelfManagedIoStart
Starts a DMA device's self-managed I/O operations.
Each time a DMA device leaves its working state, and before the framework has called the driver's
EvtDeviceD0Exit callback functions, the framework calls the following DMA callback functions, in the order that
they are listed:
EvtDmaEnablerSelfManagedIoStop
Stops a DMA device's self-managed I/O operations.
EvtDmaEnablerDisable
Disables a device's DMA capability before the device leaves its working (D0) state.
EvtDmaEnablerFlush
Deallocates a device's DMA buffers.
For more information about the order in which the framework calls a driver's event callback functions, see PnP
and Power Management Scenarios.
Using Common Buffers
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


Drivers for DMA devices sometimes must allocate buffer space that both a device and the driver can access. For
example, a device might write transfer information, such as byte counts, into this buffer space and the driver can
read it to determine the number of bytes that were transferred. This type of buffer space is called a common
buffer.
To allocate a common buffer, your driver's EvtDriverDeviceAdd callback function:
Calls WdfDmaEnablerCreate to create a DMA enabler object.
Calls WdfCommonBufferCreate or WdfCommonBufferCreateWithConfig to create the buffer.
Calls WdfCommonBufferGetAlignedLogicalAddress to obtain the buffer's logical address, which the
device can access.
Calls WdfCommonBufferGetAlignedVir tualAddress to obtain the buffer's virtual address, which the
driver can access.
The following code example is taken from the Init.c file of the PLX9x5x sample. This code shows how a KMDF
driver allocates common buffer space.

// Allocate common buffer for building writes


DevExt->WriteCommonBufferSize =
sizeof( DMA_TRANSFER_ELEMENT) * DevExt->WriteTransferElements;
status = WdfCommonBufferCreate( DevExt->DmaEnabler,
DevExt->WriteCommonBufferSize,
WDF_NO_OBJECT_ATTRIBUTES,
&DevExt->WriteCommonBuffer );
if (!NT_SUCCESS(status)) {
. . . //Error-handling code omitted
}
DevExt->WriteCommonBufferBase =
WdfCommonBufferGetAlignedVirtualAddress(
DevExt->WriteCommonBuffer);
DevExt->WriteCommonBufferBaseLA =
WdfCommonBufferGetAlignedLogicalAddress(
DevExt->WriteCommonBuffer);
RtlZeroMemory( DevExt->WriteCommonBufferBase, DevExt->WriteCommonBufferSize);

If your driver calls WdfDeviceSetAlignmentRequirement before calling WdfDmaEnablerCreate , the


buffers that WdfDmaEnablerCreate creates are aligned to the memory address boundary that the driver
specified to WdfDeviceSetAlignmentRequirement . Otherwise, common buffers are aligned to word address
boundaries. Alternatively, the driver can call WdfCommonBufferCreateWithConfig to specify an alignment
for a single buffer.
To obtain the length of a common buffer that your driver has allocated, the driver can call
WdfCommonBufferGetLength .
When the driver is finished using a common buffer, the driver calls WdfObjectDelete .
Supporting System-Mode DMA
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


System-mode DMA, in contrast to bus-master DMA, describes a configuration in which multiple devices share a
single, typically multichannel DMA controller.
Starting in Kernel-Mode Driver Framework (KMDF) version 1.11, the framework supports system-mode DMA
on System on a Chip (SoC)–based systems running on Windows 8 or later versions of the Windows operating
system.
This topic describes the code that a KMDF driver must provide in its event callback functions, as well as optional
event callback functions it can register, to handle I/O requests for a system-mode DMA device.
For information about KMDF and bus-master DMA, see Handling I/O Requests in a KMDF Driver for a Bus-
Master DMA Device.
The following figure shows the event callback functions that your driver uses to support system-mode DMA:
Creating a System-Mode DMA Enabler
Creating a system-mode DMA profile is a two-step process. The following steps represent a typical scenario:
1. Typically in its EvtDriverDeviceAdd callback function, the driver calls
WDF_DMA_ENABLER_CONFIG_INIT , setting the Profile parameter to SystemMode or
SystemModeDuplex . The driver then calls WdfDmaEnablerCreate , passing the
WDF_DMA_ENABLER_CONFIG structure that it just received.
The driver might alternatively create the enabler during EvtDevicePrepareHardware.
2. Your driver's EvtDevicePrepareHardware callback function associates the DMA enabler with its DMA
resources by calling the WdfDmaEnablerConfigureSystemProfile method. For a duplex enabler, the
driver calls WdfDmaEnablerConfigureSystemProfile twice, once to configure each transfer direction.
The driver can call WdfDmaEnablerConfigureSystemProfile after EvtDevicePrepareHardware has
completed, but the driver must call this method before it initializes DMA transactions.

Providing Optional Callback Functions


Configuring a DMA Channel
Typically, KMDF drivers do not configure DMA channels. However, in certain circumstances, drivers may need to
perform channel-specific configuration. For example, a driver might call a custom function that is implemented
by the DMA controller by using the following steps:
1. In one of the driver's request handlers, the driver calls
WdfDmaTransactionSetChannelConfigurationCallback to register a
EvtDmaTransactionConfigureDmaChannel callback function.
2. Your driver's EvtDmaTransactionConfigureDmaChannel callback function calls
WdfDmaEnablerWdmGetDmaAdapter to retrieve a pointer to the WDM DMA_ADAPTER . This structure
is the adapter object that represents the driver's system-mode DMA channel.
3. The driver can then call ConfigureAdapterChannel to enable custom functions implemented by the DMA
controller. This routine is callable only by pointer from the address returned in a DMA_OPERATIONS
structure.
4. Your driver's EvtDmaTransactionConfigureDmaChannel callback function returns TRUE if it successfully
configures the DMA channel.
5. The framework calls the driver's EvtProgramDma callback function.
Receiving Notification of Transfer Completion
Unlike devices that use bus-mastering controllers, the hardware for a system-mode DMA device might not
signal DMA transfer completion by issuing an interrupt.
If your device does not raise an interrupt to signal DMA transfer completion, your driver can provide an
EvtDmaTransactionDmaTransferComplete event callback function that the framework calls when a system-mode
DMA transfer has completed.
To register this callback function, a driver calls WdfDmaTransactionSetTransferCompleteCallback from one
of its request handlers.
Canceling DMA Transactions
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


If your driver has been built with version 1.11 or a later version of KMDF and is running on Windows 8 or later
using direct memory access (DMA) version 3, the driver can attempt to cancel a pending DMA transaction by
calling the WdfDmaTransactionCancel method.
When calling WdfDmaTransactionCancel , the driver must ensure that the specified DMA transaction is not
completed during the call. The driver can use the following technique to safely cancel a transaction, either before
DMA channel allocation or after some number of transfer operations have already completed:
1. In one of the driver's request handlers, the driver calls WdfRequestMarkCancelableEx and provides an
EvtRequestCancel callback function for the I/O request. The request handler then calls
WdfDmaTransactionExecute .
2. The driver's EvtRequestCancel callback function (which may begin running in a separate thread
immediately after the call to WdfRequestMarkCancelableEx ) calls WdfDmaTransactionCancel .
3. If the call to WdfDmaTransactionCancel occurs after the call to WdfDmaTransactionExecute , but
before the WdfDmaTransactionExecute method has started DMA allocation, transaction cancellation
succeeds and WdfDmaTransactionCancel returns TRUE. In this case, the driver's EvtRequestCancel
callback function must complete the DMA transaction. WdfDmaTransactionExecute returns an error
value.
4. If the driver calls WdfDmaTransactionCancel after the WdfDmaTransactionExecute method has
started DMA allocation, the attempt to cancel the transaction fails and WdfDmaTransactionCancel
returns FALSE. In this case, WdfDmaTransactionExecute returns STATUS_SUCCESS and the driver's
request handler must complete the DMA transaction.
At this point, if the driver is using system-mode DMA, the EvtRequestCancel callback function might call
WdfDmaTransactionStopSystemTransfer to attempt to stop the in-progress system-mode DMA
transfer. For a code example that shows how to do this, see WdfDmaTransactionStopSystemTransfer .
5. After the WdfDmaTransactionExecute method finishes DMA allocation, the framework calls the
driver's EvtProgramDma callback function (which may begin running in a separate thread immediately
after the call to WdfDmaTransactionExecute ). At this point, a call to the WdfDmaTransactionCancel
method would return FALSE.
In EvtProgramDma, the driver can call WdfRequestUnmarkCancelable to end the possibility of request
cancellation. If WdfRequestUnmarkCancelable returns STATUS_SUCCESS, the callback function must
program the hardware to start the transfer. If WdfRequestUnmarkCancelable returns
STATUS_CANCELLED, the request has been canceled. In this case, EvtProgramDma must call
WdfDmaTransactionDmaCompletedFinal to complete the DMA transaction.
The driver can use the same technique to cancel a DMA transaction after some number of transfer
operations have already completed. In this case, the driver calls WdfDmaTransactionCancel after it
calls WdfDmaTransactionDmaCompleted , but before the framework calls EvtProgramDma to
program the next transfer operation. If the driver happens to call WdfDmaTransactionCancel before it
calls WdfDmaTransactionDmaCompleted , WdfDmaTransactionDmaCompleted returns TRUE ,
indicating that the DMA transaction has been completed.
Using Single Transfer DMA
2/5/2021 • 2 minutes to read • Edit Online

By default, WDF sometimes splits a single DMA transaction into multiple DMA transfers. However, some devices
cannot handle a fragmented transaction and must instead receive all data in a single DMA operation. For
example, some PCI network controllers require one network packet at a time because they do not have the
hardware to cache and reassemble partial data.
Starting in KMDF version 1.19, a KMDF driver using DMA v3 can specify that it requires single transfer DMA
transactions. The driver can specify single transfer for a single DMA transaction only, or it can specify single
transfer for all DMA transactions created using a specified DMA enabler.

Setting single transfer for a specific DMA transaction


To set single transfer for a single transaction, use the following sequence:
1. Call WdfDmaTransactionCreate or WdfDmaTransactionRelease .
2. Call WdfDmaTransactionSetSingleTransferRequirement .
3. Call WdfDmaTransactionInitialize .
If initialization fails due to transaction fragmentation, a driver can fail the I/O request or it can rearrange the
transaction's memory buffers and reinitialize the transaction.
4. Call WdfDmaTransactionExecute .
When debugging your driver, you can use the !wdfkd.wdfdmatransaction extension to determine if single
transfer is set for a given transaction object.

Setting the single-transfer requirement for all DMA transactions


created with a particular DMA enabler
To set single transfer for all transactions created with a given enabler, specify the
WDF_DMA_ENABLER_CONFIG_REQUIRE_SINGLE_TRANSFER flag in
WDF_DMA_ENABLER_CONFIG_FL AGS when calling WdfDmaEnablerCreate .
A driver that uses this flag does not need to call WdfDmaTransactionSetSingleTransferRequirement each
time it creates or reuses a transaction object.
This setting also persists if the driver reuses the transaction object.
When debugging, use the !wdfkd.wdfdmaenabler extension to determine if single transfer is set for a given
DMA enabler object.
For information about the order in which WDF calls your driver's DMA event callback functions, see Handling
I/O Requests in a KMDF Driver for a Bus-Master DMA Device.
Reserving DMA Resources
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


Typically, framework-based drivers do not reserve map registers ahead of time. However, in certain
circumstances, drivers may need to reserve these resources in advance.
Framework-based drivers running on Windows 8 or later can reserve a specified number of map registers for a
DMA enabler that specifies a packet or system profile. To do so, the driver calls
WdfDmaTransactionAllocateResources and registers an EvtReserveDma callback function.
The framework calls the driver's EvtReserveDma function when it has reserved the map registers and the WDM
DMA adapter's lock. The driver can then initialize and initiate the transaction multiple times using the same
transaction object before finally releasing the transaction object. To release the DMA resources back to the
system, the driver calls WdfDmaTransactionFreeResources .
To determine the number of map registers required for a transaction, the driver can call
WdfDmaTransactionGetTransferInfo before calling WdfDmaTransactionAllocateResources . The driver
must initialize the transaction before calling WdfDmaTransactionGetTransferInfo .
The following steps demonstrate how a driver can reserve and release a DMA enabler for exclusive use with a
specified transaction:
1. The driver receives an I/O request.
2. The driver's request handler calls WdfDmaTransactionCreate to create a DMA transaction object for
the request.
3. The driver's request handler calls WdfDmaTransactionAllocateResources to reserve resources.
4. The framework calls EvtReserveDma when it has reserved the requested resources.
5. In EvtReserveDma, the driver calls WdfDmaTransactionInitializeUsingRequest or
WdfDmaTransactionInitialize to initialize the transaction object.
6. In EvtReserveDma, the driver calls the WdfDmaTransactionExecute method to start the transaction.
Because the transaction has reserved resources, the framework immediately calls the driver's
EvtProgramDma callback function.
7. From EvtInterruptDpc or EvtDmaTransactionDmaTransferComplete, the driver calls
WdfDmaTransactionDmaCompleted , WdfDmaTransactionDmaCompletedWithLength , or
WdfDmaTransactionDmaCompletedFinal , followed by WdfObjectDelete or
WdfDmaTransactionRelease . The driver must not delete or release the transaction until the transaction
has been completed or canceled. After the completion of this step, the map registers remain reserved.
8. The driver can repeat steps 5–7 as many times as necessary.
When the driver no longer needs the reservation, the driver calls WdfDmaTransactionFreeResources
from EvtInterruptDpc or EvtDmaTransactionDmaTransferComplete. Alternatively, the driver can call
WdfDmaTransactionFreeResources from its EvtReserveDma event callback function.
Testing DMA in KMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


The following tools can help debug framework-based drivers that support DMA:
Driver Verifier includes specific verification tests that detect improper use of various DMA operations. For
more information about DMA-specific verification, see DMA Verification.
The !dma kernel debugger extension displays information about the DMA subsystem and DMA device
drivers that are being verified by Driver Verifier.
The Kernel-Mode Driver Framework Extensions include the following DMA-specific commands:
!wdfcommonbuffer
Dumps information about a given common buffer object.
!wdfdmaenabler
Dumps information about a specific DMA enabler object and its transactions and common buffer objects.
!wdfdmaenablers
Lists all of the DMA enablers and their transactions and common buffer objects.
!wdfdmatransaction
Dumps information about a given transaction object.
Handling Hardware Resources
2/5/2021 • 2 minutes to read • Edit Online

A system's hardware resources are the I/O ports, interrupt vectors, direct memory access (DMA) channels, and
other communication paths that must be assigned to each device that is connected to the system. The topics in
this section describe how Kernel-Mode Driver Framework (KMDF) drivers negotiate hardware resource
requirements for a device, review the proposed resource list, and then receive the assigned resources. This
section also discusses how both KMDF and User-Mode Driver Framework (UMDF) drivers access and map
assigned resources.

In this section
Introduction to Hardware Resources
Framework Objects for Hardware Resources
Creating a Resource Requirements List
Modifying a Resource Requirements List
Creating a Resource List for a Boot Configuration
Modifying a Resource List
Raw and Translated Resources
Finding and Mapping Hardware Resources
Reading and Writing to Device Registers
Introduction to Hardware Resources
2/5/2021 • 3 minutes to read • Edit Online

After a user plugs in a PnP device, the driver that enumerates the device typically creates one or more logical
configurations, which are combinations of hardware resources that the device can use. These configurations
include the following:
A boot configuration that lists the hardware resources that the device requires when the system starts.
(For PnP devices, this information is supplied by the BIOS.)
Additional configurations in which the device can operate. The driver groups these additional
configurations in a resource requirements list. The PnP manager will eventually select resources from this
list to assign to the device.
After the driver creates the logical configurations, it sends them to the framework, and the framework sends
them to the PnP manager.
Next, the PnP manager determines which drivers the device requires and loads them if they are not already
loaded. The PnP manager sends the device's hardware requirements list to the device's drivers for review.
Function and filter drivers can modify this list and send it back to the PnP manager.
The PnP manager examines the modified hardware requirements list and determines which of the specified
resources are actually available on the system. If the device requires resources that the PnP manager had
previously assigned to another device, the PnP manager might attempt to redistribute resources among the
system's devices.
Next, the PnP manager creates a resource list, which is a list of resources that the PnP manager intends to assign
to the device. The PnP manager sends this list to the device's drivers for review. At this point, the function and
filter drivers can remove resources from the list but they cannot add resources to it.
Finally, the PnP manager assigns resources to the device. The framework passes the resource list to the device's
function and filter drivers, and the device's function driver performs any initialization that is necessary so that
the device and driver can access the resources.
The following steps describe the process in more detail:
1. A user plugs in a device.
2. A bus driver detects the device and enumerates it.
3. The framework calls the bus driver's EvtDeviceResourcesQuery callback function, which creates a
resource list that describes the device's boot configuration.
4. The framework calls the bus driver's EvtDeviceResourceRequirementsQuery callback function, which
creates a resource requirements list for the device.
5. The PnP manager determines which drivers the device requires and loads them, if they are not already
loaded, to create a driver stack for the device.
6. The PnP manager sends the device's resource requirements list to the driver stack for review. As the list
travels down the driver stack, the framework calls each function and filter driver's
EvtDeviceFilterRemoveResourceRequirements callback function. As the list travels back up the stack, the
framework calls each function and filter driver's EvtDeviceFilterAddResourceRequirements callback
function. Both of these callback functions can modify the resource requirements list.
7. The PnP manager creates a resource list for the device and sends it to the driver stack for review. The
framework calls each function and filter driver's EvtDeviceRemoveAddedResources callback function,
which removes resources that the driver's EvtDeviceFilterAddResourceRequirements callback function
added so the bus driver will not attempt to use them.
8. The framework receives the final resource list from the PnP manager and stores it.
9. If a driver calls WdfInterruptCreate to create interrupt objects, the framework finds interrupt resources
in the resource list and assigns them to the interrupt objects.
10. After the device has entered an uninitialized D0 state, the framework calls each driver's
EvtDevicePrepareHardware callback function, passing raw and translated versions of the device's
resource list as an input argument. The driver can save the resource list, which is valid until the
framework calls the driver's EvtDeviceReleaseHardware callback function.
Framework Objects for Hardware Resources
2/5/2021 • 2 minutes to read • Edit Online

The framework defines the following three objects, which the framework and drivers use to specify a device's
hardware resources:
Framework resource-requirements-list objects
Each framework resource-requirements-list object represents a resource requirements list. Handles to these
objects have a type of WDFIORESREQLIST. The object defines framework resource-requirements-list object
methods. A resource requirements list consists of a set of logical configurations.
Framework resource-range-list objects
Each framework resource-range-list object represents a logical configuration (that is, a set of ranges of
resources that the device is capable of using) in a resource requirements list. Handles to these objects have a
type of WDFIORESLIST. The object defines framework resource-range-list object methods.
Framework resource-list objects
Each framework resource-list object represents a logical configuration (that is, a set of specific resources) in a
resource list. Handles to these objects have a type of WDFCMRESLIST. The object defines framework resource-
list object methods.
Creating a Resource Requirements List
2/5/2021 • 2 minutes to read • Edit Online

When a bus driver detects a child device, the driver is responsible for creating a resource requirements list for
the device. Each item in the list is a logical configuration for the device.
After the driver reports the device during bus enumeration, the framework calls the driver's
EvtDeviceResourceRequirementsQuery callback function. This callback function receives a handle to a resource-
requirements-list object that represents an empty resource requirements list.
The driver must then do the following to add information to a resource requirements list:
Create an empty logical configuration.
For each logical configuration that the driver will specify, the driver must call WdfIoResourceListCreate
to create an empty logical configuration.
Add resource descriptors to the logical configuration.
To add resource descriptors to a logical configuration, the driver must do the following, for each type of
hardware resource that the device requires:
1. Fill in a driver-allocated IO_RESOURCE_DESCRIPTOR structure, which specifies a range of valid
values for a particular resource.
2. Call WdfIoResourceListAppendDescriptor or WdfIoResourceListInser tDescriptor to add the
contents of the IO_RESOURCE_DESCRIPTOR structure to a logical configuration.
If a device uses more than one instance of a resource type, all drivers in the stack that access the resource
must be aware of the order in which resources are added. For example, if a device requires two ranges of
I/O port addresses, all drivers that access the resource descriptors must be aware of the order in which
the two ranges are added to the logical configuration.
Add the logical configuration to the resource requirements list.
To add a logical configuration to the device's resource requirements list, the driver calls
WdfIoResourceRequirementsListAppendIoResList or
WdfIoResourceRequirementsListInser tIoResList .
When assigning resources to a device, the PnP manager attempts to match the requirements of the first
logical configuration in the list. If the resources required for that configuration are not available, the PnP
manager matches the next configuration in the list for which resources are available.
If your driver supports a non-PnP device, your driver typically must also call
WdfIoResourceRequirementsListSetSlotNumber and
WdfIoResourceRequirementsListSetInterfaceType .
After the driver's EvtDeviceResourceRequirementsQuery callback function returns, the framework passes the
resource requirements list to the PnP manager.
Modifying a Resource Requirements List
2/5/2021 • 2 minutes to read • Edit Online

After the PnP manager has ensured that all of a newly connected device's drivers have been loaded, it sends the
device's hardware requirements list to the device's driver stack.
As the list travels down the stack, the framework calls each function and filter driver's
EvtDeviceFilterRemoveResourceRequirements callback function, passing the hardware requirements list as an
input argument. This callback function can remove hardware resources from the hardware requirements list that
the bus driver has specified but that the function driver determines are not necessary for the device to operate.
For example, a PCI bus driver might, in accordance with the PCI specification, replicate an I/O space resource in
memory space. If your device can operate without using the I/O space resource, the device's function driver can
remove the I/O space resource from the hardware requirements list.
To remove items from the requirements list, a driver can do the following:
Call the following methods to modify the logical configurations in the resource requirements list:
WdfIoResourceRequirementsListGetCount , to obtain the number of logical configurations.
WdfIoResourceRequirementsListGetIoResList , to obtain access to a logical configuration.
WdfIoResourceRequirementsListRemove and
WdfIoResourceRequirementsListRemoveByIoResList , to remove a logical configuration.
Call the following methods to modify the resource descriptors within a logical configuration:
WdfIoResourceListGetCount , to obtain the number of resource descriptors.
WdfIoResourceListGetDescriptor , to obtain access to a resource descriptor.
WdfIoResourceListRemove and WdfIoResourceListRemoveByDescriptor , to remove a resource
descriptor.
As the list travels back up the driver stack, the framework calls each function and filter driver's
EvtDeviceFilterAddResourceRequirements callback function, passing the hardware requirements list as an input
argument. This callback function can add additional hardware resources that the function driver requires to
make the device operational.
To add items to the hardware requirements list, a driver can do the following:
Call the following methods to modify the logical configurations in the resource requirements list:
WdfIoResourceRequirementsListGetCount , to obtain the number of logical configurations.
WdfIoResourceRequirementsListGetIoResList , to obtain access to a logical configuration.
WdfIoResourceListCreate , to create a new logical configuration.
WdfIoResourceRequirementsListAppendIoResList or
WdfIoResourceRequirementsListInser tIoResList , to add a new logical configuration.
Call the following methods to modify the resource descriptors within a logical configuration:
WdfIoResourceListGetCount , to obtain the number of resource descriptors.
WdfIoResourceListGetDescriptor , to obtain access to a resource descriptor.
WdfIoResourceListAppendDescriptor or WdfIoResourceListInser tDescriptor , to add a
resource descriptor.
Creating a Resource List for a Boot Configuration
2/5/2021 • 2 minutes to read • Edit Online

After a bus driver enumerates a device, the framework calls the driver's EvtDeviceResourcesQuery callback
function. This callback function receives a handle to a resource-list object, which represents an empty resource
list. The driver must then do the following to add information to the list, for each type of hardware resource that
the device's boot configuration requires:
1. Fill in a driver-supplied CM_PARTIAL_RESOURCE_DESCRIPTOR structure, which specifies a valid value
for a particular resource.
2. Call WdfCmResourceListAppendDescriptor or WdfCmResourceListInser tDescriptor to add the
contents of the CM_PARTIAL_RESOURCE_DESCRIPTOR structure to the resource list.
After the driver's EvtDeviceResourcesQuery callback function returns, the framework passes the resource list to
the PnP manager.
Device installers can specify additional resource lists. For more information about additional resource lists, see
Hardware Resources.
Modifying a Resource List
2/5/2021 • 2 minutes to read • Edit Online

If a driver provides an EvtDeviceFilterAddResourceRequirements callback function, it must also provide an


EvtDeviceRemoveAddedResources callback function. The EvtDeviceRemoveAddedResources callback function
removes resources that the EvtDeviceFilterAddResourceRequirements callback function added so that the bus
driver will not attempt to use them.
To modify the resource descriptors in a device's resource list, a driver should call the following methods:
WdfCmResourceListGetCount , to obtain the number of resource descriptors.
WdfCmResourceListGetDescriptor , to obtain access to a resource descriptor.
WdfCmResourceListRemove and WdfCmResourceListRemoveByDescriptor , to remove a resource
descriptor.
If the driver removes a resource, it must remove it from both the raw and translated resource lists.
Raw and Translated Resources
2/5/2021 • 2 minutes to read • Edit Online

When a driver's EvtDeviceRemoveAddedResources or EvtDevicePrepareHardware callback function receives a


resource list, it receives two versions of the list. One version represents the device's raw resources, and the other
represents the device's translated resources. Both versions represent the same set of hardware resources, in the
same order.
Raw resources are resources that are identified by addresses that are relative to the bus to which the
device is connected. Typically, the driver that programs the device provides these addresses to the device.
Translated resources are resources that are identified by system physical addresses that drivers use to
access the resources.
A driver for a PCI bus device receives resources that are listed in the order in which they appear in the device’s
Base Address Registers (BARs). However, additional resource descriptors may be interleaved in the list, such that
the resource at index X in the BAR might not match the resource at the same index position in the resource list.
For more information about raw and translated resources, see the member descriptions for the
CM_PARTIAL_RESOURCE_DESCRIPTOR structure.
If a device's translated resource list contains a resource with the Type member of the
CM_PARTIAL_RESOURCE_DESCRIPTOR structure set to CmResourceTypeMemor y , every driver that accesses
that resource must do the following:
The driver's EvtDevicePrepareHardware callback function must call MmMapIoSpace to map system
physical addresses to system virtual addresses.
The driver's EvtDeviceReleaseHardware callback function must call MmUnmapIoSpace to unmap the
addresses.
For more information about mapping bus-relative addresses, see Mapping Bus-Relative Addresses to Virtual
Addresses.
Finding and Mapping Hardware Resources
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how a Kernel-Mode Driver Framework (KMDF) driver or User-Mode Driver Framework
(UMDF) driver starting in version 2 maps a translated memory resource (CmResourceTypeMemor y ) that it
receives in its EvtDevicePrepareHardware callback function.
A UMDF 1.x driver can also receive this type of resource in its
IPnpCallbackHardware2::OnPrepareHardware method. For more info, see Finding and Mapping Hardware
Resources in UMDF 1.x Drivers.
Your driver receives raw and translated versions of hardware resources in the device's resource list in its
EvtDevicePrepareHardware callback function. The driver can save the resource list, which is valid until the
framework calls the driver's EvtDeviceReleaseHardware callback function.
Typically, the driver calls WdfCmResourceListGetCount from its EvtDevicePrepareHardware callback function
to determine the number of resource descriptors in the translated resource list, and then calls
WdfCmResourceListGetDescriptor in a loop to identify memory-mapped registers, I/O ports, and interrupts.
If a driver is assigned a translated memory resource (CmResourceTypeMemor y ), it must map the physical
address into an address through which it can access device registers.
A KMDF driver calls MmMapIoSpace to map the given physical address range to nonpaged system space.
Then it uses the HAL Librar y Routines to read and write to registers.
A UMDF driver calls WdfDeviceMapIoSpace to map the physical address to a pseudo base address that it can
use in conjunction with WDF Register/Port Access Functions to read and write to registers and ports.
The driver unmaps the resources by calling MmUnmapIoSpace or WdfDeviceUnmapIoSpace from its
EvtDeviceReleaseHardware callback function.
You do not need to map resources in I/O space (CmResourceTypePor t , CmResourceTypeInterrupt ,
CmResourceTypeDma ).
If your UMDF driver calls WdfDeviceMapIoSpace , you must set the UmdfDirectHardwareAccess INF
directive to AllowDirectHardwareAccess .
For an example that shows how a driver finds and maps memory-mapped register resources, see Reading and
Writing to Device Registers.
Reading and Writing to Device Registers
2/5/2021 • 2 minutes to read • Edit Online

After a driver has mapped registers as described in Finding and Mapping Hardware Resources, a KMDF driver
uses the HAL Librar y Routines to read and write to registers, while a UMDF driver (version 2.0 or later)
typically uses the WDF Register/Port Access Functions.
If a UMDF driver needs to access memory-mapped registers directly, it can set the INF directive
UmdfRegisterAccessMode to RegisterAccessUsingUserModeMapping and then call
WdfDeviceGetHardwareRegisterMappedAddress to retrieve a user-mode mapped address. Because the
framework doesn't validate read and write accesses performed in this way, this technique is not recommended
for register access. For a complete list of UMDF INF directives, see Specifying WDF Directives in INF Files.
The following example includes code that could be compiled using KMDF (1.13 or later) or UMDF (2.0 or later).
The example shows how a driver uses its EvtDevicePrepareHardware callback function to examine its memory-
mapped register resources and map them into user-mode address space. The example then demonstrates how
to access the memory locations.
Before accessing device registers and ports, a UMDF driver must set the UmdfDirectHardwareAccess
directive to AllowDirectHardwareAccess in the driver's INF file.

NTSTATUS
MyDevicePrepareHardware (
IN WDFDEVICE Device,
IN WDFCMRESLIST ResourcesRaw,
IN WDFCMRESLIST ResourcesTranslated
)

{
PCM_PARTIAL_RESOURCE_DESCRIPTOR desc = NULL;
PCM_PARTIAL_RESOURCE_DESCRIPTOR descTranslated = NULL;
PHYSICAL_ADDRESS regBasePA = {0};
ULONG regLength = 0;
BOOLEAN found = FALSE;
ULONG i;
PFDO_DATA deviceContext;
NTSTATUS status = STATUS_SUCCESS;

UNREFERENCED_PARAMETER(ResourcesRaw);

MyKdPrint(("MyEvtDevicePrepareHardware Device 0x%p ResRaw 0x%p ResTrans "


"0x%p Count %d\n", Device, ResourcesRaw, ResourcesTranslated,
WdfCmResourceListGetCount(ResourcesTranslated)));

#ifndef _KERNEL_MODE
WDF_DEVICE_IO_TYPE stackReadWriteIotype = WdfDeviceIoUndefined;
WDF_DEVICE_IO_TYPE stackIoctlIotype = WdfDeviceIoUndefined;
WdfDeviceGetDeviceStackIoType(Device,
&stackReadWriteIotype,
&stackIoctlIotype);
MyKdPrint(("Device 0x%p stackReadWriteIoType %S stackIoctlIoType %S\n",
Device,
GetIoTypeName(stackReadWriteIotype),
GetIoTypeName(stackIoctlIotype)
));

#endif

deviceContext = ToasterFdoGetData(Device);
deviceContext = ToasterFdoGetData(Device);

//
// Scan the list and identify our resource
//
for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {
desc = WdfCmResourceListGetDescriptor(Resources, i);
descTranslated = WdfCmResourceListGetDescriptor(ResourcesTranslated, i);

switch (desc->Type) {
case CmResourceTypeMemory:
MyKdPrint(("EvtPrepareHardware: found CmResourceTypeMemory resources \n"));
//
// see if this is the memory resource we're looking for
//
if (desc->u.Memory.Length == 0x200) {
regBasePA = desc->u.Memory.Start;
regLength = desc->u.Memory.Length;
found = TRUE;
}
break;

case CmResourceTypePort:
MyKdPrint(("EvtPrepareHardware: found CmResourceTypePort"
" resource\n"));

switch(descTranslated->Type) {

case CmResourceTypePort:
deviceContext->PortWasMapped = FALSE;
deviceContext->PortBase =
ULongToPtr(descTranslated->u.Port.Start.LowPart);
deviceContext->PortCount = descTranslated ->u.Port.Length;
MyKdPrint(("Resource Translated Port: (%x) Length: (%d)\n",
descTranslated->u.Port.Start.LowPart,
descTranslated->u.Port.Length));
break;

case CmResourceTypeMemory:
//
// Map the memory
//

#if IS_UMDF_DRIVER
status = WdfDeviceMapIoSpace(
Device,
descTranslated->u.Memory.Start,
descTranslated->u.Memory.Length,
MmNonCached,
&deviceContext->PortBase
);

if (!NT_SUCCESS(status)) {
WdfVerifierDbgBreakPoint();
}
#else
deviceContext->PortBase = (PVOID)
MmMapIoSpace(
descTranslated->u.Memory.Start,
descTranslated->u.Memory.Length,
MmNonCached
);
UNREFERENCED_PARAMETER(status);

#endif
deviceContext->PortCount = descTranslated->u.Memory.Length;
deviceContext->PortWasMapped = TRUE;
MyKdPrint(("Resource Translated Memory: (%x) Length: (%d)\n",
descTranslated->u.Memory.Start.LowPart,
descTranslated->u.Memory.Length));
descTranslated->u.Memory.Length));
break;
default:
MyKdPrint(("Unhandled resource_type (0x%x)\n",
descTranslated->Type));
}
break;

case CmResourceTypeInterrupt:
MyKdPrint(("EvtPrepareHardware: found CmResourceTypeInterrupt"
"resource\n"));
break;

case CmResourceTypeConnection:
MyKdPrint(("EvtPrepareHardware: found CmResourceTypeConnection"
"resource\n"));
break;

default:
MyKdPrint(("EvtPrepareHardware: found resources of type %d"
"(CM_RESOURCE_TYPE)\n", desc->Type));
break;
}
}

//
// Next, the driver uses register/port access macros to access the port.
//

if ((PUCHAR)&deviceContext->PortBase != NULL) {
UCHAR data;

#ifndef _KERNEL_MODE
data = WDF_READ_PORT_UCHAR(Device, (PUCHAR)deviceContext->PortBase);
#else
data = READ_PORT_UCHAR((PUCHAR)deviceContext->PortBase);
#endif

MyKdPrint(("Read value %d from port address 0x%p\n", data,


deviceContext->PortBase));
}

if (i == 0) {
MyKdPrint(("EvtPrepareHardware: no cm resources found \n"));
}

return STATUS_SUCCESS;
}

NTSTATUS
MyDeviceReleaseHardware (
IN WDFDEVICE Device,
IN WDFCMRESLIST ResourcesTranslated
)

{
PFDO_DATA deviceContext;

UNREFERENCED_PARAMETER(ResourcesTranslated);

MyKdPrint(("CovEvtDeviceReleaseHardware Device 0x%p ResTrans 0x%p\n",


Device, ResourcesTranslated));

deviceContext = ToasterFdoGetData(Device);

if (deviceContext->PortWasMapped) {
#if IS_UMDF_DRIVER
#if IS_UMDF_DRIVER
WdfDeviceUnmapIoSpace(Device,
deviceContext->PortBase,
deviceContext->PortCount);
#else
MmUnmapIoSpace(deviceContext->PortBase,
deviceContext->PortCount);
#endif
}

return STATUS_SUCCESS;
}
Driver Access to Hardware
2/5/2021 • 2 minutes to read • Edit Online

The following table lists all of the event callback functions that the framework device object defines, in
alphabetical order. The table shows you the callback functions in which your driver can access the hardware that
the callback function's WDFDEVICE handle represents. You can access the hardware because the device is in its
working (D0) state.

EVEN T C A L L B A C K S F UN C T IO N SF O R F RA M EW O RK DEVIC E
O B JEC T S IS H A RDWA RE A C C ESSIB L E?

EvtDeviceArmWakeFromS0 Yes

EvtDeviceArmWakeFromSx Yes

EvtDeviceArmWakeFromSxWithReason Yes

EvtDeviceD0Entry Yes

EvtDeviceD0Exit Yes

EvtDeviceDisableWakeAtBus Parent bus might be at D0. The device might be at D0.

EvtDeviceDisarmWakeFromS0 Yes

EvtDeviceDisarmWakeFromSx Yes

EvtDeviceEject No

EvtDeviceEnableWakeAtBus Parent bus is at D0, but the device might not be.

EvtDeviceFileCreate Maybe

EvtDeviceFilterAddResourceRequirements No

EvtDeviceFilterRemoveResourceRequirements No

EvtDevicePrepareHardware Yes
EVEN T C A L L B A C K S F UN C T IO N SF O R F RA M EW O RK DEVIC E
O B JEC T S IS H A RDWA RE A C C ESSIB L E?

EvtDeviceRelationsQuery Yes, but the device might be in a sleeping state.

EvtDeviceReleaseHardware No

EvtDeviceRemoveAddedResources Yes, but resources have not been assigned to the device.

EvtDeviceResourceRequirementsQuery No

EvtDeviceResourcesQuery No

EvtDeviceSelfManagedIoCleanup No

EvtDeviceSelfManagedIoFlush No

EvtDeviceSelfManagedIoInit Yes

EvtDeviceSelfManagedIoRestart Yes

EvtDeviceSelfManagedIoSuspend No, if device has been surprise-removed; otherwise, yes.

EvtDeviceSetLock No

EvtDeviceSurpriseRemoval No

EvtDeviceUsageNotification Yes

EvtDeviceWakeFromS0Triggered Yes

EvtDeviceWakeFromSxTriggered Yes

EvtDeviceWdmIrpPreprocess Depends on the IRP.

EvtDevicePnpStateChange Depends on the state.

EvtDevicePowerPolicyStateChange Depends on the state.

EvtDevicePowerStateChange Depends on the state.


Creating an Interrupt Object
2/5/2021 • 3 minutes to read • Edit Online

A Windows Driver Frameworks (WDF) driver that handles a device's hardware interrupts must create a
framework interrupt object for each interrupt that each device can support. In framework versions 1.11 and later
running on Windows 8 or later versions of the operating system, Kernel-Mode Driver Framework (KMDF) and
User-Mode Driver Framework (UMDF) drivers can create interrupt objects requiring passive-level handling.
Unless you are writing a driver for a System on a Chip (SoC) platform, however, your driver should use DIRQL
interrupt objects.
A driver typically creates framework interrupt objects in its EvtDriverDeviceAdd callback function. A driver can
also create interrupt objects from its EvtDevicePrepareHardware callback function.
The framework calls the driver's EvtDriverDeviceAdd callback function before the Plug and Play (PnP) manager
has assigned system resources, such as interrupt vectors, to the device. After the PnP manager assigns
resources, the framework stores interrupt resources in the device's interrupt object. (Drivers that do not support
Plug and Play cannot use interrupt objects.)
To create a framework interrupt object, your driver must initialize a WDF_INTERRUPT_CONFIG structure and
pass it to the WdfInterruptCreate method.
UMDF supports the following types of interrupts:
Level-triggered (shared or exclusive)
Edge-triggered (exclusive only)
MSI (exclusive by definition)
Note UMDF does not support shared edge-triggered interrupts.
Starting in UMDF version 2.15, UMDF supports interrupts for simple devices like hardware push-buttons,
usually backed by GPIO pins, that you cannot enable or disable explicitly using hardware registers. To support
such devices, a UMDF driver must use exclusive edge-triggered interrupts.
Starting in KMDF version 1.15, KMDF also supports interrupts for such devices, without the workaround
described in Handling Active-Both Interrupts.
Also in WDF_INTERRUPT_CONFIG , your driver supplies pointers to the following driver-supplied event
callback functions:
EvtInterruptEnable
Enables a hardware interrupt.
EvtInterruptDisable
Disables a hardware interrupt.
EvtInterruptIsr
Interrupt service routine (ISR) for the interrupt.
EvtInterruptDpc
Deferred procedure call (DPC) for the interrupt.
EvtInterruptWorkItem
Work item for a passive-level interrupt.
For drivers using framework version 1.11 or later on Windows 8 or later versions of the operating system, the
driver can explicitly set the parent of a framework interrupt object (DIRQL or passive) to either a framework
device object or a framework queue object. If the driver specifies a parent, the driver must set the
AutomaticSerialization member of the interrupt object's WDF_INTERRUPT_CONFIG structure to TRUE.
(Recall that if AutomaticSerialization is TRUE, the framework synchronizes execution of the interrupt object's
EvtInterruptDpc or EvtInterruptWorkItem callback function with callback functions from other objects that are
underneath the interrupt's parent object.)
As an example, a driver might specify a queue as parent of an interrupt to synchronize the queue's callbacks with
either the interrupt's EvtInterruptDpc or EvtInterruptWorkItem callback. In this configuration, the framework
deletes the queue object when it deletes the device object.
After calling WdfInterruptCreate , the driver can optionally call WdfInterruptSetPolicy or
WdfInterruptSetExtendedPolicy to specify additional interrupt parameters. Typically the driver calls these
methods from its EvtDriverDeviceAdd callback function.
The framework automatically deletes the interrupt before deleting the interrupt's parent. Optionally, a driver can
call WdfObjectDelete to delete the interrupt at an earlier time.

Supporting Message-signaled Interrupts


Message-signaled interrupts (MSIs) are supported starting with Windows Vista. To enable the operating system
to support MSIs for your device, your driver's INF file must set some values in the registry. For information
about how to set these values, see Enabling Message-Signaled Interrupts in the Registry.
Your driver should create a framework interrupt object for each interrupt vector or MSI message that the device
can support. If the PnP manager does not grant the device all of the interrupt resources that the device can
support, the extra interrupt objects will not be used and their callback functions will not be called.
In Windows 7, the operating system does not support resource requests for more than 910 interrupt messages
per device function. In Windows 8, the operating system does not support resource requests for more than
2048 interrupts per device function.
If the device driver exceeds this limit, the device might fail to start. To operate in a computer that contains many
logical processors, the driver should not request more than one interrupt per processor.
A driver must tolerate, without failures, system rebalancing of interrupt resources in which the PnP manager
assigns to the device any set of alternative interrupt resources from the resource requirements list. For example,
the device might be assigned a smaller number of message interrupts than the driver requested. In the worst
case, the driver must be prepared to operate the device with just one line-based interrupt.
Enabling and Disabling Interrupts
2/5/2021 • 2 minutes to read • Edit Online

If your driver handles device interrupts, it must provide EvtInterruptEnable and EvtInterruptDisable callback
functions that enable and disable the interrupts. Typically, these callback functions run at the device's DIRQL and
must do whatever is necessary to enable and disable a device's interrupt mechanism. For passive-level
interrupts, these callback functions run at IRQL = PASSIVE_LEVEL while holding the passive-level interrupt lock.
If your driver must perform additional operations that are related to enabling or disabling interrupts, and if
these additional operations cannot be performed at IRQL = DIRQL, the driver can also provide
EvtDeviceD0EntryPostInterruptsEnabled and EvtDeviceD0ExitPreInterruptsDisabled callback functions. These
two callback functions run at IRQL = PASSIVE_LEVEL with no interrupt lock held, and can call framework object
methods that are unavailable at IRQL = DIRQL.
The framework calls the driver's EvtInterruptEnable and EvtDeviceD0EntryPostInterruptsEnabled callback
functions each time the device enters its working (D0) state, after the framework has called the driver's
EvtDeviceD0Entry callback function.
The framework calls the driver's EvtDeviceD0ExitPreInterruptsDisabled and EvtInterruptDisable callback
functions each time the device leaves its working state, before the framework calls the driver's EvtDeviceD0Exit
callback function. For more information about when the framework calls a driver's callback functions, see PnP
and Power Management Scenarios.
You must not assume that a device will use the same interrupt resources each time the framework calls your
driver's EvtInterruptEnable callback function. Sometimes the PnP manager redistributes system resources, and it
might assign new interrupt resources to your device.
The driver can call WdfInterruptGetInfo to determine a device's interrupt resources. The driver can call
WdfInterruptGetDevice to determine the device that an interrupt object belongs to. (A few drivers might call
WdfInterruptWdmGetInterrupt .)
To enable and disable interrupts directly, the driver can call the interrupt object's WdfInterruptEnable and
WdfInterruptDisable methods, which call the driver's EvtInterruptEnable and EvtInterruptDisable event
callback functions. However, most drivers should just allow the framework to call the EvtInterruptEnable and
EvtInterruptDisable callback functions at the proper times.
Servicing an Interrupt
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how to service a DIRQL interrupt. For information about servicing a passive-level interrupt,
see Supporting Passive Level Interrupts.
Servicing an interrupt consists of two, and sometimes three, steps:
1. Saving volatile information (such as register contents) quickly, in an interrupt service routine that runs at
IRQL = DIRQL.
2. Processing the saved volatile information in a deferred procedure call (DPC) that runs at IRQL =
DISPATCH_LEVEL.
3. Performing additional work at IRQL = PASSIVE_LEVEL, if necessary.
When a device generates a hardware interrupt, the framework calls the driver's interrupt service routine (ISR),
which framework-based drivers implement as an EvtInterruptIsr callback function.
The EvtInterruptIsr callback function, which runs at the device's DIRQL, must quickly save interrupt information,
such as register contents, that will be lost if another interrupt occurs.
Typically, the EvtInterruptIsr callback function schedules a deferred procedure call (DPC) to process the saved
information later at a lower IRQL (DISPATCH_LEVEL). Framework-based drivers implement DPC routines as
EvtInterruptDpc or EvtDpcFunc callback functions.
Most drivers use a single EvtInterruptDpc callback function for each type of interrupt. To schedule execution of
an EvtInterruptDpc callback function, a driver must call WdfInterruptQueueDpcForIsr from within the
EvtInterruptIsr callback function.
If your driver creates multiple framework queue objects for each device, you might consider using a separate
DPC object and EvtDpcFunc callback function for each queue. To schedule execution of an EvtDpcFunc callback
function, the driver must first create one or more DPC objects by calling WdfDpcCreate , typically in the driver's
EvtDriverDeviceAdd callback function. Then the driver's EvtInterruptIsr callback function can call
WdfDpcEnqueue .
Drivers typically complete I/O requests in their EvtInterruptDpc or EvtDpcFunc callback functions.
Sometimes a driver must perform some interrupt-servicing operations at IRQL = PASSIVE_LEVEL. In such cases
the driver's EvtInterruptDpc or EvtDpcFunc callback function, executing at IRQL = DISPATCH_LEVEL, can schedule
execution of one or more framework work items, which run at IRQL = PASSIVE_LEVEL.
For an example of a driver that uses work items while servicing device interrupts, see the PCIDRV sample driver.
Synchronizing Interrupt Code
2/5/2021 • 4 minutes to read • Edit Online

The following factors complicate driver code that handles hardware interrupts on multiprocessor systems:
Each time a device interrupts, it provides interrupt-specific information that is volatile because it can be
overwritten the next time that the device interrupts.
Devices interrupt at relatively high IRQLs and their interrupt service routines (ISRs) can interrupt the
execution of other driver code.
For DIRQL interrupts, the ISR must run at DIRQL while holding a driver-supplied spin lock, so that the ISR
can prevent additional interrupts while it saves volatile information. The DIRQL prevents interruption by
the current processor, and the spin lock prevents interruption by another processor.
The ISR must run quickly because the device cannot interrupt while the ISR is executing. Long ISR
execution times can slow the system or possibly cause data loss.
Both the ISR and the deferred procedure call (DPC) routine must typically access a storage area in which
the ISR stores the device's volatile data. These routines must synchronize with each other so that they do
not access the storage area at the same time.
Because of all of these factors, you must use the following rules when writing driver code that handles
interrupts:
Only the EvtInterruptIsr callback function accesses volatile interrupt data, such as device registers that
contain interrupt information.
The EvtInterruptIsr callback function should move the volatile data to a driver-defined interrupt data
buffer that the driver's EvtInterruptDpc callback function, EvtInterruptWorkItem callback function, or
multiple EvtDpcFunc callback functions can access.
If your driver provides EvtInterruptDpc or EvtInterruptWorkItem callback functions for its interrupt
objects, the best place to store interrupt data is the interrupt object's context space. The interrupt object's
callback functions can access the object's context space by using the object handle that they receive.
If your driver provides multiple EvtDpcFunc callback functions for each EvtInterruptIsr callback function,
you might store interrupt data in each DPC object's context space.
All driver code that accesses the interrupt data buffer must be synchronized so that only one routine
accesses the data at a time.
For DIRQL interrupt objects, the EvtInterruptIsr callback function accesses this data buffer at IRQL =
DIRQL while holding the interrupt object's driver-supplied spin lock. Therefore, all routines that access the
buffer must also run at DIRQL while holding the spin lock. (Typically, the interrupt's EvtInterruptDpc or
EvtDpcFunc callback function is the only other routine that must access the buffer.)
All routines that access an interrupt data buffer, except for the EvtInterruptIsr callback function, must do
one of the following:
Call WdfInterruptSynchronize to schedule an EvtInterruptSynchronize callback function that
accesses the interrupt data buffer.
Place code that accesses the interrupt data buffer between calls to WdfInterruptAcquireLock and
WdfInterruptReleaseLock .
Both of these techniques allow the EvtInterruptDpc or EvtDpcFunc function to access interrupt data at
DIRQL while holding the interrupt's spin lock. The DIRQL prevents interruption by the current processor,
and the spin lock prevents interruption by another processor.
If your device supports multiple interrupt vectors or messages, and if you want to synchronize your
driver's handling of these interrupts, you can assign a single spin lock to multiple DIRQL interrupt objects.
The framework determines the highest DIRQL of the set of interrupts, and it always acquires the spin lock
at that DIRQL so that the synchronized code cannot be interrupted by any interrupt vectors or messages
in the set.
For passive-level interrupt objects, the framework acquires the passive-level interrupt lock before calling
the driver's EvtInterruptIsr callback function at IRQL = PASSIVE_LEVEL. As a result, all routines that access
the buffer must either acquire the interrupt lock or internally synchronize buffer access. Typically, the
interrupt's EvtInterruptWorkItem callback function is the only other routine that accesses the buffer. For
information about acquiring the interrupt lock from an EvtInterruptWorkItem callback function, see the
Remarks section of that page.
You can also synchronize your driver's handling of multiple interrupt vectors by assigning a single wait
lock to multiple passive-level interrupt objects.
If some of your code that handles DIRQL interrupts must run at IRQL = PASSIVE_LEVEL, your
EvtInterruptDpc or EvtDpcFunc callback function can create one or more work items so that the code will
run as EvtWorkItem callback functions.
Alternatively, in KMDF versions 1.11 and later, the driver can request an interrupt work item by calling
WdfInterruptQueueWorkItemForIsr . (Recall that a driver's EvtInterruptIsr callback function can call
WdfInterruptQueueWorkItemForIsr or WdfInterruptQueueDpcForIsr , but not both.)
If it is important to synchronize a driver's EvtInterruptDpc and EvtDpcFunc callback functions with each
other and with other callback functions that are associated with a device, your driver can set the
AutomaticSerialization member to TRUE in the interrupt's WDF_INTERRUPT_CONFIG structure and
the DPC object's WDF_DPC_CONFIG structure. Alternatively, the driver can use framework spin locks.
(Setting the AutomaticSerialization member to TRUE does not synchronize an EvtInterruptIsr callback
function with other callback functions. Use WdfInterruptSynchronize or WdfInterruptAcquireLock
to synchronize an EvtInterruptIsr callback function, as described previously in this topic.)
For more information about synchronizing driver routines, see Synchronization Techniques for Framework-
Based Drivers.
Supporting Passive-Level Interrupts
2/5/2021 • 6 minutes to read • Edit Online

Starting with framework version 1.11, Kernel-Mode Driver Framework (KMDF) and User-Mode Driver
Framework (UMDF) drivers running on Windows 8 or later versions of the operating system can create interrupt
objects that require passive-level handling. If the driver configures an interrupt object for passive-level interrupt
handling, the framework calls the driver's interrupt service routine (ISR) and other interrupt object event
callback functions at IRQL = PASSIVE_LEVEL while holding a passive-level interrupt lock.
If you are developing a framework-based driver for a System on a Chip (SoC) platform, you can use passive-
mode interrupts to communicate with an off-SoC device over a low-speed bus, such as I²C, SPI, or UART.
Otherwise, you should use interrupts that require handling at the device's IRQL (DIRQL). If your driver supports
message-signaled interrupts (MSIs), you must use DIRQL interrupt handling. In versions 1.9 and earlier, the
framework always processes interrupts at IRQL = DIRQL.
This topic describes how to create, service, and synchronize passive-level interrupts.

Creating a Passive-Level Interrupt


To create a passive-level interrupt object, a driver must initialize a WDF_INTERRUPT_CONFIG structure and
pass it to the WdfInterruptCreate method. In the configuration structure, the driver should:
Set the PassiveHandling member to TRUE.
Provide an EvtInterruptIsr callback function, to be called at passive level.
Optionally set the AutomaticSerialization to TRUE. If the driver sets AutomaticSerialization to TRUE,
then the framework synchronizes execution of the interrupt object's EvtInterruptDpc or EvtInterruptWorkItem
callback functions with callback functions from other objects that are underneath the interrupt's parent
object.
Optionally, the driver can provide either an EvtInterruptWorkItem callback function, to be called at IRQL =
PASSIVE_LEVEL, or an EvtInterruptDpc callback function, to be called at IRQL = DISPATCH_LEVEL.
For additional information on setting the above members of the configuration structure, see
WDF_INTERRUPT_CONFIG . For information about enabling and disabling passive-level interrupts, see
Enabling and Disabling Interrupts.

Servicing a Passive-Level Interrupt


The EvtInterruptIsr callback function, which runs at IRQL = PASSIVE_LEVEL with the passive-level interrupt lock
held, typically schedules an interrupt work item or interrupt DPC to process interrupt-related information at a
later time. Framework-based drivers implement work item or DPC routines as EvtInterruptWorkItem or
EvtInterruptDpc callback functions.
To schedule the execution of an EvtInterruptWorkItem callback function, a driver calls
WdfInterruptQueueWorkItemForIsr from within the EvtInterruptIsr callback function.
To schedule the execution of an EvtInterruptDpc callback function, a driver calls WdfInterruptQueueDpcForIsr
from within the EvtInterruptIsr callback function. (Recall that a driver's EvtInterruptIsr callback function can call
WdfInterruptQueueWorkItemForIsr or WdfInterruptQueueDpcForIsr , but not both.)
Most drivers use a single EvtInterruptWorkItem or EvtInterruptDpc callback function for each type of interrupt. If
your driver creates multiple framework interrupt objects for each device, consider using a separate
EvtInterruptWorkItem or EvtInterruptDpc callback for each interrupt.
Drivers typically complete I/O requests in their EvtInterruptWorkItem or EvtInterruptDpc callback functions.
The following code example demonstrates how a driver using passive-level interrupts might schedule a
EvtInterruptWorkItem callback from within its EvtInterruptIsr function.

BOOLEAN

EvtInterruptIsr(
_In_ WDFINTERRUPT Interrupt,
_In_ ULONG MessageID
)
/*++

Routine Description:

This routine responds to interrupts generated by the hardware.


It stops the interrupt and schedules a work item for
additional processing.

This ISR is called at PASSIVE_LEVEL (passive-level interrupt handling).

Arguments:

Interrupt - a handle to a framework interrupt object


MessageID - message number identifying the device's
hardware interrupt message (if using MSI)

Return Value:

TRUE if interrupt recognized.

--*/
{

UNREFERENCED_PARAMETER(MessageID);

NTSTATUS status;
PDEV_CONTEXT devCtx;
WDFREQUEST request;
WDF_MEMORY_DESCRIPTOR memoryDescriptor;
INT_REPORT intReport = {0};
BOOLEAN intRecognized;
WDFIOTARGET ioTarget;
ULONG_PTR bytes;
WDFMEMORY reqMemory;

intRecognized = FALSE;

//
// Typically the pattern in most ISRs (DIRQL or otherwise) is to:
// a) Check if the interrupt belongs to this device (shared interrupts).
// b) Stop the interrupt if the interrupt belongs to this device.
// c) Acknowledge the interrupt if the interrupt belongs to this device.
//

//
// Retrieve device context so that we can access our queues later.
//
devCtx = GetDevContext(WdfInterruptGetDevice(Interrupt));

//
// Init memory descriptor.
//
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
&memoryDescriptor,
&intReport,
sizeof(intReport);

//
// Send read registers/data IOCTL.
// This call stops the interrupt and reads the data at the same time.
// The device will reinterrupt when a new read is sent.
//
bytes = 0;
status = WdfIoTargetSendIoctlSynchronously(
ioTarget,
NULL,
IOCTL_READ_REPORT,
&memoryDescriptor,
NULL,
NULL,
&bytes);

//
// Return from ISR if this is not our interrupt.
//
if (intReport->Interrupt == FALSE) {
goto exit;
}

intRecognized = TRUE;

//
// Validate the data received.
//
...

//
// Retrieve the next read request from the ReportQueue which
// stores all the incoming IOCTL_READ_REPORT requests
//
request = NULL;
status = WdfIoQueueRetrieveNextRequest(
devCtx->ReportQueue,
&request);

if (!NT_SUCCESS(status) || (request == NULL)) {


//
// No requests to process.
//
goto exit;
}

//
// Retrieve the request buffer.
//
status = WdfRequestRetrieveOutputMemory(request, &reqMemory);

//
// Copy the data read into the request buffer.
// The request will be completed in the work item.
//
bytes = intReport->Data->Length;
status = WdfMemoryCopyFromBuffer(
reqMemory,
0,
intReport->Data,
bytes);

//
// Report how many bytes were copied.
//
WdfRequestSetInformation(request, bytes);
WdfRequestSetInformation(request, bytes);

//
// Forward the request to the completion queue.
//
status = WdfRequestForwardToIoQueue(request, devCtx->CompletionQueue);

//
// Queue a work-item to complete the request.
//
WdfInterruptQueueWorkItemForIsr(FxInterrupt);

exit:
return intRecognized;
}

VOID
EvtInterruptWorkItem(
_In_ WDFINTERRUPT Interrupt,
_In_ WDFOBJECT Device
)
/*++

Routine Description:

This work item handler is triggered by the interrupt ISR.

Arguments:

WorkItem - framework work item object

Return Value:

None

--*/
{
UNREFERENCED_PARAMETER(Device);

WDFREQUEST request;
NTSTATUS status;
PDEV_CONTEXT devCtx;
BOOLEAN run, rerun;

devCtx = GetDevContext(WdfInterruptGetDevice(Interrupt));

WdfSpinLockAcquire(devCtx->WorkItemSpinLock);
if (devCtx->WorkItemInProgress) {
devCtx->WorkItemRerun = TRUE;
run = FALSE;
}
else {
devCtx->WorkItemInProgress = TRUE;
devCtx->WorkItemRerun = FALSE;
run = TRUE;
}
WdfSpinLockRelease(devCtx->WorkItemSpinLock);

if (run == FALSE) {
return;
}

do {
for (;;) {
//
// Complete all report requests in the completion queue.
//
request = NULL;
status = WdfIoQueueRetrieveNextRequest(devCtx->CompletionQueue,
&request);
if (!NT_SUCCESS(status) || (request == NULL)) {
break;
}

WdfRequestComplete(request, STATUS_SUCCESS);
}

WdfSpinLockAcquire(devCtx->WorkItemSpinLock);
if (devCtx->WorkItemRerun) {
rerun = TRUE;
devCtx->WorkItemRerun = FALSE;
}
else {
devCtx->WorkItemInProgress = FALSE;
rerun = FALSE;
}
WdfSpinLockRelease(devCtx->WorkItemSpinLock);
}
while (rerun);
}

VOID
EvtIoInternalDeviceControl(
_In_ WDFQUEUE Queue,
_In_ WDFREQUEST Request,
_In_ size_t OutputBufferLength,
_In_ size_t InputBufferLength,
_In_ ULONG IoControlCode
)
{
NTSTATUS status;
DEVICE_CONTEXT devCtx;
devCtx = GetDeviceContext(WdfIoQueueGetDevice(Queue));

switch (IoControlCode)
{
...
case IOCTL_READ_REPORT:

//
// Forward the request to the manual ReportQueue to be completed
// later by the interrupt work item.
//
status = WdfRequestForwardToIoQueue(Request, devCtx->ReportQueue);
break;

...
}

if (!NT_SUCCESS(status)) {
WdfRequestComplete(Request, status);
}
}

Synchronizing a Passive-Level Interrupt


To prevent deadlock, follow these guidelines when writing a driver that implements passive-level interrupt
handling:
If AutomaticSerialization is set to TRUE, do not send synchronous requests from within an
EvtInterruptDpc or EvtInterruptWorkItem callback function.
Release the passive-level interrupt lock before completing I/O requests.
Provide EvtInterruptDisable, EvtInterruptEnable, and EvtInterruptWorkItem as necessary.
If your driver must perform interrupt-related work in an arbitrary thread context, such as in a request
handler, use WdfInterruptTr yToAcquireLock and WdfInterruptReleaseLock . Do not call
WdfInterruptAcquireLock , WdfInterruptSynchronize , WdfInterruptEnable , or
WdfInterruptDisable from an arbitrary thread context. For an example of a deadlock scenario that can
be caused by calling WdfInterruptAcquireLock from an arbitrary thread context, see the Remarks
section of WdfInterruptAcquireLock .
If the call to WdfInterruptTr yToAcquireLock fails, the driver can postpone its interrupt-related work to
a work item. In that work item, the driver can safely acquire the interrupt lock by calling
WdfInterruptAcquireLock . For more information, see WdfInterruptTr yToAcquireLock .
In a non-arbitrary thread context, such as a work item, the driver can call WdfInterruptAcquireLock or
WdfInterruptSynchronize .
For more information about using interrupt locks, see Synchronizing Interrupt Code.
Using an Interrupt to Wake a Device
2/5/2021 • 2 minutes to read • Edit Online

When a device transitions to a low-power state, the framework disconnects (or reports as inactive) interrupts
that are used for I/O handling. Starting with KMDF 1.13 and UMDF 2.0 running on Windows 8.1, a WDF driver
can create a framework interrupt object that remains active when the device transitions to a low-power state,
and can then be used to awaken the device and restore it to its fully on D0 state.
If you are developing a WDF driver for a System on a Chip (SoC) platform, you can use such an interrupt to
awaken a device that does not provide a traditional wake signaling mechanism. To use this functionality, the
device must have hardware support for wake interrupts, as exposed through ACPI. The driver that creates the
interrupt must be the device's power policy owner.
When the device transitions to a low-power state, the framework does not disconnect an interrupt that has been
identified as wake-capable. When the device interrupts, the framework calls the driver's EvtDeviceD0Entry and
EvtInterruptIsr callback routines at IRQL = PASSIVE_LEVEL.
If your driver already creates a passive-level interrupt object for I/O handling, we recommend sharing that same
interrupt object for wake functionality. In this scenario, the driver's EvtInterruptIsr callback routine implements
conditional logic to perform handling for I/O-related interrupts, as well as wake handling.
However, if your driver uses an interrupt that requires handling at the device's IRQL (DIRQL), we recommend
creating an additional framework interrupt object to provide wake functionality.
Follow these steps to create a wake-capable interrupt object in your KMDF or UMDF driver:
1. Call WdfDeviceAssignS0IdleSettings , typically from EvtDriverDeviceAdd, specifying
IdleCanWakeFromS0 in the IdleCaps parameter.
2. Optionally, call WdfDeviceInitSetPowerPolicyEventCallbacks to register event callback functions
described in Supporting System Wake-Up.
3. Call WDF_INTERRUPT_CONFIG_INIT to initialize a WDF_INTERRUPT_CONFIG structure. Provide an
EvtInterruptIsr callback function, to be called at passive level. In the configuration structure, set
PassiveHandling and CanWakeDevice to TRUE . Then call WdfInterruptCreate from your driver's
EvtDevicePrepareHardware callback function to create the framework interrupt object.
4. Call WdfDeviceAssignSxWakeSettings to configure the device to wake the system from a low-power
state.

WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings);
wakeSettings.DxState = PowerDeviceD3;
wakeSettings.UserControlOfWakeSettings = WakeDoNotAllowUserControl;
wakeSettings.Enabled = WdfTrue;

status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings);


if (!NT_SUCCESS(status)) {
Trace(TRACE_LEVEL_ERROR,"WdfDeviceAssignSxWakeSettings failed %x\n", status);
return status;
}

5. When the device transitions to a low-power state, the framework does not call EvtInterruptDisable for the
wake-capable interrupt. The framework does call EvtDeviceArmWakeFromS0 if the driver has provided
one.
6. When the device signals the wake interrupt, the framework calls the driver's EvtDeviceD0Entry callback
routine.
7. If the driver's EvtDeviceD0Entry callback returns success, the framework calls the driver's EvtInterruptIsr
callback at passive level. Before the interrupt handler returns, it must silence the interrupt in the interrupt
controller. If the driver returns a failure code from EvtDeviceD0Entry, the framework disconnects the
interrupt and calls the driver's EvtInterruptDisable callback, if the driver has provided one.
8. The framework calls the following wake event callback routines, if the driver has provided any:
EvtDeviceDisarmWakeFromS0
EvtDeviceDisarmWakeFromSx
EvtDeviceWakeFromS0Triggered
EvtDeviceWakeFromSxTriggered
9. The framework continues with the normal power-up callback sequence, as described in Power-Up
Sequence for a Function or Filter Driver.
You can use the !wdfkd.wdfinterrupt debugger extension to show whether a specific interrupt has been
configured to be wake-capable.
Wake interrupt functionality cannot be used in conjunction with USB selective suspend.
Handling Active-Both Interrupts
2/5/2021 • 3 minutes to read • Edit Online

Note This topic applies only to Kernel-Mode Driver Framework (KMDF) version 1.13 and earlier.
Many devices have hardware registers that control interrupt generation and masking. Typically, KMDF and
UMDF drivers for such devices use the framework's built-in interrupt support.
However, a simple device on a System on a Chip (SoC) hardware platform might not have hardware registers for
interrupts. As a result, a driver for such a device might not be able to control when the interrupt gets generated,
or be able to mask the interrupt in hardware. If the device interrupts immediately upon connection, and the
driver is using the framework's interrupt support, it is possible for the interrupt to fire before the framework has
fully initialized the framework interrupt object. As a result, a KMDF driver must call WDM routines directly to
connect and disconnect interrupts. Because a UMDF driver cannot call these methods, you cannot write a UMDF
driver for such a device.
This topic describes how a KMDF driver might handle interrupts for such a device.
On SoC hardware platforms, active-both interrupts are typically used for very simple devices like hardware
push-buttons. When a user presses a push-button, the interrupt signal line from the device transitions from low
to high, or from high to low. When the user releases the push-button, the interrupt line transitions in the
opposite direction. A GPIO pin configured as an active-both interrupt input generates interrupts on both low-to-
high and high-to-low transitions, resulting in the system calling the peripheral device driver's interrupt service
routine (ISR) in both cases. However, the driver does not receive an indication whether the transition is low-to-
high or high-to-low.
To distinguish between low-to-high and high-to-low transitions, the driver must track the state of each interrupt.
To do so, your driver might maintain a Boolean interrupt state value that is FALSE when interrupt line state is
low and TRUE when line state is high.
Consider an example in which the line state defaults to low when the system starts. The driver initializes the
state value to FALSE in its EvtDevicePrepareHardware callback function. Then each time the driver's ISR is called,
signaling a change in state, the driver inverts the state value in its ISR.
If the line state is high when the system starts, the interrupt fires immediately after it is enabled. Because the
driver calls the IoConnectInterruptEx routine directly, instead of calling WdfInterruptCreate , it is ensured of
receiving a possible immediate interrupt.
This solution requires that the GPIO controller support active-both interrupts in hardware, or that the driver for
the GPIO controller emulate active-both interrupts in software. For information about emulating active-both
interrupts, see the description of the EmulateActiveBoth member of the CONTROLLER_ATTRIBUTE_FL AGS
structure.
The following code example shows how a KMDF driver for a peripheral device can track interrupt polarity.

typedef struct _INTERRUPT_CONTEXT INTERRUPT_CONTEXT, *PINTERRUPT_CONTEXT;


typedef struct _DEVICE_CONTEXT DEVICE_CONTEXT, *PDEVICE_CONTEXT;

struct _INTERRUPT_CONTEXT
{
BOOLEAN State;
PDEVICE_CONTEXT DeviceContext;
};
struct _DEVICE_CONTEXT
{
PKINTERRUPT Interrupt;
INTERRUPT_CONTEXT InterruptContext;
PDEVICE_OBJECT PhysicalDeviceObject;
KSPIN_LOCK SpinLock;
};

...

BOOLEAN
YourInterruptIsr(
__in PKINTERRUPT Interrupt,
__in PVOID ServiceContext
)
{
PINTERRUPT_CONTEXT InterruptContext = (PINTERRUPT_CONTEXT)ServiceContext;
PDEVICE_CONTEXT DeviceContext = InterruptContext->DeviceContext;

//
// Flip the state.
//
InterruptContext->State = !InterruptContext->State;

IoRequestDpc(DeviceContext->PhysicalDeviceObject, DeviceContext->PhysicalDeviceObject-
>CurrentIrp, InterruptContext);
}

VOID
YourInterruptDpc(
__in PKDPC Dpc,
__in PDEVICE_OBJECT DeviceObject,
__inout PIRP Irp,
__in_opt PVOID ContextPointer
)
{
PINTERRUPT_CONTEXT InterruptContext = (PINTERRUPT_CONTEXT)ContextPointer;

...
}

NTSTATUS
EvtDriverDeviceAdd(
__in WDFDRIVER Driver,
__in PWDFDEVICE_INIT DeviceInit
)
{
WDFDEVICE Device;
PDEVICE_CONTEXT DeviceContext;

...

DeviceContext->Interrupt = NULL;
DeviceContext->PhysicalDeviceObject = WdfDeviceWdmGetPhysicalDevice(Device);
KeInitializeSpinLock(&DeviceContext->SpinLock);

IoInitializeDpcRequest(DeviceContext->PhysicalDeviceObject, YourInterruptDpc);
}

NTSTATUS
EvtDevicePrepareHardware(
__in WDFDEVICE Device,
__in WDFCMRESLIST ResourcesRaw,
__in WDFCMRESLIST ResourcesTranslated
)
{
PDEVICE_CONTEXT DeviceContext = YourGetDeviceContext(Device);

for (ULONG i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++)


for (ULONG i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++)
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor =
WdfCmResourceListGetDescriptor(ResourcesTranslated, i);

if (descriptor->Type == CmResourceTypeInterrupt)
{
IO_CONNECT_INTERRUPT_PARAMETERS params;
RtlZeroMemory(&params, sizeof(params));

params.Version = CONNECT_FULLY_SPECIFIED;
params.FullySpecified.PhysicalDeviceObject = DeviceContext-
>PhysicalDeviceObject;
params.FullySpecified.InterruptObject = &DeviceContext-
>Interrupt;
params.FullySpecified.ServiceRoutine = YourInterruptIsr;
params.FullySpecified.ServiceContext = (PVOID)&DeviceContext-
>InterruptContext;
params.FullySpecified.SpinLock = &DeviceContext->SpinLock;
params.FullySpecified.Vector = descriptor->u.Interrupt.Vector;
params.FullySpecified.Irql = (KIRQL)descriptor-
>u.Interrupt.Level;
params.FullySpecified.SynchronizeIrql = (KIRQL)descriptor-
>u.Interrupt.Level;
params.FullySpecified.InterruptMode = (descriptor->Flags &
CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
params.FullySpecified.ProcessorEnableMask = descriptor-
>u.Interrupt.Affinity;
params.FullySpecified.ShareVector = descriptor-
>ShareDisposition;

//
// Default state is low.
//
DeviceContext->InterruptContext.State = 0;
DeviceContext->InterruptContext.DeviceContext = DeviceContext;

return IoConnectInterruptEx(&params);
}
}

return STATUS_SUCCESS;
}

NTSTATUS
EvtDeviceReleaseHardware(
__in WDFDEVICE Device,
__in WDFCMRESLIST ResourcesTranslated
)
{
PDEVICE_CONTEXT DeviceContext = YourGetDeviceContext(Device);

if (NULL != DeviceContext->Interrupt)
{
IO_DISCONNECT_INTERRUPT_PARAMETERS params;

params.Version = CONNECT_FULLY_SPECIFIED;
params.ConnectionContext.InterruptObject = DeviceContext->Interrupt;

IoDisconnectInterruptEx(&params);
}

return STATUS_SUCCESS;
}

In the preceding code example, the driver's EvtDriverDeviceAdd callback function configures the device context
and then calls IoInitializeDpcRequest to register a DpcForIsr routine.
The driver's InterruptService routine inverts the interrupt state value and then calls IoRequestDpc to queue the
DPC.
In its EvtDevicePrepareHardware callback function, the driver initializes the state value to FALSE and then calls
IoConnectInterruptEx . In its EvtDeviceReleaseHardware callback function, the driver calls
IoDisconnectInterruptEx to unregister its ISR.
Using I/O Targets
2/5/2021 • 2 minutes to read • Edit Online

The topics in this section describe how a Windows Driver Frameworks (WDF) driver can forward an I/O request
or create and send a new request to another driver, called an I/O target.

In this section
Introduction to I/O Targets
General I/O Targets
USB I/O Targets
Introduction to I/O Targets
2/5/2021 • 2 minutes to read • Edit Online

When a function driver, filter driver, or miniport driver receives an I/O request, the driver might be able to
process the request by itself or it might need the assistance of other drivers. If the driver needs assistance, it can
forward the request to another driver, or it can create one or more new requests and send them to another
driver.
In Kernel-Mode Driver Framework, an I/O target represents a device object that is the target of an I/O request. A
function, filter, or miniport driver can use an I/O target to send I/O requests to another driver. These drivers
often send their I/O requests to the next-lower driver in the driver stack. Therefore, each framework-based
function, filter, and miniport driver has a local I/O target for each device, which is the device's next-lower driver.
Occasionally, a driver must send an I/O request to a different target--the top of a different driver stack or, rarely,
some other driver within the sending driver's stack. Therefore, the framework also provides remote I/O targets,
which consist of all of the I/O targets except the local I/O target.
Each I/O target is represented by an I/O target object. Each I/O target object is primarily a queue that controls
when a request is delivered to the target device object. When a driver sends a request to an I/O target, the
framework stores the request in the queue until it can deliver the request to the target device object.
The framework supports both general I/O targets and specialized I/O targets:
General I/O targets can be used by all function, filter, and miniport drivers, but they do not support any
special, device-specific data formats.
Specialized I/O targets enable function, filter, and miniport drivers to easily send I/O requests that require
special, target-specific data formatting. Currently, the framework provides support for the following
specialized I/O targets:
USB I/O targets
If the framework provides specialized I/O targets that support your device's data format, your driver should use
the specialized I/O targets. Otherwise, the driver should use general I/O targets.
General I/O Targets
2/5/2021 • 2 minutes to read • Edit Online

General I/O targets do not support special, device-specific data formats, such as USB request blocks. Before
drivers send data to a general I/O target, they must put data into a write buffer in a format that the I/O target
can interpret. Likewise, when drivers read data from a general I/O target, the drivers must be able interpret the
contents of data buffers that they receive from the target.
General I/O targets are either local or remote:
Local I/O Targets
Each framework-based function driver, filter driver, and miniport driver has a local I/O target for each of the
driver's devices. A device's local I/O target is always the next-lower driver in the driver stack.
Remote I/O Targets
Remote I/O targets represent the top of a different driver stack or (rarely) a different driver in the current
driver's stack.
This section includes:
Initializing a General I/O Target
Sending I/O Requests to General I/O Targets
Controlling a General I/O Target's State
Obtaining Information About a General I/O Target
Initializing a General I/O Target
2/5/2021 • 2 minutes to read • Edit Online

The framework initializes a driver's local I/O target for a device when the driver calls WdfDeviceCreate . To
retrieve a handle to a device's local I/O target, the driver calls WdfDeviceGetIoTarget .
Most drivers send requests only to their local I/O target.
To initialize a remote I/O target for a device, the driver must:
1. Call WdfIoTargetCreate to create an I/O target object.
2. Call WdfIoTargetOpen to open an I/O target so that the driver can send requests to it.
When the driver calls WdfIoTargetOpen , it typically identifies the remote I/O target by supplying a Unicode
string that represents an object name. This name can identify a device, file, or device interface. The framework
sends I/O requests to the top of the driver stack that supports the object name.
Rarely, a driver might identify a remote I/O target by supplying a pointer to a Windows Driver Model (WDM)
DEVICE_OBJECT structure. This pointer identifies a different driver within the calling driver's stack. Framework-
based drivers rarely use this technique because they rarely have access to other drivers' DEVICE_OBJECT
structures.
The following example shows how the Ndisedge sample driver uses the above technique to create and open a
remote I/O target:

status = WdfIoTargetCreate(Adapter->WdfDevice,
WDF_NO_OBJECT_ATTRIBUTES,
&Adapter->IoTarget);
if (!NT_SUCCESS(status)) {
DEBUGP(MP_ERROR, ("WdfIoTargetCreate failed 0x%x\n",
status));
return status;
}

WDF_IO_TARGET_OPEN_PARAMS_INIT_CREATE_BY_NAME(&openParams,
&fileName,
STANDARD_RIGHTS_ALL
);

status = WdfIoTargetOpen(Adapter->IoTarget,
&openParams);
if (!NT_SUCCESS(status)) {
DEBUGP(MP_ERROR, ("WdfIoTargetOpen failed 0x%x\n", status));
return status;
}
Sending I/O Requests to General I/O Targets
2/5/2021 • 2 minutes to read • Edit Online

Your driver can send I/O requests to general I/O targets either synchronously or asynchronously.
If a driver sends I/O requests synchronously, a driver thread sends the requests one at a time. The thread waits
for each request to complete before it sends the next one. This process is simpler than sending the I/O requests
asynchronously. Your driver can send I/O requests synchronously if it does not send many requests and if
system or device performance is not reduced while your driver waits for each I/O request.
If a driver sends I/O requests asynchronously, a driver thread sends each request as soon as the request is ready
to be sent, without waiting for previously sent requests to finish. If your driver must handle many I/O requests in
short periods of time, you probably cannot allow your driver to wait for each request to complete before
sending the next request. Otherwise, you might lose data or reduce the performance of your driver's devices
and, possibly, of the entire system.
The framework's I/O target object provides two sets of methods that your driver can call: one set to send I/O
requests synchronously and the other set to send I/O requests asynchronously.
For each of these methods, you must supply a request object and some buffer space. You can use these methods
to forward a request that your driver received in one of its I/O queues or to create and send a new request.
Sending I/O Requests Synchronously
2/5/2021 • 2 minutes to read • Edit Online

The following table lists the I/O target object methods that your driver can call to send I/O requests
synchronously to an I/O target. For detailed information about how to use these methods, see the methods'
reference pages.

M ET H O D P URP O SE

WdfIoTargetSendReadSynchronously Sends a read request

WdfIoTargetSendWriteSynchronously Sends a write request

WdfIoTargetSendIoctlSynchronously Sends a device control request

WdfIoTargetSendInternalIoctlSynchronously Sends an internal device control request

WdfIoTargetSendInternalIoctlOthersSynchronousl Sends a non-standard internal device control request


y

You can also send requests synchronously by calling WdfRequestSend , but you have to format the request
first by following the rules that are described in Sending I/O Requests Asynchronously.
Sending I/O requests to an I/O target synchronously is simpler to program than sending I/O requests
asynchronously. However, you should use the following guidelines to help you decide if synchronous I/O is
appropriate for your driver:
You can use synchronous I/O if your driver does not send many I/O requests and if system or device
performance is not reduced because your driver waits for each I/O request to complete.
If your driver must handle many I/O requests in short periods of time, you probably cannot allow your
driver to wait for each request to complete before sending the next request. Otherwise, your driver might
lose data or reduce the performance of its device (and, possibly, the entire system). In such cases,
asynchronous I/O might be the better choice.
Synchronous I/O is useful for handling operations that must start and finish without additional
concurrent activity. Such operations might include resetting a USB pipe or reading device registers.
Most times, your driver should specify a time-out value when it calls an object method that sends an I/O
request synchronously. If your driver does not specify a time-out value, and if a device or a lower-level
driver fails to respond, your driver can stall. As a result, the user can experience an unresponsive
application. In addition, other drivers might not be able to obtain system resources, such as work items, if
your driver is not releasing them.
If drivers above and below yours in the stack require operations to proceed synchronously, your driver
should use synchronous I/O. Therefore, you should learn about the requirements of other drivers that
might exist in the driver stack.
The following example shows how to send a synchronous I/O control (IOCTL) request:
NTSTATUS status;
WDF_MEMORY_DESCRIPTOR inputDesc, outputDesc;
PWDF_MEMORY_DESCRIPTOR pInputDesc = NULL, pOutputDesc = NULL;
ULONG_PTR bytesReturned;

UNREFERENCED_PARAMETER(FileObject);

if (InputBuffer) {
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputDesc,
InputBuffer,
InputBufferLength);
pInputDesc = &inputDesc;
}

if (OutputBuffer) {
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDesc,
OutputBuffer,
OutputBufferLength);
pOutputDesc = &outputDesc;
}

status = WdfIoTargetSendIoctlSynchronously(
IoTarget,
WDF_NO_HANDLE, // Request
IoctlControlCode,
pInputDesc,
pOutputDesc,
NULL, // PWDF_REQUEST_SEND_OPTIONS
&bytesReturned);
if (!NT_SUCCESS(status)) {
DEBUGP(MP_ERROR,
("WdfIoTargetSendIoctlSynchronously failed 0x%x\n",
status));
}

*BytesReadOrWritten = (ULONG)bytesReturned;
Sending I/O Requests Asynchronously
2/5/2021 • 2 minutes to read • Edit Online

Before you can send an I/O request asynchronously to an I/O target, you must format the request. The following
table lists the I/O target object methods that your driver can call to format I/O requests.

M ET H O D P URP O SE

WdfIoTargetFormatRequestForRead Formats a read request

WdfIoTargetFormatRequestForWrite Formats a write request

WdfIoTargetFormatRequestForIoctl Formats a device control request

WdfIoTargetFormatRequestForInternalIoctl Formats an internal device control request

WdfIoTargetFormatRequestForInternalIoctlOthers Formats a non-standard internal device control request

To send an I/O request asynchronously, your driver must:


1. Format the request.
Use one of the methods that are listed in the previous table to format your requests. For detailed
information about how to use these methods, see the methods' reference pages.
2. Register a CompletionRoutine callback function.
If you send requests asynchronously, you typically want the framework to notify your driver when
another driver completes each request. Your driver should define a CompletionRoutine callback function
and register it by calling WdfRequestSetCompletionRoutine . For more information, see Completing
I/O Requests.
3. Send the request.
After your driver formats the request and registers a CompletionRoutine callback function, your driver
must call WdfRequestSend . This method enables you to send requests either synchronously or
asynchronously, depending on the flags set in the RequestOptions parameter. For a simpler way to send
I/O requests synchronously, see Sending I/O Requests Synchronously. For information about how to get
the completion status for an asynchronous request or for any request that is sent by calling
WdfRequestSend , see Completing I/O Requests.
A driver that calls WdfRequestSend to send an I/O request can attempt to cancel the request later. For more
information, see Canceling I/O Requests.
Some drivers might send a single I/O request to multiple devices, and thus to multiple I/O targets, by calling
WdfRequestSend more than once for each request. These drivers must call WdfRequestChangeTarget
before each call to WdfRequestSend after the first one to verify that the request can be sent to the next I/O
target.
Controlling a General I/O Target's State
2/5/2021 • 3 minutes to read • Edit Online

You can visualize I/O target objects as having two gates: an in-gate and an out-gate. The out-gate controls when
the framework delivers a request to the target device object, while the in-gate controls when a request is
allowed to enter the I/O target at all.
The framework defines the following states for general I/O targets:
Started
Both gates of the I/O target object are open. The driver can send I/O requests to the I/O target queue, and the
framework delivers the requests to the appropriate driver.
Stopped
The in-gate of the I/O target is open, but the out-gate is closed. The framework stops delivering requests to the
appropriate driver. To send I/O requests to the I/O target, the driver must set either
WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE or
WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET in each request's
WDF_REQUEST_SEND_OPTIONS structure.
Purged
Both gates of the I/O target object are closed. The driver cannot send I/O requests to the I/O target unless it sets
WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE or
WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET . In addition, the framework cancels unprocessed
requests in the I/O target object's internal queue. This state is available beginning in KMDF version 1.11.
Closed for Query-Remove
A remote I/O target is temporarily closed because its device might soon be removed.
Closed
The I/O target is closed and cannot be started or stopped.
Deleted
The I/O target's device has been removed.
The WDF_IO_TARGET_STATE enumeration defines the values that represent these states. Your driver can call
WdfIoTargetGetState to obtain an I/O target's state.
Local I/O Target States
The framework automatically opens and starts local I/O targets.
If necessary, the driver can call WdfIoTargetStop to temporarily stop a local I/O target and call
WdfIoTargetStar t to restart it. For example, the driver might stop a local I/O target if it detects a temporary
error condition and then restart the I/O target if the error condition is corrected.
In KMDF version 1.11 and later, the driver can call WdfIoTargetPurge to temporarily prevent I/O requests from
being sent to a local I/O target, and to cancel unprocessed requests in the target's queue. For example, as part of
file handle cleanup, a driver might purge a local I/O target to ensure that all requests sent to the driver are
cancelled.
If a local I/O target's device is removed, the framework automatically stops and closes the I/O target and cancels
all I/O requests that are in the target's queue. The framework notifies the driver that the device is no longer
available by calling device object event callback functions. For more information about these callback functions,
see PnP and Power Management Scenarios.
Remote I/O Target States
Drivers must call WdfIoTargetOpen to open remote I/O targets. When a driver opens a remote I/O target, the
framework automatically starts the I/O target.
If necessary, the driver can call WdfIoTargetStop to temporarily stop a remote I/O target and call
WdfIoTargetStar t to restart it.
In KMDF version 1.11 and later, the driver can call WdfIoTargetPurge to temporarily prevent I/O requests from
being sent to a remote I/O target, and to cancel unprocessed requests in the target's queue.
If a remote I/O target's device is removed, the framework automatically stops and closes the I/O target and
cancels all I/O requests that are in the target's queue, unless the driver registers the following event callback
functions:
EvtIoTargetQueryRemove
Informs the driver that a remote I/O target's device might be removed. Your driver must call
WdfIoTargetCloseForQuer yRemove if you want the driver to allow removal of the device.
EvtIoTargetRemoveComplete
Informs the driver that a remote I/O target's device has been removed. This callback function must call
WdfIoTargetClose .
EvtIoTargetRemoveCanceled
Informs the driver that an attempt to remove a remote I/O target's device has been canceled. This callback
function must call WdfIoTargetOpen , and the driver typically calls
WDF_IO_TARGET_OPEN_PARAMS_INIT_REOPEN to initialize its WDF_IO_TARGET_OPEN_PARAMS_INIT
function.
If a driver has finished using a remote I/O target and will not use the target again, and the target has no child
request objects that are still pending, the driver can call WdfObjectDelete without first calling
WdfIoTargetClose . If the target has any child request objects that are still pending, the driver must call
WdfIoTargetClose before it can safely call WdfObjectDelete .
Obtaining Information About a General I/O Target
2/5/2021 • 2 minutes to read • Edit Online

To obtain information about an I/O target, your driver can call the following methods that the I/O target object
defines:
WdfIoTargetGetDevice
Returns the framework device object that is associated with a local or remote I/O target.
WdfIoTargetQuer yTargetProper ty or WdfIoTargetAllocAndQuer yTargetProper ty
Retrieves device properties that are associated with a local or remote I/O target's device.
WdfIoTargetGetState
Returns state information for a local or remote I/O target.
WdfIoTargetWdmGetTargetDeviceObject
Returns a pointer to the Windows Driver Model (WDM) device object that is associated with a local or remote
I/O target.
WdfIoTargetWdmGetTargetPhysicalDevice
Returns a pointer to the WDM physical device object (PDO) that represents a remote I/O target's device.
WdfIoTargetWdmGetTargetFileObject
Returns a pointer to the WDM file object that is associated with a remote I/O target.
WdfIoTargetWdmGetTargetFileHandle
Returns a handle to the file that is associated with a remote I/O target.
USB I/O Targets
2/5/2021 • 2 minutes to read • Edit Online

This section describes how Kernel-Mode Driver Framework (KMDF) and User-Mode Driver Framework (UMDF)
drivers starting in version 2 interact with universal serial bus (USB) devices.
Each USB device, and each pipe that a USB device interface supports, has a separate I/O target. Control transfers
that the USB device handles are sent to the device's I/O target. I/O transfers that a specific pipe handles are sent
to that pipe's I/O target.
The framework communicates with a USB device's I/O target by sending USB request blocks (URBs ). The
framework provides object methods that hide the URBs from your driver so that the driver does not have to
build and send them itself. If you would prefer that your driver build URBs, a KMDF driver can use an additional
set of object methods that build and send URBs.
For information about how to determine what type of driver you need for your USB device, see Choosing a
driver model for developing a USB client driver.
This section includes:
Working with USB Devices
Working with USB Interfaces
Working with USB Pipes
Working with USB Devices
2/5/2021 • 4 minutes to read • Edit Online

This topic describes the operations that a Kernel-Mode Driver Framework (KMDF) or User-Mode Driver
Framework (UMDF) driver starting in version 2 can perform using the USB device object methods provided by
Windows Driver Frameworks (WDF).
It contains the following sections:
Creating a USB device object
Configuring a USB Device
Obtaining Device Information
Getting USB Descriptors
Sending a Control Transfer
Resetting and Power-Cycling a Device's Port
Sending an URB to a Device
For step-by-step directions on writing a simple KMDF-based USB client driver, see How to write your first USB
client driver (KMDF).

Creating a USB device object


To use the framework's USB I/O target objects (WDFUSBDEVICE, WDFUSBINTERFACE, and WDFUSBPIPE), your
client driver must first call WdfUsbTargetDeviceCreateWithParameters to create a USB device object.
Typically, a driver calls WdfUsbTargetDeviceCreateWithParameters from its EvtDevicePrepareHardware
callback function.
When the driver calls WdfUsbTargetDeviceCreateWithParameters , the framework creates a
WDFUSBDEVICE object and associates it with the FDO that represents the USB device. The method returns a
handle to the new framework USB device object that the USB client driver can then use to communicate with the
physical device.
After calling WdfUsbTargetDeviceCreateWithParameters , the driver can call
WdfUsbTargetDeviceGetDeviceDescriptor and WdfUsbTargetDeviceRetrieveConfigDescriptor to
obtain USB descriptors from the device. Those descriptors contain information about the device's first
configuration, its interface settings, and their defined endpoints. (The USB descriptors are defined in the official
USB specification.)

Configuring a USB Device


The WdfUsbTargetDeviceCreateWithParameters method also creates a framework USB interface object for
each USB interface that the device's first configuration contains.
After calling WdfUsbTargetDeviceCreateWithParameters , the client driver must call
WdfUsbTargetDeviceSelectConfig to select a configuration. This method creates framework interface objects
for each alternate setting of the interface in the selected configuration.
The method also creates pipe objects that represent endpoints defined in each alternate setting of each interface
of the selected configuration.
After you have selected a configuration, you can change alternate settings for the configuration's interfaces, if
necessary.
You can also call WdfUsbTargetDeviceSelectConfig to deconfigure a device.
For related information, see:
How to select a configuration for a USB device
How to select an alternate setting in a USB interface

Obtaining Device Information


After configuring a device, your client driver can call the following methods to obtain information about a USB
device:
WdfUsbTargetDeviceQuer yUsbCapability
Determines whether the host controller and USB driver stack support a specific capability. Before calling
WdfUsbTargetDeviceQuer yUsbCapability , a driver must call
WdfUsbTargetDeviceCreateWithParameters .
WdfUsbTargetDeviceGetIoTarget
Returns a handle to the I/O target object that is associated with a USB device. The driver can pass this handle to
WdfRequestSend or WdfIoTargetStop .
WdfUsbTargetDeviceRetrieveInformation
Retrieves version and capability information that is associated with a USB device.
WdfUsbTargetDeviceIsConnectedSynchronous (KMDF only)
Determines if the device is connected.
WdfUsbTargetDeviceRetrieveCurrentFrameNumber (KMDF only)
Retrieves the current USB frame number.

Getting USB Descriptors


To obtain the Unicode strings that are contained in a USB device's descriptors, the driver can call any of the
following methods:
WdfUsbTargetDeviceGetDeviceDescriptor
Obtains a device's USB device descriptor.
WdfUsbTargetDeviceRetrieveConfigDescriptor
Obtains a device's USB configuration descriptor, interface descriptors, and endpoint descriptors.
WdfUsbTargetDeviceQuer yString
Copies a Unicode string to a driver-supplied buffer.
WdfUsbTargetDeviceAllocAndQuer yString
Copies a Unicode string to a framework-supplied buffer.
WdfUsbTargetDeviceFormatRequestForString
Formats a request for a Unicode string. The driver can call WdfRequestSend to send the request
synchronously or asynchronously.

Sending a Control Transfer


Your driver can call the following methods to send an I/O request that describes a standard, device class-specific,
or vendor-specific USB control transfer.
WdfUsbTargetDeviceSendControlTransferSynchronously
Synchronously sends a USB control transfer request.
WdfUsbTargetDeviceFormatRequestForControlTransfer
Formats a request for a USB control transfer. The driver can call WdfRequestSend to send the request
synchronously or asynchronously.
For related information, see How to send a USB control transfer.

Resetting and Power-Cycling a Device's Port


Your driver can call the following methods to reset or power-cycle the USB port that a device is connected to:
WdfUsbTargetDeviceResetPor tSynchronously
Synchronously sends a request to reset a device's USB port.
WdfUsbTargetDeviceCyclePor tSynchronously (KMDF only)
Synchronously sends a request to power-cycle a device's USB port.
WdfUsbTargetDeviceFormatRequestForCyclePor t (KMDF only)
Formats a request to power-cycle a device's USB port. The driver must call WdfRequestSend to send the
request synchronously or asynchronously.
For related information, see How to recover from USB pipe errors.

Sending an URB to a Device


If your KMDF driver communicates with its USB device by sending I/O requests that contain URBs, the driver can
call the following methods:
WdfUsbTargetDeviceCreateUrb (KMDF only)
Allocates a USB request block (URB). Before calling WdfUsbTargetDeviceCreateUrb , a driver must call
WdfUsbTargetDeviceCreateWithParameters .
WdfUsbTargetDeviceCreateIsochUrb (KMDF only)
Allocates an isochronous USB request block (URB). Before calling WdfUsbTargetDeviceCreateIsochUrb , a
driver must call WdfUsbTargetDeviceCreateWithParameters .
WdfUsbTargetDeviceSendUrbSynchronously (KMDF only)
Synchronously sends an I/O request that contains an URB.
WdfUsbTargetDeviceFormatRequestForUrb (KMDF only)
Formats an I/O request that contains a URB. The driver must call WdfRequestSend to send the request
synchronously or asynchronously.
WdfUsbTargetDeviceWdmGetConfigurationHandle (KMDF only)
Returns a device's USBD configuration handle. Some URBs require this handle.
For general conceptual background on URBs, see Allocating and Building URBs.
Working with USB Interfaces
2/5/2021 • 2 minutes to read • Edit Online

The framework represents each USB interface as a framework USB interface object. When a driver creates a
framework USB device object, the framework creates a framework USB interface object for each USB interface
that the device's first USB configuration contains.
Most USB devices have only one interface, and the interface has only one alternate setting. Drivers for such
devices typically do not need to use the object methods that the framework's USB interface object defines.
If your driver supports USB devices that provide multiple interfaces or alternate settings, interface object
methods enable the driver to perform the following operations:
Obtain interface information.
Select an alternate setting for a USB interface.
Obtaining Interface Information
After your driver has called WdfUsbTargetDeviceCreateWithParameters , it can call
WdfUsbTargetDeviceGetInterface to obtain a handle to a framework USB interface object that represents
one of the device's USB interfaces. Then your driver can call several methods that the USB interface object
defines for obtaining information about the USB interface.
Your driver can call the following methods anytime after it has called
WdfUsbTargetDeviceCreateWithParameters :
WdfUsbInterfaceGetInterfaceNumber
Returns the USB interface number that is associated with a USB interface object.
WdfUsbInterfaceGetDescriptor
Retrieves that USB interface descriptor that is associated with one of the alternate settings of a USB interface.
WdfUsbInterfaceGetNumEndpoints
Returns the number of endpoints that are associated with one of the alternate settings of a USB interface.
WdfUsbInterfaceGetEndpointInformation
Retrieves information about an endpoint and its associated pipe.
Your driver can call the following methods after it has called WdfUsbTargetDeviceSelectConfig :
WdfUsbInterfaceGetConfiguredSettingIndex
Returns an index value that identifies the alternate setting that is currently selected for a USB interface.
WdfUsbInterfaceGetNumConfiguredPipes
Returns the number of pipes that are configured for a specified USB device interface.
WdfUsbInterfaceGetConfiguredPipe
Returns a handle to the framework pipe object that is associated with a specified USB device interface and pipe
index.
Selecting an Alternate Setting for a USB Interface
After a driver has called WdfUsbTargetDeviceCreateWithParameters , the driver can call
WdfUsbInterfaceGetNumSettings to obtain the number of alternate settings that a USB interface supports.
After a driver has called WdfUsbTargetDeviceSelectConfig to select a configuration for a USB device, the
driver can call WdfUsbInterfaceSelectSetting to select an alternate setting for one of the configuration's USB
interfaces.
The device's alternate settings must be numbered contiguously, starting with zero.
For related information, see How to select an alternate setting in a USB interface.
Working with USB Pipes
2/5/2021 • 5 minutes to read • Edit Online

The framework represents each pipe in a USB interface as a framework USB pipe object. When a driver
configures a USB device, the framework creates a framework USB pipe object for each pipe in each selected
interface. Pipe object methods enable a driver to perform the following operations:
Obtain pipe information.
Read from a pipe.
Write to a pipe.
Stop or reset a pipe.
Send a URB to a pipe.
Obtaining Pipe Information
After calling WdfUsbInterfaceGetConfiguredPipe to obtain a handle to a framework USB pipe object, your
driver can call the following methods that the USB pipe object defines for obtaining information about the USB
pipe:
WdfUsbTargetPipeGetIoTarget
Returns a handle to the I/O target object that is associated with a USB pipe. The driver can pass this handle to
WdfRequestSend .
WdfUsbTargetPipeGetInformation
Retrieves information about a USB pipe and its endpoint.
WdfUsbTargetPipeGetType
Returns the type of a USB pipe.
WdfUsbTargetPipeIsInEndpoint
Determines whether a USB pipe is connected to an input endpoint.
WdfUsbTargetPipeIsOutEndpoint
Determines whether a USB pipe is connected to an output endpoint.
WDF_USB_PIPE_DIRECTION_IN
Determines whether a USB endpoint is an input endpoint.
WDF_USB_PIPE_DIRECTION_OUT
Determines whether a USB endpoint is an output endpoint.
For related information, see How to enumerate USB pipes.
Reading from a Pipe
To read data from a USB input pipe, your driver can use any (or all) of the following three techniques:
Read data synchronously
To read data synchronously from a USB input pipe, your driver can call the
WdfUsbTargetPipeReadSynchronously method. This method builds and sends a read request, and it
returns after the I/O operation has completed.
Read data asynchronously
To read data asynchronously from a USB input pipe, your driver can call the
WdfUsbTargetPipeFormatRequestForRead method to build a read request. Then the driver can call
WdfRequestSend to send the request asynchronously (or synchronously).
Read data asynchronously and continuously
A continuous reader is a framework-supplied mechanism for ensuring that a read request is always
available to a USB pipe. This mechanism guarantees that the driver will always be ready to receive data
from a device that provides an asynchronous, unsolicited input stream. For example, a driver for a
network interface card (NIC) might use a continuous reader to receive input data.
To configure a continuous reader for an input pipe, the driver's EvtDevicePrepareHardware callback
function must call the WdfUsbTargetPipeConfigContinuousReader method. This method queues a
set of read requests to the device's I/O target.
Also, the driver's EvtDeviceD0Entry callback function must call WdfIoTargetStar t to start the continuous
reader and the driver's EvtDeviceD0Exit callback function must call WdfIoTargetStop to stop the
continuous reader.
Each time that data is available from the device, the I/O target will complete a read request and the
framework will call one of two callback functions: EvtUsbTargetPipeReadComplete, if the I/O target
successfully read the data, or EvtUsbTargetPipeReadersFailed, if the I/O target reports an error.
If you do not supply the optional EvtUsbTargetPipeReadersFailed callback, the framework responds to a
failed read attempt by sending another read request. Therefore if the bus is in a state where it is not
accepting reads, the framework continually sends new requests to recover from a failed read.
After a driver has called WdfUsbTargetPipeConfigContinuousReader , the driver cannot use
WdfUsbTargetPipeReadSynchronously or WdfRequestSend to send I/O requests to the pipe unless
the driver's EvtUsbTargetPipeReadersFailed callback function is called and returns FALSE .
By default, the framework reports an error if your driver specifies a read buffer that is not a multiple of the
pipe's maximum packet size. Your driver can call WdfUsbTargetPipeSetNoMaximumPacketSizeCheck to
disable this test of read buffer sizes.
For related information, see:
How to send USB bulk transfer requests
How to transfer data to USB isochronous endpoints
How to use the continuous reader for reading data from a USB pipe
Writing to a Pipe
To write data to a USB output pipe, your driver can use one (or both) of the following techniques:
Write data synchronously
To write data synchronously to a USB output pipe, your driver can call the
WdfUsbTargetPipeWriteSynchronously method. This method builds and sends a write request, and it
returns after the I/O operation has completed.
Write data asynchronously
To write data asynchronously to a USB input pipe, your driver can call the
WdfUsbTargetPipeFormatRequestForWrite method to build a write request. Then the driver can call
WdfRequestSend to send the request asynchronously.
For related information, see How to send USB bulk transfer requests.
Stopping and Resetting a Pipe
Your driver can call the following methods to stop or reset a USB pipe:
WdfUsbTargetPipeAbor tSynchronously
Synchronously sends a request to stop a USB pipe.
WdfUsbTargetPipeFormatRequestForAbor t
Formats a request to stop a USB pipe. The driver can call WdfRequestSend to send the request synchronously
or asynchronously.
WdfUsbTargetPipeResetSynchronously
Synchronously sends a request to reset a USB pipe.
WdfUsbTargetPipeFormatRequestForReset
Formats a request to reset a USB pipe. The driver must call WdfRequestSend to send the request
synchronously or asynchronously.
If your driver's USB target completes an I/O request with an error status value, your driver should do the
following:
1. Stop the pipe, and cancel any additional I/O requests that the driver has sent to the USB target, if the
target has not completed the requests.
Call WdfIoTargetStop with the WdfIoTargetCancelSentIo flag set.
2. Synchronously send an abort request to the pipe.
Call WdfUsbTargetPipeAbor tSynchronously , or call WdfUsbTargetPipeFormatRequestForAbor t
followed by WdfRequestSend with the WDF_REQUEST_SEND_OPTION_SYNCHRONOUS flag set.
3. Synchronously send a reset request to the pipe.
Call WdfUsbTargetPipeResetSynchronously , or call WdfUsbTargetPipeFormatRequestForReset
followed by WdfRequestSend with the WDF_REQUEST_SEND_OPTION_SYNCHRONOUS flag set.
4. Restart the pipe.
Call WdfIoTargetStar t .
5. Resend the I/O request that failed, and all I/O requests that followed the failed request.
After a significant number of multiple failures, the driver should attempt to reset the USB port by doing the
following:
1. Stop all active pipes, and cancel any additional I/O requests that the driver has sent to each pipe's USB
target, if the target has not completed them.
For each active pipe, call WdfIoTargetStop with the WdfIoTargetCancelSentIo flag set.
2. Synchronously send a request to reset the USB port.
Call WdfUsbTargetDeviceResetPor tSynchronously .
3. Restart the pipes.
Call WdfIoTargetStar t for each pipe that the driver stopped.
4. Resend the last I/O request that failed, and all I/O requests that followed the failed request.
For related information, see How to recover from USB pipe errors.
Sending an URB to a Pipe
If your KMDF driver communicates with a USB pipe by sending I/O requests that contain URBs, the driver can
call the following methods:
WdfUsbTargetPipeSendUrbSynchronously (KMDF only)
Synchronously sends an I/O request that contains a URB.
WdfUsbTargetPipeFormatRequestForUrb (KMDF only)
Formats an I/O request that contains a URB. The driver can call WdfRequestSend to send the request
synchronously or asynchronously.
WdfUsbTargetPipeWdmGetPipeHandle (KMDF only)
Returns a device's USBD pipe handle. Some URBs require this handle.
Introduction to Framework Objects
2/5/2021 • 2 minutes to read • Edit Online

The interfaces that Windows Driver Frameworks (WDF) provides to drivers are object-based. The framework
defines several objects. These objects export methods (functions) and properties (data) that drivers can access.
Framework objects also initiate events, which drivers can support by providing event callback functions.
Framework-based drivers never directly access framework objects. Instead, drivers reference the objects by
handles, which the driver passes as input to object methods.
All framework objects have the following characteristics:
Reference count
The framework maintains a count of the number of references to each object. When the framework creates an
object, it sets the object's reference count to one. When the framework has finished using an object, it
decrements the reference count. The framework cannot delete the object until the reference count is
decremented to zero, so drivers can prevent the deletion of an object by incrementing its reference count.
Context space
Framework-based drivers can create object-specific context space for every framework object that the driver
receives or creates. Drivers should store all object-specific data in an object's context space. For more
information about context space, see Framework Object Context Space.
Deletion callback functions
Drivers can register callback functions that the framework calls when it is deleting an object. The callback
functions can remove driver-assigned resources, such as object-specific memory allocations. For more
information about these callback functions, see Framework Object Life Cycle.
Parent object
All framework objects can have a parent object. The framework designates a default parent object for most
objects. When a driver creates an object, it can designate a parent object that overrides the object's default
parent object. To designate an object's parent object, drivers set the ParentObject member of the object's
WDF_OBJECT_ATTRIBUTES structure. (For a few object types, drivers cannot override the default parent
object.) When the framework or a driver deletes a parent object, the framework also deletes the parent object's
children.
For an overview of all of the objects that are defined by WDF, see Summary of Framework Objects.
Framework Object Methods
2/5/2021 • 2 minutes to read • Edit Online

Each framework object exports a set of methods (functions). Each method serves one of two purposes:
It performs an action that is associated with the object.
For example, the WdfIoQueueCreate method creates an I/O queue for a device.
Methods that perform an action typically return an NTSTATUS value.
It retrieves or modifies a property that is associated with the object.
For example, the WdfRequestGetInformation method returns information about an I/O request's
completion status.
Methods that retrieve a property typically return the property's value, while methods that modify a
property typically do not return a value.
Each object method accepts an object handle as input. If a driver passes an invalid object handle to an object
method, a system bug check occurs.
Framework Object Events
2/5/2021 • 2 minutes to read • Edit Online

Some framework objects can generate events. Framework-based drivers can register to receive notification of
all, some, or none of an object's events. To register for an event, the driver provides an event callback function.
The framework calls the callback function when the event occurs.
For example, a driver can register an EvtIoDefault callback function for an I/O queue. The framework will call this
callback function each time the framework is ready to remove an I/O request from the I/O queue and deliver it
to the driver.
Framework Object Properties
2/5/2021 • 2 minutes to read • Edit Online

Most framework objects contain sets of properties. Properties represent information that is available to a driver.
From the driver's perspective, some properties are read-only and some are read/write.
For each readable property, the framework defines a "get" method that a driver can call to retrieve the
property's value. Each "get" method returns the current value of the property.
For each writable property, the framework defines a "set" method that a driver can call to modify the property's
value. The driver supplies the property's new value as an input parameter to the "set" method.
For example, the framework device object defines two methods, WdfDeviceGetDeviceState and
WdfDeviceSetDeviceState , that a driver can call to get or set a device's Plug and Play (PnP) state.
Framework Object Life Cycle
2/5/2021 • 2 minutes to read • Edit Online

A framework object's "life cycle" spans the time from when an object is created to when it is deleted. An object's
reference count controls when it will be deleted.
Creating a Framework Object
Most framework objects are created by a driver's call to the object's creation method. For example, each
framework driver must call WdfDriverCreate to create a framework driver object.
Other framework objects are created by the framework. For example, when a user application opens a device for
read or write operations, the framework creates a framework file object and passes it to the driver's
EvtDeviceFileCreate callback function.
A few framework objects can be created by either the framework or by a driver. For example, when the I/O
manager delivers an I/O request to a driver, the framework creates a framework request object and delivers it to
the driver, typically by calling one of the driver's request handlers. A driver can also create framework request
objects and deliver them to other drivers.
Using Reference Counts
The framework maintains a reference count for each object. When an object is created, the framework sets its
reference count to one. If the reference count becomes zero, the framework deletes the object.
Drivers can modify an object's reference count by calling WdfObjectReference to increment the reference
count or WdfObjectDereference to decrement the reference count. (A driver can call
WdfObjectDereference only if it has previously called WdfObjectReference .)
In most cases, drivers do not have to increment or decrement an object's reference count. The framework
increments the count before it passes the object's handle to the driver, and it decrements the count when the
driver no longer needs the object.
Drivers call WdfObjectReference to ensure that an object will not be deleted (by the framework or by a driver
thread) before the driver has finished using it. For an example situation in which a driver should call
WdfObjectReference and WdfObjectDereference , see Synchronizing Cancellation of Sent Requests.
Deleting a Framework Object
Objects are deleted either because a driver calls WdfObjectDelete or because the framework calls an internal
deletion routine, but an object is deleted only if its reference count is zero. After the driver or the framework has
attempted to delete an object, the object's handle remains valid until after the reference count becomes zero. A
driver cannot delete an object by simply calling WdfObjectDereference to decrement the object's reference
count to zero--the driver must also call WdfObjectDelete .
If a framework object is the child object of a parent and the parent is being deleted, the framework attempts to
delete the child object before it deletes the parent. Object deletion starts from the object farthest from the
parent and works up the object hierarchy toward the root.
Drivers can register the following two callback functions that the framework calls when the driver or the
framework is deleting an object:
An EvtCleanupCallback callback function, which the framework calls so that the driver can call
WdfObjectDereference if it had previously called WdfObjectReference for the object that is being
deleted.
An EvtDestroyCallback callback function, which the framework calls after the object's reference count has
been decremented to zero.
One of these callback functions must deallocate any object-specific resources that the driver allocated when the
object was created.
The framework always handles the deletion of some framework objects, and drivers must not attempt to delete
these objects. For a list of framework objects that drivers cannot delete, see WdfObjectDelete .
Framework Object Context Space
2/5/2021 • 3 minutes to read • Edit Online

Object context space is extra, nonpageable, memory space that a driver can allocate and assign to an object.
Each framework-based driver can create one or more object-specific context spaces for every framework object
that the driver receives or creates.
Framework-based drivers should store all object-specific data, either by value or by pointer, within the context
space of the object to which the data belongs.
For example, a driver for USB devices might create context space for its framework device objects. In the context
space, the driver might store such device-specific information as the device's USB_DEVICE_DESCRIPTOR and
USB_CONFIGURATION_DESCRIPTOR structures, plus a handle to a collection object that represents a device
interface's pipes.
The framework does not pass framework objects from one driver to another, so you cannot use an object's
context space to pass data between two drivers.
To define an object's context space, you must create one or more structures. Each structure represents a separate
context space. Your driver will use each structure member to store a piece of object-specific information.
Additionally, your driver must ask the framework to generate an accessor method for each structure. This
accessor method accepts an object handle as input and returns the address of the object's context space.
Whenever your driver calls an object creation method, such as WdfDeviceCreate , the method optionally
allocates context space. All object creation methods accept an optional WDF_OBJECT_ATTRIBUTES structure
as input. This structure describes the context space that you want the framework to allocate for the object.
To add additional context space to an object after the driver has called the object's creation method, the driver
can call the WdfObjectAllocateContext method--which, like the object creation methods, accepts a
WDF_OBJECT_ATTRIBUTES structure as input.
When the framework allocates context space for an object, it also zero-initializes the context space.
When either the framework or a driver deletes a framework object, the framework deletes all of the object's
context space.
If your driver uses context space to store pointers to buffers that the driver allocates when it creates an object,
the driver should provide an EvtCleanupCallback function that deallocates the buffers when the object is deleted.
To define an object's context space structure and accessor method for the objects that your driver creates, your
driver must use the following steps:
1. Define a structure that describes the data that you want to store. For example, if you want to create
context data for your driver's device objects, your driver might define a structure called
MY_DEVICE_CONTEXT.
2. Use either the WDF_DECL ARE_CONTEXT_TYPE macro or the
WDF_DECL ARE_CONTEXT_TYPE_WITH_NAME macro. Both of these macros do the following:
Create and initialize a WDF_OBJECT_CONTEXT_TYPE_INFO structure.
Define an accessor method that your driver will later use to access an object's context space. The
accessor method's return value is a pointer to the object's context space.
The WDF_DECLARE_CONTEXT_TYPE macro creates the accessor method's name from your structure's
name. For example, if your context structure's name is MY_DEVICE_CONTEXT, the macro creates an
accessor method that is named WdfObjectGet_MY_DEVICE_CONTEXT .
The WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro lets you specify the accessor method's name.
For example, you might specify GetMyDeviceContext as the name for your context accessor method
for device objects.
3. Call WDF_OBJECT_ATTRIBUTES_INIT to initialize the object's WDF_OBJECT_ATTRIBUTES structure.
4. Use the WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE macro to set the ContextTypeInfo
member of the WDF_OBJECT_ATTRIBUTES structure to the address of the
WDF_OBJECT_CONTEXT_TYPE_INFO structure.
5. Call an object creation method, such as WdfDeviceCreate .
After your driver has created an object, the driver can call WdfObjectAllocateContext at any time to add
additional context space to the object.
Because steps 1 and 2 define global data structures and create a driver-callable routine, your driver must
complete these steps in an area of the driver that declares global data--typically a header file. These steps must
not be completed from within your driver's routines.
Your driver must complete steps 3, 4, and 5 from within a driver routine that creates an object, such as an
EvtDriverDeviceAdd callback function that calls WdfDeviceCreate .
The framework can create two types of objects -- framework request objects and framework file objects -- on
behalf of your driver. Your driver can register context space for these objects by calling
WdfDeviceInitSetRequestAttributes and WdfDeviceInitSetFileObjectConfig , respectively. Your driver can
also call WdfObjectAllocateContext to allocate context space for these objects.
After an object has been created, the driver can obtain a pointer to the object's context space by using either of
the following techniques:
Call the context accessor method that you created in step 2 in the preceding procedure by using either
the WDF_DECL ARE_CONTEXT_TYPE or the WDF_DECL ARE_CONTEXT_TYPE_WITH_NAME macro.
Call WdfObjectGetTypedContext , supplying the name of your driver-defined context structure.
If your driver has a context space pointer, it can find the object that the context space belongs to by calling
WdfObjectContextGetObject .
Framework Object Custom Types
2/5/2021 • 2 minutes to read • Edit Online

Starting in KMDF version 1.11, the framework supports custom type names. A custom type name is a string that
driver can associate with a WDFOBJECT instance. Drivers define their own custom type names. The driver
specifies a custom type name for an object after the driver has called the object's creation method.
Use these macros to manipulate custom type names:
To define a custom type name, call WDF_DECL ARE_CUSTOM_TYPE from an area of the driver that
declares global data, such as a header file.
Call WdfObjectAddCustomType or WdfObjectAddCustomTypeWithData to associate a custom type
with a framework object.
Call WdfObjectIsCustomType to determine whether a specified object is of a specified custom type.
After calling WdfObjectAddCustomTypeWithData , the driver can later call
WdfObjectGetCustomTypeData to retrieve the data.
A driver can associate multiple custom types with a single framework object. A driver can also associate multiple
framework objects with a single custom type.
In output from KMDF debugger extensions, custom type names are displayed along with other WDF object
information.

WDF_Object_Name, [custom_Type1_Name, custom_Type2_Name]


Using General Framework Objects
2/5/2021 • 2 minutes to read • Edit Online

The general framework object is the framework object from which all other types of framework objects are
derived.
Like other framework objects, general objects support a reference count, context space, deletion callback
functions, and a parent object, as described in Introduction to Framework Objects.
Drivers can create and use general framework objects. If your driver calls WdfObjectCreate to create general
objects, the driver can:
Create one or more context spaces for each general object.
You can use object context space to store information about system resources that you want to associate
with the general object.
For more information about context space, see Framework Object Context Space.
Assign a parent to the general object.
The general object will be deleted when the parent object is deleted. For example, if your driver specifies a
framework device object as the parent object of one of its general objects, the framework will delete the
general object when it deletes the device object.
Drivers specify an object's parent object by setting the ParentObject member of the object's
WDF_OBJECT_ATTRIBUTES structure.
Provide deletion callback functions.
The driver can provide EvtCleanupCallback and EvtDestroyCallback functions, which can deallocate
system resources that the driver allocated when it created the general object. For example, if the driver
called ExAllocatePool when it created a general object, the cleanup or destroy callback function can call
ExFreePool .
Using general objects can be a convenient way to manage driver-allocated resources. For example, a higher-
level driver might require multiple memory allocations to process a received I/O request, if the driver sends the
request to multiple devices or breaks the request into several smaller ones. The driver can create one or more
general objects that are children of the received I/O request, and it can store information about the memory
allocations in the general objects' context space.
Framework Object Collections
2/5/2021 • 3 minutes to read • Edit Online

Drivers can group framework objects into collections that are represented by framework collection objects.
For example, if a driver receives a framework request object that represents a large I/O request, the driver might
have to break the large request into smaller requests that it can send to an I/O target. To break a large request
into smaller ones, the driver must create a set of request objects that represent the smaller requests. To keep
track of these driver-created request objects, the driver might create a collection object and add them to the
collection.
Typically, the objects in an object collection consist of a single type of framework object, but a driver can create a
collection that consists of different types of objects.
Your driver can also create a collection of collections. That is, a collection can consist of a set of collection objects.
Framework-based drivers can perform the following operations on object collections:
Create a collection object.
To create a new collection, drivers can call WdfCollectionCreate .
Add an object to a collection.
To add objects to a collection, drivers can call WdfCollectionAdd , one or more times. Each call to
WdfCollectionAdd appends an object to the end of the collection and increments the appended object's
reference count.
Remove an object from a collection.
To remove an object from a collection and decrement its reference count, drivers can call
WdfCollectionRemove or WdfCollectionRemoveItem . When an object is removed, all objects after
the removed one will have their index automatically decremented.
Obtain the number of objects in a collection.
To determine the number of objects that a collection contains, drivers can call WdfCollectionGetCount .
Obtain a handle to an object in the collection.
If a driver calls WdfCollectionGetItem , supplying an index value as an input argument, the driver
receives a handle to the object that is associated with the index value. (An index value of zero represents
the first object in the collection, an index value of one represents the second object, and so on--like a
linked list. When the driver removes item i from a collection, item i+1 becomes item i.)
Drivers can also call WdfCollectionGetFirstItem or WdfCollectionGetLastItem to obtain a handle to
the first or last item that was added to the collection.
Lock a collection.
A driver can call WdfWaitLockAcquire to synchronize access to a collection at IRQL = PASSIVE_LEVEL,
or it can call WdfSpinLockAcquire synchronize access at IRQL = DISPATCH_LEVEL. After a driver
acquires a lock, the collection cannot be accessed by other code in the driver that also calls
WdfWaitLockAcquire or WdfSpinLockAcquire . After completing an operation on the collection, the
driver must call WdfWaitLockRelease .
Calling WdfWaitLockAcquire or WdfSpinLockAcquire does not prevent other code in the driver from
simultaneously accessing the collection, if that other code does not also call WdfWaitLockAcquire or
WdfSpinLockAcquire .
Delete a collection.
To delete a collection object, drivers can call WdfObjectDelete . More typically, however, drivers specify a
parent object when they create a collection, and the framework deletes the collection object when it
deletes the parent object.
For example, if a driver creates a set of request objects so that it can break a large I/O request into smaller
requests, it can make the large I/O request's request object the parent object of the collection object.
Eventually the driver's I/O target will call WdfRequestComplete to complete the smaller requests. At
that point, the driver can call WdfRequestComplete for the large I/O request, causing the framework to
delete the request object and its child object: the collection object.
When the framework deletes a collection object that contains objects that have not been removed, the
framework removes the objects from the collection and decrements their reference counts, but it deletes
only the collection object.
Sometimes a driver must examine all of the objects within a collection. The following code example
demonstrates this situation:

WdfWaitLockAcquire(CollectionLockHandle, NULL);
ItemCount = WdfCollectionGetCount(CollectionHandle);
for (i=0; i<ItemCount; i++) {
ObjectHandle = WdfCollectionGetItem(CollectionHandle, i);
// 1. Call object-specific methods to obtain object properties.
// 2. Perform object-specific operations.
}
WdfWaitLockRelease(CollectionLockHandle);
Summary of Framework Objects
2/5/2021 • 2 minutes to read • Edit Online

The following table lists all of the framework objects and provides some basic information about each object.
The mode column indicates whether the object can be used in KMDF and UMDF drivers, or KMDF only.
For a list of callbacks and methods and which frameworks are applicable, see Summary of WDF Callbacks and
Methods.

C A N DRIVER
O VERRIDE
DEFA ULT DEFA ULT
NAME H A N DL E P URP O SE PA REN T PA REN T ? M O DE REF EREN C E

Child-list WDFCHILDLI Represents a Device object No KM WDF Child-


object ST list of child List Object
devices that Reference
are connected
to a parent
device.

Collection WDFCOLLEC Represents an Driver object Yes KM/UM WDF


object TION object Collection
collection. Object
Reference

Common WDFCOMM Represents a DMA enabler No KM WDF


buffer object ONBUFFER common object Common
buffer. Buffer Object
Reference

Device object WDFDEVICE Represents a Driver object No KM/UM WDF Device


device. Object
Reference

DMA enabler WDFDMAEN Enables a Device object Yes KM WDF DMA


object ABLER driver to use Object
the Reference
framework's
DMA
capabilities.

DMA WDFDMATRA Represents a DMA enabler No KM WDF DMA


transaction NSACTION DMA object Object
object transaction. Reference

DPC object WDFDPC Represents a None Yes KM WDF DPC


deferred Object
procedure Reference
call.

Driver object WDFDRIVER Represents a None No KM/UM WDF Driver


driver. Object
Reference
C A N DRIVER
O VERRIDE
DEFA ULT DEFA ULT
NAME H A N DL E P URP O SE PA REN T PA REN T ? M O DE REF EREN C E

File object WDFFILEOBJE Represents a Device object No KM/UM WDF File


CT file. Object
Reference

General WDFOBJECT Represents a Driver object Yes KM/UM WDF General


object general Object
object. Reference

Interrupt WDFINTERRU Represents a Device object Yes KM/UM WDF


object PT hardware Interrupt
interrupt Object
resource. Reference

I/O target WDFIOTARGE Represents a Device object Yes KM/UM WDF I/O
object T driver to Target Object
which Reference
another
driver sends
I/O requests.

Lookaside-list WDFLOOKASI Represents a Driver object Yes KM WDF Memory


object DE lookaside list. Object
Reference

Memory WDFMEMOR Represents a Driver object Yes KM/UM WDF Memory


object Y memory Object
buffer. Reference

Queue object WDFQUEUE Represents an Device object Yes KM/UM WDF Queue
I/O queue Object
that receives Reference
I/O requests.

Registry key WDFKEY Represents a Driver object Yes KM/UM WDF Registry
object registry key. Key Object
Reference

Request WDFREQUES Represents an None, if Yes, if created KM/UM WDF Request


object T I/O request. created by by driver. Object
framework. Reference
Driver object,
if created by
driver.

Resource list WDFCMRESLI Represents a Driver object No KM/UM WDF


object ST resource list. Resource
Object
Reference

Resource WDFIORESLIS Represents a Resource No KM WDF


range list T logical requirements Resource
object configuration. list object Object
Reference
C A N DRIVER
O VERRIDE
DEFA ULT DEFA ULT
NAME H A N DL E P URP O SE PA REN T PA REN T ? M O DE REF EREN C E

Resource WDFIORESRE Represents a Driver object No KM WDF


requirements QLIST resource Resource
list object requirements Object
list. Reference

Spin-lock WDFSPINLOC Represents a Driver object Yes KM/UM WDF


object K spin lock. Synchronizati
on Methods

String object WDFSTRING Represents a Driver object Yes KM/UM WDF String
Unicode Object
string. Reference

Timer object WDFTIMER Represents a None Yes KM/UM WDF Timer


timer. Object
Reference

USB device WDFUSBDEVI Represents a Device object No KM/UM WDF USB


object CE device Reference
connected to
a USB.

USB interface WDFUSBINTE Represents a USB device No KM/UM WDF USB


object RFACE USB device object Reference
interface.

USB pipe WDFUSBPIPE Represents a USB interface No KM/UM WDF USB


object USB device object Reference
pipe.

Wait-lock WDFWAITLO Represents a Driver object Yes KM/UM WDF


object CK wait lock. Synchronizati
on Methods

WMI instance WDFWMIINS Represents an WMI provider No KM WDF WMI


object TANCE instance of a object Reference
WMI data
block.

WMI provider WDFWMIPR Represents a Device object No KM WDF WMI


object OVIDER WMI data Reference
block.

Work-item WDFWORKIT Represents a None Yes KM/UM WDF Work-


object EM work item. Item Object
Reference
Using Memory Buffers
2/5/2021 • 3 minutes to read • Edit Online

Drivers typically use memory buffers to pass data to and from the framework and other drivers or to store
information locally. This topic describes framework memory objects, lookaside lists, MDLs, and local buffers.
Using Framework Memory Objects
The framework uses memory objects to describe the memory buffers that a driver receives from and passes to
the framework. Each framework memory object represents one buffer.
To create a memory object, your driver calls one of the following object methods:
WdfMemor yCreate , which creates a memory object and allocates a memory buffer of a specified size.
WdfMemor yCreatePreallocated , which creates a memory object for a preallocated buffer.
WdfMemor yCreateFromLookaside , which creates a memory buffer from a lookaside list.
To obtain a memory object that represents a received I/O request's buffers, your driver calls
WdfRequestRetrieveInputMemor y and WdfRequestRetrieveOutputMemor y . For more information
about retrieving an I/O request's buffers, see Accessing Data Buffers in Framework-Based Drivers.
To obtain the address and size of a memory object's buffer, your driver calls WdfMemor yGetBuffer .
To move data into or out of a memory object's buffer, your driver calls either WdfMemor yCopyFromBuffer or
WdfMemor yCopyToBuffer . These object methods check the source and destination sizes and prevent buffer
overrun errors.
If your driver creates a memory object by calling WdfMemor yCreatePreallocated , it can subsequently assign
a different buffer to the memory object by calling WdfMemor yAssignBuffer .
When a driver sends an I/O request to an I/O target, it typically passes an input or output buffer to a framework
I/O target object method. The driver specifies the buffer by either passing a WDF_MEMORY_DESCRIPTOR
structure that describes the buffer or by passing a memory object handle. (I/O target object methods that send
I/O requests synchronously require a WDF_MEMORY_DESCRIPTOR structure, and methods that send I/O
requests asynchronously require a memory object handle.)
For information about when a memory buffer is valid, see Memory Buffer Life Cycle.
Using Lookaside Lists
If your driver will require many buffers of approximately the same size, it should allocate them from a lookaside
list. The driver creates a lookaside list by calling WdfLookasideListCreate . Subsequently, the driver can obtain
buffers from the lookaside list by calling WdfMemor yCreateFromLookaside .
Each time the driver calls WdfMemor yCreateFromLookaside , the framework creates a memory object,
obtains a buffer from the lookaside list, and assigns the buffer to the object. When the driver has finished using
one of these memory objects it calls WdfObjectDelete , which deletes the memory object and returns the
buffer space to the lookaside list.
The operating system manages the memory resources that are assigned to the lookaside list. If the driver
requests a buffer from the lookaside list when none are available, such as the first time that the driver calls
WdfMemor yCreateFromLookaside , the system allocates a buffer and assigns it to the list. When the driver
calls WdfObjectDelete (and the buffer space is returned to the lookaside list), the system keeps the now
unassigned buffer in the list until the driver needs it again. The system increases the list's size as necessary; for
example, drivers that more frequently request buffers receive larger lookaside lists. On the other hand, the
system might reduce the number of buffers in the list if the driver is not using them all.
Using MDLs
Some drivers use memory descriptor lists (MDLs) to describe buffers. For example, a driver for a direct memory
access (DMA) device must pass a MDL to the WdfDmaTransactionInitialize method, if it calls that method.
A driver that uses MDLs can obtain an MDL that represents a received I/O request's buffers by calling
WdfRequestRetrieveInputWdmMdl and WdfRequestRetrieveOutputWdmMdl .
Most framework-based drivers do not use MDLs.
Allocating Local Buffers
A driver that requires local, internal buffer space that it will not pass to the framework does not have to create
memory objects to represent the buffers. The driver can call ExAllocatePoolWithTag to allocate internal
buffers. When the driver has finished using the buffer, it must call ExFreePoolWithTag .
However, drivers can also use memory objects for local buffers. An advantage to using memory buffers, instead
of calling ExAllocatePoolWithTag , is that the framework automatically deletes memory objects and their
buffers when each object's parent object is deleted.

IMPORTANT
The ExAllocatePool DDIs discussed in this topic have been deprecated in Windows 10, version 2004 and have been
replaced by ExAllocatePool2 and ExAllocatePool3. For more information, see Updating deprecated ExAllocatePool calls to
ExAllocatePool2 and ExAllocatePool3.

Aligning Buffers
Your driver can use the WDF_ALIGN_SIZE_UP or WDF_ALIGN_SIZE_DOWN function to calculate a buffer
size that is aligned to a specified alignment offset. This calculation is useful if your driver must allocate multiple
contiguous buffers, if each buffer must begin at an address alignment boundary.
Memory Buffer Life Cycle
2/5/2021 • 5 minutes to read • Edit Online

A memory buffer's life cycle spans the time from when the buffer is created to when it is deleted. This topic
describes buffer usage scenarios and how they affect when the buffer is deleted.
In the kernel-mode driver framework (KMDF), a request object represents an I/O request. Every request object is
associated with one or more memory objects, and each memory object represents a buffer that is used for input
or output in the request.
When the framework creates request and memory objects to represent an incoming I/O request, it sets the
request object as the parent of the associated memory objects. Therefore, the memory object can persist no
longer than the lifetime of the request object. When the framework-based driver completes the I/O request, the
framework deletes the request object and the memory object, so the handles to these two objects become
invalid.
However, the underlying buffer is different. Depending on which component created the buffer and how it
created the buffer, the buffer might have a reference count and might be owned by the memory object—or it
might not. If the memory object owns the buffer, then the buffer has a reference count and its lifetime is limited
to that of the memory object. If some other component created the buffer, then the lifetimes of the buffer and
the memory object are not related.
A framework-based driver can also create its own request objects to send to I/O targets. A driver-created request
can reuse an existing memory object that the driver received in an I/O request. A driver that frequently sends
requests to I/O targets can reuse the request objects that it creates.
Understanding the lifetimes of the request object, the memory object, and the underlying buffer is important to
ensure that your driver does not attempt to reference an invalid handle or buffer pointer.
Consider the following usage scenarios:
Scenario 1: Driver receives an I/O request from KMDF, handles it, and completes it.
Scenario 2: Driver receives an I/O request from KMDF and forwards it to an I/O target.
Scenario 3: Driver issues an I/O request that uses an existing memory object.
Scenario 4: Driver issues an I/O request that uses a new memory object.
Scenario 5: Driver reuses a request object that it created.

Scenario 1: Driver receives an I/O request from KMDF, handles it, and
completes it.
In the simplest scenario, KMDF dispatches a request to the driver, which performs I/O and completes the
request. In this case, the underlying buffer might have been created by a user-mode application, by another
driver, or by the operating system itself. For information about how to access buffers, see Accessing Data Buffers
in Framework-Based Drivers.
When the driver completes the request, the framework deletes the memory object. The buffer pointer is then
invalid.

Scenario 2: Driver receives an I/O request from KMDF and forwards it


to an I/O target.
In this scenario, the driver forwards the request to an I/O target. The following sample code shows how a driver
retrieves a handle to the memory object from an incoming request object, formats the request to send to the I/O
target, and sends the request:

VOID
EvtIoRead(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t Length
)
{
NTSTATUS status;
WDFMEMORY memory;
WDFIOTARGET ioTarget;
BOOLEAN ret;
ioTarget = WdfDeviceGetIoTarget(WdfIoQueueGetDevice(Queue));

status = WdfRequestRetrieveOutputMemory(Request, &memory);


if (!NT_SUCCESS(status)) {
goto End;
}

status = WdfIoTargetFormatRequestForRead(ioTarget,
Request,
memory,
NULL,
NULL);
if (!NT_SUCCESS(status)) {
goto End;
}

WdfRequestSetCompletionRoutine(Request,
RequestCompletionRoutine,
WDF_NO_CONTEXT);

ret = WdfRequestSend (Request, ioTarget, WDF_NO_SEND_OPTIONS);


if (!ret) {
status = WdfRequestGetStatus (Request);
goto End;
}

return;

End:
WdfRequestComplete(Request, status);
return;

When the I/O target has completed the request, the framework calls the completion callback that the driver set
for the request. The following code shows a simple completion callback:
VOID
RequestCompletionRoutine(
IN WDFREQUEST Request,
IN WDFIOTARGET Target,
PWDF_REQUEST_COMPLETION_PARAMS CompletionParams,
IN WDFCONTEXT Context
)
{
UNREFERENCED_PARAMETER(Target);
UNREFERENCED_PARAMETER(Context);

WdfRequestComplete(Request, CompletionParams->IoStatus.Status);

return;

When the driver calls WdfRequestComplete from its completion callback, the framework deletes the memory
object. The memory object handle that the driver retrieved is now invalid.

Scenario 3: Driver issues an I/O request that uses an existing memory


object.
Some drivers issue their own I/O requests and send them to I/O targets, which are represented by I/O target
objects. The driver can either create its own request object or reuse a framework-created request object. Using
either technique, a driver can reuse a memory object from a previous request. The driver must not change the
underlying buffer, but it can pass a buffer offset when it formats the new I/O request.
For information about how to format a new I/O request that uses an existing memory object, see Sending I/O
Requests to General I/O Targets.
When the framework formats the request to send to the I/O target, it takes out a reference on the recycled
memory object on behalf of the I/O target object. The I/O target object retains this reference until one of the
following actions occurs:
The request has been completed.
The driver reformats the request object again by calling one of the WdfIoTargetFormatRequestXxx or
WdfIoTargetSendXxxSynchronously methods. For more information about these methods, see Framework
I/O Target Object Methods.
The driver calls WdfRequestReuse .
When the new I/O request is complete, the framework calls the I/O completion callback that the driver set for
this request. At this point, the I/O target object still holds a reference on the memory object. Therefore, in the I/O
completion callback, the driver must call WdfRequestReuse on the driver-created request object before it
completes the original request from which it retrieved the memory object. If the driver does not call
WdfRequestReuse , a bug check occurs because of the extra reference.

Scenario 4: Driver issues an I/O request that uses a new memory


object.
The framework provides three ways for drivers to create new memory objects, depending on the source of the
underlying buffer. For more information, see Using Memory Buffers.
If the buffer is allocated by the framework or from a driver-created lookaside list, the memory object owns the
buffer, so the buffer pointer remains valid as long as the memory object exists. Drivers that issue asynchronous
I/O requests should always use buffers that are owned by memory objects so that the framework can ensure
that the buffers persist until the I/O request has completed back to the issuing driver.
If the driver assigns a previously allocated buffer to a new memory object by calling
WdfMemor yCreatePreallocated , the memory object does not own the buffer. In this case, the lifetime of the
memory object and the lifetime of the underlying buffer are not related. The driver must manage the lifetime of
the buffer and must not attempt to use an invalid buffer pointer.

Scenario 5: Driver reuses a request object that it created.


A driver can reuse the request objects that it creates, but it must reinitialize each such object by calling
WdfRequestReuse before each reuse. For more information, see Reusing Framework Request Objects.
For sample code that reinitializes a request object, see the Toaster and NdisEdge samples that are provided with
the KMDF release.
Using Timers
2/5/2021 • 4 minutes to read • Edit Online

This topic describes how to use the framework's built-in timer support. It applies to both Kernel-Mode Driver
Framework (KMDF) drivers as well as User-Mode Driver Framework (UMDF) drivers starting in version 2.
The framework provides a timer object that enables drivers to create timers. After a driver creates a timer object
and starts the timer's clock, the framework calls a driver-supplied callback function after a specified amount of
time has elapsed. Optionally, your driver can set up the timer so that the framework calls the callback function
repeatedly, whenever a specified amount of time has elapsed.
To create a framework timer object, your driver must call the WdfTimerCreate method. This method registers
an EvtTimerFunc callback function and a periodic time interval. If you want the framework to call the callback
function only once, your driver specifies zero for the periodic time interval.
Typically, you will know the number of timers that your driver will need for each device. Therefore, the driver can
create timer objects by calling WdfTimerCreate in its EvtDriverDeviceAdd callback function, and it can store
timer object handles in a device or queue object's context space.
To start the timer, your driver calls WdfTimerStar t , passing a "due time". The framework starts the timer's clock
and calls the EvtTimerFunc callback function when the specified amount of time has elapsed.
If the driver supplied a periodic time interval when it called WdfTimerCreate , the timer is referred to as a
periodic timer. A periodic timer's clock continues to run after the initial "due time" has elapsed, and the
framework calls the driver's callback function repeatedly, whenever the periodic time interval has elapsed.
Periodic timers do not start automatically. Like non-periodic timers, the driver must still call WdfTimerStar t
after creating the timer to start it the first time.
A driver might call WdfTimerStar t from its EvtTimerFunc callback function in order to restart a non-periodic
timer after it expires.
To stop a timer, the driver can call WdfTimerStop . Your driver can reuse timers by starting and stopping them
repeatedly.
When your driver creates a timer object, it must specify a parent object. The framework stops the timer and
deletes the timer object when the parent is deleted. To obtain a timer object's parent object, your driver can call
WdfTimerGetParentObject .
In KMDF versions prior to version 1.9, you cannot easily use timer objects if you want all of your driver's callback
functions to run at IRQL = PASSIVE_LEVEL. The framework implements the timer object's EvtTimerFunc callback
function as a deferred procedure call (DPC) that is called at IRQL = DISPATCH_LEVEL. Therefore, if you want your
timer expiration code to run at PASSIVE_LEVEL the EvtTimerFunc callback function must queue a work item that
runs at PASSIVE_LEVEL.
In KMDF versions 1.9 and later, you can create passive-level timers, which are timers that run at PASSIVE_LEVEL.
To create a passive-level timer, specify the WdfExecutionLevelPassive execution level when your driver calls
WdfTimerCreate . As a result, the framework implements EvtTimerFunc callback functions as work items that
run at PASSIVE_LEVEL. Note that passive-level timers cannot be periodic timers.
Starting in UMDF version 2.0, the framework implements the timer object's EvtTimerFunc callback functions as
worker threads from the user-mode thread pool. As a result, a UMDF driver's timer callback functions always
run at PASSIVE_LEVEL.
No Wake Timers
System power efficiency is reduced by timers that repeatedly cause the system to resume from low-power
states. One way to improve battery life is to delay non-critical periodic operations rather than waking the
system. Starting in Windows 8.1, you can use no wake timers to perform such non-critical operations in either a
KMDF or UMDF driver. A no wake timer does not wake the system if it expires while the system is in a low-
power state. Instead, the framework calls the driver's EvtTimerFunc callback function the next time the system is
in its fully on, S0 state.
No wake timers are available starting with KMDF version 1.13 and UMDF version 2.0.
To create a no wake timer, set the TolerableDelay member of WDF_TIMER_CONFIG to
TolerableDelayUnlimited .
For more information about no wake timers, see No-Wake Timers.

High Resolution Timers


Standard framework timers have an accuracy that matches the system clock tick interval, which is by default
15.6 milliseconds. Starting in Windows 8.1, you can create high resolution timers. A high resolution timer has an
accuracy of one millisecond. You might use a high resolution timer for a critical operation that requires a precise,
predictable expiration time. As a result of the frequent servicing that it requires, a high resolution timer may
result in decreased battery life.
High resolution timers are available only to KMDF drivers, starting with KMDF version 1.13.
To create a high resolution timer, set the UseHighResolutionTimer member of WDF_TIMER_CONFIG to
WdfTrue , and then adjust the Period value to the desired resolution.
The following table shows examples of timer behavior based on different values that the driver provides for
Period . These examples assume that the system clock tick interval is 15 milliseconds.

P ERIO D, IN M S STA N DA RD T IM ER H IGH RESO L UT IO N T IM ER

10 The timer expires between 0 The timer expires as soon after 10


milliseconds and 25 milliseconds. milliseconds as possible.

16 The timer expires between 15 The timer expires as soon after 16


milliseconds and 30 milliseconds. milliseconds as possible.

For more information about high resolution timers, see High-Resolution Timers.
For more information about how timer accuracy is related to the granularity of the system clock, see Timer
Accuracy.
Using String Objects
2/5/2021 • 2 minutes to read • Edit Online

This topic describes the support that Windows Driver Frameworks (WDF) provides for string objects. It applies
to both Kernel-Mode Driver Framework (KMDF) drivers and User-Mode Driver Framework (UMDF) drivers
starting in version 2.
WDF uses only Unicode strings. All of the methods that are defined by framework objects accept only Unicode
strings.
The framework defines the framework string object that KMDF and UMDF drivers can use to represent Unicode
strings.
Your driver can call WdfStringCreate to create a string object and to optionally assign a Unicode string to the
object.
Some of the framework's object methods, such as WdfRegistr yQuer yString , accept a string object handle as
input and assign a string to the string object.
To access the string that is assigned to a string object, your driver can call WdfStringGetUnicodeString .
Using Framework Work Items
2/5/2021 • 5 minutes to read • Edit Online

A work item is a task that a driver performs in an EvtWorkItem event callback function. These functions run
asynchronously, at IRQL = PASSIVE_LEVEL, in the context of a system worker thread.
Framework-based drivers commonly use work items if an EvtInterruptDpc or EvtDpcFunc function, which runs
at IRQL = DISPATCH_LEVEL, must perform additional processing at IRQL = PASSIVE_LEVEL.
In other words, a driver can use work items if a function that runs at IRQL = DISPATCH_LEVEL must call a
function that can be called only at IRQL = PASSIVE_LEVEL.
Typically, a driver's EvtInterruptDpc or EvtDpcFunc callback function creates a work-item object and adds it to the
system's work-item queue. Subsequently, a system worker thread dequeues the object and calls the work item's
EvtWorkItem callback function.
Sample Drivers That Use Work Items
Sample framework-based drivers that use work items include 1394, AMCC5933, PCIDRV, and Toaster.
Setting Up a Work Item
To set up a work item, your driver must:
1. Create the work item.
Your driver calls WdfWorkItemCreate to create a work-item object and to identify an EvtWorkItem
callback function that will process the work item.
2. Store information about the work item.
Typically, drivers use the context memory of the work-item object to store information about the task that
the EvtWorkItem callback function should perform. When the EvtWorkItem callback function is called, it
can retrieve the information by accessing this context memory. For information about how to allocate
and access context memory, see Framework Object Context Space.
3. Add the work item to the system's work-item queue.
Your driver calls WdfWorkItemEnqueue , which adds the driver's work item to the work-item queue.
When your driver calls WdfWorkItemCreate , it must supply a handle to either a framework device object or a
framework queue object. When the system deletes that object, it also deletes any existing work items that are
associated with the object. The work item object will be disposed and its associated work-item callback will be
cleaned up before the parent object's EvtCleanupCallback callback is invoked.
For more info about the cleanup rules for a framework object hierarchy, see Framework Object Life Cycle.
Using the Work-Item Callback Function
After the work item has been added to the work-item queue, it remains in the queue until a system worker
thread becomes available. The system worker thread removes the work item from the queue and then calls the
driver's EvtWorkItem callback function, passing the work-item object as input.
Typically, the EvtWorkItem callback function performs the following steps:
1. Obtains driver-supplied information about the work item by accessing the context memory of the work-
item object.
2. Performs the task that you specified. If necessary, the callback function can call
WdfWorkItemGetParentObject to determine the work item's parent object.
3. Calls WdfObjectDelete to delete the work-item object or, if the driver will requeue the work item,
indicates that the handle to the work item is now available for reuse.
The task that each work item's callback function performs must be relatively short. The operating system
provides a limited number of system worker threads, so your driver can impede system performance if it uses
work-item callback functions to perform time-consuming tasks.
Creating and Deleting Work Items
Drivers can use one of the following two techniques to create and delete work items:
Use each work item once: create the work item when you need it and delete it immediately after it is used.
This technique is useful for drivers that require infrequent use (less often than once per minute) of a
small number of work items.
For example, a driver's EvtInterruptDpc callback function can call WdfWorkItemCreate and then
WdfWorkItemEnqueue , and the work item's EvtWorkItem callback function can call WdfObjectDelete .
If your driver follows this scenario, and if its EvtInterruptDpc callback function receives a
STATUS_INSUFFICIENT_RESOURCES return value from WdfWorkItemCreate , the driver must be able to
postpone the required work until system resources (typically memory) become available.
Create one or more work items that your driver requeues as necessary.
This technique is useful for drivers that use work items frequently (more often than once per minute), or
if your driver's EvtInterruptDpc callback function cannot easily handle a
STATUS_INSUFFICIENT_RESOURCES return value from WdfWorkItemCreate .
The system does not allocate a worker thread to a work item until the driver calls
WdfWorkItemEnqueue . Therefore, even though system worker threads are a limited resource, creating
work items while initializing a device consumes a small amount of memory but does not otherwise affect
system performance.
The following steps describe a possible scenario:
1. A driver's EvtDriverDeviceAdd callback function calls WdfWorkItemCreate to obtain a work item
handle.
2. The driver's EvtInterruptDpc callback function creates a list of actions that the EvtWorkItem callback
function must perform and then calls WdfWorkItemEnqueue , using the handle from step 1.
3. The driver's EvtWorkItem callback function performs the list of actions and sets a flag to indicate that
the callback function has run.
Subsequently, each time that the driver's EvtInterruptDpc callback function is called it must determine if
the EvtWorkItem callback function has run. If the EvtWorkItem callback function has not run, the
EvtInterruptDpc callback function does not call WdfWorkItemEnqueue , because the work item is still
queued. In this case, the EvtInterruptDpc callback function only updates the list of actions for the
EvtWorkItem callback function.
Each work item is associated with a device or a queue. When the associated device or queue is removed,
the framework deletes all of the associated work items, so if you are using this technique, the driver does
not have to call WdfObjectDelete .
A few drivers might need to call WdfWorkItemFlush to flush their work items from the work-item queue. For
an example use of WdfWorkItemFlush , see the method's reference page.
If the driver calls WdfObjectDelete on an outstanding work item, the result depends on the state of the work
item:

W O RK IT EM STAT E RESULT

Created but not enqueued Work item is cleaned up immediately.

Enqueued Call to WdfObjectDelete waits until work item finishes


execution, then work item is cleaned up

Executing If the driver calls WdfObjectDelete from within


EvtWorkItem (on same thread), WdfObjectDelete returns
immediately. Once EvtWorkItem finishes, the work item will
be cleaned up. Otherwise, WdfObjectDelete waits for
EvtWorkItem to finish.
Using Device Interfaces (WDF)
2/5/2021 • 5 minutes to read • Edit Online

A device interface is a symbolic link to a Plug and Play (PnP) device that an application can use to access the
device. A user-mode application can pass the interface's symbolic link name to an API element, such as the
Microsoft Win32 CreateFile function. To obtain a device interface's symbolic link name, the user-mode
application can call SetupDi functions. For more information about SetupDi functions, see Using Device
Installation Functions.
Each device interface belongs to a device interface class. For example, a driver stack for a CD-ROM device might
provide an interface that belongs to the GUID_DEVINTERFACE_CDROM class. One of the CD-ROM device's
drivers would register an instance of the GUID_DEVINTERFACE_CDROM class to inform the system and
applications that a CD-ROM device is available. For more information about device interface classes, see
Overview of Device Interface Classes.
Registering a Device Interface
To register an instance of a device interface class, a framework-based driver can call
WdfDeviceCreateDeviceInterface from within its EvtDriverDeviceAdd callback function. If the driver
supports multiple instances of the interface, it can assign a unique reference string to each instance.
After the driver has registered a device interface, the driver can call
WdfDeviceRetrieveDeviceInterfaceString to obtain the symbolic link name that the system has assigned to
the device interface.
For information about other ways that drivers can register device interfaces, see Registering a Device Interface
Class.
Enabling and Disabling a Device Interface
After a driver calls WdfDeviceCreateDeviceInterface from EVT_WDF_DRIVER_DEVICE_ADD, the framework
automatically enables all of a device's interfaces when the device goes through PnP enumeration and disables
the interfaces when the device undergoes PnP removal.
Note that any device power state changes or PnP resource rebalance does not change the interface's state. To
prevent the interface from being automatically enabled during PnP start, call
WdfDeviceSetDeviceInterfaceStateEx (set the EnableInterface parameter to FALSE) for that interface.
Interfaces created after the device already starts won't be automatically enabled. The driver must call
WdfDeviceSetDeviceInterfaceState or WdfDeviceSetDeviceInterfaceStateEx to enable such interfaces.
A driver can disable and re-enable a device interface if necessary. For example, if a driver determines that its
device has stopped responding, the driver can call WdfDeviceSetDeviceInterfaceState or
WdfDeviceSetDeviceInterfaceStateEx to disable the device's interfaces and prohibit applications from
obtaining new handles to the interface. (Existing handles to the interface are not affected.) If the device later
becomes available, the driver can call WdfDeviceSetDeviceInterfaceState or
WdfDeviceSetDeviceInterfaceStateEx again to reenable the interfaces.
Receiving Requests to Access a Device Interface
When an application or kernel-mode component requests access to a driver's device interface, the framework
calls the driver's EvtDeviceFileCreate callback function. The driver can call WdfFileObjectGetFileName to
obtain the name of the device or file that the application or kernel-mode component is accessing. If the driver
specified a reference string when it registered the device interface, the operating system includes the reference
string in the file or device name that WdfFileObjectGetFileName returns.
Accessing Another Driver's Device Interface
This section shows how a Kernel-Mode Driver Framework (KMDF) driver or a User-Mode Driver Framework
(UMDF) version 2 driver registers for notification of arrival or removal of a device interface provided by another
driver, and then creates a remote I/O target to communicate with the device represented by the device interface.
For information on how to do this in a UMDF version 1 driver, see Using Device Interfaces in UMDF Drivers.
To register for notification of device interface events, a KMDF driver calls IoRegisterPlugPlayNotification ,
while a UMDF 2 driver calls CM_Register_Notification . In both cases, the driver calls the appropriate routine
from its EvtDriverDeviceAdd callback function.
The following code example shows how a local UMDF 2 driver registers for notifications and then opens the
remote I/O target.
1. The remote driver registers for a device interface by calling WdfDeviceCreateDeviceInterface from
EvtDriverDeviceAdd.

UNICODE_STRING ref;
RtlInitUnicodeString(&ref, MY_HID_FILTER_REFERENCE_STRING);
status = WdfDeviceCreateDeviceInterface(
hDevice,
(LPGUID) &GUID_DEVINTERFACE_MY_HIDFILTER_DRIVER,
&ref // ReferenceString
);

if (!NT_SUCCESS (status)) {
MyKdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status));
return status;
}

2. The local driver calls CM_Register_Notification from EvtDriverDeviceAdd to register for notification
when a device interface is available. Provide a pointer to a notification callback routine that the
framework calls when device interfaces are available.

DWORD cmRet;
CM_NOTIFY_FILTER cmFilter;

ZeroMemory(&cmFilter, sizeof(cmFilter));
cmFilter.cbSize = sizeof(cmFilter);
cmFilter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
cmFilter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_MY_HIDFILTER_DRIVER;

cmRet = CM_Register_Notification(
&cmFilter, // PCM_NOTIFY_FILTER pFilter,
(PVOID) hDevice, // PVOID pContext,
MyCmInterfaceNotification, // PCM_NOTIFY_CALLBACK pCallback,
&fdoData->CmNotificationHandle // PHCMNOTIFICATION pNotifyContext
);
if (cmRet != CR_SUCCESS) {
MyKdPrint( ("CM_Register_Notification failed, error %d\n", cmRet));
status = STATUS_UNSUCCESSFUL;
return status;
}

3. The system calls the local driver's notification callback routine each time that the specified device
interface arrives or is removed. The callback routine can examine the EventData parameter to determine
which device interface has arrived. It might then queue a work item to open the device interface.
DWORD
MyCmInterfaceNotification(
_In_ HCMNOTIFICATION hNotify,
_In_opt_ PVOID Context,
_In_ CM_NOTIFY_ACTION Action,
_In_reads_bytes_(EventDataSize) PCM_NOTIFY_EVENT_DATA EventData,
_In_ DWORD EventDataSize
)
{
PFDO_DATA fdoData;
UNICODE_STRING name;
WDFDEVICE device;
NTSTATUS status;
WDFWORKITEM workitem;

UNREFERENCED_PARAMETER(hNotify);
UNREFERENCED_PARAMETER(EventDataSize);

device = (WDFDEVICE) Context;


fdoData = ToasterFdoGetData(device);

switch(Action) {
case CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL:
MyKdPrint( ("MyCmInterfaceNotification: Arrival of %S\n",
EventData->u.DeviceInterface.SymbolicLink));

//
// Enqueue a work item to open target
//

break;
case CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL:
MyKdPrint( ("MyCmInterfaceNotification: removal of %S\n",
EventData->u.DeviceInterface.SymbolicLink));
break;
default:
MyKdPrint( ("MyCmInterfaceNotification: Arrival unknown action\n"));
break;
}

return 0;
}

4. From the work item callback function, the local driver calls WdfIoTargetCreate to create the remote
target, and WdfIoTargetOpen to open a remote I/O target.
When calling WdfIoTargetOpen , the driver optionally registers an EvtIoTargetQueryRemove callback
function to receive removal notification, along with the opportunity to decline the removal. If the driver
does not provide EvtIoTargetQueryRemove, the framework closes the I/O target when the device is
removed.
In rare cases, a UMDF 2 driver can call CM_Register_Notification a second time, to register for
notification of device removal. For example, if the driver calls CreateFile to get a HANDLE to the device
interface, it should register for notification of device removal so that it can properly respond to query
remove attempts. In most cases, the UMDF 2 driver calls CM_Register_Notification only once, and
relies on WDF support for device removal.
VOID
EvtWorkItem(
_In_ WDFWORKITEM WorkItem
)
{
//
// create and open remote target
//

return;
}

Related topics
Registering for Notification of Device Interface Arrival and Device Removal
WDF_DECLARE_CONTEXT_TYPE macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WDF_DECLARE_CONTEXT_TYPE macro creates a name and an accessor method for a driver's object-specific
context space.

Syntax
void WDF_DECLARE_CONTEXT_TYPE(
_contexttype
);

Parameters
_contexttype
The structure type name of a driver-defined structure that describes the contents of an object's context space.

Return value
This macro does not return a value.

Remarks
For more information about using this macro, see Framework Object Context Space.

Examples
The following code example defines a context structure (MY_REQUEST_CONTEXT) for a request object, registers
the structure, and then invokes the WDF_DECLARE_CONTEXT_TYPE macro. The macro creates an accessor
method for the context structure and names the method WdfObjectGet_MY_REQUEST_CONTEXT .

typedef struct _MY_REQUEST_CONTEXT {


LIST_ENTRY ListEntry;
WDFMEMORY Memory;
} MY_REQUEST_CONTEXT, *PMY_REQUEST_CONTEXT;

WDF_DECLARE_CONTEXT_TYPE(MY_REQUEST_CONTEXT)

The following code example creates a request object, and then it uses the
WdfObjectGet_MY_REQUEST_CONTEXT accessor method to obtain a pointer to the object's context space.
WDFREQUEST Request;
WDF_OBJECT_ATTRIBUTES MyRequestObjectAttributes;
PMY_REQUEST_CONTEXT pMyContext;

WDF_OBJECT_ATTRIBUTES_INIT(&MyRequestObjectAttributes);
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(
&MyRequestObjectAttributes,
MY_REQUEST_CONTEXT
);
status = WdfRequestCreate(
&MyRequestObjectAttributes
NULL,
&Request
);
if (!NT_SUCCESS(status)) {
return status;
}
pMyContext = WdfObjectGet_MY_REQUEST_CONTEXT(Request);

Requirements
Target platform Universal

Minimum KMDF version 1.0

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

See also
WdfObjectGetTypedContext
WDF_DECL ARE_CONTEXT_TYPE_WITH_NAME
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME
macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro creates an accessor method with a specified name for
a driver's object-specific context space.

Syntax
void WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(
_contexttype,
_castingfunction
);

Parameters
_contexttype
The structure type name of a driver-defined structure that describes the contents of an object's context space.
_castingfunction
A C-language routine name. The macro uses this name as the name for the accessor method that it creates for
the object's context space.

Return value
This macro does not return a value.

Remarks
For more information about using this macro, see Framework Object Context Space.

Examples
The following code example defines a context structure (MY_REQUEST_CONTEXT) for a request object. Then, the
example invokes the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro to register the structure and specify
that the context accessor method will be named RequestGetMyContext .

typedef struct _MY_REQUEST_CONTEXT {


LIST_ENTRY ListEntry;
WDFMEMORY Memory;
} MY_REQUEST_CONTEXT, *PMY_REQUEST_CONTEXT;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MY_REQUEST_CONTEXT, RequestGetMyContext)

The following code example creates a request object and then uses the RequestGetMyContext accessor
method to obtain a pointer to the object's context space.
WDFREQUEST Request;
WDF_OBJECT_ATTRIBUTES MyRequestObjectAttributes;
PMY_REQUEST_CONTEXT pMyContext;

WDF_OBJECT_ATTRIBUTES_INIT(&MyRequestObjectAttributes);
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(
&MyRequestObjectAttributes,
MY_REQUEST_CONTEXT
);
status = WdfRequestCreate(
&MyRequestObjectAttributes
NULL,
&Request
);

if (!NT_SUCCESS(status)) {
return status;
}

pMyContext = RequestGetMyContext(Request);

Requirements
Target platform Universal

Minimum KMDF version 1.0

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

See also
WdfObjectGetTypedContext
WDF_DECL ARE_CONTEXT_TYPE
WDF_DECLARE_CUSTOM_TYPE macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WDF_DECL ARE_CUSTOM_TYPE macro creates a name and an accessor method for a driver's custom
type.

Syntax
void WDF_DECLARE_CUSTOM_TYPE(
_customtype
);

Parameters
_customtype
The driver-defined name of a custom type.

Return value
This macro does not return a value.

Remarks
When calling WDF_DECL ARE_CUSTOM_TYPE , a driver defines its own custom type name. When selecting a
custom type name, choose a name that is specific to the domain of the driver. As a convention, do not start your
custom type name with the prefix Wdf.
For more information about object custom types, see Framework Object Custom Types.

Examples
The following code example calls the WDF_DECL ARE_CUSTOM_TYPE macro to declare the
MY_CUSTOM_TYPE custom type name. The driver must put this line in an area of the driver that declares global
data, typically a header file.

WDF_DECLARE_CUSTOM_TYPE(MY_CUSTOM_TYPE)

The following code example creates a request object, and then it uses the WdfObjectAddCustomType method
to associate the MY_CUSTOM_TYPE custom type with the request object.
WDFREQUEST Request;
WDF_OBJECT_ATTRIBUTES MyRequestObjectAttributes;

WDF_OBJECT_ATTRIBUTES_INIT(&MyRequestObjectAttributes);

status = WdfRequestCreate(
&MyRequestObjectAttributes
NULL,
&Request
);

if (!NT_SUCCESS(status)) {
return status;
}

status = WdfObjectAddCustomType(
Request,
MY_CUSTOM_TYPE
);

if (!NT_SUCCESS(status)) {
return status;
}

Requirements
Target platform Universal

Minimum KMDF version 1.11

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

See also
WdfObjectAddCustomType
WdfObjectAddCustomTypeWithData
WdfObjectGetCustomTypeData
WdfObjectIsCustomType
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE
macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE macro initializes a driver's
WDF_OBJECT_ATTRIBUTES structure and inserts an object's driver-defined context information into the
structure.

Syntax
void WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
_attributes,
_contexttype
);

Parameters
_attributes
A pointer to a WDF_OBJECT_ATTRIBUTES structure.
_contexttype
The structure type name of a driver-defined structure that describes the contents of an object's context space.

Return value
This macro does not return a value.

Remarks
Before calling WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE , you must call
WDF_DECL ARE_CONTEXT_TYPE or WDF_DECL ARE_CONTEXT_TYPE_WITH_NAME globally (not within a
function).
The WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE macro combines the
WDF_OBJECT_ATTRIBUTES_INIT function and the WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE
macro.

Examples
The following code example defines a WDM_NDIS_REQUEST context structure. Then, the example invokes the
WDF_DECL ARE_CONTEXT_TYPE_WITH_NAME macro to register the structure and specify that the context
accessor method will be named RequestGetMyContext . Then, in a function, the example allocates a
WDF_OBJECT_ATTRIBUTES structure, and then initializes the WDF_OBJECT_ATTRIBUTES structure.
typedef struct _WDM_NDIS_REQUEST
{
PMP_ADAPTER Adapter;
NDIS_OID Oid;
NDIS_REQUEST_TYPE RequestType;
PVOID InformationBuffer;
ULONG InformationBufferLength;
PULONG BytesReadOrWritten;
PULONG BytesNeeded;
} WDM_NDIS_REQUEST, *PWDM_NDIS_REQUEST;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WDM_NDIS_REQUEST, RequestGetMyContext);

// above are in global space

...

WDF_OBJECT_ATTRIBUTES attributes;

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( &attributes, WDM_NDIS_REQUEST );

Requirements
Target platform Universal

Minimum KMDF version 1.0

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

See also
WDF_OBJECT_ATTRIBUTES
WDF_OBJECT_ATTRIBUTES_INIT
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE
macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE macro inserts an object's driver-defined context
information into the object's WDF_OBJECT_ATTRIBUTES structure.

Syntax
void WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(
_attributes,
_contexttype
);

Parameters
_attributes
A pointer to an object's WDF_OBJECT_ATTRIBUTES structure.
_contexttype
The structure type name of a driver-defined structure that describes the contents of an object's context space.

Return value
This macro does not return a value.

Remarks
You should use the WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE macro after calling
WDF_OBJECT_ATTRIBUTES_INIT .
For more information about using the WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE macro, see Framework
Object Context Space.
For a code example that uses this macro, see WDF_DECL ARE_CONTEXT_TYPE .

Requirements
Target platform Universal

Minimum KMDF version 1.0

Minimum UMDF version 2.0


Header Wdfobject.h (include Wdf.h)

See also
WDF_DECL ARE_CONTEXT_TYPE
WDF_OBJECT_ATTRIBUTES
WDF_OBJECT_ATTRIBUTES_INIT
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE
WDF_PTR_ADD_OFFSET macro
2/5/2021 • 2 minutes to read • Edit Online

The WDF_PTR_ADD_OFFSET macro adds an offset value to an address and returns the resulting address.

Syntax
PVOID WDF_PTR_ADD_OFFSET(
_ptr,
_offset
);

Parameters
_ptr
Specifies an address.
_offset
Specifies the offset value in bytes.

Return value
Returns a pointer to the resulting address.

Remarks
This macro invokes WDF_PTR_ADD_OFFSET_TYPE with the _type parameter set to PVOID.
The macro is defined as follows:

#define WDF_PTR_ADD_OFFSET(_ptr, _offset) \


WDF_PTR_ADD_OFFSET_TYPE(_ptr, _offset, PVOID)

Here is an example from the Toaster sample (toaster\func\featured\wmi.c). In the example, the driver calls
WDF_PTR_ADD_OFFSET to add an offset to an address to determine a destination buffer address to pass to
the WDF_WMI_BUFFER_APPEND_STRING function.
//
// Write the instance name
//
size -= wnodeSize;
status = WDF_WMI_BUFFER_APPEND_STRING(
WDF_PTR_ADD_OFFSET(wnode, wnode->OffsetInstanceName),
size,
&deviceName,
&length
);

//
// Size was precomputed, this should never fail
//
ASSERT(NT_SUCCESS(status));

//
// Write the data, which is the model name as a string
//
size -= wnodeInstanceNameSize;
WDF_WMI_BUFFER_APPEND_STRING(
WDF_PTR_ADD_OFFSET(wnode, wnode->DataBlockOffset),
size,
&modelName,
&length
);

Requirements
Target platform Universal

Minimum KMDF version 1.5

Minimum UMDF version 2.0

Header Wdfcore.h (include Wdf.h)


WDF_PTR_ADD_OFFSET_TYPE macro
2/5/2021 • 2 minutes to read • Edit Online

The WDF_PTR_ADD_OFFSET_TYPE macro adds an offset value to an address and returns the resulting
address cast to the specified type.

Syntax
_type WDF_PTR_ADD_OFFSET_TYPE(
_ptr,
_offset,
_type
);

Parameters
_ptr
Specifies an address.
_offset
Specifies the offset value in bytes.
_type
Specifies the data type to return.

Return value
Returns a pointer to the resulting address. You select the data type of the return value in the _type parameter of
the macro.

Remarks
The macro is defined as follows:

#define WDF_PTR_ADD_OFFSET_TYPE(_ptr, _offset, _type) \


((_type) (((PUCHAR) (_ptr)) + (_offset)))

Requirements
Target platform Universal

Minimum KMDF version 1.5

Minimum UMDF version 2.0

Header Wdfcore.h (include Wdf.h)


WDF_PTR_GET_OFFSET macro
2/5/2021 • 2 minutes to read • Edit Online

The WDF_PTR_GET_OFFSET macro subtracts an address from another address and returns the resulting offset
value.

Syntax
size_t WDF_PTR_GET_OFFSET(
_base,
_addr
);

Parameters
_base
Specifies the value to subtract from the starting address.
_addr
Specifies the starting address.

Return value
Returns the offset between the two specified addresses.

Remarks
The macro is defined as follows:

#define WDF_PTR_GET_OFFSET(_base, _addr) \


(size_t) (((PUCHAR) _addr) - ((PUCHAR) _base))

Requirements
Target platform Universal

Minimum KMDF version 1.5

Minimum UMDF version 2.0

Header Wdfcore.h (include Wdf.h)


WdfObjectAddCustomType macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WdfObjectAddCustomType macro associates a framework object with a custom type.

Syntax
NTSTATUS WdfObjectAddCustomType(
_handle,
_type
);

Parameters
_handle
A handle to a framework object.
_type
The driver-defined name for the custom type.

Return value
WdfObjectAddCustomType returns STATUS_SUCCESS if the operation succeeds. Otherwise, this method
might return one of the following values:

RET URN C O DE DESC RIP T IO N

STATUS_OBJECT_PATH_INVALID The specified handle cannot have a custom type added


to it.

STATUS_INSUFFICIENT_RESOURCES The custom type could not be allocated.

STATUS_OBJECT_NAME_EXISTS The driver has already added the specified custom type.

STATUS_DELETE_PENDING The object that the Handle parameter specifies is being


deleted. In this situation, the framework does not add
the custom type.

Remarks
WdfObjectAddCustomType is a simplified version of WdfObjectAddCustomTypeWithData .
For more information about object driver types, see Framework Object Custom Types.

Examples
This example code shows how to add a custom type to a queue.

NTSTATUS status;
WDF_IO_QUEUE_CONFIG queueConfig;
WDFQUEUE queue;

WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,
WdfIoQueueDispatchParallel);

status = WdfIoQueueCreate(device,
&queueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&queue);

if (!NT_SUCCESS(status)) {
TraceEvents(TRACE_LEVEL_ERROR, DBG_INFO,
"Failed to create queue, status=0x%x\n", status);
goto Done;
}

status = WdfObjectAddCustomType(queue, TEST_TYPE1);

if (!NT_SUCCESS(status)) {
TraceEvents(TRACE_LEVEL_ERROR, DBG_INFO,
"Failed to add TEST_TYPE1 to WDFOBJECT 0x%p, status=0x%x\n",
queue, status);
goto Done;
}

End:
return status;

Requirements
Target platform Universal

Minimum KMDF version 1.11

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

See also
WDF_DECL ARE_CUSTOM_TYPE
WdfObjectAddCustomTypeWithData
WdfObjectGetCustomTypeData
WdfObjectIsCustomType
WdfObjectAddCustomTypeWithData macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WdfObjectAddCustomTypeWithData macro associates a framework object with a custom type, and
optionally associates this pair with a data buffer and event callback functions.

Syntax
NTSTATUS WdfObjectAddCustomTypeWithData(
_handle,
_type,
_data,
_cleanup,
_destroy
);

Parameters
_handle
A handle to a framework object.
_type
The driver-defined name for the custom type.
_data
A pointer to a driver-supplied data buffer, or NULL. This parameter is optional.
_cleanup
A pointer to the driver's EvtCleanupCallback callback function, or NULL. This parameter is optional.
_destroy
A pointer to the driver's EvtDestroyCallback callback function, or NULL. This parameter is optional.

Return value
WdfObjectAddCustomTypeWithData returns STATUS_SUCCESS if the operation succeeds. Otherwise, this
method might return one of the following values:

RET URN C O DE DESC RIP T IO N

STATUS_OBJECT_PATH_INVALID The specified handle cannot have a custom type added


to it.

STATUS_INSUFFICIENT_RESOURCES The custom type could not be allocated.

STATUS_OBJECT_NAME_EXISTS The driver has already added the specified custom type.
RET URN C O DE DESC RIP T IO N

STATUS_DELETE_PENDING The object that the Handle parameter specifies is being


deleted. In this situation, the framework does not add
the custom type.

Remarks
If your driver calls WdfObjectAddCustomTypeWithData with a pointer to a data buffer, the driver can
provide an EvtCleanupCallback or EvtDestroyCallback callback function to deallocate the memory buffer when
the object is deleted.
For more information about object custom types, see Framework Object Custom Types.
For a code example, see WdfObjectAddCustomType .

Requirements
Target platform Universal

Minimum KMDF version 1.11

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

See also
WDF_DECL ARE_CUSTOM_TYPE
WdfObjectAddCustomType
WdfObjectGetCustomTypeData
WdfObjectIsCustomType
WdfObjectDereference macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WdfObjectDereference macro decrements the reference count for a specified framework object.

Syntax
VOID WdfObjectDereference(
[in] WDFOBJECT Handle
);

Parameters
Handle [in]
A handle to a framework object.

Return value
None.
A bug check occurs if the driver supplies an invalid object handle.

Remarks
If the object's reference count becomes zero, the object might be deleted before WdfObjectDereference
returns.
A driver can call WdfObjectDereference only if it has previously called WdfObjectReference .
Instead of calling WdfObjectDereference , a driver can call WdfObjectDereferenceWithTag or
WdfObjectDereferenceActual .
For more information about object reference counts, see Framework Object Life Cycle.

Examples
The following code example decrements an object's reference count.

WdfObjectDereference(Object);

Requirements
Target platform Universal

Minimum KMDF version 1.0


Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

Library Wdf01000.sys (KMDF); WUDFx02000.dll (UMDF)

IRQL <= DISPATCH_LEVEL

DDI compliance rules DriverCreate , MemAfterReqCompletedIntIoctlA ,


MemAfterReqCompletedIoctlA ,
MemAfterReqCompletedReadA ,
MemAfterReqCompletedWriteA ,
wdfioqueuefindrequestfailed ,
wdfioqueueretrievefoundrequest

See also
WdfObjectDereferenceActual
WdfObjectDereferenceWithTag
WdfObjectReference
WdfObjectDereferenceWithTag macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WdfObjectDereferenceWithTag macro decrements the reference count for a specified framework object
and assigns the driver's current file name and line number to the reference. This macro also assigns a tag value
to the reference.

Syntax
VOID WdfObjectDereferenceWithTag(
[in] WDFOBJECT Handle,
[in] PVOID Tag
);

Parameters
Handle [in]
A handle to a framework object.
Tag [in]
A driver-defined value that identifies an object reference. The tag value must match a tag value that the driver
previously supplied to WdfObjectReferenceWithTag .

Return value
None.
A bug check occurs if the driver supplies an invalid object handle.

Remarks
If the object's reference count becomes zero, the object might be deleted before
WdfObjectDereferenceWithTag returns.
Calling WdfObjectDereferenceActual or WdfObjectDereferenceWithTag instead of
WdfObjectDereference provides additional information (tag string, line number, and file name) to Microsoft
debuggers. WdfObjectDereferenceActual allows your driver to specify the line number and file name, while
WdfObjectDereferenceWithTag uses the driver's current line number and file name.
You can view the tag, line number, and file name values by using the !wdftagtracker debugger extension. The
debugger extension displays the tag value as both a pointer and a series of characters. For more about
debugger extensions, see Debugging a KMDF Driver.
For more information about object reference counts, see Framework Object Life Cycle.

Examples
The following code example decrements an object's reference count and assigns a tag value to the reference.
WdfObjectDereferenceWithTag(
object,
pTag
);

Requirements
Target platform Universal

Minimum KMDF version 1.0

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

Library Wdf01000.sys (KMDF); WUDFx02000.dll (UMDF)

IRQL <= DISPATCH_LEVEL

See also
WdfObjectDereference
WdfObjectReferenceWithTag
WdfObjectGetCustomTypeData macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WdfObjectGetCustomTypeData macro retrieves the data that the driver previously associated with a
framework object and custom type.

Syntax
PULONG WdfObjectGetCustomTypeData(
[in] Handle,
[in] Type
);

Parameters
Handle [in]
A handle to a framework object.
Type [in]
The symbol name of a custom type.

Return value
WdfObjectGetCustomTypeData returns the data that the driver associated with a framework object and
custom type in a previous call to WdfObjectAddCustomTypeWithData .

Remarks
For more information about object driver types, see Framework Object Custom Types.

Requirements
Target platform Universal

Minimum KMDF version 1.11

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

See also
WDF_DECL ARE_CUSTOM_TYPE
WdfObjectAddCustomType
WdfObjectAddCustomTypeWithData
WdfObjectIsCustomType
WdfObjectGetTypedContext macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WdfObjectGetTypedContext macro returns a pointer to an object's context space.

Syntax
PVOID WdfObjectGetTypedContext(
Handle,
Type
);

Parameters
Handle
A handle to a framework object.
Type
The symbol name of a driver-defined structure that describes an object's context space.

Return value
WdfObjectGetTypedContext returns a pointer to the specified object's context space.

Remarks
You can use the WdfObjectGetTypedContext macro to obtain a pointer to any framework object's context
space. Use this macro as an alternative to calling an object-specific context accessor method that is created by
the WDF_DECL ARE_CONTEXT_TYPE macro or the WDF_DECL ARE_CONTEXT_TYPE_WITH_NAME macro.
Note that if you use WdfObjectGetTypedContext , you still must use WDF_DECLARE_CONTEXT_TYPE or
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME to declare your object context.
For more information about these macros, see Framework Object Context Space.

Examples
The following code example defines a context structure (MY_REQUEST_CONTEXT) for a request object and then
registers the structure.

typedef struct _MY_REQUEST_CONTEXT {


LIST_ENTRY ListEntry;
WDFMEMORY Memory;
} MY_REQUEST_CONTEXT, *PMY_REQUEST_CONTEXT;

WDF_DECLARE_CONTEXT_TYPE(MY_REQUEST_CONTEXT)

The following code example creates a request object and obtains a pointer to its context space.
WDFREQUEST Request;
WDF_OBJECT_ATTRIBUTES MyRequestObjectAttributes;
PMY_REQUEST_CONTEXT pMyContext;

WDF_OBJECT_ATTRIBUTES_INIT(&MyRequestObjectAttributes);
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(
&MyRequestObjectAttributes,
MY_REQUEST_CONTEXT
);
status = WdfRequestCreate(
&MyRequestObjectAttributes,
NULL,
&Request
);

if (!NT_SUCCESS(status)) {
return status;
}
pMyContext = WdfObjectGetTypedContext(
Request,
MY_REQUEST_CONTEXT
);

Requirements
Target platform Universal

Minimum KMDF version 1.0

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

Library Wdf01000.sys (KMDF); WUDFx02000.dll (UMDF)

IRQL Any level

See also
WDF_DECL ARE_CONTEXT_TYPE
WDF_DECL ARE_CONTEXT_TYPE_WITH_NAME
WdfObjectIsCustomType macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WdfObjectIsCustomType macro determines whether a framework object is of a specified custom type.

Syntax
BOOLEAN WdfObjectIsCustomType(
[in] Handle,
[in] Type
);

Parameters
Handle [in]
A handle to a framework object.
Type [in]
The symbol name of a custom type.

Return value
Returns TRUE if the specified object is of the specified custom type. Otherwise, returns FALSE.

Remarks
For more information about object custom types, see Framework Object Custom Types.

Requirements
Target platform Universal

Minimum KMDF version 1.11

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

See also
WDF_DECL ARE_CUSTOM_TYPE
WdfObjectAddCustomType
WdfObjectAddCustomTypeWithData
WdfObjectGetCustomTypeData
WdfObjectReference macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WdfObjectReference macro increments the reference count for a specified framework object.

Syntax
VOID WdfObjectReference(
[in] WDFOBJECT Handle
);

Parameters
Handle [in]
A handle to a framework object.

Return value
None.
A bug check occurs if the driver supplies an invalid object handle.

Remarks
If your driver calls WdfObjectReference to increment a reference count, the driver must call
WdfObjectDereference to decrement the count.
Instead of calling WdfObjectReference , a driver can call WdfObjectReferenceWithTag or
WdfObjectReferenceActual .
For more information about object reference counts, see Framework Object Life Cycle.

Examples
The following code example increments an object's reference count.

WdfObjectReference(Object);

Requirements
Target platform Universal

Minimum KMDF version 1.0

Minimum UMDF version 2.0


Header Wdfobject.h (include Wdf.h)

Library Wdf01000.sys (KMDF); WUDFx02000.dll (UMDF)

IRQL <= DISPATCH_LEVEL

DDI compliance rules DriverCreate , MemAfterReqCompletedIntIoctlA ,


MemAfterReqCompletedIoctlA ,
MemAfterReqCompletedReadA ,
MemAfterReqCompletedWriteA

See also
WdfObjectReferenceActual
WdfObjectReferenceWithTag
WdfObjectReferenceWithTag macro
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


The WdfObjectReferenceWithTag macro increments the reference count for a specified framework object
and assigns the driver's current file name and line number to the reference. The macro also assigns a tag value
to the reference.

Syntax
VOID WdfObjectReferenceWithTag(
[in] WDFOBJECT Handle,
[in] PVOID Tag
);

Parameters
Handle [in]
A handle to a framework object.
Tag [in]
A driver-defined value that the framework stores as an identification tag for the object reference.

Return value
None.
A bug check occurs if the driver supplies an invalid object handle.

Remarks
If your driver calls WdfObjectReferenceWithTag to increment a reference count, the driver must call
WdfObjectDereferenceWithTag to decrement the count.
Calling WdfObjectReferenceActual or WdfObjectReferenceWithTag instead of WdfObjectReference
provides additional information (tag value, line number, and file name) to Microsoft debuggers.
WdfObjectReferenceActual allows your driver to specify the line number and file name, while
WdfObjectReferenceWithTag uses the driver's current line number and file name.
You can view the tag, line number, and file name values by using the !wdftagtracker debugger extension. The
debugger extension displays the tag value as both a pointer and a series of characters. For more about
debugger extensions, see Debugging a KMDF Driver.
For more information about object reference counts, see Framework Object Life Cycle.

Examples
The following code example increments an object's reference count and assigns a tag value to the reference.
WdfObjectReferenceWithTag(
object,
pTag
);

Requirements
Target platform Universal

Minimum KMDF version 1.0

Minimum UMDF version 2.0

Header Wdfobject.h (include Wdf.h)

Library Wdf01000.sys (KMDF); WUDFx02000.dll (UMDF)

IRQL <= DISPATCH_LEVEL

See also
WdfObjectReference
Framework Object Creation Errors
2/5/2021 • 2 minutes to read • Edit Online

When a driver's attempt to create a framework object fails, the object creation method returns an NTSTATUS
value that indicates the failure type.
If the driver specifies invalid information in a WDF_OBJECT_ATTRIBUTES structure, the framework can return:
STATUS_WDF_OBJECT_ATTRIBUTES_INVALID
The driver specified an object context name, but the context size is zero.
The driver specified a context size override value, but it did not provide a
WDF_OBJECT_CONTEXT_TYPE_INFO structure.
The driver specified a ContextSizeOverride value in WDF_OBJECT_ATTRIBUTES that is less than the
ContextSize member of the WDF_OBJECT_CONTEXT_TYPE_INFO structure.
The driver specified an ExecutionLevel value in WDF_OBJECT_ATTRIBUTES that is not within the valid range of
values.
The driver specified an SynchronizationScope value in WDF_OBJECT_ATTRIBUTES that is not within the valid
range of values.
STATUS_WDF_PARENT_ASSIGNMENT_NOT_ALLOWED
The driver attempted to assign a parent to the object, but the framework does not allow drivers to assign
parents to the object type.
STATUS_WDF_PARENT_ALREADY_ASSIGNED
The driver attempted to assign a parent to an object, but a parent is already assigned to the object.
STATUS_WDF_PARENT_IS_SELF
The driver attempted to make an object its own parent.
STATUS_WDF_SYNCHRONIZATION_SCOPE_INVALID
The driver specified a WDF_SYNCHRONIZATION_SCOPE -typed value that is invalid for the object type.
STATUS_WDF_EXECUTION_LEVEL_INVALID
The driver specified a WDF_EXECUTION_LEVEL -typed value that is invalid for the object type.
If the Size member of any framework-defined structure does not match the structure's actual size, the
framework can return STATUS_INFO_LENGTH_MISMATCH.
If the framework cannot allocate memory for the new object, it can return STATUS_INSUFFICIENT_RESOURCES.
Individual object creation methods might also return additional NTSTATUS values. For more information about
each creation method's additional return values, see the method's reference page.
Supporting PnP and Power Management in Your
Driver
2/5/2021 • 2 minutes to read • Edit Online

By default, the framework handles all PnP and power management requests that the system sends to
framework-based drivers. Additionally, by default, the framework delivers I/O requests to a function driver only
if the driver's hardware is available and in its working (D0) state.
When writing a framework-based driver, you can use much of the framework's default behavior to easily
support the PnP and power management capabilities of your device. However, if all of the drivers in your driver
stack used only the framework's default PnP and power management behavior, your device probably would not
work properly. For example, the device's function driver might have to enable the device when the device enters
its working (D0) state.
Therefore, the framework device object provides a set of event callback functions and a set of object methods
that enable framework-based drivers to participate in PnP and power management operations. These callback
functions and object methods allow each driver in the stack to provide only the PnP and power management
support that is necessary.
Typically, each of the various drivers in a driver stack is responsible for supporting a few PnP and power
management operations. The operations that a driver must support depend on the type of driver that you are
writing and the capabilities that the device provides. For more information about which operations your driver
should support, see:
Supporting PnP and Power Management in Software-only Drivers
Supporting PnP and Power Management in Function Drivers
Supporting PnP and Power Management in
Software-only Drivers
2/5/2021 • 2 minutes to read • Edit Online

Software-only drivers are drivers that do not access any hardware. Some software-only drivers reside in a driver
stack that does not access hardware. Because these drivers do not access hardware, they typically do not have to
perform any PnP or power management operations.
Other software-only drivers are filter drivers: they reside in a stack of drivers that do access hardware, but the
filter drivers do not access hardware. When a filter driver receives an I/O request that specifies a PnP or power
management operation, the driver typically just passes the request to the next driver. The framework intercepts
these requests and passes them on, so framework-based drivers never see the requests.
If you are writing a software-only driver, your driver creates device objects but you typically do not need to
provide any event callback functions to handle PnP or power management events. If the driver uses framework
queue objects, you will need to set the PowerManaged member of the queue's WDF_IO_QUEUE_CONFIG
structure to WdfFalse or WdfUseDefault .
A few software-only drivers are also function drivers. In other words, a single driver might act as a software-only
driver to support a virtual device that does not access hardware, and as a function driver to support a hardware
device.
Supporting PnP and Power Management in
Function Drivers
2/5/2021 • 2 minutes to read • Edit Online

Function drivers control the operation of a device and therefore they access device hardware. These drivers
must support PnP and power management operations and typically register several event callback functions
when they create device objects.
Typically, a function driver's EvtDriverDeviceAdd event callback function calls
WdfDeviceInitSetPnpPowerEventCallbacks to register the following callback functions:
EvtDevicePrepareHardware, which delivers the device's system-assigned resources to the driver. The
driver can perform operations, such as mapping the device's bus-relative memory into the processor's
virtual address space, that make the hardware accessible to the driver.
EvtDeviceD0Entry, which performs operations, such as loading firmware, that are needed each time that
the driver's device enters its working (D0) state.
EvtDeviceD0Exit, which performs operations that are needed each time that the driver's device leaves its
working (D0) state and enters a low-power state.
EvtDeviceReleaseHardware, which releases any system resources that EvtDevicePrepareHardware
allocated.
Like all framework-defined callback functions, the ones in the preceding list are optional. You have to supply
them only if your driver needs them.
Function drivers can call WdfDeviceSetPnpCapabilities and WdfDeviceSetPowerCapabilities to report a
device's PnP and power management capabilities to the operating system.
Typically, you will use the framework's power-managed I/O queues for most I/O requests. If an I/O queue is
power-managed, the framework delivers requests to the driver only if its device is in its working (D0) state. For
more information about power-managed I/O queues, see Power Management for I/O Queues.
Typically, the device's function driver is the power policy owner for the driver stack. The power policy owner
determines the appropriate device power state for a device and sends requests to the device's driver stack
whenever the device's power state should change. For framework-based drivers, the framework handles this
responsibility, so you do not have to provide code in your driver to request changes in a device's power state.
The power policy owner has two additional responsibilities: it controls a device's ability to enter a low-power
state when it is idle and the system remains in its working (S0) state, and it controls the device's ability to
generate a wake signal when it detects an external event from a low-power state. If your device has idle or wake
capabilities, your function driver can provide additional callback functions. For more information about the
responsibilities of the power policy owner, see Power Policy Ownership.
PnP and Power Management Scenarios
2/5/2021 • 2 minutes to read • Edit Online

The following topics identify typical PnP and power management scenarios and show the sequence in which the
framework calls a driver's event callback functions during these scenarios:
A User Plugs in a Device
A User Unplugs a Device
A Device Enters a Low-Power State
A Device Returns to Its Working State
The PnP Manager Redistributes System Resources
A User Plugs in a Device
2/5/2021 • 2 minutes to read • Edit Online

In the following scenario, the device node includes a KMDF bus driver and one or more KMDF function or filter
drivers that support a PnP device.
When a user plugs the device into the bus while the system is running, the device's bus driver and the
framework perform the following tasks:
The bus driver for the device detects the device and calls
WdfChildListAddOrUpdateChildDescriptionAsPresent . (This process is known as "dynamic
enumeration.")
The framework calls the bus driver's EvtChildListCreateDevice callback function, so the bus driver can call
WdfDeviceCreate to create a framework device object for the physical device (a PDO).
The framework calls the bus driver's EvtDeviceResourcesQuery and
EvtDeviceResourceRequirementsQuery callback functions to determine the system hardware resources
that the device requires.
For more information about the power-up sequence for a KMDF bus driver, see Power-Up Sequence for a Bus
Driver.
Next, the PnP manager determines which additional drivers (function drivers and filter drivers) the device
requires. If these drivers are not already loaded, the PnP manager loads them and calls their DriverEntr y
routines. For each function or filter driver, the following actions occur:
The framework calls each additional driver's EvtDriverDeviceAdd callback function so that the driver can
call WdfDeviceCreate to create a framework device object that represents the device for the driver.
Function drivers create a functional device object (FDO), and filter drivers create a filter device object
(Filter DO).
The framework calls each function and filter driver's EvtDeviceFilterRemoveResourceRequirements
callback function and then each driver's EvtDeviceFilterAddResourceRequirements callback function.
Immediately before the device is started, the framework calls the EvtDeviceRemoveAddedResources
callback function. These three callback functions allow the filter and function drivers to modify the list of
hardware resources that the device requires, before the PnP manager assigns resources to the device. For
more information, see Hardware Resources for Framework-Based Drivers
The framework ensures that the device has reached its working (D0) power state.
For each function and filter driver that supports the device, the framework does the following, in
sequence, one driver at a time, starting with the driver that is lowest in the driver stack:
1. The framework calls the driver's EvtDevicePrepareHardware callback function (if it exists) and passes
the list of hardware resources that the PnP manager has assigned to the device.
2. The framework calls the driver's EvtDeviceD0Entry callback function (if it exists).
3. The framework calls the driver's EvtInterruptEnable callback function (if it exists) for each interrupt,
and then it calls the driver's EvtDeviceD0EntryPostInterruptsEnabled callback function (if it exists), so
that the driver can enable device interrupts.
4. If the hardware and driver support DMA, the framework calls the driver's EvtDmaEnablerFill,
EvtDmaEnablerEnable, and EvtDmaEnablerSelfManagedIoStart callback functions (if they exist) for
each DMA channel that was created.
5. The framework calls the driver's EvtChildListScanForChildren callback function (if it exists).
6. The framework starts all of the device's power-managed I/O queues.
7. If the driver is using self-managed I/O, the framework calls the driver's EvtDeviceSelfManagedIoInit
callback function.
For more information about the power-up sequence for KMDF function or filter drivers, Power-Up Sequence for
a Function or Filter Driver.
A User Unplugs a Device
2/5/2021 • 3 minutes to read • Edit Online

While a system is running, a user can remove a device in one of two ways: by orderly removal, which means that
the user informs the system that the device is about to be removed (for example, by using the Unplug or Eject
Hardware program); or by surprise removal, which means that the user unplugs the device without informing
the system. If the bus supports surprise removal (for example, USB), the device's drivers must be able to handle
the device's sudden disappearance.
Orderly Removal
The user requests removal by using the system's Unplug or Eject Hardware program, by disabling the device by
using Device Manager, or by pushing an ejectable device's eject button. The framework allows the device to be
removed or disabled, unless the driver has:
Called WdfDeviceSetSpecialFileSuppor t and a special file is open on the device.
Called WdfDeviceSetStaticStopRemove .
Supplied an EvtDeviceQueryRemove callback function, and the callback function has vetoed the removal.
For each function and filter driver that supports the device, the framework does the following, in sequence, one
driver at a time, starting with the driver that is highest in the driver stack:
1. If the driver is using self-managed I/O, the framework calls the driver's EvtDeviceSelfManagedIoSuspend
callback function.
2. The framework stops all of the driver's power-managed I/O queues.
3. If the hardware and driver support DMA, the framework calls the driver's
EvtDmaEnablerSelfManagedIoStop, EvtDmaEnablerFlush, and EvtDmaEnablerDisable callback functions
(if they exist) for each DMA channel that was created.
4. The framework calls the driver's EvtDeviceD0ExitPreInterruptsDisabled callback function (if it exists), and
then calls the driver's EvtInterruptDisable callback function (if it exists) for each interrupt so that the driver
can disable device interrupts.
5. The framework calls the driver's EvtDeviceD0Exit callback function (if it exists).
6. The framework calls the driver's EvtDeviceReleaseHardware callback function (if it exists), passing it the
list of hardware resources that the PnP manager has assigned to the device.
7. If the driver is using self-managed I/O, the framework calls the driver's EvtDeviceSelfManagedIoFlush
callback function.
8. If the driver is using self-managed I/O, the framework calls the driver's EvtDeviceSelfManagedIoCleanup
callback function.
The bus driver is the driver in the stack that is called last. When the framework calls the bus driver's
EvtDeviceD0Exit callback function, the callback function sets the power state of the device (a child device of the
bus) to D3. The bus driver can control when the framework calls its EvtDeviceReleaseHardware callback function
by calling WdfDeviceInitSetReleaseHardwareOrderOnFailure .
Surprise Removal
A user unplugs a device unexpectedly. The bus driver for the device's bus discovers that the device is missing
and calls WdfChildListUpdateChildDescriptionAsMissing .
For each function and filter driver that supports the device, the framework does the following, in sequence, one
driver at a time, starting with the driver that is highest in the driver stack:
1. The framework calls the driver's EvtDeviceSurpriseRemoval callback function (if it exists).
2. If the device was in its working (D0) state when it was unplugged, the framework stops all of the driver's
power-managed I/O queues.
3. If the device was in its working (D0) state when it was unplugged, and if the driver is using self-managed
I/O, the framework calls the driver's EvtDeviceSelfManagedIoSuspend callback function.
4. If the hardware and driver support DMA, the framework calls the driver's
EvtDmaEnablerSelfManagedIoStop, EvtDmaEnablerFlush, and EvtDmaEnablerDisable callback functions
(if they exist) for each DMA channel that was created.
5. The framework calls the driver's EvtDeviceD0ExitPreInterruptsDisabled and EvtInterruptDisable callback
functions (if they exist) so that the driver can disable device interrupts.
6. The framework calls the driver's EvtDeviceD0Exit callback function (if it exists).
7. The framework calls the driver's EvtDeviceReleaseHardware callback function (if it exists), passing the list
of hardware resources that the PnP manager has assigned to the device.
8. If the driver is using self-managed I/O, the framework calls the driver's EvtDeviceSelfManagedIoFlush
callback function.
9. If the driver is using self-managed I/O, the framework calls the driver's EvtDeviceSelfManagedIoCleanup
callback function.
Note that a device can be unexpectedly removed at any time. Therefore, the framework might call the driver's
EvtDeviceSurpriseRemoval callback function at a time other than that shown in the previous steps. For example,
if a user unexpectedly unplugs the device while it is entering a low-power state, the framework might call the
EvtDeviceSurpriseRemoval callback function after it calls the EvtDeviceReleaseHardware callback function. You
must not code an EvtDeviceSurpriseRemoval callback function in a manner that assumes that it and other
callback functions are called in a particular sequence.
In addition, the framework does not synchronize a device's EvtDeviceSurpriseRemoval callback function with any
of the callback functions listed in the previous steps for that device. Therefore, the EvtDeviceSurpriseRemoval
callback function might run while another of the previously listed callback functions is also running.
A Device Enters a Low-Power State
2/5/2021 • 2 minutes to read • Edit Online

A device leaves its working (D0) state and enters a low-power state if one of the following occurs:
The device is idle (that is, not being accessed) and is capable of entering a low-power idle state while the
system remains in its working (S0) state.
The system's power state has changed from its working (S0) state to a low-power state. (Drivers can call
WdfDeviceGetSystemPowerAction to determine the reason that a system's power state is changing.)
For each function and filter driver that supports the device, the framework does the following, in sequence, one
driver at a time, starting with the driver that is highest in the driver stack:
1. If the driver is using self-managed I/O, the framework calls the driver's EvtDeviceSelfManagedIoSuspend
callback function.
2. The framework stops all of the driver's power-managed I/O queues and calls their EvtIoStop callback
functions (if they exist).
3. If the driver is the device's power policy owner, the framework calls its EvtDeviceArmWakeFromS0,
EvtDeviceArmWakeFromSx, or EvtDeviceArmWakeFromSxWithReason callback function.
4. If the hardware and driver support DMA, the framework calls the driver's
EvtDmaEnablerSelfManagedIoStop, EvtDmaEnablerFlush, and EvtDmaEnablerDisable callback functions
(if they exist) for each DMA channel created.
5. The framework calls the driver's EvtDeviceD0ExitPreInterruptsDisabled callback function (if it exists), and
then it calls the driver's EvtInterruptDisable callback function (if it exists) for each interrupt, so that the
driver can disable device interrupts.
6. The framework calls the driver's EvtDeviceD0Exit callback function (if it exists).
The bus driver is the driver in the stack that is called last. When the framework calls the bus driver's
EvtDeviceD0Exit callback function, the callback function sets the power state of the device (a child device of the
bus) to a low-power state. The framework specifies the D3 low-power state unless the power policy owner has
specified a different low-power state.
A Device Returns to Its Working State
2/5/2021 • 2 minutes to read • Edit Online

A device that is in a low-power state returns to its working state if one of the following occurs:
The device detects an external event and triggers a wake signal on its bus. The bus driver that detects the
wake signal calls WdfDeviceIndicateWakeStatus . As a result, the framework calls the bus driver's
EvtDeviceDisableWakeAtBus callback function.
The device has been idle and a driver calls WdfDeviceStopIdle .
The system's power state has changed from a low-power state to its working (S0) state.
In each of these situations, the framework calls the bus driver's EvtDeviceD0Entry callback function, which then
restores the device (a child device of the bus) to its working (D0) state.
For each function and filter driver that supports the device, the framework does the following, in sequence, one
driver at a time, starting with the driver that is lowest in the driver stack:
1. The framework calls the driver's EvtDeviceD0Entry callback function (if it exists).
2. The framework calls the driver's EvtInterruptEnable callback function (if it exists) for each interrupt, and
then it calls the driver's EvtDeviceD0EntryPostInterruptsEnabled callback function (if it exists), so that the
driver can enable device interrupts.
3. If the hardware and driver support DMA, the framework calls the driver's EvtDmaEnablerFill,
EvtDmaEnablerEnable, and EvtDmaEnablerSelfManagedIoStart callback functions (if they exist) for each
DMA channel that was created.
4. If the driver is the device's power policy owner, the framework calls its EvtDeviceDisarmWakeFromS0 or
EvtDeviceDisarmWakeFromSx callback function.
5. The framework calls the driver's EvtChildListScanForChildren callback function (if it exists).
6. The framework restarts all of the driver's power-managed I/O queues and calls their EvtIoResume
callback functions (if necessary).
7. If the driver is using self-managed I/O, the framework calls the driver's EvtDeviceSelfManagedIoRestart
callback function.
The PnP Manager Redistributes System Resources
2/5/2021 • 2 minutes to read • Edit Online

If a user adds a device to a system, and if the device requires system resources that the PnP manager has
already assigned to another device, the PnP manager attempts to reassign resources.
During this process, the PnP manager stops devices and takes them out of their working (D0) states. It then
delivers new resource lists to the devices so that they can restart, using the new resources.
When redistributing resources, the PnP manager will not alter a device's resource assignment if one of the
device's drivers has:
Called WdfDeviceSetSpecialFileSuppor t and a special file is open on the device.
Called WdfDeviceSetStaticStopRemove .
Supplied an EvtDeviceQueryStop callback function, and the callback function has vetoed the
reassignment.
Power-Down Sequence
For each function and filter driver that supports the device being stopped, the framework does the following, in
sequence, one driver at a time, starting with the driver that is highest in the driver stack:
1. If the driver is using self-managed I/O, the framework calls the driver's EvtDeviceSelfManagedIoSuspend
callback function.
2. The framework stops all of the device's power-managed I/O queues.
3. If the hardware and driver support DMA, the framework calls the driver's
EvtDmaEnablerSelfManagedIoStop, EvtDmaEnablerFlush, and EvtDmaEnablerDisable callback functions
for each DMA channel that was created.
4. Calls the driver's EvtDeviceD0ExitPreInterruptsDisabled and EvtInterruptDisable callback functions (if they
exist) so that the driver can disable device interrupts.
5. The framework calls the driver's EvtDeviceD0Exit callback function (if it exists).
6. The framework calls the driver's EvtDeviceReleaseHardware callback function (if it exists) passing the list
of hardware resources that the PnP manager has assigned to the device.
The bus driver is the lowest driver in the stack and is called last. When the framework calls the bus driver's
EvtDeviceD0Exit callback function, it passes a handle to the framework device object representing the device's
PDO and a TargetState value of WdfPowerDeviceD3Final . The bus driver can control when the framework
calls its EvtDeviceReleaseHardware callback function by calling
WdfDeviceInitSetReleaseHardwareOrderOnFailure .
Power-Up Sequence
The first driver called is the bus driver. When the framework calls the bus driver's EvtDeviceD0Entry callback
function, the callback function restores the device (a child device of the bus) to its working (D0) state.
For each function and filter driver that supports the device, the framework does the following, in sequence, one
driver at a time, starting with the driver that is lowest in the driver stack:
1. The framework calls the driver's EvtDevicePrepareHardware callback function (if it exists), passing the list
of hardware resources that the PnP manager has assigned to the device.
2. The framework calls the driver's EvtDeviceD0Entry callback function (if it exists).
3. The framework calls the driver's EvtInterruptEnable and EvtDeviceD0EntryPostInterruptsEnabled callback
functions (if they exist) so that the driver can enable device interrupts.
4. If the hardware and driver support DMA, the framework calls the driver's EvtDmaEnablerFill,
EvtDmaEnablerEnable, and EvtDmaEnablerSelfManagedIoStart callback functions for each DMA channel
that was created.
5. The framework calls the driver's EvtChildListScanForChildren callback function (if it exists).
6. The framework restarts all of the device's power-managed I/O queues.
7. If the driver is using self-managed I/O, the framework calls the driver's EvtDeviceSelfManagedIoRestart
callback function.
PnP and Power Management Callback Sequences
2/5/2021 • 2 minutes to read • Edit Online

The following topics show the sequence in which the framework calls a WDF (KMDF and UMDF v2) driver's PnP
and Power Management event callback functions:
Power-Up Sequence for a Function or Filter Driver
Power-Up Sequence for a Bus Driver
Power-Down and Removal Sequence for a Function or Filter Driver
Power-Down and Removal Sequence for a Bus Driver
Surprise-Removal Sequence
WDM IRPs and corresponding WDF event callbacks
The following topics identify typical PnP and power management scenarios and show the sequence in which the
framework calls a driver's event callback functions during these scenarios:
A User Plugs in a Device
A User Unplugs a Device
A Device Enters a Low-Power State
A Device Returns to Its Working State
The PnP Manager Redistributes System Resources
Power-Up Sequence for a Function or Filter Driver
2/5/2021 • 2 minutes to read • Edit Online

The following figure shows the order in which the framework calls a WDF (KMDF and UMDF V2) function or
filter driver's event callback functions when bringing a device to the fully operational state, starting from the
Device Inserted state at the bottom of the figure:

The broad horizontal lines mark the steps that are involved in starting a device. The column on the left side of
the figure describes the step, and the column on the right lists the event callbacks that accomplish it.
At the bottom of the figure, the device is not present on the system. When the user inserts the device, the
framework begins by calling the driver’s EvtDriverDeviceAdd callback so that the driver can create a device
object to represent the device. The framework continues calling the driver’s callback routines by progressing up
through the sequence until the device is operational. Remember that the framework invokes the event callbacks
in bottom-up order as shown in the figure, so EvtDeviceFilterRemoveResourceRequirements is called before
EvtDeviceFilterAddResourceRequirements and so on. If the device was stopped to rebalance resources or was
physically present but in a low-power state, not all of the steps are required, as the figure shows.
Power-Up Sequence for a Bus Driver
2/5/2021 • 2 minutes to read • Edit Online

The following figure shows the order in which the framework calls a KMDF bus driver's event callback functions
when bringing a device to the fully operational state, starting from the Device Inserted state at the bottom of the
figure:

The framework does not physically delete a PDO until the corresponding device is physically removed from the
system. For example, if a user disables the device in Device Manager but does not physically remove it, the
framework retains its device object. Thus, the three steps at the bottom of the figure occur only during Plug and
Play enumeration—that is, during initial boot or when the user inserts a new device. If the device was previously
disabled but not physically removed, the framework starts by calling the EvtDevicePrepareHardware callback.
Power-Down and Removal Sequence for a Function
or Filter Driver
2/5/2021 • 2 minutes to read • Edit Online

The following figure shows the order in which the framework calls a KMDF function or filter driver's event
callback functions when powering down and removing the device. The sequence starts at the top of the figure
with an operational device that is in the working power state (D0):

As the figure shows, the KMDF power-down and removal sequence involves calling the corresponding "undo"
callbacks in the reverse order in which the framework called the functions that are involved in making the device
operational. The framework deletes the device object after it deletes the device object context area.
Power-Down and Removal Sequence for a Bus
Driver
2/5/2021 • 2 minutes to read • Edit Online

The following figure shows the order in which the framework calls a KMDF bus driver's event callback functions
when powering down and removing a device that is connected to the bus. The sequence starts at the top of the
figure with an operational device that is in the working power state (D0):

The framework does not delete the PDO until the device is physically removed from the system. For example, if
a user disables the device in Device Manager or stops it in the Safely Remove Hardware utility but does not
physically remove the device, the framework retains the PDO. If the device is later re-enabled, the framework
uses the same PDO and begins the startup sequence by calling the EvtDevicePrepareHardware callback, as
shown in Power-Up Sequence for a Physical Device Object.
Note : Typically, the framework calls a bus driver's EvtDeviceReleaseHardware callback function after it has called
the EvtDeviceReleaseHardware function for all child devices that the driver enumerates. In the event of the
parent encountering a device power-up or power-down failure, the framework might call the driver's
EvtDeviceReleaseHardware before it has called the EvtDeviceReleaseHardware functions for all child devices.
Consider calling WdfDeviceInitSetReleaseHardwareOrderOnFailure to ensure that the framework calls the bus
driver's EvtDeviceReleaseHardware callback only after all child devices have been removed.
Surprise-Removal Sequence
2/5/2021 • 2 minutes to read • Edit Online

If the user removes the device without warning, by simply unplugging it without using Device Manager or the
Safely Remove Hardware utility, the device is considered "surprise-removed." When this occurs, the framework
follows a slightly different removal sequence. It also follows the surprise-removal sequence if another driver
calls IoInvalidateDeviceState on the device, even if the device is still physically present. In the surprise-
removal sequence, the framework calls the EvtDeviceSurpriseRemoval callback before calling any of the other
callbacks in the removal sequence. When the sequence is complete, the framework destroys the device object.
Drivers for all removable devices must ensure that the callbacks in both the shutdown and startup paths can
handle failure, particularly failures that are caused by the removal of the hardware. Any attempts to access the
hardware should not wait indefinitely, but should be subject to time-outs or a watchdog timer.
The following diagram shows the callbacks that are involved in a surprise removal:

If the device was not in the working state when it was removed, the framework calls the
EvtDeviceReleaseHardware event callback immediately after EvtDeviceSurpriseRemoval. It omits the intervening
steps, which were already performed when the device exited from the working state.
Power Management for I/O Queues
2/5/2021 • 3 minutes to read • Edit Online

When the framework receives an I/O request that is directed to one of your driver's devices, the framework puts
the request in an I/O queue. The driver can obtain I/O requests from the I/O queue by providing request
handlers or by polling the queue. For more information about I/O queues, see Framework Queue Objects.
As you are designing your driver, you should group the I/O requests that your driver will receive into two
categories:
1. Requests that require a device to be in its working (D0) state, including:
Read or write requests that require the device's function driver to read data from, or write data to, the
device.
Device control requests that a function or bus driver cannot service without accessing the device.
2. Requests that do not require a device to be in its working (D0) state, including:
Device control requests that a function or bus driver can service without accessing the device.
Possibly all the requests that a filter driver receives.
All the requests that all drivers in a driver stack receive, if the stack supports a software-only device
that does not communicate with any hardware.
Unless you are writing a filter driver, or a driver for a stack that does not communicate with hardware, it is likely
that your driver will receive some requests that require the device to be in its working state, together with some
that do not.
To support these two types of requests, the framework provides two types of I/O queues: those that are power-
managed and those that are not. When your driver creates each of its I/O queues, it sets the PowerManaged
member in the queue's WDF_IO_QUEUE_CONFIG structure to either WdfTrue or WdfFalse to indicate one of
the following:
If your driver sets PowerManaged to WdfTrue , the queue is power-managed.
When I/O requests are available in a power-managed queue, the framework delivers the requests to the
driver only if the device is in its working (D0) state. Therefore, whenever your driver receives a request
from a power-managed queue, the framework guarantees that the device is available. If the device is not
in its working state, the framework stores requests in the queue until the device becomes available.
If the device is in a low-power state because it is idle, and if the framework puts an I/O request in one of
your driver's power-managed queues, the framework asks the driver stack to restore the device to its
working state before it delivers the request to your driver.
If the device is in a low-power state because the system is not in its working (S0) state, and if the
framework puts an I/O request in one of your driver's power-managed queues, the framework waits until
the device returns to its working (D0) state and then delivers the request to your driver.
Because the framework does not deliver I/O requests from a power-managed queue to the driver if the
device is not in its working state, drivers that are located above the power policy owner in the driver stack
must not use power-managed I/O queues. If a driver that is located above the power policy owner uses a
power-managed queue, and if the device is in a low-power state, the driver does not receive the request
and cannot pass it to the power policy owner. Therefore the power policy owner, which controls the
device's power state, does not wake the device.
If your driver sets PowerManaged to WdfFalse , the queue is not power-managed.
When I/O requests are available in a queue that is not power-managed, the framework delivers the
requests to the driver regardless of whether the device is in its working (D0) state. If you have set up your
queue so that it only receives requests that do not require accessing the device, your driver can service
each request, even if the device is not available.
For more information about power-managed I/O queues, see Using Power-Managed I/O Queues.
A few drivers require some direct control over Plug and Play (PnP) and power management operations. These
drivers can use self-managed I/O. For more information, see Using Self-Managed I/O.
Using Self-Managed I/O
2/5/2021 • 3 minutes to read • Edit Online

Most framework-based drivers take advantage of the framework's PnP and power management capabilities for
the devices they support. In other words, most framework-based drivers let the framework manage a device's
PnP and power states by doing all of the following:
Supplying EvtDeviceD0Entry and EvtDeviceD0Exit callback functions.
Supplying EvtDevicePrepareHardware and EvtDeviceReleaseHardware callback functions.
Using power-managed queues for I/O requests that require the device to be in its working state, and
using queues that are not power-managed for all other requests.
However, a few framework-based drivers will require greater knowledge of the state of their devices, including
drivers in the following situations:
The operations that a driver performs are not determined by a set of I/O requests that the driver receives
from framework I/O queues.
A driver communicates with older, non-framework drivers and deals directly with WDM interfaces.
The I/O requests that a driver receives cannot be divided into two groups: those that require the device to
be in its working state and those that do not.
Most drivers are not in one of the preceding situations, but if your driver is, it might need to have more direct
control over the device's PnP and power management operations. Such drivers can use self-managed I/O. Using
self-managed I/O means that the driver is notified (by means of a set of callback functions) whenever one if its
devices is plugged in or unplugged, and whenever the device is temporarily stopped.
Note that a driver can use self-managed I/O and still use the framework's I/O queues, either as power-managed
queues or not. For example, a driver can use the framework's I/O queues, not power-managed, with a set of self-
managed I/O callback functions.
To use self-managed I/O, the driver registers an extra set of event callback functions when it calls
WdfDeviceInitSetPnpPowerEventCallbacks . These event callback functions are:
EvtDeviceSelfManagedIoInit, which initializes and starts the device's I/O operations.
EvtDeviceSelfManagedIoSuspend, which suspends I/O operations.
EvtDeviceSelfManagedIoRestart, which restarts the device's I/O operations after they have been
suspended.
EvtDeviceSelfManagedIoFlush, which removes unserviced I/O requests.
EvtDeviceSelfManagedIoCleanup, which deallocates resources that were allocated by
EvtDeviceSelfManagedIoInit.
When your device enters its working (D0) state for the first time, the framework calls your driver's
EvtDeviceSelfManagedIoInit callback function. This happens each time a user plugs your device into the system
and each time the system is restarted.
There are three circumstances in which a driver must stop a device's I/O operations: the device is about to enter
a low-power state, it is about to be removed, or it has already been removed unexpectedly. The following list
examines each of these circumstances in detail:
The device is about to enter a low-power state and will eventually return to its working state.
When your device is about to enter a low-power state (because either your device has been idle, the
entire system is entering a low-power state, or the PnP manager is redistributing system hardware
resources), the framework calls your driver's EvtDeviceSelfManagedIoSuspend callback function. After the
device reenters its working state, the framework calls your driver's EvtDeviceSelfManagedIoRestart
callback function.
The device is about to be removed.
To handle user-requested device removal, the framework calls your driver's
EvtDeviceSelfManagedIoSuspend callback function before stopping the device. After stopping the device,
the framework calls your driver's EvtDeviceSelfManagedIoFlush callback function. After the device has
been removed, the framework calls the EvtDeviceSelfManagedIoCleanup callback function.
The device has already been removed unexpectedly (surprise removal).
If the driver for the device's bus determines that the device is no longer present, or if another driver in the
stack determines that the device is not responding, the driver that discovered the problem informs the
PnP manager. The PnP manager then informs the rest of the drivers that the device is gone. For
framework-based drivers, the framework receives the PnP manager's message and calls your driver's
EvtDeviceSelfManagedIoSuspend, EvtDeviceSelfManagedIoFlush, and EvtDeviceSelfManagedIoCleanup
callback functions.
(Your driver can also register an EvtDeviceSurpriseRemoval callback function. If the device was in its
working (D0) state when removed, the framework calls EvtDeviceSurpriseRemoval before it calls the self-
managed I/O callback functions. If the device was in a low-power state when removed,
EvtDeviceSurpriseRemoval is called after EvtDeviceSelfManagedIoSuspend)
For more information about the order in which the framework calls a driver's event callback functions, see PnP
and Power Management Scenarios.
Although rarely necessary, the framework allows drivers to have even more control over a device's PnP and
power states, by accessing the state machines in the framework.
Handling Requests to Stop a Device
2/5/2021 • 2 minutes to read • Edit Online

There are two circumstances in which, before asking a device's drivers to stop a device, the PnP manager asks
the drivers if stopping the device is a good idea:
A user has plugged in a new device, and the PnP manager must redistribute the system's hardware
resources to accommodate the new device.
A user has indicated that he or she would like to remove the device.
There are several ways in which a driver can handle these situations:
If your driver has called WdfDeviceSetSpecialFileSuppor t because a device is supporting a special
file, and if a special file is open on the device, the framework will not allow the device to be stopped.
To temporarily prevent all stoppages for a relatively short period of time, the driver can call
WdfDeviceSetStaticStopRemove .
To evaluate and process each stop attempt individually, the driver can provide EvtDeviceQueryStop and
EvtDeviceQueryRemove callback functions.
If the device is not supporting special files, and if stopping or removing a device is never a problem for the
driver or device, the driver doesn't provide EvtDeviceQueryStop and EvtDeviceQueryRemove callback functions
and never calls WdfDeviceSetStaticStopRemove . In this case the PnP manager always stops the device
without first checking to see if the driver allows it.
Redistributing Resources
Sometimes the PnP manager must redistribute the system's hardware resources. Typically, this redistribution
occurs because a bus driver has reported that a new device has been plugged in, and the new device requires
already-assigned resources. Devices must be stopped before resources are reassigned.
If it is necessary for your driver to sometimes prevent the PnP manager from stopping a busy device, the driver
can provide an EvtDeviceQueryStop callback function. If your driver's EvtDeviceQueryStop callback function
returns an error status value, the PnP manager will not stop the device.
If the driver determines that it is safe to stop the device, the callback function returns STATUS_SUCCESS. If none
of the device's other drivers prevent stoppage, the PnP manager temporarily stops the device.
For information about the order in which the framework calls a driver's event callback functions when the PnP
manager stops a device to redistribute resources, see The PnP Manager Redistributes System Resources.
A User Removes or Disables a Device
A user can remove or disable some devices. For example:
If your driver has set the Removable member (and not the SurpriseRemovalOK member) of the
device's WDF_DEVICE_PNP_CAPABILITIES structure, the user can run the Unplug or Eject Hardware
program and then unplug or eject the device.
If your driver has not set the NotDisableable member of the device's WDF_DEVICE_STATE structure,
the user can use Device Manager to disable the device.
In such cases, the PnP manager attempts to stop the device before the user removes it.
If it is necessary for your driver to sometimes prevent removal of a busy device, the driver can provide an
EvtDeviceQueryRemove callback function. If any driver's EvtDeviceQueryRemove callback function returns an
error status value, the PnP manager will not stop the device.
If the driver determines that it is safe for the user to remove the device, the callback function returns
STATUS_SUCCESS. If none of the device's other drivers prevent removal, the PnP manager stops the device.
For information about the order in which the framework calls a driver's event callback functions when stopping
a device for removal, see A User Unplugs a Device.
Power Policy Ownership
2/5/2021 • 2 minutes to read • Edit Online

For each device, one (and only one) of the device's drivers must be the device's power policy owner. The power
policy owner determines the appropriate device power state for a device and sends requests to the device's
driver stack whenever the device's power state should change.
Framework-based drivers do not contain code that requests changes in a device's power state, because the
framework provides that code. By default, whenever the system enters a system sleeping state, the framework
asks the driver for your device's bus to lower the device power state to D3. (Your driver can change the default
behavior so that the framework sets your device's sleep state to D1 or D2, if the device provides wake-up
capabilities.) When the system power returns to its working (S0) state, the framework requests the bus driver to
restore your device to its working (D0) state.
The power policy owner is also responsible for enabling and disabling the following device features:
Your device's ability to enter a low-power (sleeping) state when it is idle and the system remains in its
working (S0) state
Your device's ability to wake itself up from a sleeping state when it detects an external event
Your device's ability to wake up the entire system from a system sleeping state when it detects an external
event
If your device supports these idle power-down and system wake-up capabilities, the power policy owner can
also call WdfDeviceInitSetPowerPolicyEventCallbacks to register a set of power policy event callback
functions.
By default, for framework-based drivers, the device's function driver is the power policy owner. (If there is no
function driver and the bus driver has called WdfPdoInitAssignRawDevice , the bus driver is the power policy
owner). If you want to change the power policy owner for a driver stack, the default power policy owner must
call WdfDeviceInitSetPowerPolicyOwnership to disable ownership, and the driver that will be the power
policy owner must call WdfDeviceInitSetPowerPolicyOwnership to enable ownership.
The framework does the following work for the power policy owner:
It handles all power policy communication between your driver and the rest of the driver stack. For
example, your driver does not have to request the bus driver to change the device's power state, because
the framework makes the request.
If your driver registers power policy event callback functions, the framework calls them when it is time to
enable or disable the device's ability to wake itself from a low-power state.
If your driver allows users to modify idle and wake settings, the framework provides a user interface in
the form of a property sheet page that Device Manager displays.
For more information about the power policy owner's responsibilities, see the following topics:
Supporting Idle Power-Down
Supporting System Wake-Up
User Control of Device Idle and Wake Behavior
Supporting Functional Power States
Supporting Idle Power-Down
2/5/2021 • 3 minutes to read • Edit Online

Some devices can enter a low-power (Dx) state while the system remains in its working (S0) state. Starting in
Windows 8, devices can transition to a low-power functional power state (Fx) prior to entering a Dx state. For
such devices, the framework initiates lowering power of the device or component after the device has been idle
(not used) for a predetermined (and settable) amount of time.
Some of these devices can also trigger a wake-up signal on the bus when they detect an external event. The bus
driver responds to this signal, and the driver stack restores the device to its working state. (Devices that do not
detect external events remain in a low-power state until the framework asks the bus driver to initiate restoring
the device to its working state.)
If your device or component can be powered down when it is idle, the EvtDriverDeviceAdd callback function in
the power policy owner must perform the following two steps:
1. Call WdfDeviceAssignS0IdleSettings to specify:
The low-power state that the device will enter
The amount of time that the device must remain idle before its power state is lowered
Whether the device can detect an external event and trigger a wake-up signal on the bus
Whether users can control the device's idle settings
Whether the device's idle power-down capability is enabled or disabled
Whether the device will return to its working (D0) state when the system returns to its working (S0)
state
Whether the idle timeout value for the device is determined by the power management framework
(PoFx)
Whether the framework can put the device in the D3cold power state when the idle timeout period
expires
For more information about these settings, see the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS
structure, as well as Supporting Functional Power States.
2. Call WdfDeviceInitSetPowerPolicyEventCallbacks to register the following event callback functions,
if you need them for your device:
EvtDeviceArmWakeFromS0, which enables the device hardware (not the bus) to respond to an
external wake-up event
EvtDeviceDisarmWakeFromS0, which disables the device's ability (not the bus's ability) to respond to
an external wake-up event
EvtDeviceWakeFromS0Triggered, which informs the driver that the bus detected a wake signal.

Idle Conditions
The framework considers the device to be idle, and starts counting idle time, when all of the following
conditions are met:
None of the power-managed queues created for this device instance have any requests waiting in queue or
dispatched to the driver. If a request was dispatched to the driver and the driver sent it to an I/O target, the
request is still related to the queue. The device will not be considered idle, unless the driver used the send
and forget option to send the request. Requests in non-power managed queues are not counted toward
device idle.
If the driver previously called WdfDeviceStopIdle , the driver has subsequently called
WdfDeviceResumeIdle .
If the power policy owner is a bus driver, none of the child devices of the bus driver are in D0.
If your driver (or a user) enables idle power-down for your device, you might have to use the
WdfDeviceStopIdle method. If the device is in its working (D0) state, this method prevents the device from
idling until the driver calls WdfDeviceResumeIdle . If the device is in a low-power state when the driver calls
WdfDeviceStopIdle , and if the system is in its working (S0) state, the framework requests the bus driver to
restore the device to its working (D0) state. Every successful call to WdfDeviceStopIdle must be matched by a
call to WdfDeviceResumeIdle . For information about viewing the power reference count in the debugger, see
Debugging Power Reference Leaks in WDF.
For more information about when your driver might have to call WdfDeviceStopIdle , see the method's
reference page.
If the device can wake itself from a low-power state, the driver for the device's bus participates in waking the
device. The bus driver typically provides EvtDeviceEnableWakeAtBus and EvtDeviceDisableWakeAtBus callback
functions. These functions do whatever is necessary on the bus adapter to enable and disable a device's ability to
wake from a low-power state.
For information about registry entries that control a device's idle capabilities, see User Control of Device Idle and
Wake Behavior.
Supporting System Wake-Up
2/5/2021 • 2 minutes to read • Edit Online

While the system is in a low-power state, some devices can detect an external event, such as an incoming
network packet, and then wake the system. For example, if a PCI device has a system wakeup capability, as
indicated in the device's Power Management Capabilities (PMC) register, it wakes the system by raising the
Power Management Event (PME) signal on the PCI bus.
If your device can wake the system from a system-wide low-power state, the EvtDriverDeviceAdd callback
function in the power policy owner must perform the following two steps:
1. Call WdfDeviceAssignSxWakeSettings to specify:
The low-power state that the device will enter
Whether users can control the device's idle settings
Whether the device's wake capability is enabled or disabled
For more information about these settings, see the WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS
structure.
2. Call WdfDeviceInitSetPowerPolicyEventCallbacks to register the following event callback functions,
if you need them for your device:
EvtDeviceArmWakeFromSx or EvtDeviceArmWakeFromSxWithReason, which enable the device
hardware to respond to an external wake-up event.
EvtDeviceDisarmWakeFromSx, which disables the device's ability to respond to an external wake-up
event.
EvtDeviceWakeFromSxTriggered, which informs the driver that the bus detected a wake signal.
Bus drivers also participate in waking up the system. The driver for the device's bus typically provides
EvtDeviceEnableWakeAtBus and EvtDeviceDisableWakeAtBus callback functions. These functions do whatever is
necessary on the bus adapter to enable and disable a device's ability to wake from a low-power state.
When a bus driver determines that a device has triggered a wake signal, it must call
WdfDeviceIndicateWakeStatus to inform the framework that the device's power should be restored. The
framework then passes this information to the rest of the drivers in the driver stack.
For information about registry entries that control a device's wake capabilities, see User Control of Device Idle
and Wake Behavior.
User Control of Device Idle and Wake Behavior
2/5/2021 • 2 minutes to read • Edit Online

If a device has idle power-down or wake-up capabilities, you can decide whether users should be allowed to
enable or disable these capabilities.
Your driver can use members of the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure to specify
whether users with registry access can enable or disable a device's idle power-down capability.
Your driver can use members of the WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS structure to specify
whether users with registry access can enable or disable a device's wake-up capability.
Both of these structures allow the driver to enable the capability, disable the capability, or give users control of
the capability. To give users control, in the appropriate settings structure the driver sets the
UserControlOfIdleSettings or UserControlOfWakeSettings member to IdleAllowUserControl or
WakeAllowUserControl , respectively, and the Enabled member to WdfTrue or WdfUseDefault ,.
If your driver allows users to modify idle and wake settings, the framework provides a user interface, in the form
of a property sheet page that Device Manager displays so that users can enable or disable the idle and wake
capabilities. (The framework modifies IdleInWorkingState and WakeFromSleepState registry values. Drivers
and their installation files must not read or modify these values.)
If a user modifies a device's settings, the framework updates the device's power state to match the new settings,
if necessary. For example, if the user disables a device's idle power-down capability while the device is already in
a low-power state because it was idle, the framework returns the device to its working state.
If your driver allows users to modify idle and wake settings, the framework enables these settings by default.
Some driver writers might want to initially disable the settings before allowing users to modify them.
Therefore, for version 1.9 and later versions of KMDF, the framework provides two driver-definable registry
values, named WdfDefaultIdleInWorkingState and WdfDefaultWakeFromSleepState , which are stored in
the device's Device Parameters\WDF subkey, under the device's hardware key. The values are REG_DWORD-
typed, with "0" indicating the capability is disabled and "1" indicating the capability is enabled.
Your driver's INF file can use an INF AddReg directive to create and set the WdfDefaultIdleInWorkingState
and WdfDefaultWakeFromSleepState registry values. For example, if your driver enables a device's idle
power-down capability, but if the capability must be disabled when the device is installed, the driver's INF file
can set WdfDefaultIdleInWorkingState to "0".
The framework examines the WdfDefaultIdleInWorkingState and WdfDefaultWakeFromSleepState
registry values only if the driver has set the UserControlOfIdleSettings or UserControlOfWakeSettings
member to IdleAllowUserControl or WakeAllowUserControl , respectively, and the Enabled member to
WdfTrue or WdfUseDefault , in the appropriate settings structure.
Supporting Functional Power States
2/5/2021 • 2 minutes to read • Edit Online

Starting in Windows 8, the power manager includes the run-time power management framework (PoFx). PoFx
supports power and clock management at the component (or subdevice) level.
Starting in KMDF version 1.11, KMDF drivers can take advantage of the fine-grained power control that PoFx
offers. In particular, a KMDF driver can define multiple logical components within a single device, each of which
can be independently power managed.
For example, a function driver might define a unique set of functional power states for each logical component
of a device. Similar to device and system power states, F0 indicates that the component is fully on, while
optional states F1, F2, and so on indicate progressively lower power states. To support Fx states, a driver must be
the power policy owner for the device.
The following table summarizes framework support for different functional power state scenarios.

W H EN TO USE/ H O W TO
TYPE K M DF SUP P O RT UM DF SUP P O RT IM P L EM EN T

Single component, Supported Supported When you want the


single state (F0) power engine plug-in
(PEP) to determine the
idle timeout value, and
your driver has only
one F-state.
Call
WdfDeviceAssignS0I
dleSettings with
IdleTimeoutType =
SystemManagedIdle
Timout or
SystemManagedIdle
TimoutWithHint .
W H EN TO USE/ H O W TO
TYPE K M DF SUP P O RT UM DF SUP P O RT IM P L EM EN T

Single component, Supported Not supported When your driver has


multiple states (F0, F1, more than one F-state.
F2…)
Call
WdfDeviceWdmAs
signPowerFramew
orkSettings to
register WDM PoFx
callbacks.
Call
WdfDeviceAssign
S0IdleSettings
with
IdleTimeoutType =
SystemManagedI
dleTimout .
In this case, KMDF
handles most
interactions with the
PoFx.
For sample code, see
PoFx sample drivers.

Multiple components, Supported using WDM Not supported When your driver has
single or multiple states interfaces multiple components.
In this case, you must
use the PoFx interfaces
directly.
For sample code, see
PoFx sample drivers.

Because KMDF adds minimal abstraction on top of PoFx, it is helpful to have a basic understanding of PoFx
before writing your driver. Accordingly, we recommend that you read Overview of the Power Management
Framework before reading these topics.
Supporting Single-Component Devices with Single
or Multiple Functional Power States
2/5/2021 • 4 minutes to read • Edit Online

A KMDF driver for a single-component device can define one or more functional power states for the
component and register callback functions that the power management framework (PoFx) calls when the Fx
state of the component changes or its active/idle condition changes. Starting in UMDF version 2.0, a UMDF
driver for a single-component device can define a single functional power state (F0).
For more information about PoFx, see Overview of the Power Management Framework.
To implement Fx state support for a single-component device, you must do the following in order before or
during the first time a device starts.
1. This step is for KMDF drivers only. Call WdfDeviceWdmAssignPowerFrameworkSettings to specify
the power framework settings that WDF uses when registering with PoFx. In the
WDF_POWER_FRAMEWORK_SETTINGS structure that the driver provides when it calls
WdfDeviceWdmAssignPowerFrameworkSettings , the driver can provide pointers to several callback
functions. If the driver supports only a single functional power state (F0), this step is optional.
2. This step applies to KMDF drivers and UMDF drivers. Call WdfDeviceAssignS0IdleSettings and set the
IdleTimeoutType field of the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure to
SystemManagedIdleTimeout or SystemManagedIdleTimeoutWithHint . Doing so causes WDF to
register with PoFx.
For KMDF drivers, when registering with PoFx, the framework uses the information that the driver
provided in WDF_POWER_FRAMEWORK_SETTINGS when it called
WdfDeviceWdmAssignPowerFrameworkSettings .
Because a device can start more than once, for example in the event of resource rebalancing, a driver might
perform the previous steps within the EvtDeviceSelfManagedIoInit callback function. If the driver has registered
an EvtDeviceSelfManagedIoInit callback function, the framework calls it once for each device, after the
framework has called the driver's EvtDeviceD0Entry callback function for the first time.
The remainder of the information in this topic applies only to KMDF drivers.

Powering Up
When the driver calls WdfDeviceWdmAssignPowerFrameworkSettings , it can provide a pointer to a
EvtDeviceWdmPostPoFxRegisterDevice callback function.
The framework calls the driver's EvtDeviceWdmPostPoFxRegisterDevice callback function after the framework
has registered with PoFx. Here is an example of a typical power up sequence:
1. EvtDevicePrepareHardware
2. EvtDeviceD0Entry (PrevState = WdfPowerDeviceD3Final )
3. EvtInterruptEnable
4. EvtDeviceWdmPostPoFxRegisterDevice // PoFx handle is available
The driver provides the EvtDeviceWdmPostPoFxRegisterDevice callback if it must perform any additional
operations using the POHANDLE for the power framework registration. For example, it could specify latency,
residency, and wake requirements. For more information about routines that use the POHANDLE, see Device
Power Management Routines.
Your driver can also use the POHANDLE to exchange power control requests with PoFx:
To send a power control request to PoFx, the driver provides a EvtDeviceWdmPostPoFxRegisterDevice
callback function, and then uses the resulting POHANDLE to call PoFxPowerControl .
To perform power control operations requested by PoFx, the driver provides a PowerControlCallback callback
routine in its WDF_POWER_FRAMEWORK_SETTINGS structure.

Powering Down
WDF calls the EvtDeviceWdmPrePoFxUnregisterDevice callback function before deleting a specified registration
with PoFx.
The driver can provide a pointer to a ComponentIdleStateCallback routine in the
WDF_POWER_FRAMEWORK_SETTINGS structure that it provides to
WdfDeviceWdmAssignPowerFrameworkSettings . PoFx calls this routine to notify the driver of a pending
change to the Fx power state of the specified component. In this callback routine, the driver can perform
hardware-specific operations related to the functional state change.
For example, before transitioning a component into a low-power Fx state, a driver might save hardware state
and disable interrupts and DMA. The driver calls WdfInterruptRepor tInactive to inform the system that the
interrupt is no longer active. Turning off interrupts during F-state transitions may reduce overall system power
consumption.
The driver can also provide a pointer to a ComponentIdleConditionCallback routine in its
WDF_POWER_FRAMEWORK_SETTINGS structure. PoFx calls this routine to notify the driver that a
component has become idle. In this routine, the driver begins the process of stopping its power-managed
queues and self-managed I/O operations:
1. Call WdfIoQueueStop once for each of the device’s power-managed queues. In each call to
WdfIoQueueStop , supply a EvtIoQueueState callback. Typically, the driver calls WdfIoQueueStop from
within ComponentIdleConditionCallback.
2. Ensure that requests that are dispatched to the driver from each of the power-managed queues are
completed quickly. Depending on the driver, this may involve some or all of the following:
If the driver does not hold requests for an extended time and does not forward them to an I/O target
that does so, continue to step 3.
If the driver holds certain requests for an extended time, requeue these requests to a manual queue. In
its ComponentActiveConditionCallback routine, the driver can then retrieve the requests.
If the driver forwards certain requests to an I/O target that holds them for an extended time, cancel
these requests. Resubmit the requests in ComponentActiveConditionCallback.
3. When each queue has been stopped, the framework calls EvtIoQueueState. If the driver is stopping
multiple power-managed queues, the framework calls EvtIoQueueState multiple times, once for each
queue.
The driver must call PoFxCompleteIdleCondition after the last EvtIoQueueState function has been
called. For example, the driver could make this call from within the last EvtIoQueueState.
In order to determine which call is last, the driver might use a counter to track the number of times that
the framework has called EvtIoQueueState. The Singlecomp sample illustrates this technique. This sample
is available beginning in the Windows 8 WDK.
Here is an example of a typical power down sequence:
1. ComponentIdleConditionCallback
2. ComponentIdleStateCallback
3. EvtInterruptDisable
4. EvtDeviceD0Exit
Restart power-managed queues and self-managed I/O operations in ComponentActiveConditionCallback.
If the driver previously called WdfInterruptRepor tInactive , re-enable inactive interrupts by calling
WdfInterruptRepor tActive from either ComponentActiveConditionCallback or ComponentIdleStateCallback.
Supporting Multiple-Component Devices with
Single or Multiple Functional Power States
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


A KMDF driver for a multiple-component device can define one or more functional power states for each
component.
In this case, the driver registers directly with the power management framework (PoFx). To specify that WDF
should not register with PoFx, the driver calls WdfDeviceAssignS0IdleSettings with the IdleTimeoutType
member of the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure set to
DriverManagedIdleTimeout . Typically, the driver calls this method from its EvtDriverDeviceAdd callback
function.
Next, the driver must register with PoFx. To do so, the driver calls PoFxRegisterDevice and then
PoFxStar tDevicePowerManagement . Your driver must register with PoFx only once, when the device is first
started. One way to do this is by calling these routines from a driver-supplied EvtDeviceSelfManagedIoInit
function. EvtDeviceSelfManagedIoInit is called only the first time the device is started.
When the device is removed, the driver must call PoFxUnregisterDevice to unregister the device from PoFx. To
unregister only once, we recommend the driver call this routine from a driver-supplied
EvtDeviceSelfManagedIoFlush function. EvtDeviceSelfManagedIoFlush is called only when the device is being
removed. By unregistering in EvtDeviceSelfManagedIoFlush, the driver retains power registration during sleep
and rebalance transitions and does not have to maintain power references for I/O requests that remain pending
during these transitions.
When the driver calls PoFxRegisterDevice, it receives a power registration handle (POHANDLE) that it can use to
interact directly with PoFx, as described in the following topics:
Coordinating I/O Requests with Component Power State
Reporting Device Powered On When System Returns to S0
Supporting Idle Power-Down on Multiple-Component Devices
In addition, the driver can call power framework routines directly to send power control requests and specify
latency, residency, and wake requirements.
For more information about PoFx, see Overview of the Power Management Framework.
Coordinating I/O Requests with Component Power
State
2/5/2021 • 4 minutes to read • Edit Online

[Applies to KMDF only]


A KMDF driver for a multiple-component device must only send requests to components that are in an active
state. Typically, the driver assigns I/O queues to components or sets of components.
Consider first a queue that is assigned to a single component. The driver starts the queue when the component
becomes active and stops the queue when the component becomes idle. As such, when KMDF calls a request
handler for the queue, the device is in its fully on (D0) state, and the required component is active. The request
handler can safely access component hardware.
The same concept applies to a queue that is assigned to a set of components. In this case, the driver starts the
queue when all of the components in the set are active. The driver stops the queue when any one of the
components becomes idle.
This topic describes how a KMDF driver for a multiple-component device might implement such support in a
situation involving multiple request types that require different combinations of components.

Example
For each request type supported by the driver, identify the required components. For example, consider a device
that has three components: 0, 1 and 2, for which the driver receives three types of requests: A, B, and C. The
component requirements of the requests are as follows:

REQ UEST T Y P E C O M P O N EN T S N EEDED

A 0,2

B 1

C 0,1,2

In this example, there are three distinct sets of components, one for each request type. The driver supplies one
default, power-managed I/O queue for the device, as well as one additional power-managed queue
corresponding to each set of components. In the example above, the driver creates one primary queue and three
secondary queues, one corresponding to each component set. This queue configuration is shown in the
following diagram:
The driver maintains a bitmask for each component set. Each bit in the bitmask represents the active/idle state
of one of the components. If the bit is set, the component is active. If the bit is cleared, the component is idle.
When a request arrives, a request handler for the top-level queue determines which components the request
needs and calls PoFxActivateComponent for each one. The request handler then forwards the request to the
secondary I/O queue corresponding to that component’s set.
When a component becomes active, the power management framework (PoFx) calls the driver’s
ComponentActiveConditionCallback routine. In this callback, the driver sets the bit corresponding to the
specified component, in each bitmask where that component is represented. If all of the bits in a given bitmask
are set, all of the components in the corresponding set are active. For each component set that is fully active, the
driver calls WdfIoQueueStar t to start the corresponding secondary I/O queue.
For example, consider the hypothetical device above. Suppose that component 0 is active, while components 1
and 2 are idle. When component 2 becomes active, PoFx calls that component's
ComponentActiveConditionCallback routine. Request types A and C use component 2, so the driver manipulates
the bitmasks for these two request types. Because all the bits in the bitmask for request type A are now set, the
driver starts the queue for request type A. However, not all bits are set for request type C (component 1 is still
idle). The driver does not start the queue for request type C.
When a secondary I/O queue is started, the framework begins delivering the requests that are stored in the
queue. In the request handler for the secondary I/O queue, the driver can safely process the requests because
the component is active and a power reference has been taken on the component for each of the requests.
When the driver finishes processing a request, it calls PoFxIdleComponent for each component that the
request was using, and then completes the request. When there are no more requests using a component, the
power framework calls the driver’s ComponentIdleConditionCallback routine.
In this callback, the driver clears the bit corresponding to the specified component, in each bitmask where that
component is represented. If a given bitmask indicates that the component is the first one in the corresponding
set to transition to the idle condition, the driver calls WdfIoQueueStop to stop the corresponding secondary
I/O queue. By doing so, the driver ensures that the queue does not dispatch requests unless all of the
components in the corresponding set are active.
Consider again the above example. Suppose that all components are active and therefore all queues are started.
When component 1 becomes idle, PoFx calls the ComponentIdleConditionCallback routine for component 1. In
this callback, the driver manipulates the bitmasks for request types B and C because they use component 1.
Because component 1 is the first component to become idle for both these request types, the driver stops the
queues for request types B and C.
Suppose that at this point, component 0 becomes idle. In the ComponentIdleConditionCallback for component
0, the driver manipulates the bitmasks for request types A and C. Because component 0 is the first component to
become idle for request type A (component 2 is still active), the driver stops the queue for request type A.
However, for request type C, component 0 is not the first component to become idle. The driver does not stop
the queue for request type C (it did so earlier).
To use the technique described in this example, the driver must also register an EvtIoCanceledOnQueue callback
function for each of its secondary queues. If a request were to be canceled while in the secondary queue, the
driver could use this callback to call PoFxIdleComponent for each corresponding component. Doing so
releases the power reference that the request handler took when it called PoFxActivateComponent before
forwarding the request to the secondary queue.
Reporting Device Powered On When System
Returns to S0
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


When the system returns to its working (S0) state from a low-power state, the PnP manager sends a system set-
power IRP (IRP_MN_SET_POWER ) to return the device to its working (D0) state. WDF handles the system set-
power IRP. However, because in the multi-component scenario the driver has directly registered with the power
management framework (PoFx), the driver must call PoFxRepor tDevicePoweredOn when the device has
completed the transition to its fully on (D0) power state. The driver can accomplish this by registering a WDM
preprocess routine to receive notification when a system set-power IRP arrives.
The driver can use the following procedure:
1. Call WdfDeviceInitAssignWdmIrpPreprocessCallback to register a EvtDeviceWdmIrpPreprocess
callback function for IRP_MN_SET_POWER . In the callback, the driver sets a flag in its device extension to
indicate that it needs to call PoFxRepor tDevicePoweredOn from its next EvtDeviceD0Entry callback.
2. In EvtDeviceD0Entry, if the flag is set, the driver clears the flag and calls PoFxRepor tDevicePoweredOn .
3. The driver also checks the flag in EvtDeviceSelfManagedIoFlush. If the flag is set, the device failed to return to
D0 and the device has been removed. In this case, the driver calls PoFxRepor tDevicePoweredOn and then
unregisters with the power framework.
Supporting Idle Power-Down on Multiple-
Component Devices
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


A KMDF driver for a multiple-component device can support idle power-down and functional power states.
Because in this case the driver registers directly with the power management framework (PoFx), the driver must
coordinate the resulting Dx state changes with PoFx.

Providing Device Power Policy Idle Settings


When it calls WdfDeviceAssignS0IdleSettings , the driver must set IdleTimeoutType to
DriverManagedIdleTimeout in the WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS structure. In addition,
the driver must set PowerUpIdleDeviceOnSystemWake to WdfTrue , and IdleCaps to
IdleCannotWakeFromS0 , as shown in the following example.

WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS s0IdleSettings;

WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&s0IdleSettings,
IdleCannotWakeFromS0);
s0IdleSettings.IdleTimeoutType = DriverManagedIdleTimeout;
s0IdleSettings.PowerUpIdleDeviceOnSystemWake = WdfTrue;
s0IdleSettings.IdleTimeout = 1;
status = WdfDeviceAssignS0IdleSettings(device, &s0IdleSettings);

Transitioning from Working (D0) to Low-Power (Dx) State


In EvtDeviceSelfManagedIoInit, the driver calls WdfDeviceStopIdle to take a power reference, which prevents
WDF from putting the device in a low-power state.
The driver releases the power reference by calling WdfDeviceResumeIdle from its
DevicePowerRequiredCallback callback routine.
The driver typically specifies a very short idle timeout so that WDF puts the device into a low-power state soon
after all power references are released.

Transitioning from Low-Power (Dx) to Working (D0) State


In DevicePowerRequiredCallback, the driver must bring the device to its working (D0) state. To do so, it must
defer to a worker thread a call to WdfDeviceStopIdle with the WaitForD0 parameter set to TRUE. This blocking
call to WdfDeviceStopIdle must not be made from within DevicePowerRequiredCallback.
Instead, the driver must defer the blocking call to a worker thread that is running at passive level and is
guaranteed not to make the WdfDeviceStopIdle call in the context of a power-managed queue’s I/O dispatch
routine.
If the driver has previously called WdfDeviceInitSetPowerPageable (meaning it can access pageable data
during power transitions), the driver can call WdfWorkItemCreate to create a framework work item. If the
driver has not set power-pageable, the driver must create its own system thread. For more information, see
PsCreateSystemThread .
After WdfDeviceStopIdle returns, even if the method returns an error, the driver must call
PoFxRepor tDevicePoweredOn .
Porting a Driver from WDM to WDF
2/5/2021 • 2 minutes to read • Edit Online

The topics in this section describe how to convert an existing WDM driver to a Kernel-Mode Driver Framework
(KMDF) driver or a User-Mode Driver Framework (UMDF) version 2 driver.
Architecturally, Windows Driver Frameworks (WDF) drivers are similar to WDM drivers. A WDM driver consists
of a DriverEntry function, various dispatch routines that the operating system calls to service I/O requests, and
additional driver-specific utility functions. A WDF driver consists of a DriverEntr y function, various event
callback functions that the framework calls to service I/O requests, and additional driver-specific utility functions.
However, within this broad structure, the two models have important differences.

In this section
Which Drivers Can Be Ported and Where
WDM Concepts for WDF Drivers
Differences Between WDM and WDF
Preparing for Porting
Steps in Porting
Summary of KMDF and WDM Equivalents
Which Drivers Can Be Ported and Where
2/5/2021 • 2 minutes to read • Edit Online

This topic describes which WDM drivers can be ported to Windows Driver Frameworks (WDF), and how to
decide whether to port to Kernel-Mode Driver Framework (KMDF) or User-Mode Driver Framework (UMDF).

Which WDM drivers can I port to WDF?


Whether a particular driver can be ported to WDF depends on the following criteria:
The operating system versions on which the driver runs
The type of device that the driver supports
The driver model that the driver uses
In general, you can use KMDF or UMDF to write drivers that conform to WDM, supply entry points for the major
I/O dispatch routines, and handle IRPs.
For some device types, system-supplied device class and port drivers provide driver dispatch functions and call
a vendor-supplied miniport driver to handle specific I/O details. These miniport drivers are essentially callback
libraries and are not supported by WDF. In addition, WDF does not support device types that use Windows
Image Acquisition (WIA).
You can use KMDF to create drivers that run on Windows 2000 and later. You can use UMDF version 1 to write
drivers that run on Windows XP and later, and UMDF version 2 to target Windows 8.1 and later.
For information about device and driver types that UMDF and KMDF support, see Choosing a Driver Model.

Which framework should I port my WDM driver to, KMDF or UMDF 2?


1. Review the list of KMDF-only functionality in Comparing UMDF 2.0 Functionality to KMDF. If your driver
does not require any of these features, and you are targeting Windows 8.1 or later, open a new UMDF 2
driver template in Visual Studio.
If you realize later that you need a KMDF-only feature, it's straightforward to convert your UMDF 2 driver
to KMDF, as described in How to convert a KMDF driver to a UMDF 2.0 driver (and vice-versa).
2. You can also write a mode-agnostic driver, meaning one that can be compiled using either KMDF or
UMDF. To write a mode-agnostic driver, start with a UMDF 2 template. Use the DDI versioning info listed
in Summary of WDF Callbacks and Methods to ensure that you only call methods that are available in
both KMDF and UMDF 2. Conditionally tag any header references with the preprocessor macros
described in How to convert a KMDF driver to a UMDF 2.0 driver (and vice-versa). To switch your driver,
you would create an empty driver project using a Visual Studio template for the target framework, and
copy your source code over.

Related topics
Getting Started with UMDF
KMDF Version History
UMDF Version History
User-Mode Driver Framework Frequently Asked Questions
WDM Concepts for WDF Drivers
2/5/2021 • 4 minutes to read • Edit Online

Windows Driver Frameworks (WDF) is a wrapper around Microsoft Windows Driver Model (WDM) interfaces.
Although the framework simplifies many WDM concepts and hides others completely so that you do not have
to work with them, you should still understand some of the basic concepts of WDM drivers. Specifically, you
should understand driver types, driver stacks, device stacks, and I/O request packets.
Driver types
Windows-based drivers are divided into three types: bus drivers, function drivers, and filter drivers. Bus drivers
support I/O buses by detecting child devices that are plugged into a parent bus and reporting their
characteristics. (This activity is called bus enumeration.) Function drivers control I/O operations for devices and
buses. Filter drivers receive, review, and possibly modify data that flows between user applications and drivers,
or between individual drivers.
Drivers for buses are essentially function drivers that also enumerate children. A driver acts as a "bus driver"
when it enumerates the child devices on a bus. Otherwise, the same driver acts as the "function driver" for the
bus when it handles I/O operations that access the bus adapter's hardware.
A User-Mode Driver Framework (UMDF) driver cannot be a bus driver.
Driver stacks
In the Windows operating system, WDM drivers are layered in a vertical calling sequence that is called a driver
stack. The topmost driver in the stack typically receives I/O requests from user applications, after the requests
have passed through the operating system's I/O manager. The lower driver layers typically communicate with
computer hardware.
A simple driver stack includes a bus driver at the bottom of the stack, which handles bus-specific I/O operations
and enumerates the child devices that are connected to it. Typically, one or more device-specific function drivers
are above the bus driver. These function drivers handle I/O operations to the devices that are connected to the
bus. Filter drivers can be above the function drivers, or they can reside between a bus driver and function driver.
A running system has several driver stacks that support different types of devices.
Device stacks
Each driver stack supports one or more device stacks. A device stack is a set of device objects that are created
from WDM-defined DEVICE_OBJECT structures. Each device stack represents one device. Each driver creates a
device object for each of its devices and attaches each device object to a device stack. Device stacks are created
and removed as devices are plugged in and unplugged, and each time the system is rebooted.
When a bus driver detects that child devices have been plugged in or unplugged, it informs the Plug and Play
(PnP) manager. In response, the PnP manager asks the bus driver to create a physical device object (PDO) for
each child device that is connected to the parent device (that is, the bus). The PDO becomes the bottom of a
device stack.
Next, the PnP manager loads function and filter drivers to support each device (if they are not already loaded),
and then the PnP manager calls these drivers so that each can create a device object and add it to the top of the
device stack. Function drivers create functional device objects (FDOs), and filter drivers create filter device
objects (filter DOs).
When the I/O manager sends an I/O request to a device's drivers, it passes the request to the driver that created
the topmost device object in the device stack. If that driver asks the I/O manager to pass the request to the next-
lower driver, the I/O manager uses the device stack to determine the next-lower driver. (The next-lower driver is
the driver that created the next-lower device object.)
WDF creates a framework device object for each WDM device object. Framework-based drivers access these
framework device objects instead of WDM device objects.
I/O request packets
The I/O manager sends an application's I/O requests to drivers by creating I/O request packets (IRPs). An IRP can
contain a request to perform an I/O operation (such as a read/write operation) or a request to perform an I/O
control (IOCTL) action (such as returning status). In addition, the PnP manager creates IRPs that represent PnP
and power management operations that drivers must perform, and it sends these IRPs to drivers.
Typically, the I/O manager creates a read or write IRP when a user application requests a read or write operation.
The I/O manager passes the IRP to the driver at the top of the driver stack, and that driver either services the
request or passes the request to the next-lower driver. Some requests travel to the bottom of the stack, and
some are completely processed by higher-level drivers.
Each time a driver receives an IRP, the driver also receives a pointer to the device object that represents the
device that must handle the operation. Therefore, the drivers in a driver stack use device objects to determine
which of their plugged-in devices a particular request is supposed to go to.
WDF drivers typically do not directly access IRPs. The framework converts the WDM IRPs that represent read,
write, and device I/O control operations to framework request objects that Kernel-Mode Driver Framework
(KMDF) and UMDF drivers receive in I/O queues. The framework handles PnP and power management IRPs
internally and uses event callback functions to inform the driver of PnP and power events.
Differences Between WDM and WDF
2/5/2021 • 8 minutes to read • Edit Online

The WDM model is closely tied to the operating system. Drivers interact directly with the operating system by
calling system service routines and manipulating operating system structures. Because WDM drivers are trusted
kernel-mode components, the system provides limited checks on driver input.
In comparison, the Windows Driver Frameworks (WDF) model focuses on the driver’s requirements, and the
framework library handles the majority of the interactions with the system.
The framework intercepts I/O requests, takes default actions where appropriate, and invokes the driver’s
callbacks as required. The WDF model is object based and event driven. Objects represent common driver
constructs, such as a device, a lock, or a queue. A Kernel-Mode Driver Framework (KMDF) or User-Mode Driver
Framework (UMDF) driver contains an entry point (DriverEntr y ), the event-related callback functions that are
required to service the device and support I/O, and any additional internal utility functions on which the
implementation depends.
This section describes important differences between WDM and WDF in the following areas:
Driver Structure
Device Objects and Driver Roles
Object Model
Object Creation
Object Context Area
Supported IRP Types
I/O Queues
Synchronization and Concurrency
Driver Installation

Driver Structure
Both WDM and WDF drivers contain a DriverEntr y routine, a number of routines that are called to handle
particular I/O requests, and various support routines.
In a WDM driver, the I/O dispatch routines map to particular major IRP codes. The dispatch routines receive IRPs
from the I/O manager, parse them, and respond accordingly.
In a WDF driver, the framework registers its own dispatch routines, which receive IRPs from the I/O manager,
parse them, and then invoke the driver’s event callback functions to handle them. The event callback functions
typically perform a more specific task than the general I/O dispatch routines of the WDM driver.
A typical WDF driver for a Plug and Play device contains:
A DriverEntr y routine.
An EvtDriverDeviceAdd routine, which is similar in function to a WDM AddDevice routine.
One or more I/O queues.
One or more I/O event callback functions, which are similar in function to a WDM driver’s I/O DispatchXxx
routines.
Callbacks to handle the Plug and Play and power events that the driver supports.
Callbacks to handle the WMI requests that the driver supports. (KMDF-only)
Additional callbacks, as appropriate, for object cleanup, file creation, and I/O targets, and so on.

Device Objects and Driver Roles


Both WDM and WDF drivers create one or more device objects. Each device object represents a driver role that
is the target of I/O requests. A physical device object (PDO) represents a bus driver, a functional device object
(FDO) represents a function driver, and a filter device object (filter DO) represents a filter driver.
In WDM drivers, these driver roles are implicit, so the driver must keep track of which role each device object
represents and respond to IRPs appropriately.
WDF drivers, however, indicate explicitly whether a device object represents a PDO (KMDF only), FDO, or filter
DO and register event callbacks that are specific to that role. For example, PDOs are the target of resource
requirements queries and device ejection requests, whereas FDOs and filter DOs do not handle such requests.
A WDF driver configures each device object to receive certain types of I/O requests. The framework calls the
driver to handle only those I/O requests and performs a default action for all other requests. If the device object
represents a filter driver, the framework passes all other requests to the next lower driver. If the device object
represents a bus or function driver, the framework fails all other request types.
For Plug and Play and power requests, the framework calls the KMDF or UMDF driver only for the requests that
are appropriate for each device object—and at the appropriate time. For example, an FDO must respond to
certain requests after the underlying PDO has already responded. In a WDM driver, the FDO must set an I/O
completion routine, pass the IRP down the stack, and process it after lower drivers. A WDF driver simply
implements the corresponding callback routine, and the framework calls it after lower drivers have completed
processing.
For information on how to create framework device objects, see Creating a Framework Device Object.
Some drivers also handle certain I/O requests that are independent of Plug and Play. A WDM driver creates a
DEVICE_OBJECT as the target for such requests, but does not attach it to the Plug and Play device stack. To
accomplish the same result, a KMDF driver creates a control device object. Some framework-based drivers use
control device objects to implement “sideband” I/O mechanisms so that they can receive certain types of I/O
requests regardless of device state.

Object Model
WDF supports a coherent object model in which objects are opaque to drivers, provide driver-configurable
context areas, and are referenced by a handle. WDM objects are system-wide objects that are accessible to
drivers and are referenced by pointers. A driver that corrupts a WDM object can corrupt the entire system.
Corrupting a WDF object is not only more difficult—because the framework validates the data that the driver
supplies—but also causes system-wide problems much less often.
For information about the naming convention for KMDF objects, see WDF Architecture.
The framework maintains a reference count for each object, which thus provides some control over its lifetime.
For more information, see Framework Object Life Cycle.
Although many of the WDF objects correspond to WDM objects, the WDF objects support features that would
require additional code in a WDM driver. All WDF objects support driver-definable object context areas so that a
driver can store information that is related to a particular instance of an object with the object itself. Objects
typically track state as well. For example, WDFQUEUE objects are more than just a list of I/O requests; they
support several types of dispatching, automatic synchronization with Plug and Play, and request cancellation.
For WDFMEMORY objects, the framework-managed reference count helps prevent memory leaks and
premature release of resources.

Object Creation
Object Creation
WDF drivers follow a regular pattern to create all types of objects:
1. Initialize the configuration structure for the object, if one exists.
2. Optionally initialize the attributes structure for the object.
3. Call the creation method to create the object.
The configuration structure and the attributes structure supply basic information about the object and how the
driver uses it. All object types use WDF_OBJECT_ATTRIBUTES as the attributes structure, but the configuration
structure for each type of object is different and some objects do not have one. For example, there is a
WDF_DRIVER_CONFIG structure but not a WDF_DEVICE_CONFIG structure.
The configuration structure holds pointers to object-specific information, such as the driver’s event callback
functions for the object. The driver fills in this structure and then passes it to the framework when it calls the
object creation method. For example, a call to WdfDriverCreate includes a pointer to a
WDF_DRIVER_CONFIG structure that contains a pointer to the driver’s EvtDriverDeviceAdd callback function.
The framework defines functions that are named WDF_Object_CONFIG_INIT to initialize the configuration
structures, where Object represents the name of the object type. The WDF_OBJECT_ATTRIBUTES_INIT
function initializes a driver's WDF_OBJECT_ATTRIBUTES structure.

Object Context Area


Every instance of an object can have one or more object context areas. The object context area is a storage area
for data that is related to that particular instance, such as a driver-allocated event object. The driver determines
the size and layout of the object context area. For a device object, the object context area is the equivalent of the
WDM device extension. For information about defining and initializing a context area, see Framework Object
Context Space.

Supported IRP Types


WDF supports a subset of Windows IRPs. For a summary of the major WDM IRP types and the corresponding
WDF event callback functions, see WDM IRPs and WDF Event Callback Functions.
Even if your driver receives IRPs other than those listed in the table, you can port it to KMDF. KMDF provides a
mechanism through which a driver can receive “raw” WDM IRPs but also use the KMDF features for other types
of IRPs. For more information, see Handling WDM IRPs Outside of the Framework.

I/O Queues
Nearly all drivers queue I/O requests. WDM drivers typically use one of the following approaches:
Implement a StartIo function and call IoStar tPacket and IoStar tNextPacket to use the system’s device
queue for I/O requests.
Use the IoCsqXxx or other list-management functions to implement its own internal I/O queues.
Use the KeXxxDeviceQueue functions to initialize and manage a queue that is protected by a spin lock.
A WDF driver creates a WDF queue object (WDFQUEUE) to represent an I/O queue. The WDF queue object is
similar to a cancel-safe queue but provides additional features.
When you port a WDM driver to WDF, you can use the WDF queuing mechanism regardless of the mechanism
that the WDM driver uses. For more information about queues, see Framework Queue Objects.

Synchronization and Concurrency


WDF drivers benefit from some built-in synchronization support that is not available to WDM drivers. Although
this support does not mean that the driver can ignore concurrency and synchronous access to data, WDF drivers
nevertheless require significantly fewer locks and less synchronization code than do WDM drivers.
For more information about the synchronization features that the framework provides, see Synchronization
Techniques.

Driver Installation
Like WDM drivers, KMDF and UMDF drivers are installed by using INF files. However, WDF driver installation
sometimes requires a framework co-installer that is provided with the Windows Driver Kit (WDK). The co-
installer ensures that a compatible version of the framework library is present on the target system. For
information about installation, see Building and Loading a WDF Driver.
Preparing for Porting
2/5/2021 • 2 minutes to read • Edit Online

In some ways, converting a driver from WDM to Windows Driver Frameworks (WDF) is more reimplementation
than porting. This is neither as difficult nor as time-consuming as you might expect. Most of the WDM driver’s
hardware-specific code can remain relatively intact, although it will use some different object types. WDF
defaults replace much of the boilerplate code that a WDM driver requires—particularly for Plug and Play—and
WDF provides built-in support for many tricky aspects of driver implementation, such as I/O cancellation (and
the associated race conditions) and system power state transitions.
The following general guidelines apply to porting a driver:
Refer to the samples. WDF ships with a rich set of samples, most of which are ports of the similarly named
WDM drivers.
Work incrementally. Because the framework implements default behavior for I/O, Plug and Play, power
management, and WMI requests, you can code and debug one device or driver feature at a time.
For Kernel-Mode Driver Framework (KMDF), implement WMI event tracing to provide detailed trace logs for
use in debugging.
In many situations, the WDF defaults provide greater functionality than the existing WDM driver might have
implemented. Before trying to port complicated code—particularly for synchronization or queue
management—be certain what WDF provides. It might save a considerable amount of time spent porting the
driver.
Use the WDF-specific debugger extensions that are included in the Windows Driver Kit (WDK).
Enable the KMDF verifier or UMDF verifier while debugging.

WDM Driver Analysis


Regardless of the type of device and driver involved, the most important issue in porting a driver is to
understand the I/O flow through the driver. Before you start writing code, carefully analyze the existing WDM
driver. You should be able to answer these questions:
How many device objects does the driver require, and what driver roles (FDO, PDO, filter DO) do they
represent? In nearly all cases, the WDF driver will use the same type and number of device objects as the
WDM driver.
Which I/O requests must the driver support?
How many queues does the driver require for those requests? What are the characteristics of those queues?
Which aspects of I/O processing can take place concurrently, and which must be serialized?
Which I/O requests does the driver complete, and which does it pass down the stack?
The answers to these questions determine how the core of the WDF driver is structured, where and when the
I/O processing takes place, what type of synchronization the driver requires, and which WDF objects the driver
must create to perform I/O. If the driver supports hardware, you must also thoroughly understand the device:
Does the device generate interrupts?
Which DMA model (if any) does the hardware support? Note that if your driver requires DMA, you must
write a KMDF driver.
Does the driver manage power policy for the device stack?
Finally, if the driver supports WMI (also KMDF only), you must understand how to gather the data it exports and
which WMI callbacks the driver requires.
Steps in Porting
2/5/2021 • 2 minutes to read • Edit Online

Depending on the type of driver, porting involves performing the following steps:
1. Port the DriverEntry routine and add code to create the WDFDRIVER object.
2. Port the AddDevice routine to an EvtDriverDeviceAdd callback, and add code to create the WDFDEVICE
objects.
3. Add support for interrupts if the driver supports interrupt handling.
At this point, you can perform the remaining steps incrementally and in any order, testing and debugging after
each addition. For example, you can start by implementing the I/O queues and using the framework defaults for
Plug and Play and power management. After you have debugged the basic I/O support, you can add support for
more extensive Plug and Play and power management requests. The remaining steps are as follows:
Add support for Plug and Play and power management.
Add I/O support.
Add support for DMA, if the device performs DMA.†
Port WMI code.†
Port code to handle requests that the framework does not handle on behalf of KMDF drivers.†
Revise the INF that installs the driver.
† This functionality is only available to Kernel-Mode Driver Framework (KMDF) drivers.
Except as noted, the information in this section applies to all types of drivers (PDO, FDO, and filter DO). However,
if you are porting a bus driver (PDO) to KMDF, you will also need to port the device enumeration code. For
information about enumerating devices, see Enumerating the Devices on a Bus.
For reference information describing the ways that the various WDF objects, methods, and event callback
functions map to common WDM objects and functions, see Summary of KMDF and WDM Equivalents.
Porting DriverEntry
2/5/2021 • 2 minutes to read • Edit Online

In both WDM and framework-based drivers, the DriverEntr y function is the primary entry point. The function
prototype is the same in both models. In a WDM driver, the system calls DriverEntr y when the driver is first
loaded into memory. DriverEntry sets a pointer to the driver’s AddDevice routine in the DriverExtension-
>AddDevice field of the DRIVER_OBJECT structure, sets pointers to its I/O dispatch routines in the
MajorFunction array of the DRIVER_OBJECT structure, and then returns. In a framework-based driver, the
system calls the framework’s internal FxDriverEntr y function upon loading the driver. This internal function
initializes the framework and then calls the driver’s DriverEntr y function. DriverEntr y sets a pointer to the
driver’s EvtDriverDeviceAdd callback and calls WdfDriverCreate to create the WDFDRIVER object, as the
following example shows:

NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject
IN PUNICODE_STRING RegistryPath
)
{
WDF_DRIVER_CONFIG config;

WDF_DRIVER_CONFIG_INIT( &config,
ToasterEvtDeviceAdd );
status = WdfDriverCreate(
DriverObject,
RegistryPath,
WDF_NO_OBJECT_ATTRIBUTES,
&config,
WDF_NO_HANDLE
);

return STATUS_SUCCESS;
}

DriverEntr y also initializes any global data or resources that the driver requires, such as creating a lookaside
list or initializing tracing. Note that although WdfDriverCreate returns a handle to the WDFDRIVER object, the
driver does not retain this handle, just as a WDM driver might not retain the DRIVER_OBJECT pointer that was
passed to its DriverEntr y routine. The reason is the same: only a few drivers use the pointer to the driver
object.
Porting AddDevice to EvtDriverDeviceAdd
2/5/2021 • 4 minutes to read • Edit Online

Every Kernel-Mode Driver Framework (KMDF) or User-Mode Driver Framework (UMDF) driver that supports
Plug and Play must have an EvtDriverDeviceAdd callback, which is the functional equivalent of a WDM driver’s
AddDevice function.
A WDM AddDevice function creates the device object, creates the device interfaces, and initializes WMI but also
initializes numerous variables in the driver’s device extension. WDM drivers typically defer the creation of I/O
queues and the interrupt object until the DispatchPnP function is called to handle an IRP_MN_START_DEVICE
request.
The framework-based driver’s EvtDriverDeviceAdd callback creates a WDFDEVICE object to represent the device
that has just been enumerated. It also performs numerous additional initialization tasks to provide the
framework with the information that it requires to set up its own internal structures and the underlying WDM
structures.
As a result, for most framework-based drivers the EvtDriverDeviceAdd callback is significantly longer than the
corresponding WDM AddDevice function. In a framework-based driver, nearly all of the device’s initialization
code is in the EvtDriverDeviceAdd function. However, in the WDM version, the initialization code tends to be
spread out through multiple functions in the driver.
The code in EvtDriverDeviceAdd appears in the following order:
1. Fill in the WDFDEVICE_INIT structure, which supplies information that is used to create the device object. For
more information about using WDFDEVICE_INIT, see Creating a Framework Device Object.
2. Set up the device object’s context area, which is analogous to the WDM device extension.
3. Create the device object.
4. Perform additional initialization and start-up tasks, such as creating I/O queues and interrupt objects.
A KMDF bus driver typically creates multiple device objects: an FDO for its role as the function driver for the bus
itself and a PDO for each child device that is attached to the bus. The framework calls the driver’s
EvtDriverDeviceAdd function when the system enumerates the bus. The driver itself then enumerates its child
devices and creates PDOs to represent them. KMDF supports both static and dynamic enumeration of child
devices. It also includes additional PDO-specific features.

Device Object Context Area


Drivers typically require storage that is associated with a device object to maintain pointers and object-specific
data. In a WDM driver, the DeviceExtension field of the DEVICE_OBJECT structure provides such storage. In a
framework-based driver, the object context area of the WDFDEVICE object serves the same purpose.
For information about allocating and accessing context space for framework objects, see Framework Object
Context Space.

Device Object Creation


A WDM driver creates a DEVICE_OBJECT structure to represent each device object and attaches the device
object to the Plug and Play device stack. Framework-based drivers also create device objects, which are referred
to by using WDFDEVICE handles.
After the WDF driver calls the required initialization methods, it sets attributes for the device object (typically, the
size and type of the context area) and then calls WdfDeviceCreate to create the device object.
WdfDeviceCreate creates a WDFDEVICE object and an underlying WDM DEVICE_OBJECT , attaches the WDM
DEVICE_OBJECT to the device stack, and returns a handle to the WDFDEVICE object.

Additional EvtDriverDeviceAdd Tasks


After the framework-based driver creates the device object, it should:
Create I/O queues and specify request handlers for the device object.
Create device interfaces.
Set device idle policy and wake settings, if the device object owns power policy.
Create an interrupt object, if the hardware supports interrupts.
Initialize WMI.†
† This functionality is only available to KMDF drivers.
A framework-based driver should set up the I/O queues and create the interrupt object in the
EvtDriverDeviceAdd callback, immediately after creating the device object. The framework connects the interrupt
object and starts the queues at the appropriate time later, during start-device processing.

Child Device Enumeration (PDOs, KMDF Only)


A driver that controls a bus typically creates multiple device objects: an FDO for its role as the function driver for
the bus itself and a PDO for each child device that is attached to the bus. KMDF supports both static and
dynamic enumeration of child devices. It also includes additional PDO-specific features.
The framework invokes the driver’s EvtDriverDeviceAdd function when the Plug and Play manager enumerates
the bus. EvtDriverDeviceAdd creates an FDO for the bus, and then enumerates the child devices and creates a
PDO for each one. The driver can enumerate the child devices either statically or dynamically.
Certain callback functions apply only to device objects that represent PDOs. When the driver initializes the
device object, it registers the corresponding callbacks. PDOs respond to queries about device resources and
resource requirements, requests to lock or eject the device, and requests to enable and disable the device wake
signal.
In WDM drivers, these requests arrive as minor IRP codes in an IRP_MJ_PNP or IRP_MJ_POWER request.
KMDF drivers handle them by implementing callbacks and registering the callbacks during device object
initialization by calling WdfPdoInitSetEventCallbacks . The following table lists the PDO-specific callbacks:

K M DF C A L L B A C K W DM IRP

EvtDeviceResourcesQuery IRP_MN_QUERY_RESOURCES

EvtDeviceResourceRequirementsQuery IRP_MN_QUERY_RESOURCE_REQUIREMENTS

EvtDeviceEject IRP_MN_EJECT

EvtDeviceSetLock IRP_MN_SET_LOCK

EvtDeviceEnableWakeAtBus IRP_MN_WAIT_WAKE
K M DF C A L L B A C K W DM IRP

EvtDeviceDisableWakeAtBus IRP_MN_WAIT_WAKE

Additional WdfPdoInitXxx methods enable the driver to specify device-specific data, such as device IDs.
Porting Interrupts
2/5/2021 • 2 minutes to read • Edit Online

The code for supporting and servicing interrupts is similar in WDF and WDM drivers. There is one primary
difference:
A WDF driver creates the WDFINTERRUPT object and registers its interrupt service routine (ISR) callback by
calling WdfInterruptCreate from its EvtDriverDeviceAdd callback.
A WDM driver creates a KINTERRUPT structure and connects it during IRP_MN_START_DEVICE processing.
The EvtInterruptIsr callback in a WDF driver performs the same tasks as the WDM driver’s InterruptService
routine. The EvtInterruptIsr callback calls WdfInterruptQueueDpcForIsr to queue the EvtInterruptDpc callback
for later processing at DISPATCH_LEVEL. In response, the framework adds a DPC object to the system queue that
runs this callback.
For more information about framework interrupt objects, see Handling Hardware Interrupts.
Porting PnP and Power Management
2/5/2021 • 2 minutes to read • Edit Online

WDF implements intelligent defaults for Plug and Play (PnP) and power management, so simple drivers
(including most filter drivers) do not require additional code to meet the basic requirements for PnP. The
framework automatically creates and manages PnP, power management, and power policy state machines. By
default:
The FDO owns power policy for the device.
Only the EvtDriverDeviceAdd callback is required; all other PnP and power management callbacks are
optional. A driver implements other callbacks to support device-specific features.
The framework implements power management for all WDFQUEUE objects, so that by default requests are
dispatched from the queue to the driver’s I/O event callbacks only when the device hardware is available
(that is, in the D0 state).
If the device does not support interrupts or map memory, or require initialization or deinitialization when power
transitions occur, the WDF driver requires only the EvtDriverDeviceAdd callback. When a device is inserted or
removed, the framework invokes PnP and power event callbacks in a defined order. The topics in this section
describe the order, which varies slightly for PDOs, FDOs, and filter DOs:
Power-Up Sequence for a Function or Filter Device Object
Power-Up Sequence for a Physical Device Object
Power-Down and Removal Sequence for a Function or Filter Device Object
Power-Down and Removal Sequence for a Physical Device Object
Surprise-Removal Sequence
For a complete list of the callbacks that correspond to each minor PnP and power IRP code, see WDM IRPs and
WDF Event Callback Functions.
For more information about supporting PnP and power management in a framework-based driver, see the
following topics:
Supporting PnP and Power Management in Your Driver
Power Policy Ownership
Porting I/O
2/5/2021 • 2 minutes to read • Edit Online

KMDF drivers handle I/O requests by creating one or more queues and associating one or more I/O event
callback functions with each queue. To port a WDM driver’s I/O handling code to KMDF:
Port I/O queues.
Port I/O dispatch routines to I/O event callbacks.
Revise code that handles completed requests.
Revise Canceled Request Logic.
Revise Forward Request Logic.
Revise code that issues I/O requests.
Porting I/O Queues
2/5/2021 • 2 minutes to read • Edit Online

WDF drivers create queues and register I/O event callbacks in the EvtDriverDeviceAdd callback. By default, each
I/O queue object is the child of a device object. The WDF driver can configure the following tasks for each queue:
Which I/O request types are directed to the queue.
Whether requests are dispatched in parallel (as soon as they arrive), sequentially (one at a time), or manually
(upon driver request).
Whether I/O event callback routines are called concurrently or serially.
Whether the framework or the driver manages the queue through system and device power transitions.
For more information about creating queues, see Creating I/O Queues
Porting I/O Dispatch Routines to I/O Event Callback
Functions
2/5/2021 • 5 minutes to read • Edit Online

The core of a WDM driver’s I/O dispatch routines maps to the WDF driver’s I/O event callback functions.
However, the I/O event callback functions differ in several important ways from a WDM driver’s I/O dispatch
routines:
When the framework invokes a WDF driver’s I/O event callback, the callback receives the request in a
noncancelable state. The request cannot be canceled unless the driver explicitly marks it as cancelable.
The driver specifies whether the framework synchronizes calls to the I/O event callbacks so that only one
such callback runs concurrently for each queue or for each device object, or whether the framework applies
no synchronization at all. For more information about selecting synchronization options, see Using
Automatic Synchronization.
These differences mean that most I/O event callback functions contain significantly less code to synchronize
access and to prevent race conditions than the corresponding WDM DispatchXxx routines.
Aside from synchronization, the primary differences between a WDM driver’s I/O dispatch routines and a WDF
driver’s I/O event callback functions lie in how the driver retrieves parameters and how it accesses I/O buffers.

Parameters for I/O Requests


Depending on the types of requests that a WDF driver handles and the way it configures its I/O queues, a driver
might not be required to parse the parameters to an I/O request as a WDM driver does. When the framework
calls the I/O event callbacks for read, write, and device I/O control requests (EvtIoRead, EvtIoWrite,
EvtIoDeviceControl, EvtIoInternalDeviceControl), it extracts the most commonly used parameters from the IRP
and passes them as parameters to the callback. For example, the framework calls a driver’s EvtIoRead callback
with a handle to the WDFREQUEST object and the number of bytes to read. If the driver does not require a
device offset or a sort key, it can simply retrieve the buffer from the WDFREQUEST object by calling one of the
WdfRequestRetrieveOutputXxx methods; it does not need to retrieve additional parameters.
In an EvtIoDefault callback, however, the framework passes only a handle to the queue and a handle to the
request object. Consequently, the driver must call WdfRequestGetParameters to get the parameters,
including the type of request (WdfRequestTypeXxx ). WdfRequestGetParameters returns a
WDF_REQUEST_PARAMETERS structure that contains the parameters that were passed with a create, read,
write, device I/O control, or internal device I/O control request.

Access to Buffers for Buffered and Direct I/O


When the framework receives a request for I/O, it creates a WDFREQUEST object that encapsulates the
underlying WDM IRP. It then queues the WDFREQUEST object and eventually dispatches it according to the
driver’s dispatch specification for the queue. The driver uses WDF methods to retrieve parameters and buffers
for the I/O request. A driver can get the underlying WDM IRP at any time by calling WdfRequestWdmGetIrp .
Like WDM drivers, WDF drivers can support buffered, direct, or neither I/O. A driver sets the type of I/O that is
supported for each device object by calling WdfDeviceInitSetIoType in the EvtDriverDeviceAdd callback
before creating the device object. Unlike a WDM driver, however, a KMDF driver accesses the buffers in the same
way whether it performs buffered or direct I/O and uses the same methods for each.
Although a WDF driver accesses buffers in the same way for both buffered and direct I/O, it uses different
methods to retrieve the buffers depending on the type of I/O request. The following sections describe how the
driver handles each type of I/O request:
Create Requests
Read Requests
Write Requests
Device I/O Control Requests
Internal Device I/O Control Requests

Create Requests
A WDF driver can handle create requests (IRP_MJ_CREATE ) in one of two ways:
Bypass queuing and instead supply an EvtDeviceFileCreate callback.
Have the framework queue create requests and implement an EvtIoDefault callback to handle such requests
from the queue.
For detailed information about handling file creation requests, see Framework File Objects.

Read Requests
To retrieve a buffer for a read request (IRP_MJ_READ ), a WDF driver calls one of the
WdfRequestRetrieveOutputXxx methods. The buffer that each of these methods returns depends on whether
the driver performs buffered, direct, or neither I/O.
For information about WDM equivalents for buffer pointers, see WDM Equivalents for KMDF Buffer Pointers.

Write Requests
To retrieve a buffer for a write request (IRP_MJ_WRITE ), a WDF driver calls one of the
WdfRequestRetrieveInputXxx methods. The buffer that each of these methods returns depends on whether
the driver performs buffered, direct, or neither I/O.
For information about WDM equivalents for buffer pointers, see WDM Equivalents for KMDF Buffer Pointers.

Device I/O Control Requests


To handle a device I/O control request (IRP_MJ_DEVICE_CONTROL ), a WDF driver calls either
WdfRequestRetrieveInputXxx methods or WdfRequestRetrieveOutputXxx methods to get buffers for
buffered and direct I/O. The corresponding input and output methods return the same buffer, so the driver can
use either one. The buffer that each of these methods returns depends on whether the driver performs buffered,
direct, or neither I/O, just as in read and write requests.
If the driver handles device I/O control requests that originate in another device stack or use the
Parameters.Other fields, the driver should call WdfRequestGetParameters to get a buffer pointer instead of
calling WdfRequestRetrieveInputBuffer and WdfRequestRetrieveOutputBuffer . Because the source of
these requests is guaranteed to be a kernel-mode component, the driver can trust the returned buffer pointer.
However, it must still validate the buffer lengths and any other parameters.
For information about WDM equivalents for buffer pointers, see WDM Equivalents for KMDF Buffer Pointers.

Internal Device I/O Control Requests


Internal device I/O control requests (IRP_MJ_INTERNAL_DEVICE_CONTROL ) are issued only by kernel-mode
components and are used internally by some operating system components to pass request blocks (xRB
protocols such as SCSI request blocks [SRBs] or universal request blocks [URBs]). Many different types of
buffers can accompany such requests.
Retrieving and interpreting parameters for internal device I/O control requests can be problematic. The problem
occurs because some such requests pass the length in the InputBufferLength and OutputBufferLength
fields of the Parameters.DeviceIoControl structure of the WDM IRP, but some do not. Nevertheless, the
framework extracts whatever values are in the InputBufferLength and OutputBufferLength fields and
passes them as parameters to the EvtIoInternalDeviceControl callback. It does not perform any internal
validation on these values.
To get the buffers themselves, the driver calls one of the following methods:
WdfRequestRetrieveInputBuffer , which returns the Parameters.DeviceIoControl.Type3InputBuffer
field of the IRP.
WdfRequestRetrieveOutputBuffer , which returns the UserBuffer field of the IRP.
Revise Code That Handles Completed Requests
2/5/2021 • 2 minutes to read • Edit Online

Windows Driver Frameworks (WDF) provides three methods that complete I/O requests:
WdfRequestComplete
WdfRequestCompleteWithInformation
WdfRequestCompleteWithPriorityBoost (KMDF only)
For information about using these methods, see Completing I/O Requests.
Revise Canceled Request Logic
2/5/2021 • 2 minutes to read • Edit Online

When an I/O request is canceled, a WDM driver must manage several difficult race conditions. A request might
be canceled while it is in a queue or while the driver is processing it. In each case the driver must use a
combination of locks to ensure that it cancels and completes the request only once.
The WDF queuing mechanism greatly simplifies cancellation. If a request is canceled while it is on a queue, the
framework handles cancellation without notifying the driver. The driver can request notification by registering
an EvtIoCanceledOnQueue callback function. After the framework has delivered a request to the driver, the
request is not cancelable by default. A driver can call WdfRequestIsCanceled at any time to find out whether
the request has been canceled.
For more information, see Canceling I/O Requests.
Revise Forward Request Logic
2/5/2021 • 2 minutes to read • Edit Online

If a driver cannot complete a request by itself, it passes the request down the stack to the next lower driver. For a
WDF driver, the next lower driver is considered the default I/O target and is represented by a WDFIOTARGET
object. To get a handle to this object, the driver calls WdfDeviceGetIoTarget .
For information about how a WDF driver passes a request down to the next lower driver in the stack, see
Forwarding I/O Requests.
Revise Code That Issues I/O Requests
2/5/2021 • 2 minutes to read • Edit Online

WDF defines several methods that a driver can use to create and format I/O requests. The following table
summarizes these methods:

K M DF M ET H O D A C T IO N

WdfIoTargetFormatRequestForIoctl Similar to manually formatting the next I/O stack location.


WdfIoTargetFormatRequestForInternalIoctl
WdfIoTargetFormatRequestForInternalIoctlOthers

WdfIoTargetFormatRequestForRead Similar to IoBuildAsynchronousFsdRequest .


WdfIoTargetFormatRequestForWrite

WdfIoTargetSendIoctlSynchronously Similar to IoBuildDeviceIoControlRequest , followed by


IoCallDriver .
WdfIoTargetSendInternalIoctlSynchronously
WdfIoTargetSendInternalIoctlOthersSynchronousl
y

WdfIoTargetSendReadSynchronously Similar to IoBuildSynchronousFsdRequest , followed by


IoCallDriver .
WdfIoTargetSendWriteSynchronously

WdfRequestCancelSentRequest Similar to IoCancelIrp for a PIRP that was sent with


IoCallDriver . The framework provides locks to ensure that
the PIRP is not completed or freed between the calls to
IoCallDriver and IoCancelIrp .

WdfRequestCreate Similar to IoAllocateIrp . Creates a new WDFREQUEST


object, sets attributes, and returns handle to caller.

WdfRequestFormatRequestUsingCurrentType Similar to IoFor wardIrpSynchronously but does not call


IoCallDriver ; driver must call WdfRequestSend .

WdfRequestSend Similar to IoFor wardIrpSynchronously but does not call


IoCallDriver ; driver must call WdfRequestSend .

To send a request to another device stack, a WDF driver uses a remote I/O target. For information about how to
initialize a remote I/O target, see Initializing a General I/O Target.
To get the completion status for an asynchronous request or for any request that is sent by calling
WdfRequestSend , the driver calls WdfRequestGetStatus . For a synchronous request, it can retrieve status
immediately. For an asynchronous request, the driver’s I/O completion callback typically retrieves status. For
more information about sending requests synchronously or asynchronously, see Sending I/O Requests to
General I/O Targets.
Porting DMA
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


Performing DMA (Direct Memory Access) in a KMDF driver is simpler than in a WDM driver because the
framework handles many of the details on behalf of the driver.
Basically, the framework-based driver creates a DMA enabler object, specifies the DMA capabilities of the device,
and supplies a callback function that manipulates the hardware to perform the transfer.
The framework determines the number of map registers that are required for the transfer, allocates the map
registers, builds a scatter/gather list (if the device supports scatter/gather DMA), and flushes the processor
cache and the buffers whenever necessary.
For implementation details, see Handling DMA Operations in KMDF Drivers.
Porting WMI
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


An IRP_MJ_SYSTEM_CONTROL request represents a request for WMI data. WDM drivers handle such
requests by implementing a DispatchSystemControl function and registering as a WMI data provider. WDM
drivers that do not respond to such requests implement a DispatchSystemControl routine that simply passes the
IRPs down to the next lower driver.
For KMDF drivers, the framework provides default handling for IRP_MJ_SYSTEM_CONTROL . Drivers that do
not provide WMI data are not required to include any WMI-related code. Instead, the framework passes the
request to the next lower driver on behalf of the driver.
For implementation details, see Supporting WMI in KMDF Drivers.
Requests That KMDF Does Not Support
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


Kernel-Mode Driver Framework (KMDF) does not support I/O requests that have the following major IRP codes:
IRP_MJ_CREATE_MAILSLOT
IRP_MJ_CREATE_NAMED_PIPE
IRP_MJ_DEVICE_CHANGE
IRP_MJ_DIRECTORY_CONTROL
IRP_MJ_FILE_SYSTEM_CONTROL
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_LOCK_CONTROL
IRP_MJ_QUERY_EA
IRP_MJ_QUERY_INFORMATION
IRP_MJ_QUERY_QUOTA
IRP_MJ_QUERY_SECURITY
IRP_MJ_QUERY_VOLUME_INFORMATION
IRP_MJ_SET_EA
IRP_MJ_SET_INFORMATION
IRP_MJ_SET_QUOTA
IRP_MJ_SET_SECURITY
IRP_MJ_SET_VOLUME_INFORMATION
When the framework receives such a request, its default action depends on the device object that was the target
of the request. For an FDO or PDO, the framework completes the IRP with the status
STATUS_INVALID_DEVICE_REQUEST. For a filter DO, the framework passes the IRP to the next lower driver.
Although the framework does not support these request types, a KMDF driver can still handle them. For more
information, see Handling an IRP that the Framework Does Not Support.
Summary of WDF and WDM Equivalents
2/5/2021 • 2 minutes to read • Edit Online

This section provides tables that compare Windows Driver Frameworks (WDF) objects and methods with the
corresponding Windows Driver Mode (WDM) objects and functions. The tables list:
WDM Equivalents for WDF Buffer Pointers
WDM IRPs and WDF Event Callback Functions
WDM Equivalents for WDF Buffer Pointers
2/5/2021 • 2 minutes to read • Edit Online

A Kernel-Mode Driver Framework (KMDF) or User-Mode Driver Framework (UMDF) driver uses the following
methods for retrieving I/O buffers for buffered and direct I/O. Unless otherwise specified, the methods apply to
both KMDF and UMDF.
WdfRequestRetrieveOutputBuffer
WdfRequestRetrieveOutputWdmMdl (KMDF only)
WdfRequestRetrieveOutputMemor y
WdfRequestRetrieveInputBuffer
WdfRequestRetrieveInputWdmMdl (KMDF only)
WdfRequestRetrieveInputMemor y
The following tables describe what the retrieval methods return for IRP_MJ_READ, IRP_MJ_WRITE, and
IRP_MJ_DEVICE_CONTROL requests for buffered and direct I/O. Requests for neither I/O require special
handling because the driver must retrieve the buffers while running in the context of the requesting user-mode
process.

Buffers for IRP_MJ_READ Requests


To retrieve a buffer for a read request, a KMDF driver calls one of the WdfRequestRetrieveOutput Xxx
methods. The buffer that each of these methods returns varies, depending on whether the driver performs
buffered or direct I/O. The following table describes the pointer that is returned by each method in WDM terms.

F UN C T IO N B UF F ERED I/ O DIREC T I/ O

WdfRequestRetrieveOutputBuffer Irp->AssociatedIrp.SystemBuffer MmGetSystemAddressForMdlSafe


(Irp->MdlAddress )

WdfRequestRetrieveOutputWdm Builds a memory descriptor list (MDL) Irp->MdlAddress


Mdl (KMDF only) for Irp-
>AssociatedIrp.SystemBuffer and
returns the MDL.

WdfRequestRetrieveOutputMemo Returns a WDFMEMORY object. Call Returns a WDFMEMORY object. Call


ry WdfMemor yGetBuffer on this WdfMemor yGetBuffer on this
object to get Irp- object to get
>AssociatedIrp.SystemBuffer . MmGetSystemAddressForMdlSafe
(Irp->MdlAddress ).

Buffers for IRP_MJ_WRITE Requests


To retrieve a buffer for a write request, a KMDF driver calls one of the WdfRequestRetrieveInput Xxx methods.
The buffer that each of these methods returns varies, depending on whether the driver performs buffered or
direct I/O. The following table describes the pointer that is returned by each method in WDM terms.

F UN C T IO N B UF F ERED I/ O DIREC T I/ O
F UN C T IO N B UF F ERED I/ O DIREC T I/ O

WdfRequestRetrieveInputBuffer Irp->AssociatedIrp.SystemBuffer MmGetSystemAddressForMdlSafe


(Irp->MdlAddress )

WdfRequestRetrieveInputWdmMd Builds an MDL for Irp- Irp->MdlAddress


l (KMDF only) >AssociatedIrp.SystemBuffer and
returns the MDL.

WdfRequestRetrieveInputMemor y Returns a WDFMEMORY object. Call Returns a WDFMEMORY object. Call


WdfMemor yGetBuffer on this WdfMemor yGetBuffer on this
object to get Irp- object to get
>AssociatedIrp.SystemBuffer . MmGetSystemAddressForMdlSafe
(Irp->MdlAddress ).

Buffers for IRP_MJ_DEVICE_CONTROL Requests


To retrieve a buffer for a device I/O control request, a KMDF driver calls either WdfRequestRetrieveInputXxx
or WdfRequestRetrieveOutputXxx methods. The buffer that each of these methods returns varies, depending
on whether the driver performs buffered or direct I/O, as shown in the following table:

F UN C T IO N B UF F ERED I/ O DIREC T I/ O

WdfRequestRetrieveInputBuffer Irp->AssociatedIrp.SystemBuffer MmGetSystemAddressForMdlSafe


(Irp->MdlAddress )

WdfRequestRetrieveInputWdmMd Builds an MDL for Irp- Builds an MDL for Irp-


l (KMDF only) >AssociatedIrp.SystemBuffer and >AssociatedIrp.SystemBuffer and
returns the MDL. returns the MDL.

WdfRequestRetrieveInputMemor y Returns a WDFMEMORY object. Call Returns a WDFMEMORY object. Call


WdfMemor yGetBuffer on this WdfMemor yGetBuffer on this
object to get Irp- object to get
>AssociatedIrp.SystemBuffer . MmGetSystemAddressForMdlSafe
(Irp->MdlAddress ).

WdfRequestRetrieveOutputBuffer Irp->AssociatedIrp.SystemBuffer MmGetSystemAddressForMdlSafe


(Irp->MdlAddress )

WdfRequestRetrieveOutputWdm Builds a memory descriptor list (MDL) Irp->MdlAddress


Mdl (KMDF only) for Irp-
>AssociatedIrp.SystemBuffer and
returns the MDL.

WdfRequestRetrieveOutputMemo Returns a WDFMEMORY object. Call Returns a WDFMEMORY object. Call


ry WdfMemor yGetBuffer on this WdfMemor yGetBuffer on this
object to get Irp- object to get
>AssociatedIrp.SystemBuffer . MmGetSystemAddressForMdlSafe
(Irp->MdlAddress ).
WDM IRPs and WDF Event Callback Functions
2/5/2021 • 4 minutes to read • Edit Online

Kernel-Mode Driver Framework (KMDF) and User-Mode Driver Framework (UMDF) support a subset of
Windows IRPs. The following table lists the major WDM IRP types and the corresponding framework event
callback functions. Unless otherwise specified, the callbacks apply to both KMDF and UMDF.

M A JO R IRP C O DE W DF EVEN T C A L L B A C K F UN C T IO N

IRP_MJ_CLEANUP EvtFileCleanup

IRP_MJ_CLOSE EvtFileClose

IRP_MJ_CREATE EvtDeviceFileCreate or EvtIoDefault

IRP_MJ_CREATE_MAILSLOT No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_DEVICE_CHANGE No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_DEVICE_CONTROL EvtIoDeviceControl or EvtIoDefault

IRP_MJ_DIRECTORY_CONTROL No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_FILE_SYSTEM_CONTROL No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_FLUSH_BUFFERS No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl or EvtIoDefault

IRP_MJ_LOCK_CONTROL No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_PNP Many; see KMDF Callbacks for IRP_MJ_PNP.

IRP_MJ_POWER Many; see KMDF Callbacks for IRP_MJ_POWER.

IRP_MJ_QUERY_EA No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_QUERY_INFORMATION No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_QUERY_QUOTA No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)
M A JO R IRP C O DE W DF EVEN T C A L L B A C K F UN C T IO N

IRP_MJ_QUERY_SECURITY No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_QUERY_VOLUME_INFORMATION No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_READ EvtIoRead or EvtIoDefault

IRP_MJ_SET_EA No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_SET_INFORMATION No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_SET_QUOTA No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_SET_SECURITY No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_SET_VOLUME_INFORMATION No direct support; implement EvtDeviceWdmIrpPreprocess


(KMDF only)

IRP_MJ_SHUTDOWN For control device objects, implement


EvtDeviceShutdownNotification (KMDF only)
For all Plug and Play device objects: Not supported;
implement EvtDeviceWdmIrpPreprocess (KMDF only).

IRP_MJ_SYSTEM_CONTROL Create WDFWMIPROVIDER and WDFWMIINSTANCE objects


and implement EvtWmiXxx (KMDF only) callbacks.

IRP_MJ_WRITE EvtIoWrite or EvtIoDefault

KMDF Callbacks for IRP_MJ_PNP


The following table lists, in order of execution, the KMDF callbacks that correspond to the minor IRP codes for
IRP_MJ_PNP . The arrows indicate whether a WDM FDO handles the IRP as it travels up or down the stack.
Note In a KMDF driver, Plug and Play and power management are integrated operations and the driver does
not receive the individual minor IRP_MJ_PNP or IRP_MJ_POWER requests. Instead, the framework calls a
core set of callbacks at power up and a corresponding set at power down, and calls additional callbacks before
and after this core set as appropriate for each individual Plug and Play request. For comprehensive diagrams
that show the power-up and power-down sequences, see Porting PnP and Power Management Functionality.

IRP _M J_P N P M IN O R C O DE K M DF C A L L B A C K S

↓IRP_MN_CANCEL_REMOVE_DEVICE None

↓IRP_MN_CANCEL_STOP_DEVICE None

↑IRP_MN_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification
IRP _M J_P N P M IN O R C O DE K M DF C A L L B A C K S

↓IRP_MN_EJECT EvtDeviceEject (KMDF only)

↓IRP_MN_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements (KMDF only)

↑IRP_MN_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements (KMDF only)

IRP_MN_QUERY_BUS_INFORMATION None. The KMDF driver calls WdfDeviceInitXxx methods to


set device properties during initialization so that the
framework can respond to this query on its own without
notifying the driver.

IRP_MN_QUERY_CAPABILITIES None. The KMDF driver calls WdfDeviceInitXxx methods to


set device properties during initialization so that the
framework can respond to this query on its own without
notifying the driver.

↓IRP_MN_QUERY_DEVICE_REL ATIONS (bus, removal, EvtDeviceRelationsQuery


and ejection relations)

IRP_MN_QUERY_DEVICE_TEXT None. The KMDF driver calls WdfDeviceInitXxx methods to


set device properties during initialization so that the
framework can respond to this query on its own without
notifying the driver.

IRP_MN_QUERY_ID None. The KMDF driver calls WdfDeviceInitXxx methods to


set device properties during initialization so that the
framework can respond to this query on its own without
notifying the driver.

↓IRP_MN_QUERY_INTERFACE EvtDeviceProcessQueryInterfaceRequest (KMDF only)

IRP_MN_QUERY_PNP_DEVICE_STATE None. The KMDF driver calls WdfDeviceInitXxx methods to


set device properties during initialization so that the
framework can respond to this query on its own without
notifying the driver.

↓IRP_MN_QUERY_REMOVE_DEVICE EvtDeviceQueryRemove

↓IRP_MN_QUERY_RESOURCE_REQUIREMENTS EvtDeviceResourceRequirementsQuery (KMDF only)

↓IRP_MN_QUERY_RESOURCES EvtDeviceResourcesQuery (KMDF only)

↓IRP_MN_QUERY_STOP_DEVICE EvtDeviceQueryStop

IRP_MN_READ_CONFIG None. The KMDF driver calls WdfDeviceInitXxx methods to


set device properties during initialization so that the
framework can respond to this query on its own without
notifying the driver.
IRP _M J_P N P M IN O R C O DE K M DF C A L L B A C K S

↓IRP_MN_REMOVE_DEVICE After IRP_MN_QUERY_REMOVE_DEVICE :


EvtDeviceSelfManagedIoSuspend EvtIoStop
(WdfRequestStopActionSuspend flag)
EvtDmaEnablerSelfManagedIoStop (KMDF only)
EvtDmaEnablerDisable (KMDF only) EvtDmaEnablerFlush
(KMDF only) EvtDeviceD0ExitPreInterruptsDisabled
EvtInterruptDisable EvtDeviceD0Exit
(WdfPowerDeviceD3Final state)
EvtDeviceReleaseHardware EvtIoStop
(WdfRequestStopActionPurge flag) for power-managed
queues EvtDeviceSelfManagedIoFlush EvtIoStop
(WdfRequestStopActionPurge flag) for non-power-
managed queues EvtDeviceSelfManagedIoCleanup
EvtCleanupCallback for WDFDEVICE EvtDestroyCallback for
WDFDEVICE
After IRP_MN_SURPRISE_REMOVAL :
EvtIoStop (WdfRequestStopActionPurge flag) for non-
power-managed queues EvtDeviceSelfManagedIoCleanup
EvtCleanupCallback for WDFDEVICE EvtDestroyCallback for
WDFDEVICE

↓IRP_MN_SET_LOCK EvtDeviceSetLock (KMDF only)

↑IRP_MN_START_DEVICE After enumeration:


EvtDeviceRemoveAddedResources (KMDF only)
EvtDevicePrepareHardware EvtDeviceD0Entry
EvtInterruptEnable EvtDeviceD0EntryPostInterruptsEnabled
EvtDmaEnablerFill (KMDF only) EvtDmaEnablerEnable (KMDF
only) EvtDmaEnablerSelfManagedIoStart (KMDF only)
EvtDeviceSelfManagedIoInit
After IRP_MN_STOP_DEVICE :
EvtDeviceRemoveAddedResources (KMDF only)
EvtDevicePrepareHardware EvtDeviceD0Entry
EvtInterruptEnable EvtDeviceD0EntryPostInterruptsEnabled
EvtDmaEnablerFill (KMDF only) EvtDmaEnablerEnable (KMDF
only) EvtDmaEnablerSelfManagedIoStart (KMDF only)
EvtIoResume EvtDeviceSelfManagedIoRestart

↓IRP_MN_STOP_DEVICE EvtDeviceSelfManagedIoSuspend EvtIoStop


(WdfRequestStopActionSuspend flag)
EvtDmaEnablerSelfManagedIoStop (KMDF only)
EvtDmaEnablerDisable (KMDF only) EvtDmaEnablerFlush
(KMDF only) EvtDeviceD0ExitPreInterruptsDisabled
EvtInterruptDisable EvtDeviceD0Exit
(WdfPowerDeviceD3Final state)
EvtDeviceReleaseHardware
IRP _M J_P N P M IN O R C O DE K M DF C A L L B A C K S

↓IRP_MN_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval EvtDeviceSelfManagedIoSuspend


EvtIoStop (WdfRequestStopActionSuspend flag)
EvtDmaEnablerSelfManagedIoStop (KMDF only)
EvtDmaEnablerDisable (KMDF only) EvtDmaEnablerFlush
(KMDF only) EvtDeviceD0ExitPreInterruptsDisabled
EvtInterruptDisable EvtDeviceD0Exit
(WdfPowerDeviceD3Final state)
EvtDeviceReleaseHardware EvtIoStop
(WdfRequestStopActionPurge flag) for power-managed
queues EvtDeviceSelfManagedIoFlush

IRP_MN_WRITE_CONFIG None. The KMDF driver calls WdfDeviceInitXxx methods to


set device properties during initialization so that the
framework can respond to this query on its own without
notifying the driver.

KMDF Callbacks for IRP_MJ_POWER


The following table lists, in order of execution, the KMDF callbacks that correspond to the minor IRP codes for
IRP_MJ_POWER . The arrows indicate whether a WDM FDO handles the IRP as it travels up or down the stack.
Note Note: In a KMDF driver, Plug and Play and power management are integrated operations and the driver
does not receive the individual minor IRP_MJ_PNP or IRP_MJ_POWER requests. Instead, the framework calls
a core set of callbacks at power up and a corresponding set at power down, and calls additional callbacks before
and after this core set as appropriate for each individual Plug and Play request. For comprehensive diagrams
that show the power-up and power-down sequences, see Porting PnP and Power Management Functionality.

IRP _M J_P O W ER M IN O R C O DE F RA M EW O RK C A L L B A C K S

↓IRP_MN_SET_POWER for D1, D2, or D3 (power down) EvtDeviceSelfManagedIoSuspend EvtIoStop


(WdfRequestStopActionSuspend flag)
EvtDeviceArmWakeFromS0 or EvtDeviceArmWakeFromSx
EvtDmaEnablerSelfManagedIoStop (KMDF only)
EvtDmaEnablerDisable (KMDF only) EvtDmaEnablerFlush
(KMDF only) EvtDeviceD0ExitPreInterruptsDisabled
EvtInterruptDisable EvtDeviceD0Exit

↑IRP_MN_SET_POWER for D0 (power up) EvtDeviceD0Entry EvtInterruptEnable


EvtDeviceD0EntryPostInterruptsEnabled EvtDmaEnablerFill
(KMDF only) EvtDmaEnablerEnable (KMDF only)
EvtDmaEnablerSelfManagedIoStart (KMDF only)
EvtIoResume EvtDeviceSelfManagedIoRestart

↓IRP_MN_SET_POWER for Sx None

↑IRP_MN_SET_POWER for Sx None

IRP_MN_POWER_SEQUENCE None

↓IRP_MN_WAIT_WAKE EvtDeviceEnableWakeAtBus (KMDF only)

↑IRP_MN_WAIT_WAKE EvtDeviceDisableWakeAtBus (KMDF only)


Framework Queue Objects
2/5/2021 • 2 minutes to read • Edit Online

Framework queue objects represent I/O queues, which are containers for the I/O requests that a driver receives.
Each driver can create one or more I/O queues for each device. The framework queue object defines a set of
event callback functions that the driver can provide and a set of object methods that the driver can call.
When the framework receives an I/O request that is directed to one of the driver's devices, the framework places
the request in the appropriate I/O queue. If your driver registers one or more request handlers, the framework
can notify your driver each time an I/O request is available. Alternatively, your driver can poll the I/O queue for
requests.
This section includes:
Creating I/O Queues
Deleting I/O Queues
Managing I/O Queues
Using Power-Managed I/O Queues
Guaranteeing Forward Progress of I/O Operations
I/O Queue States
Example Uses of I/O Queues
Creating I/O Queues
2/5/2021 • 2 minutes to read • Edit Online

Most drivers create I/O queues in their EvtDriverDeviceAdd callback function. To create an I/O queue for a
device, the driver calls the framework queue object's WdfIoQueueCreate method (which creates a framework
queue object). The driver supplies a WDF_IO_QUEUE_CONFIG structure to the method. This structure
contains configuration information about the queue, such as the queue's dispatching method and pointers to
request handlers that the framework calls when requests are available in the queue. The structure also indicates
whether the queue will be power-managed and whether the driver supports zero-length buffers for the queue's
I/O requests.
If the driver sets the DefaultQueue member of the WDF_IO_QUEUE_CONFIG structure to TRUE , the queue
becomes the device's default I/O queue. If your driver creates a default I/O queue, the framework places all of
the device's I/O requests in this queue, unless you create additional queues to receive some of the requests. A
driver can obtain a handle to a device's default I/O queue by calling the WdfDeviceGetDefaultQueue method.
If you want to use more than one I/O queue for a device, the driver can call WdfIoQueueCreate to create as
many queue objects as you need. If a driver creates multiple queues, it can call
WdfDeviceConfigureRequestDispatching , which instructs the framework to direct different types of
requests to different queues. For example, you can specify that all read requests will be delivered to one queue
and all write requests will be delivered to another queue.
If your driver creates a set of I/O queues and calls WdfDeviceConfigureRequestDispatching to direct each
type of request that your driver can receive to a specific queue, the driver does not need a default queue.
If a driver does not provide an I/O queue for requests of a particular type, and if your driver is a function driver,
the framework completes requests of that type with a completion status value of
STATUS_INVALID_DEVICE_REQUEST. If your driver is a filter driver and has called WdfFdoInitSetFilter , the
framework automatically forwards these requests to the next-lower driver in the driver stack. Thus, for example,
a filter driver that does not process read requests does not have to provide an I/O queue that receives read
requests.
For examples of how drivers can use I/O queues, see Example Uses of I/O Queues.
Dispatching Methods for I/O Requests
2/5/2021 • 3 minutes to read • Edit Online

When a driver calls WdfIoQueueCreate to create an I/O queue, it specifies a dispatching method for the
queue. The framework provides three dispatching methods: sequential, parallel, and manual. The driver can
specify any of these dispatching methods for any I/O queue, including a device's default I/O queue.
The driver sets a queue's dispatching method by specifying a WDF_IO_QUEUE_DISPATCH_TYPE -typed value
in the queue's WDF_IO_QUEUE_CONFIG structure.
For example uses of each dispatching method, see Example Uses of I/O Queues.
Sequential Dispatching
If your driver or device can process only one I/O request from a queue at a time, you should set up the device's
I/O queues to use sequential dispatching, which is also called synchronous dispatching. With this type of
dispatching, the framework delivers requests to the driver one at a time. The framework does not deliver the
next request until the driver completes, cancels, or requeues the previous request.
After the framework delivers a request to one of the driver's request handlers, the driver processes the request.
If the driver forwards the request to a general I/O target, it typically calls one of the I/O target object's
synchronous methods. For more information about these methods, see Sending I/O Requests Synchronously.
The driver must eventually complete or cancel every request that it receives from an I/O queue.
A driver that has set up an I/O queue for sequential dispatching can call WdfIoQueueRetrieveNextRequest or
WdfIoQueueRetrieveRequestByFileObject to obtain another request from the queue before the last
received request has been completed or canceled. You might want to do this in a function driver, so that the
driver can start the next hardware operation while the driver's EvtInterruptDpc callback function is still
processing data from the previous hardware operation.
If you create several I/O queues and set them all up for sequential dispatching, the framework dispatches
requests from each queue sequentially, but the queues run in parallel. If your driver or device can process only
one request at a time of any type, you must use a single I/O queue with an EvtIoDefault callback function.
Parallel Dispatching
If your driver and device can process multiple I/O requests simultaneously, you can set up the device's I/O
queues to use parallel dispatching so that the driver can process the requests asynchronously. This dispatching
method is also called asynchronous dispatching.
If a driver sets up an I/O queue to use parallel dispatching, the framework delivers I/O requests to the driver as
soon as they are available in the queue. The result is that the driver might have to process several requests at
once.
Each time one of the driver's request handlers receives a request, the driver must process the request and then
complete the request. If the driver forwards the request to a general I/O target, it typically calls one of the I/O
target object's asynchronous methods. For more information about these methods, see Sending I/O Requests
Asynchronously. The driver must eventually complete or cancel every request that it receives from an I/O queue.
A driver that uses parallel dispatching can call WdfIoQueueStop or WdfIoQueueStopSynchronously to
temporarily stop a queue, and then call WdfIoQueueStar t to restart the queue.
Manual Dispatching
If you want your driver to have complete control over the delivery of I/O requests, you can set up a device's I/O
queue to use manual dispatching, which means that the framework does not deliver requests to the driver
unless the driver explicitly asks for one.
To obtain a request from a manual queue, the driver can call WdfIoQueueRetrieveNextRequest or
WdfIoQueueRetrieveRequestByFileObject in a loop that polls the queue. Alternatively, the driver can call
WdfIoQueueReadyNotify to register a callback function that the framework will call when one or more
requests are available in the queue. After the framework calls the callback function, the driver can call
WdfIoQueueRetrieveNextRequest or WdfIoQueueRetrieveRequestByFileObject in a loop to retrieve the
requests.
After the driver obtains a request from the queue, it must process the request. The driver must eventually
complete or cancel each request.
Request Handlers
2/5/2021 • 2 minutes to read • Edit Online

If your driver has specified either the sequential or the parallel dispatching method for an I/O queue, the
framework calls a driver-supplied callback function each time it is ready to deliver one of the queue's requests to
the driver.
For each I/O queue, the driver can provide one or more of the following callback functions, which are called
request handlers:
EvtIoRead
The framework calls an I/O queue's EvtIoRead callback function when a read request is available in the queue.
EvtIoWrite
The framework calls an I/O queue's EvtIoWrite callback function when a write request is available in the queue.
EvtIoDeviceControl
The framework calls an I/O queue's EvtIoDeviceControl callback function when a device I/O control request is
available in the queue.
EvtIoInternalDeviceControl
The framework calls an I/O queue's EvtIoInternalDeviceControl callback function when an internal device I/O
control request is available in the queue.
EvtIoDefault
The framework calls an I/O queue's EvtIoDefault callback function when any request is available, if the driver has
not supplied the associated request-type-specific callback function.
The driver registers callback functions when it calls WdfIoQueueCreate to create an I/O queue for a device.
Each of these callback functions receives two input arguments: a handle to the I/O request that the framework is
delivering to the driver and a handle to the I/O queue that held the request. A callback function can determine
the target device by calling WdfIoQueueGetDevice .
The framework calls your driver's request handlers in an arbitrary thread context. A driver should not wait for an
extended period of time while executing in an arbitrary thread context. In some cases, your driver might use
kernel dispatcher objects as synchronization mechanisms. For information about when your driver can wait for
dispatcher objects, and what to do when it can't, see Introduction to Kernel Dispatcher Objects.
Deleting I/O Queues
2/5/2021 • 2 minutes to read • Edit Online

Framework-based drivers must delete only some of the I/O queues that they create. If a driver creates a default
I/O queue or an I/O queue that it configures by calling WdfDeviceConfigureRequestDispatching , the
framework deletes the queue object for the driver.
For example, if you intend for each device's I/O queues to exist as long as each device remains plugged into the
system, your driver will create its I/O queues in its EvtDriverDeviceAdd callback function. Your driver might
create a default queue that receives all requests except read requests and a separate queue that receives only
read requests.
The driver cannot delete these I/O queues. Instead, the framework deletes the queue objects when it deletes the
device object to which the queue belongs. For information about why your driver cannot delete these I/O
queues, see the following note.
If, however, your driver creates temporary I/O queues outside of its EvtDriverDeviceAdd callback function, it
must call WdfObjectDelete to delete these queues when it has finished using them. For example, a driver that
provides an EvtDeviceFileCreate callback function might create an I/O queue to handle I/O requests that are
associated with a particular framework file object. In this case the driver's EvtFileCleanup callback function must
call WdfIoQueuePurge to purge the queue and then call WdfObjectDelete to delete it.
Note The framework does not permit a driver to delete its default I/O queue, or any I/O queue that the driver
configures to receive all I/O requests of a particular type (by calling
WdfDeviceConfigureRequestDispatching ). If your driver calls WdfObjectDelete to delete the queue object
that represents one of these queues, WdfObjectDelete returns without deleting the object. WdfObjectDelete
does not provide a return status, so the framework reports an error only if you are using the framework's
verifier.
Managing I/O Queues
2/5/2021 • 4 minutes to read • Edit Online

Starting an I/O Queue


When a driver calls WdfIoQueueCreate to create an I/O queue, the framework automatically enables the
queue to receive I/O requests and to deliver them to a driver.
Drivers typically call WdfIoQueueCreate from within an EvtDriverDeviceAdd callback function. The framework
can begin delivering I/O requests to the driver after the driver's EvtDriverDeviceAdd callback function returns.
If your driver is using power-managed I/O queues, the framework cannot begin delivering requests to your
driver until the device enters its working state and the framework has called the driver's EvtDeviceD0Entry
callback function.

Stopping and Restarting an I/O Queue


Your driver can call WdfIoQueueStop or WdfIoQueueStopSynchronously to temporarily prevent the
framework from delivering I/O requests from an I/O queue. To resume delivery of I/O requests, the driver calls
WdfIoQueueStar t .
If your driver uses power-managed I/O queues, the framework automatically stops a device's queues when the
device leaves its working (D0) state, and the framework restarts the queues when the device state returns to D0.

Adding Requests to an I/O Queue


When the system sends a read, write, or device I/O control request to a driver, the framework places the request
in an I/O queue. The driver can control the types of requests that the framework stores in each queue by calling
WdfDeviceConfigureRequestDispatching .
A driver can also requeue requests that it has received from the framework, by calling
WdfRequestFor wardToIoQueue .

Obtaining Requests from an I/O Queue


If a driver specifies the sequential or the parallel dispatching method for an I/O queue, it receives requests in
request handlers.
If a driver specifies the manual or sequential dispatching method, it can obtain requests by calling
WdfIoQueueRetrieveNextRequest or WdfIoQueueRetrieveRequestByFileObject .

Searching for an I/O Request


If a driver specifies the manual dispatching method for an I/O queue, it can use the following steps to search for
particular requests in the queue:
1. Call WdfIoQueueFindRequest to locate a request that matches driver-specified criteria.
2. Call WdfIoQueueRetrieveFoundRequest to retrieve the request that WdfIoQueueFindRequest
located.

Purging or Draining an I/O Queue


Purging an I/O queue means stopping insertion of I/O requests into the queue and canceling any requests that
are already in the queue.
Draining an I/O queue means stopping insertion of I/O requests into the queue, while allowing any requests
that are already in the queue to be delivered to the driver.
Drivers typically purge or drain their queues only if the queues are not power-managed. For power-managed
I/O queues, drivers can provide EvtIoStop and EvtIoResume callback functions.
If some of your driver's queues are not power-managed, you might want to purge or drain a queue if its
associated device or I/O channel becomes unavailable. Typically, you will purge, instead of drain, a queue unless
there is a high likelihood that each request contains very important information. For example, a driver for a
network device might purge its queues, while a driver for a storage device would likely drain its queues.
If you want your driver to purge or drain an I/O queue, the driver can call one of the following queue object
methods:
WdfIoQueuePurge or WdfIoQueuePurgeSynchronously , to stop queuing I/O requests to an I/O
queue and to cancel unprocessed requests.
WdfIoQueueDrain or WdfIoQueueDrainSynchronously , to stop queuing I/O requests to an I/O
queue while allowing already-queued requests to be delivered and processed.
Exercise caution when calling WdfIoQueueDrain and WdfIoQueueDrainSynchronously . Because a drain
operation waits for requests to be completed, you should only drain a queue if you are certain that the queue's
pending requests will complete in a timely fashion. If you do not know how long I/O requests will take to
complete and it is acceptable to cancel outstanding requests, consider purging the queue.

Moving Requests from One I/O Queue to Another


After your driver has received an I/O request, you might want the driver to requeue the request into a different
I/O queue. To do this, the driver calls WdfRequestFor wardToIoQueue or
WdfRequestFor wardToParentDeviceIoQueue , which adds the request to the tail of a specified queue.
Eventually, the framework will deliver the request to the driver again by using the specified queue's dispatching
method. For more information about moving I/O requests from one I/O queue to another, see Requeuing I/O
Requests.

Intercepting an I/O Request before it is Queued


It is possible for a driver to intercept an I/O request before the framework places the request in an I/O queue. To
intercept I/O requests, the driver must call WdfDeviceInitSetIoInCallerContextCallback to register an
EvtIoInCallerContext callback function.
The framework associates the EvtIoInCallerContext callback function with a device. As a result, the framework
calls the EvtIoInCallerContext callback function every time it receives a request that the system is sending to the
device.
Typically, when an EvtIoInCallerContext callback function receives a request, it performs some preliminary
processing for the request. Next, the callback function calls WdfDeviceEnqueueRequest , which gives the
request back to the framework. The framework can then place the request in the proper I/O queue, just as it
would have if it had not called the EvtIoInCallerContext callback function.
The primary reason that a driver might provide an EvtIoInCallerContext callback function is that the driver has to
handle I/O operations that support the I/O method called neither buffered nor direct I/O. For this I/O method,
the driver must access received buffers in the process context of the originator of the I/O request. For more
information, see Accessing Data Buffers in Framework-Based Drivers.
Obtaining I/O Queue Properties
To obtain properties of a framework queue object, the driver can call the following methods:
WdfIoQueueGetDevice , to obtain a handle to the device object that the queue object belongs to.
WdfIoQueueGetState , to obtain state information about the queue.
Using Power-Managed I/O Queues
2/5/2021 • 2 minutes to read • Edit Online

When a driver creates an I/O queue, it can specify whether the queue is power-managed. When I/O requests are
available in a power-managed queue, the framework delivers the requests to the driver only if the device is in its
working (D0) state. The framework does not allow the device to leave its working state until all I/O requests that
the framework has delivered from the power-managed queue to the driver have been completed, canceled, or
postponed.
For more information about power-managed I/O queues, see Power Management for I/O Queues.

Callback functions for Power-Managed Queues


If your driver uses power-managed I/O queues, it can provide two additional callback functions:
EvtIoStop
The EvtIoStop callback function stops processing a specified I/O request. When the device leaves its working
(D0) state or is removed, the framework calls an I/O queue's EvtIoStop callback function once for every I/O
request that the driver has not completed, including requests that the driver owns and those that it has
forwarded to an I/O target.
EvtIoResume
The EvtIoResume callback function resumes processing a previously stopped I/O request. The framework calls
an I/O queue's EvtIoResume callback function when it resumes delivering I/O requests to the driver from the
queue, after the device has returned to its working state.
Each time the framework calls a driver's EvtIoStop callback function, the function typically completes or cancels
the I/O request, or calls WdfRequestStopAcknowledge to return ownership of the request to the framework.
While doing so is optional, you should in general provide an EvtIoStop callback function for a power-managed
queue. By providing EvtIoStop, your driver can help to shorten the time that elapses before your device, and
possibly the system, enters a low-power state.
If you do not provide EvtIoStop for a power-managed queue, the framework waits until all requests delivered
from the power-managed queue to the driver are complete before moving the device (or system) to a lower
power state or removing the device. Potentially, this inaction can prevent a system from entering its hibernation
state or another low system power state. In extreme cases, it can cause the system to crash with bugcheck code
9F.
If your driver does not forward requests to an I/O target and does not hold requests for an indeterminate time,
you could safely omit EvtIoStop for a power-managed queue.

Waiting for Dispatcher Objects


In general, drivers should only use dispatcher objects as synchronization mechanisms within a nonarbitrary
thread context.
Because request handlers run in an arbitrary thread context, a request handler for a power-managed queue
must not wait for kernel dispatcher objects to be set. Doing so may result in deadlock.
For more information about when a driver can wait for dispatcher objects, and what to do when it can't, see
Introduction to Kernel Dispatcher Objects.
I/O Queue States
2/5/2021 • 2 minutes to read • Edit Online

The framework defines the following states for I/O queues:


Idle
The I/O queue contains no I/O requests, and the driver is not processing any requests that it received from the
I/O queue.
Ready
The I/O queue can receive I/O requests from the framework, and it can deliver I/O requests to the driver.
Stopped
The I/O queue can receive I/O requests from the framework, but it cannot deliver I/O requests to the driver, and
the driver is not processing any requests that it received from the I/O queue.
Drained
The I/O queue is empty, it cannot receive new I/O requests from the framework, and all I/O requests that were in
the I/O queue have been delivered to the driver.
Purged
The I/O queue is empty, it cannot receive new I/O requests from the framework, and all I/O requests that were in
the I/O queue have been canceled.
The framework can set a new I/O queue to the ready state after your driver calls WdfIoQueueCreate . However,
power-managed I/O queues enter the ready state only if the device is in its working (D0) state.
Your driver can change an I/O queue's state by:
Calling WdfIoQueueStop or WdfIoQueueStopSynchronously to place the queue in its stopped state.
Calling WdfIoQueueDrain or WdfIoQueueDrainSynchronously to place the queue in its drained
state.
Calling WdfIoQueuePurge or WdfIoQueuePurgeSynchronously to place the queue in its purged
state.
Calling WdfIoQueueStar t to return the queue to its ready state.
To obtain an I/O queue's current state, your driver can call WdfIoQueueGetState .
Example Uses of I/O Queues
2/5/2021 • 6 minutes to read • Edit Online

For each device that is connected to a system and supported by a particular driver, the driver can use the
following combinations of I/O queues and request handlers:
A single, default I/O queue and a single request handler, EvtIoDefault. The framework will deliver all of the
device's requests to the default queue, and it will call the driver's EvtIoDefault handler to deliver each
request to the driver.
A single, default I/O queue and multiple request handlers such as EvtIoRead, EvtIoWrite, and
EvtIoDeviceControl. The framework will deliver all of the device's requests to the default queue. It will call
the driver's EvtIoRead handler to deliver read requests, the EvtIoWrite handler to deliver write requests,
and the EvtIoDeviceControl handler to deliver device I/O control requests.
Multiple I/O queues, such as one for read requests and another for write requests. For each queue, the
driver provides only one request handler because the queue receives only one type of request.
Multiple I/O queues, each with multiple request handlers.
Some example scenarios include:
A Single Sequential I/O Queue
Multiple Sequential I/O Queues and a Manual Queue
A Single Parallel I/O Queue
Multiple Parallel I/O Queues

A Single Sequential I/O Queue


If you are writing a function driver for a disk drive that can only service read and write requests one at a time,
the function driver needs only one I/O queue per device.
The driver can use the default I/O queue that the framework creates when the driver calls WdfIoQueueCreate
and sets DefaultQueue to TRUE in the queue's WDF_IO_QUEUE_CONFIG structure. In the
WDF_IO_QUEUE_CONFIG structure, the driver should also specify:
WdfIoQueueDispatchSequential as the dispatching method, so the default I/O queue will deliver I/O
requests to the driver synchronously.
A single event callback function, EvtIoDefault, that will receive all I/O requests.
Each time an I/O request is available in the driver's default I/O queue, the framework will deliver the request to
the driver by calling the driver's EvtIoDefault request handler. If another request becomes available in the queue,
the framework will not deliver it until the driver calls WdfRequestComplete for the previously delivered
request.

Multiple Sequential I/O Queues and a Manual Queue


Consider a serial port device that has the following characteristics:
It can simultaneously perform one read operation and one write operation.
It cannot perform multiple read or write operations asynchronously.
It can receive device I/O control requests for status information. The device's driver might take a long
time to complete some of these requests (such as a request to wait for a status change).
A function driver for this device could use multiple, sequential I/O queues per device. The driver would call
WdfIoQueueCreate three times: once to create a default queue and twice to create two additional I/O queues.
In the WDF_IO_QUEUE_CONFIG structure for each of these queues, the driver should specify:
WdfIoQueueDispatchSequential as the dispatching method for each queue, so that the framework
will deliver I/O requests to the driver synchronously.
A different request handler for each queue (EvtIoDefault, EvtIoRead, and EvtIoWrite), which will receive
the queue's I/O requests.
After calling WdfIoQueueCreate , the driver could call WdfDeviceConfigureRequestDispatching twice - to
forward all read requests to one of the additional queues and all write requests to the other.
With this configuration, the device's default I/O queue EvtIoDefault callback function will receive only the device
I/O control requests for status information.
If the driver has to hold a status request for a long time, it can create a fourth queue and specify
WdfIoQueueDispatchManual as the dispatching method. When the driver receives a request for information
that it must wait for, it can place the request in this extra queue until the status information becomes available.
Then the driver can retrieve the request from the queue and complete it. In the meantime, the default queue can
deliver another request to the driver.

A Single Parallel I/O Queue


IDE disk controllers can overlap some I/O operations, but not others. For example, while a controller is
processing a read or write operation on one disk, it can send a seek command to another disk. On the other
hand, multiple, simultaneous read and write commands are not supported.
A function driver for this controller must examine each I/O request. If the driver receives a seek command, it
must determine if the seek command can be processed. The seek command cannot be processed if:
The specified disk drive is already busy.
A disk drive is being formatted and, therefore, no other drives can be active.
For each device that is connected to the controller, the driver could call WdfIoQueueCreate to create a default
I/O queue. In the WDF_IO_QUEUE_CONFIG structure for each of these queues, the driver should specify:
WdfIoQueueDispatchParallel as the dispatching method for each queue, so that the framework will
deliver I/O requests to the driver asynchronously.
An EvtIoDefault event callback function for each queue, which will receive the queue's I/O requests.
With this configuration, a single, parallel I/O queue is assigned to each device. The driver must examine each I/O
request that the framework delivers from each I/O queue. If the driver can process the request immediately, it
does so. Otherwise, the driver calls WdfIoQueueStop , which causes the framework to stop delivering requests
until the driver calls WdfIoQueueStar t .

Multiple Parallel I/O Queues


A SCSI host adapter is an example of a device that supports asynchronous, overlapped I/O operations. Up to 32
devices can be connected to the adapter. Consider a system with the following configuration:
Some of the devices connected to the SCSI adapter support "reselection", and some do not. If a SCSI
device supports reselection, then during an I/O operation the device can temporarily release the adapter
so the adapter can service another device. The first device later reselects itself to finish its operation.
The SCSI adapter uses hardware mailboxes to pass requests and responses between the driver and the
devices. If a device is ready for a request but there are no available mailboxes, the device must wait.
For best performance, the function driver for this SCSI host adapter should receive I/O requests from the
framework as soon as they are available. The driver must examine each request and determine if it can be
started immediately or must be postponed until the device and resources (such as mailbox memory) are
available.
The driver should probably use multiple, parallel I/O queues. For each device that is connected to the adapter,
the driver would call WdfIoQueueCreate to create a default I/O queue. In the WDF_IO_QUEUE_CONFIG
structure for each of these queues, the driver should specify:
WdfIoQueueDispatchParallel as the dispatching method for each queue, so that the framework will
deliver I/O requests to the driver asynchronously.
An EvtIoDefault event callback function for each queue, which will receive the queue's I/O requests.
Each I/O queue's EvtIoDefault callback function must examine the queue's I/O requests, as they are delivered,
and determine whether each one can be serviced immediately. If the device and system resources are available,
the driver starts the I/O operation. If the device or resources are not available, the driver must call
WdfIoQueueStop to stop delivery of additional requests until the current one can be processed.
Optionally, the driver can call WdfIoQueueCreate to create additional queues for each device. Then the driver
can call WdfRequestFor wardToIoQueue to requeue some types of requests to the additional queues. When
the framework delivers requests from an additional queue, the driver can call WdfIoQueueStop , if necessary,
on that queue instead of the default queue, thereby minimizing the number or type of requests for which
delivery is postponed.
Introduction to Registry Keys for Drivers
2/5/2021 • 2 minutes to read • Edit Online

Drivers typically use a set of system-defined registry keys to store or access driver-specific or device-specific
information. Your driver might access the following registry keys:
Parameters key
The driver's Parameters key can contain configuration information for your driver and can be accessed
by calling WdfDriverOpenParametersRegistr yKey . For Kernel-Mode Driver Framework (KMDF)
drivers, this key is located in the appropriate Ser vices tree for the driver. For User-Mode Driver
Framework (UMDF) drivers, this key is located in the HKLM\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\WUDF\Ser vices tree, under the driver's service name. The subkey for the driver
always uses the driver's service name, even if the driver binary's file name differs from the service name.
When the system calls your driver's DriverEntr y routine, it passes the driver a path to the driver's key in
the appropriate Ser vices tree. Your driver must pass this path to WdfDriverCreate . Subsequently, the
driver can obtain the path by calling WdfDriverGetRegistr yPath .
Software key
A driver's software key is also called its driver key. The system stores information about each driver under
its software key.
Your driver can call WdfFdoInitOpenRegistr yKey and WdfDeviceOpenRegistr yKey to open a
device's software key.
Your driver's INF file can contain INF AddReg directives that set registry values under the software key
using INF DDInstall sections .
Hardware keys
When a driver stack informs the Plug and Play (PnP) manager that a device is connected to the system,
the PnP manager creates a hardware key for the device. This key is also called a device key. Settings
related to the hardware (such as interrupt settings) can be stored here by drivers.
Your driver can call WdfFdoInitOpenRegistr yKey and WdfDeviceOpenRegistr yKey to open a
device's hardware key.
Your driver's INF file can contain INF AddReg directives that set registry values under the hardware
key using INF DDInstall.HW sections .
To determine whether your driver type requires that you store information under specific registry keys, see the
sections of this documentation that discuss your driver's device type by using the table of contents.
For more information about registry keys for drivers, see:
Using the Registry in a Driver
Using Framework Registry-Key Objects
2/5/2021 • 2 minutes to read • Edit Online

Framework-based drivers access the registry by using framework registry-key objects. The registry-key object
defines methods that enable your driver to create, open, and close registry keys; add and remove registry
values; and read or write the data that is assigned to a registry value.
To open a registry key, your driver must call WdfRegistr yOpenKey . If the key does not exist, the driver must
call WdfRegistr yCreateKey , which creates a new key and opens it.
When your driver opens a registry key, the framework creates a registry-key object that represents the opened
key and returns an object handle to the driver. The driver must use the object handle to access the key, any
subkeys that exist under the key, and any values that exist under the key or its subkeys.
To read the data that is currently assigned to a registry value name, the driver can call one of the following
object methods:
WdfRegistr yQuer yMemor y
Retrieves the data that is currently assigned to a value name, stores the data in a framework-allocated buffer,
and creates a framework memory object to represent the buffer.
WdfRegistr yQuer yMultiString
Retrieves the string data that is currently assigned to a multi-string-typed value name, creates a framework
string object for each string, and adds each string object to an object collection.
WdfRegistr yQuer yString
Retrieves the string data that is currently assigned to a string-typed value name and assigns the string to a
specified framework string object.
WdfRegistr yQuer yUnicodeString
Retrieves the string data that is currently assigned to a string-typed value name and copies the string to a
specified UNICODE_STRING structure.
WdfRegistr yQuer yULong
Retrieves the unsigned long word (REG_DWORD) data that is currently assigned to a value name and copies the
data to a specified location.
WdfRegistr yQuer yValue
Retrieves the data that is currently assigned to a value name and copies the data to a driver-supplied buffer.
To write data to a registry value, the driver can call one of the following methods. If the value name already
exists, the operating system updates the value's data.
WdfRegistr yAssignMemor y
Assigns data that is contained in a memory buffer to a specified value name in the registry.
WdfRegistr yAssignMultiString
Assigns a set of strings to a specified value name in the registry. The strings are contained in a driver-supplied
collection of framework string objects.
WdfRegistr yAssignString
Assigns a string to a specified value name in the registry. The string is contained in a framework string object.
WdfRegistr yAssignUnicodeString
Assigns a specified Unicode string to a specified value name in the registry.
WdfRegistr yAssignULong
Assigns a specified unsigned long word value to a specified value name in the registry.
WdfRegistr yAssignValue
Assigns the contents of a driver-supplied data buffer to a specified value name in the registry.
To remove a registry value, the driver must call WdfRegistr yRemoveValue . To remove a key, the driver must
call WdfRegistr yRemoveKey .
To obtain WDM information about the registry, a driver can call WdfRegistr yWdmGetHandle , which returns a
WDM handle to the registry key that a framework registry-key object represents.
After your driver has finished accessing a registry key, it must call WdfRegistr yClose or WdfObjectDelete to
close the key and delete the registry-key object.
Accessing the Unified Device Property Model
2/5/2021 • 2 minutes to read • Edit Online

This topic describes how a Windows Driver Frameworks (WDF) driver retrieves or modifies properties that are
exposed through the unified device property model. The methods listed are available starting in User-Mode
Driver Framework (UMDF) version 2.0 and Kernel-Mode Driver Framework (KMDF) version 1.13.
Both KMDF and UMDF drivers can call the following methods:
WdfDeviceAllocAndQuer yProper tyEx
WdfDeviceAssignProper ty
WdfDeviceQuer yProper tyEx
Both KMDF and UMDF drivers can call the following methods only before calling WdfDeviceCreate . For more
information about calling WdfDeviceCreate , see Creating a Framework Device Object.
After calling WdfDeviceCreate , a driver can obtain device property information by calling the corresponding
WdfDevice Xxx Proper ty method.
WdfFdoInitAllocAndQuer yProper tyEx
WdfFdoInitQuer yProper tyEx
The -Ex methods above differ from their non-Ex counterparts in that they allow you to specify properties using
the WDF_DEVICE_PROPERTY_DATA structure, instead of the subset that you can specify using
DEVICE_REGISTRY_PROPERTY .
Before receiving device property data, drivers typically call Wdf Xxx Quer yProper ty just to obtain the required
buffer size. For some properties, the data size can change between when the required size is returned and when
the driver calls Wdf Xxx Quer yProper ty again. Therefore, drivers should call Wdf Xxx Quer yProper ty inside a
loop that executes until the return status is not STATUS_BUFFER_TOO_SMALL .
It is best to use Wdf Xxx Quer yProper ty only if the required buffer size is known and unchanging, because in
that case the driver has to call Wdf Xxx Quer yProper ty only once. If the required buffer size is unknown or
varies, the driver should call Wdf Xxx AllocAndQuer yProper ty .

Accessing Device Interface Properties


UMDF drivers can use the following methods to retrieve or modify device interface properties that are exposed
through the unified property model:
WdfDeviceAllocAndQuer yInterfaceProper ty
WdfDeviceAssignInterfaceProper ty
WdfDeviceQuer yInterfaceProper ty
To retrieve or modify a device interface property, a KMDF driver must call
IoGetDeviceInterfaceProper tyData or IoSetDeviceInterfaceProper tyData directly.
Framework Request Objects
2/5/2021 • 2 minutes to read • Edit Online

Framework request objects represent I/O requests that the I/O manager has sent to a driver. Framework-based
drivers process each I/O request by calling framework request object methods.
Each I/O request contains a WDM I/O request packet (IRP structure), but framework-based drivers typically do
not need to access the IRP structure.

In this section
Creating Framework Request Objects
Using Request Object Context
Request Ownership
Processing I/O Requests
Obtaining Information About an I/O Request
Accessing Data Buffers in WDF Drivers (KMDF or UMDF)
Managing Buffer Access Methods in UMDF Drivers
Reusing Framework Request Objects
Creating Framework Request Objects
2/5/2021 • 2 minutes to read • Edit Online

Most framework request objects are created by the framework, but your driver can also create request objects.
Request Objects Created by the Framework
When a framework-based driver receives an I/O request packet (IRP) from the I/O manager, the framework
intercepts the IRP and creates a framework request object. The framework places the request object into an I/O
queue and, if the driver has registered request handlers for the queue, calls the appropriate handler.
The following diagram illustrates the steps that occur when the framework creates a request object for a read
operation.

The following steps correspond to the numbers in the preceding diagram:


1. A user-mode application reads a file by calling the Microsoft Win32 ReadFile function.
2. The ReadFile function calls the I/O manager, which runs in kernel mode.
3. The I/O manager allocates an IRP structure and stores an IRP_MJ_READ function code in the structure.
4. The I/O manager calls the DispatchRead standard driver routine for driver x, passing a pointer to the IRP
structure. Because driver x is a framework-based driver, the framework provides the driver's
DispatchRead routine.
5. The framework creates a request object that represents the IRP structure. The framework adds the
request object to one of the driver's queue objects.
6. The framework calls the driver's EvtIoRead request handler, passing a queue object handle and a request
object handle.
Request Objects Created by a Driver
Framework-based drivers can also create request objects. For example, a driver might create request objects if it
receives a read or write request for an amount of data that is larger than the driver's I/O targets can handle at
one time. In such a situation, the driver can divide the data into several smaller requests and use additional
request objects to send these smaller requests to one or more I/O targets.
To create a request object, your driver should call WdfRequestCreate followed by framework object methods
that initialize the request, such as WdfUsbTargetPipeFormatRequestForRead .
If a driver receives WDM IRPs in a WDM dispatch routine and then services or forwards them by using the
framework, the driver can call WdfRequestCreateFromIrp .
Using Request Object Context
2/5/2021 • 2 minutes to read • Edit Online

Every framework request object, whether created by the framework or by a driver, can contain driver-defined
context space. When a framework-based driver initializes a framework device object, the driver can call
WdfDeviceInitSetRequestAttributes to specify a WDF_OBJECT_ATTRIBUTES structure that describes
context space for the device's request objects.
The framework allocates context space for request objects as follows:
When the framework creates request objects for your driver, it allocates context space with the size that
your driver specified when it called WdfDeviceInitSetRequestAttributes .
If your driver creates additional request objects by calling WdfRequestCreate , you can specify a context
size by providing a WDF_OBJECT_ATTRIBUTES structure.
For more information about allocating and accessing context space for framework objects, see Framework
Object Context Space.
Request Ownership
2/5/2021 • 2 minutes to read • Edit Online

When the I/O manager sends an I/O request to a framework-based driver, the framework intercepts the request
and creates a framework request object. The framework "owns" the request object, because only the framework
can access the request and perform operations on the object.
After the framework creates a request object, it places the object in one of the driver's I/O queues. The
framework continues to own the request object until it removes the request from the queue and delivers it to
the driver.
After the driver receives the request object, it owns the request. The driver can access the request object through
a handle and perform operations on the object. While the driver owns the request object it can requeue,
complete, cancel, or forward the request, after which it no longer owns the request object and cannot access it.
As ownership of a request object passes between a driver and the framework, the object handle's value does not
change. For example, if a driver receives a request from an I/O queue, requeues it to a different queue, and then
receives the request again, the handle's value will not change. Likewise, if a driver forwards a request to an I/O
target and later receives notification that the I/O target completed the request, the driver's notification callback
function receives the same handle value that the driver supplied to the I/O target.
Processing I/O Requests
2/5/2021 • 2 minutes to read • Edit Online

When a driver receives an I/O request, it can:


Requeue the request to a different queue.
Complete the request.
Cancel the request.
Forward the request to an I/O target.
The driver cannot ignore or delete the request.
Receiving I/O Requests
2/5/2021 • 2 minutes to read • Edit Online

If a framework-based driver is using the sequential or parallel dispatching method for an I/O queue, it receives
I/O requests from the queue as input arguments to its request handlers.
If a framework-based driver is using the manual dispatching method for an I/O queue, it obtains I/O requests
from the queue by polling the queue.
After the driver receives a request, it owns the request until it requeues, completes, cancels, or forwards the
request.
Requeuing I/O Requests
2/5/2021 • 2 minutes to read • Edit Online

Drivers can requeue I/O requests that they obtain from an I/O queue. A driver can requeue a I/O request to
another I/O queue that the driver has created for the same device. In addition, a bus driver can requeue an I/O
request from a child device's I/O queue to a parent device's I/O queue.
Requeuing an I/O Request to a Different I/O Queue for a Device
After a driver's request handlers receives an I/O request from a driver's I/O queue, the driver can call
WdfRequestFor wardToIoQueue to requeue the request to another queue.
For example, if you want your driver to allocate resources to a request before processing the request, the
driver's EvtIoDefault callback function could receive all requests, store resource information in each request's
context memory, and then call WdfRequestFor wardToIoQueue to requeue each request to an additional
queue.
If your driver calls WdfRequestFor wardToIoQueue to requeue an I/O request that the driver obtained from
an I/O queue that is using the sequential dispatching method, the framework will deliver the next I/O request
from the sequential queue to the driver without waiting for the requeued request to complete.
If your driver is using the manual dispatching method, it can call the WdfRequestRequeue method to return
an I/O request to the head of the I/O queue from which the driver obtained it. After calling
WdfRequestRequeue , the driver's next call to WdfIoQueueRetrieveNextRequest retrieves the requeued
request.
Requeuing an I/O Request to a Parent Device's I/O Queue
A function driver for a parent device can act as a bus driver that enumerates the child devices of the parent
device and creates physical device objects (PDOs) for the child devices. Such drivers can sometimes receive I/O
requests for a child device that the parent device must handle.
For example, a protocol bus (such as USB) typically controls the hardware resources that are assigned to each
connected device. Therefore, the function driver for the parent bus typically handles I/O operations for each
child device. When the I/O manager sends an I/O request to the device stack of one of the child devices, the
function driver for the bus receives the I/O request in one of the child device's I/O queues, because that driver
created the child device's PDO. Before the driver can process the I/O request in the context of the parent bus
device, it must requeue the I/O request from the child device's I/O queue to an I/O queue that belongs to the
parent device.
However, drivers cannot call WdfRequestFor wardToIoQueue to move requests from a child's queue to a
parent's queue. Because the I/O manager creates separate device stacks for the parent and child devices, the
underlying WDM device object must first be changed from one that represents the child device to one that
represents the parent.
Prior to version 1.9 of KMDF, drivers could send I/O requests from a child device to its parent only by creating
remote I/O targets, increasing the size of the child device's device stack, and specifying the correct WDM device
object.
Beginning with KMDF version 1.9, a driver can call WdfPdoInitAllowFor wardingRequestToParent before it
creates a child device and then call WdfRequestFor wardToParentDeviceIoQueue to requeue a request from
the child's I/O queue to a parent queue. If a driver usesWdfPdoInitAllowFor wardingRequestToParent and
WdfRequestFor wardToParentDeviceIoQueue , the framework increases the child's device stack size and
assigns the correct WDM device object to the I/O request.
Completing I/O Requests
2/5/2021 • 4 minutes to read • Edit Online

Every framework-based driver must eventually complete every I/O request that it receives from the framework.
Drivers complete requests by calling the request object's WdfRequestComplete ,
WdfRequestCompleteWithInformation , or WdfRequestCompleteWithPriorityBoost method.
When to Complete a Request
A driver must complete a request when it determines that one of the following cases is true:
The requested I/O operation has finished successfully.
The requested I/O operation was started but failed before it finished.
The requested I/O operation is not supported, or was not valid at the time it was received, and could not
be started.
The requested I/O operation was canceled.
If the driver services the I/O request by creating I/O activity on the device, the driver typically calls
WdfRequestComplete from its EvtInterruptDpc or EvtDpcFunc callback function.
If the driver receives an unsupported or otherwise invalid request, it typically calls WdfRequestComplete from
the request handler that received the request.
If the I/O operation was canceled, the driver typically calls WdfRequestComplete from its EvtRequestCancel
callback function.
If the driver forwards the I/O request to an I/O target, the driver completes the request after the I/O target
completes the request, as follows:
If your driver forwards the I/O request synchronously to the I/O target, the driver's call to the I/O target
returns only after a lower-level driver has completed the request (unless an error occurs). After the I/O
target returns, your driver must call WdfRequestComplete .
If your driver forwards the I/O request asynchronously, you will want your driver to be notified when a
lower-level driver completes the request. If your driver registers a CompletionRoutine callback function,
the framework calls this callback function after the I/O target completes the request. The
CompletionRoutine callback function typically calls WdfRequestComplete .
To register a CompletionRoutine callback function, the driver must call WdfRequestSetCompletionRoutine
before it forwards the I/O request to an I/O target.
If your driver does not need to be notified when an I/O target completes an asynchronously forwarded I/O
request, the driver does not have to register a CompletionRoutine callback function. Instead, the driver can set
the WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET flag when calling WdfRequestSend . In this case
the driver does not call WdfRequestComplete .
A driver does not complete an I/O request that it has created by calling WdfRequestCreate or
WdfRequestCreateFromIrp . Instead, the driver must call WdfObjectDelete to delete the request object,
typically after an I/O target has completed the request.
For example, a driver might receive a read or write request for an amount of data that is larger than the driver's
I/O targets can handle at one time. The driver must divide the data into several smaller requests and send these
smaller requests to one or more I/O targets. Techniques for handling this situation include:
Calling WdfRequestCreate to create a single additional request object that represents a smaller request.
The driver can send this request synchronously to an I/O target. The smaller request's CompletionRoutine
callback function can call WdfRequestReuse so that the driver can reuse the request and send it to the
I/O target again. After the I/O target completes the last of the smaller requests, the CompletionRoutine
callback function can call WdfObjectDelete to delete the driver-created request object and the driver
can call WdfRequestComplete to complete the original request.
Calling WdfRequestCreate to create several additional request objects that represent the smaller
requests.
The driver's I/O targets can process these multiple smaller requests asynchronously. The driver can
register a CompletionRoutine callback function for each of the smaller requests. Each time that the
CompletionRoutine callback function is called, it can call WdfObjectDelete to delete a driver-created
request object. After the I/O target completes all of the smaller requests, the driver can call
WdfRequestComplete to complete the original request.
Providing Completion Information
When a driver completes a request, it can optionally provide some additional information that other drivers can
access. For example, a driver might provide the number of bytes that were transferred for a read or write
request. To provide this information, the driver can do either of the following:
Call WdfRequestSetInformation before calling WdfRequestComplete .
Call WdfRequestCompleteWithInformation .
Obtaining Completion Information
To obtain information about an I/O request that another driver has completed, a driver can:
Call WdfRequestGetStatus to obtain the completion status value that the lower-level driver specified
when it called WdfRequestComplete .
Call WdfRequestGetCompletionParams to obtain a WDF_REQUEST_COMPLETION_PARAMS
structure that contains additional information about the completed request, such as handles to memory
objects that represent the request's buffers, or bus-specific information.
A driver can call WdfRequestGetCompletionParams only after it calls WdfRequestSend to send the
I/O request synchronously or asynchronously to an I/O target. The driver must not call
WdfRequestGetCompletionParams after it calls one of the methods that send I/O requests to I/O
targets only synchronously (such as WdfIoTargetSendReadSynchronously ).
Call WdfRequestGetInformation to obtain additional I/O completion information that the lower-level
driver specified when it called WdfRequestSetInformation or
WdfRequestCompleteWithInformation , if drivers in the driver stack provide such information.
If a driver sends an I/O request synchronously, it typically calls WdfRequestGetStatus ,
WdfRequestGetCompletionParams , and WdfRequestGetInformation after the synchronous call returns. If
a driver sends an I/O request asynchronously, it typically calls these methods from within a CompletionRoutine
callback function.
For more information about completing I/O requests, see Synchronizing Cancel and Completion Code.
Canceling I/O Requests
2/5/2021 • 4 minutes to read • Edit Online

A device's in-progress I/O operation (such as a request to read several blocks from a disk) can be canceled by an
application, the system, or a driver. If a device's I/O operation is canceled, the I/O manager attempts to cancel all
unprocessed I/O requests that are associated with the I/O operation. The device's drivers can register to be
notified when the I/O manager attempts to cancel I/O requests, and the drivers can cancel the requests that they
own by completing them with a completion status of STATUS_CANCELLED.
The framework handles some of the cancellation work for framework-based drivers. If a device's I/O operation is
canceled, the framework completes the following I/O requests (with a completion status of
STATUS_CANCELLED) that are associated with the canceled operation:
Undelivered I/O requests that the framework has placed in the driver's default I/O queue.
Undelivered I/O requests that the framework has forwarded to another queue because the driver called
WdfDeviceConfigureRequestDispatching .
Because the framework cancels these requests, it does not deliver them to the driver.
After the framework has delivered an I/O request to the driver, the driver owns the request and the framework
cannot cancel it. At this point, only the driver can cancel the I/O request, but the framework must notify the
driver that a request should be canceled. Drivers receive this notification by providing an EvtRequestCancel
callback function.
Sometimes a driver receives an I/O request from an I/O queue but, instead of processing the request, the driver
requeues the request to the same or another I/O queue for later processing. Examples of this situation include
the following:
The framework delivers an I/O request to one of the driver's request handlers, and the driver
subsequently calls either WdfRequestFor wardToIoQueue (or
WdfRequestFor wardToParentDeviceIoQueue ) to place the request in a different queue or
WdfRequestRequeue to place the request back into the same queue.
The framework delivers an I/O request to the driver's EvtIoInCallerContext callback function, the driver
calls WdfDeviceEnqueueRequest to pass the request back to the framework, and the framework
subsequently places the request in one of the driver's I/O queues.
In these cases, the framework can cancel the I/O request because the request is in an I/O queue. However, if the
driver has registered an EvtIoCanceledOnQueue callback function for the I/O queue in which the request resides,
the framework calls the callback function, instead of canceling the request, when the associated I/O operation is
being canceled. If the framework calls the driver's EvtIoCanceledOnQueue callback function, the driver must
complete the request.
In summary, when an I/O operation is canceled, the framework always cancels all associated I/O requests that
were never delivered to the driver. If the driver receives a request and then requeues it, the framework will
cancel the request (if the request is in the queue) unless the driver provides an EvtIoCanceledOnQueue callback
function for the I/O queue.
Calling WdfRequestMarkCancelable or WdfRequestMarkCancelableEx
A driver can call WdfRequestMarkCancelable or WdfRequestMarkCancelableEx to register an
EvtRequestCancel callback function. If the driver has called WdfRequestMarkCancelable or
WdfRequestMarkCancelableEx , and if the I/O operation associated with the request is canceled, the
framework calls the driver's EvtRequestCancel callback function so the driver can cancel the I/O request.
A driver should call WdfRequestMarkCancelable or WdfRequestMarkCancelableEx if it will own a request
for a relatively long time. For example, a driver might have to wait for a device to respond, or it might wait for
lower drivers to complete a set of requests that the driver created when it received a single request.
If a driver does not call WdfRequestMarkCancelable or WdfRequestMarkCancelableEx , or if a driver calls
WdfRequestUnmarkCancelable after calling WdfRequestMarkCancelable or
WdfRequestMarkCancelableEx , the driver is not aware of the cancellation and therefore handles the request
as it normally would.
Calling WdfRequestIsCanceled
If a driver has not called WdfRequestMarkCancelable or WdfRequestMarkCancelableEx to register an
EvtRequestCancel callback function, it can call WdfRequestIsCanceled to determine if the I/O manager has
attempted to cancel an I/O request. If WdfRequestIsCanceled returns TRUE and the driver owns the request,
the driver should cancel the request. If the driver does not own the request, it should not call
WdfRequestIsCanceled .
A driver that has not called WdfRequestMarkCancelable or WdfRequestMarkCancelableEx might call
WdfRequestIsCanceled in the following circumstances:
A driver that waits for device interrupts might call WdfRequestIsCanceled from its EvtInterruptDpc
callback function.
A driver that polls its device might call WdfRequestIsCanceled from it polling thread.
A driver that breaks a DMA transaction into several smaller transfers might call WdfRequestIsCanceled
after each transfer is finished.
A driver that receives a large read or write request that it breaks into several smaller requests might call
WdfRequestIsCanceled after the driver's I/O target completes each of the smaller requests, if the driver
has not called WdfRequestMarkCancelable or WdfRequestMarkCancelableEx for the received
request.
Canceling the Request
Canceling an I/O request might involve any of the following:
Stopping an in-progress I/O operation.
Not forwarding the request to an I/O target.
Calling WdfRequestCancelSentRequest to attempt to cancel a request that the driver had previously
submitted to an I/O target.
If a driver is canceling an I/O request for a request object that the driver received from the framework, the driver
must always complete the request by calling WdfRequestComplete ,
WdfRequestCompleteWithInformation , or WdfRequestCompleteWithPriorityBoost , with a Status
parameter of STATUS_CANCELLED. (If the driver called WdfRequestCreate to create a request object, the driver
calls WdfObjectDelete instead of completing the request.)
Synchronizing Cancellation
For information about synchronizing code that cancels I/O requests, see:
Synchronizing Cancel and Completion Code
Synchronizing Cancellation of Sent Requests
Synchronizing Cancel and Completion Code
2/5/2021 • 2 minutes to read • Edit Online

If your driver calls WdfRequestMarkCancelable or WdfRequestMarkCancelableEx to make an I/O request


cancelable, there is potential for a synchronization problem. For example, your driver and device might perform
device I/O operations asynchronously by means of EvtInterruptIsr and EvtInterruptDpc callback functions, and
both the EvtInterruptDpc and EvtRequestCancel callback functions might contain calls to
WdfRequestComplete .
The driver must call WdfRequestComplete only once, to either complete or cancel the request. But if the
EvtInterruptDpc and EvtRequestCancel callback functions are not synchronized with each other, the framework
can call one while the other is executing.
Avoiding this problem is easy if your driver uses the framework's automatic synchronization, because automatic
synchronization ensures that the callback functions will be called one at a time.
If your driver does not use the framework's automatic synchronization, it can use framework locks to
synchronize cancel and completion code.
Whether the driver uses framework's automatic synchronization or provides its own synchronization, the
driver's EvtRequestCancel callback function must call WdfRequestComplete to cancel a request. The driver's
EvtInterruptDpc callback function should call WdfRequestUnmarkCancelable as follows:

Status = WdfRequestUnmarkCancelable(Request);
if( Status != STATUS_CANCELLED ) {
WdfRequestComplete(Request, RequestStatus);
}

This code ensures that the driver does not call WdfRequestComplete to complete the request if the driver has
already called it to cancel the request.
For more information about the rules that your driver must follow when it calls
WdfRequestUnmarkCancelable , see WdfRequestUnmarkCancelable .
Synchronizing Cancellation of Sent Requests
2/5/2021 • 2 minutes to read • Edit Online

When a driver attempts to cancel an I/O request that it has forwarded to an I/O target, the driver must ensure
that it passes a valid request handle to the WdfRequestCancelSentRequest method. The request handle
becomes invalid if the I/O target completes the request, because the driver's CompletionRoutine callback
function will call WdfRequestComplete (which attempts to delete the request object).
To avoid this problem, the driver can keep track of the requests that it has sent to the I/O target by, for example,
creating a collection of request objects. The driver can call WdfSpinLockAcquire to synchronize access to the
collection.
When the driver's CompletionRoutine callback function is called, it acquires the lock, removes the completed
request's handle from the collection, and calls WdfSpinLockRelease to release the lock.
Before attempting to cancel a request that the driver has forwarded to an I/O target, the driver can:
1. Call WdfSpinLockAcquire to acquire a spin lock.
2. Find the request object's handle in the collection, to ensure that driver's completion routine hasn't
completed the request and removed the handle from the collection.
3. Call WdfObjectReference to increment the request object's reference count so that the object cannot be
deleted.
4. Call WdfSpinLockRelease to release the spin lock.
5. Call WdfRequestCancelSentRequest .
6. Call WdfObjectDereference to decrement the object's reference count.
This sequence ensures that if the I/O target completes the request before the driver calls
WdfRequestCancelSentRequest , the request's handle is still valid (because of the incremented reference
count) even if the driver's CompletionRoutine callback function calls WdfRequestComplete .
Forwarding I/O Requests
2/5/2021 • 2 minutes to read • Edit Online

When a driver receives an I/O request that it cannot process, it typically does one of the following:
It forwards the received request to another driver.
It creates additional requests and sends them to another driver.
Framework-based drivers forward requests by using I/O targets, which represent other drivers on the system.
Drivers can use any of the following techniques to forward a request to an I/O target:
A driver can forward I/O requests to the next-lower driver by calling WdfDeviceGetIoTarget , followed
by WdfRequestFormatRequestUsingCurrentType , and finally WdfRequestSend .
This technique is useful only if the driver receives a request that it does not have to modify before
forwarding.
A driver can call WdfFdoInitSetFilter to register itself as a filter driver.
If a filter driver does not provide an I/O queue for a particular type of I/O request, the framework
automatically forwards requests of that type to the next-lower driver.
Typically, a function driver examines each I/O request's contents. If a function driver cannot process a
request, it might modify the request and forward it to an I/O target. Or, it might create one or more new
requests and send them to an I/O target.
The framework's I/O target object defines several methods for sending I/O requests to other drivers. For
example, a driver can call WdfIoTargetFormatRequestForRead , followed by WdfRequestSend , to
send a read request to an I/O target. For more information about I/O targets, see Using I/O Targets.
Rarely, a driver writer might want to specify the contents of a request's underlying WDM I/O stack
location before sending a request to an I/O target. For those cases, the driver can call
WdfRequestWdmFormatUsingStackLocation before it calls WdfRequestSend .
Sometimes, a driver must send the same request to several I/O targets, typically because the driver must send a
single command to all of its devices. Before sending a request to an I/O target, the driver can call
WdfRequestChangeTarget to verify that the I/O target is accessible.
The driver must eventually complete every request that it forwards to an I/O target, unless it sets the
WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET flag when calling WdfRequestSend .
Note that when a driver forwards a request, the framework does not literally transfer the framework request
object from the sending driver to the receiving driver. Instead, the framework creates a new request object in the
driver that receives the request. Only the request's underlying I/O request packet (IRP ) is transferred from one
driver to another.
Obtaining Information About an I/O Request
2/5/2021 • 2 minutes to read • Edit Online

Before processing an I/O request, a driver must determine the request type. When a framework-based driver
creates I/O queues for a device, it typically sets up the I/O queues and request handlers so that each queue or
request handler receives requests of a particular type (read, write, or device I/O control).
After determining the request type, the driver must obtain the request's input and output buffers, if they are
needed. For information about obtaining a request's buffers, see Accessing Data Buffers in Framework-Based
Drivers.
To provide additional information about an I/O request that a driver has received, the framework request object
defines the following methods:
WdfRequestGetIoQueue , which returns a handle to the I/O queue from which the I/O request was
delivered.
WdfRequestGetRequestorMode , which returns the processor access mode (user or kernel) of the
request's originator.
WdfRequestGetFileObject , which returns a handle to the framework file object that is associated with
the request.
WdfRequestWdmGetIrp , which returns the WDM IRP structure that is associated with the request.
WdfRequestGetParameters , which retrieves non-IRP request parameters in WDM format.
After a driver completes an I/O request, other drivers in the driver stack can call additional request object
methods to obtain request completion information. For more information about these additional methods, see
Completing I/O Requests.
Accessing Data Buffers in WDF Drivers (KMDF or
UMDF)
2/5/2021 • 9 minutes to read • Edit Online

When a Windows Driver Frameworks (WDF) driver receives a read, write, or device I/O control request, the
request object contains either an input buffer, an output buffer, or both.
Input buffers contain information that the driver needs. For write requests, this information is typically data that
a function driver must send to a device. For device I/O control requests, an input buffer might contain
information that indicates the type of operation that the driver must perform.
Output buffers receive information from the driver. For read requests, this information is typically data that a
function driver receives from a device. For device I/O control requests, an output buffer might receive status or
other information that was specified by the request's I/O control code.
The technique that your driver uses to access a request's data buffers depends on the driver's method for
accessing data buffers for a device. There are three access methods:
Buffered I/O. The I/O manager creates intermediate buffers that it shares with the driver.
Direct I/O. The I/O manager locks the buffer space into physical memory, and then provides the driver with
direct access to the buffer space.
Neither buffered nor direct I/O. The I/O manager provides the driver with the virtual addresses of the
request's buffer space. The I/O manager does not validate the request's buffer space, so the driver must
verify that the buffer space is accessible and lock the buffer space into physical memory.
A Kernel-Mode Driver Framework (KMDF) driver can use any of the three access methods. A User-Mode Driver
Framework (UMDF) driver can use buffered or direct I/O for read, write, and IOCTL requests, and can convert
requests that specify the METHOD_NEITHER method.

Specifying Buffer Access Method


KMDF Drivers
For read and write requests, all drivers in a driver stack must use the same method for accessing a device's
buffers, except for the highest-level driver, which can use the "neither" method, regardless of which method is
used by lower drivers.
Starting in version 1.13, a KMDF driver specifies the access method for all of a device's read and write requests
by calling WdfDeviceInitSetIoTypeEx for each device. For example, if a driver specifies the buffered I/O
method for one of its devices, the I/O manager uses the buffered I/O method when delivering read and write
requests to the driver for that device.
For device I/O control requests, the I/O control code (IOCTL) contains bits that specify the buffer access method.
As a result, a KMDF driver does not need to take any action to select a buffering method for IOCTLs. For more
information about IOCTLs, see Defining I/O Control Codes. Unlike read and write requests, all of a device's
IOCTLs do not have to specify the same access method.
UMDF Drivers
A UMDF driver specifies preferences for the access method that the framework uses for read and write requests,
as well as device I/O control requests. The values that a UMDF driver provides are only preferences, and are not
guaranteed to be used by the framework. For more information, see Managing Buffer Access Methods in UMDF
Drivers.
A UMDF driver specifies the access method for all of a device's read, write and IOCTL requests by calling
WdfDeviceInitSetIoTypeEx for each device. For example, if a driver specifies the buffered I/O method for one
of its devices, the framework uses the buffered I/O method when delivering read, write and IOCTL requests to
the driver for that device.
Note the difference in buffer access technique for IOCTLs between KMDF and UMDF. KMDF drivers do not
specify buffer access method for IOCTLs, whereas UMDF drivers do specify the buffer access method for IOCTLs.
If a WDF driver describes an I/O request's buffer by using a technique that is incorrect for the I/O method that
an I/O target uses, the framework corrects the buffer description. For example, if a driver uses an MDL to
describe a buffer that it passes to WdfIoTargetSendReadSynchronously , and if the I/O target uses buffered
I/O (which requires that buffers be specified using virtual addresses instead of MDLs), the framework converts
the buffer description from an MDL to a virtual address and length. However, it is more efficient if your driver
specifies buffers in the correct format.
For information about framework memory objects, lookaside lists, MDLs, and local buffers, see Using Memory
Buffers.
For information about when memory buffers are deleted, see Memory Buffer Life Cycle.

Accessing Data Buffers for Buffered I/O


If your driver is using buffered I/O, its behavior changes depending on the type of data request and whether it's
using KMDF or UMDF.
KMDF Drivers
When a KMDF driver uses buffered I/O, the I/O manager creates one intermediate buffer that the driver can
access for every type of request. Here's what happens:
Write requests. The I/O manager transfers input info from the calling app's input buffer before it calls the
driver stack. Then, the KMDF driver reads input info from the intermediate buffer and writes it to the device.
Read requests. The KMDF driver reads info from the device and stores it in the intermediate buffer. Then, the
I/O manager copies the output data from the intermediate buffer to the app's output buffer.
Device I/O control requests. The KMDF driver reads or writes data for that request to or from the
intermediate buffer.
UMDF Drivers
When a UMDF driver uses buffered I/O, the driver host process creates one or two intermediate buffers,
depending on the type of request. Here's what happens:
Write requests. The framework creates one buffer, transfers input info from the calling app's input buffer, and
then calls the driver stack. The UMDF driver reads input info from the intermediate buffer and writes it to the
device.
Read requests. A UMDF driver reads info from a device and stores it in a buffer that the framework created.
The driver host process copies the output data from the intermediate buffer to the app's output buffer.
Device I/O control requests. The framework creates two buffers corresponding to input and output buffers of
the IOCTL that the driver can access. The framework copies the input info from the IOCTL into the new
intermediate buffer and makes it available to the driver. The framework does not copy the contents of the
output buffer, so the driver shouldn't attempt to read from it (otherwise it will end up reading garbage data).
Any data that the driver writes to the output buffer is copied back into the original IOCTL buffer and is
returned to the app upon successful completion of the I/O request. Note that any data that the driver writes
to the input buffer is discarded and not returned to the calling app.
To retrieve a handle to a framework memory object that represents the buffer, both KMDF and UMDF drivers call
WdfRequestRetrieveInputMemor y or WdfRequestRetrieveOutputMemor y , depending on whether this is
a read or write request. The driver can then retrieve a pointer to the buffer by calling WdfMemor yGetBuffer .
To read and write the buffer, the driver calls WdfMemor yCopyFromBuffer or WdfMemor yCopyToBuffer .
To retrieve the virtual address and length of the buffer, the driver calls WdfRequestRetrieveInputBuffer or
WdfRequestRetrieveOutputBuffer .
To allocate and build a memory descriptor list (MDL) for the buffer, a KMDF driver calls
WdfRequestRetrieveInputWdmMdl or WdfRequestRetrieveOutputWdmMdl .

Accessing Data Buffers for Direct I/O


KMDF Drivers
If your driver is using direct I/O, the I/O manager verifies the accessibility of the buffer space that the originator
of the I/O request (typically a user-mode application) specified, locks the buffer space into physical memory, and
then provides the driver with direct access to the buffer space.
UMDF Drivers
If your driver has specified a preference for direct I/O, and all the UMDF requirements for direct I/O have been
met (see Managing Buffer Access Methods in UMDF Drivers), the framework maps the memory buffer it
receives from the I/O manager directly into the driver's host process address space, and thus provides the driver
with direct access to the buffer space.
To retrieve a handle to a framework memory object that represents the buffer space, the driver calls
WdfRequestRetrieveInputMemor y or WdfRequestRetrieveOutputMemor y . The driver can then retrieve
a pointer to the buffer by calling WdfMemor yGetBuffer . To read and write the buffer, the driver calls
WdfMemor yCopyFromBuffer or WdfMemor yCopyToBuffer .
To retrieve the virtual address and length of the buffer space, the driver calls WdfRequestRetrieveInputBuffer
or WdfRequestRetrieveOutputBuffer .
If a device's drivers are using direct I/O, the I/O manager describes buffers by using MDLs. To retrieve a pointer
to a buffer's MDL, a KMDF driver calls WdfRequestRetrieveInputWdmMdl or
WdfRequestRetrieveOutputWdmMdl . A UMDF driver cannot access MDLs.

Accessing Data Buffers for Neither Buffered Nor Direct I/O


KMDF Drivers
If your driver is using the buffer access method known as the neither buffered I/O nor direct I/O method (or, the
"neither" method, for short), the I/O manager simply provides the driver with the virtual addresses that the
originator of the I/O request specified for the request's buffer space. The I/O manager does not validate the I/O
request's buffer space, so the driver must verify that the buffer space is accessible and lock the buffer space into
physical memory.
The virtual addresses that the I/O manager provides can be accessed only in the process context of the
originator of the I/O request. Only the highest-level driver in the driver stack is guaranteed to execute in the
originator's process context.
To obtain access to an I/O request's buffer space, the highest-level driver must provide an EvtIoInCallerContext
callback function. The framework calls this callback function each time it receives an I/O request for the driver.
If a request's buffer access method is "neither," a KMDF driver must do the following for each buffer:
1. Call WdfRequestRetrieveUnsafeUserInputBuffer or
WdfRequestRetrieveUnsafeUserOutputBuffer to obtain the buffer's virtual address.
2. Call WdfRequestProbeAndLockUserBufferForRead or
WdfRequestProbeAndLockUserBufferForWrite to probe and lock the buffer and to obtain a handle
to a framework memory object for the buffer.
3. Save the memory object handles in the request's context space.
4. Call WdfDeviceEnqueueRequest , which returns the request to the framework.
The framework subsequently adds the request to one of the driver's I/O queues. If the driver has provided
request handlers, the framework will eventually call the appropriate request handler.
The request handler can retrieve the request's memory object handles from the request's context space. The
driver can pass the handles to WdfMemor yGetBuffer to obtain the buffer's address.
Occasionally, a highest-level driver must use the preceding steps to access a user-mode buffer, even if the driver
is not using the "neither" access method. For example, suppose the driver is using buffered I/O. An I/O control
code that uses the buffered access method might pass a structure that contains an embedded pointer to a user-
mode buffer. In such a case, the driver must provide an EvtIoInCallerContext callback function that extracts the
pointers from the structure and then uses the preceding steps 2 through 4.
UMDF Drivers
UMDF doesn't support neither buffered nor direct I/O type buffers, so a UMDF driver never needs to handle this
type of buffer directly.
However, if the framework receives such buffers for read or write from the I/O manager, it makes them available
to a UMDF driver as buffered I/O or direct I/O, depending on the access method selected by the driver. If the
framework receives an IOCTL specifying the "neither" buffer method, it can optionally convert the buffer access
method of the IOCTL request to buffered I/O or direct I/O based on the presence of an INF directive. See
Managing Buffer Access Methods in UMDF Drivers for more info.
Managing Buffer Access Methods in UMDF Drivers
2/5/2021 • 4 minutes to read • Edit Online

If you are writing a UMDF driver, you can specify preferences for the buffer access method that the framework
uses for read and write requests, as well as device I/O control requests. The values that a UMDF driver provides
are only preferences, and are not guaranteed to be used by the framework.
Specifying a Preferred Buffer Access Method
Retrieving the Access Method for an I/O Request
Converting from Neither Buffered I/O nor Direct I/O

Specifying a Preferred Buffer Access Method


Starting in UMDF version 2.0, a UMDF driver calls WdfDeviceInitSetIoTypeEx to register preferred access
methods for read/write requests and for device I/O control requests.
If the driver does not call WdfDeviceInitSetIoTypeEx , UMDF uses the buffered method for I/O requests to this
device.
The framework uses the following rules to determine which access method to use:
All UMDF drivers in a driver stack must use the same method for accessing a device's buffers, and the
framework gives preference to buffered I/O.
If UMDF determines that some drivers prefer either buffered I/O or direct I/O for a device while other
drivers prefer only buffered I/O for the device, UMDF uses buffered I/O for all drivers. If one or more of a
stack's drivers prefer only buffered I/O while others prefer only direct I/O, UMDF logs an event to the
system event log and does not start the driver stack.
Your driver can call WdfDeviceGetDeviceStackIoType to determine the buffer access methods that
UMDF has assigned to a device's read/write requests and I/O control requests.
In some cases, UMDF assigns direct I/O to a device, but for best performance, uses buffered I/O for one
or more of the device's requests. For example, UMDF uses buffered I/O for small buffers if it can copy the
data to the driver's buffer faster than it can map the buffers for direct access.
Optionally, your driver can provide a DirectTransferThreshold value when it calls
WdfDeviceInitSetIoTypeEx . The framework uses this value to determine the smallest buffer size for
which the framework will use direct I/O. Typically, you do not need to provide this value because the
framework uses settings that provide the best performance.
UMDF uses direct I/O only for buffer space that begins and ends on a memory page boundary. If either
the beginning or the end of a buffer does not lie on a page boundary, UMDF uses buffered I/O for that
part of the buffer. In other words, UMDF might use both buffered I/O and direct I/O for a large data
transfer that consists of several I/O requests.
For device I/O control requests, UMDF uses direct I/O only if the I/O control code (IOCTL) specifies direct
I/O and only if all of the UMDF drivers for that device have called WdfDeviceInitSetIoTypeEx to specify
the direct access method.

Retrieving the Access Method for an I/O Request


Drivers use the same set of request object methods to access data buffers, regardless of the buffer access
method. Therefore, most drivers typically do not need to know whether UMDF is using buffered I/O or direct I/O
for an I/O request.
In some cases, you can improve a driver's performance if you know the access method for an I/O request. For
example, consider a high-throughput device that typically uses direct I/O. When the driver receives an I/O
request, it copies data from the shared buffer space into local driver memory for validation.
However, the driver might occasionally receive a buffer that uses buffered I/O. Because the I/O manager has
already copied this data into an intermediate buffer, the driver does not need to copy the parameters locally. By
avoiding the copy operation, the driver improves performance.
A UMDF driver calls WdfRequestGetEffectiveIoType to obtain an I/O request's buffer access method. As
described above, the I/O type for a specific request may differ from the framework-assigned I/O type settings
for a device.

Converting from Neither Buffered I/O nor Direct I/O


A UMDF driver cannot use the "neither" method.
However, the definitions of some device I/O control codes (IOCTLs) specify that the requests use the "neither"
method. Optionally, a UMDF driver can convert the buffer access method of such device I/O control requests to
buffered I/O or direct I/O. Use the following steps:
1. Include the UmdfMethodNeitherAction directive in an INF DDInstall section of your driver's INF file.
You can set the directive's value to indicate that UMDF should pass device I/O control requests that use
the "neither" access method to the driver. (Otherwise, UMDF completes these I/O requests with an error
status value.)
2. Access the I/O request's buffers by using the object methods that UMDF provides for buffered I/O or
direct I/O.
You should enable support of IOCTL requests that use the "neither" method only if you are sure that UMDF can
convert the access method to buffered I/O or direct I/O. For example, if the IOCTL specifies a customized request
that does not follow the buffer specification rules that are described at Buffer Descriptions for I/O Control Codes,
UMDF cannot convert the buffers.
Reusing Framework Request Objects
2/5/2021 • 2 minutes to read • Edit Online

To improve performance, framework-based drivers that create and send lots of nearly identical asynchronous
requests to an I/O target can reuse request objects instead of creating a new request object for each request. A
driver can reuse a request object after the request has been completed.
If a driver has created a request object by calling WdfRequestCreate or WdfRequestCreateFromIrp , it can
reuse the request by calling WdfRequestReuse . A driver can also reuse request objects that it has received
from the framework in its I/O queues, but it cannot change the IRP that the received request object contains.
If you are careful to avoid situations that cause the unsuccessful return values described in WdfRequestReuse ,
your driver can call WdfRequestReuse from within a CompletionRoutine callback function. (The
CompletionRoutine callback function has a VOID return value and therefore cannot report errors.)
If your driver provides a CompletionRoutine callback function for a request object that it reuses, the driver must
call WdfRequestSetCompletionRoutine after calling WdfRequestReuse .
Using Automatic Synchronization
2/5/2021 • 10 minutes to read • Edit Online

Almost all of the code in a framework-based driver resides in event callback functions. The framework
automatically synchronizes most of a driver's callback functions, as follows:
The framework always synchronizes general device object, functional device object (FDO), and physical
device object (PDO) event callback functions with each other so that only one of the callback functions
(except EvtDeviceSurpriseRemoval, EvtDeviceQueryRemove, and EvtDeviceQueryStop) can be called at a
time for each device. These callback functions support Plug and Play (PnP) and power management
events and are called at IRQL = PASSIVE_LEVEL.
Optionally, the framework can synchronize the execution of the callback functions that handle a driver's
I/O requests, so that these callback functions run one at a time. Specifically, the framework can
synchronize the callback functions for queue, interrupt, deferred procedure call (DPC), timer, work-item,
and file objects, along with the request object's EvtRequestCancel callback function. The framework calls
most of these callback functions at IRQL = DISPATCH_LEVEL, but you can force the queue and file object
callback functions to run at IRQL = PASSIVE_LEVEL. (Work-item callback functions always run at
PASSIVE_LEVEL.)
The framework implements this automatic synchronization by using a set of internal synchronization locks. The
framework ensures that two or more threads cannot call the same callback function at the same time, because
each thread must wait until it can acquire a synchronization lock before calling a callback function. (Optionally,
drivers can also acquire these synchronization locks when necessary. For more information, see Using
Framework Locks.)
Your driver should store object-specific data in object context space. If your driver uses only framework-defined
interfaces, only callback functions that receive a handle to the object can access this data. If the framework is
synchronizing calls to the driver's callback functions, only one callback function will be called at a time and the
object's context space will be accessible to only one callback function at a time.
Unless your driver implements passive-level interrupt handling, code that services interrupts and accesses
interrupt data must run at the device's IRQL (DIRQL) and requires additional synchronization. For more
information, see Synchronizing Interrupt Code.
If your driver enables automatic synchronization of the callback functions that handle I/O requests, the
framework synchronizes these callback functions so that they run one at a time. The following table lists the
callback functions that the framework synchronizes.

O B JEC T T Y P E SY N C H RO N IZ ED C A L L B A C K F UN C T IO N S

Queue object Request handlers, EvtIoQueueState, EvtIoResume,


EvtIoStop

File object All callback functions

Request object EvtRequestCancel

Optionally, the framework can also synchronize these callback functions with any interrupt, DPC, work-item, and
timer object callback functions that your driver provides for the device (excluding the interrupt object's
EvtInterruptIsr callback function). To enable this additional synchronization, the driver must set the
AutomaticSerialization member of these objects' configuration structures to TRUE .
In summary, the framework's automatic synchronization capability provides the following features:
The framework always synchronizes each device's PnP and power management callback functions.
Optionally, the framework can synchronize an I/O queue's request handlers, and a few additional callback
functions (see the previous table).
A driver can ask the framework to synchronize callback functions for interrupt, DPC, work-item, and timer
objects.
Drivers must synchronize code that services interrupts and accesses interrupt data by using the
techniques that are described in Synchronizing Interrupt Code.
The framework does not synchronize a driver's other callback functions, such as the driver's
CompletionRoutine callback function, or the callback functions that the I/O target object defines. Instead,
the framework provides additional locks that drivers can use to synchronize these callback functions.
Choosing a Synchronization Scope
You can choose to have the framework synchronize all of the callback functions that are associated with all of a
device's I/O queues. Alternatively, you can choose to have the framework separately synchronize the callback
functions for each of a device's I/O queues. The synchronization options that are available to your driver are as
follows:
Device-level synchronization
The framework synchronizes the callback functions that the previous table contains, for all of the device's
I/O queues, so that they run one at a time. The framework achieves this synchronization by acquiring the
device's synchronization lock before calling a callback function.
Queue-level synchronization
The framework synchronizes the callback functions that the previous table contains, for each individual
I/O queue, so that they run one at a time. The framework achieves this synchronization by acquiring the
queue's synchronization lock before calling a callback function.
No synchronization
The framework does not synchronize the execution of the callback functions that the previous table
contains and does not acquire a synchronization lock before calling the callback functions. If
synchronization is required, the driver must provide it.
To specify whether you want the framework to provide device-level synchronization, queue-level
synchronization, or no synchronization for your driver, you can specify a synchronization scope for your driver
object, device objects, or queue objects. The SynchronizationScope member of an object's
WDF_OBJECT_ATTRIBUTES structure identifies the object's synchronization scope. The synchronization scope
values that your driver can specify are:
WdfSynchronizationScopeDevice
The framework synchronizes by obtaining a device object's synchronization lock.
WdfSynchronizationScopeQueue
The framework synchronizes by obtaining a queue object's synchronization lock.
WdfSynchronizationScopeNone
The framework does not synchronize and does not obtain a synchronization lock.
WdfSynchronizationScopeInheritFromParent
The framework obtains the object's SynchronizationScope value from the object's parent object.
In general, we do not recommend using device-level synchronization.
For more information about the synchronization scope values, see WDF_SYNCHRONIZATION_SCOPE .
The default synchronization scope for driver objects is WdfSynchronizationScopeNone . The default
synchronization scope for device and queue objects is WdfSynchronizationScopeInheritFromParent .
If you want the framework to provide device-level synchronization for all devices, you can use the following
steps:
1. Set SynchronizationScope to WdfSynchronizationScopeDevice in the
WDF_OBJECT_ATTRIBUTES structure of the driver's driver object.
2. Use the default WdfSynchronizationScopeInheritFromParent value for each device object.
Alternatively, to provide device-level synchronization for individual devices, you can use the following steps:
1. Use the default WdfSynchronizationScopeNone value for the driver object.
2. Set SynchronizationScope to WdfSynchronizationScopeDevice in the
WDF_OBJECT_ATTRIBUTES structure of individual device objects.
If you want the framework to provide queue-level synchronization for a device, the following techniques are
available:
For framework versions 1.9 and later, you should enable queue-level synchronization for individual
queues by setting WdfSynchronizationScopeQueue in the WDF_OBJECT_ATTRIBUTES structure of
the queue object. This is the preferred technique.
Alternatively, you can use the following steps in all framework versions:
1. Set SynchronizationScope to WdfSynchronizationScopeQueue in the
WDF_OBJECT_ATTRIBUTES structure of the device object.
2. Use the default WdfSynchronizationScopeInheritFromParent value for each device's queue
objects.
If you do not want the framework to synchronize the callback functions that handle your driver's I/O requests,
use the default SynchronizationScope value for your driver's driver, device, and queue objects. In this case, the
framework does not automatically synchronize the driver's I/O request-related callback functions, and the
callback functions can be called at IRQL <= DISPATCH_LEVEL.
Note that setting a SynchronizationScope value synchronizes only the callback functions that the previous
table contains. If you want the framework to also synchronize the driver's interrupt, DPC, work-item, and timer
object callback functions, the driver must set the AutomaticSerialization member of these objects'
configuration structures to TRUE .
However, you can set AutomaticSerialization to TRUE only if all of the callback functions that you want to
synchronize run at the same IRQL. Choosing an execution level, which is described next, might result in
incompatible IRQL levels. In such a situation, the driver must use framework locks instead of setting
AutomaticSerialization . For more information about the configuration structures for interrupt, DPC, work-
item, and timer objects, and for more information about restrictions that apply to setting
AutomaticSerialization in these structures, see WDF_INTERRUPT_CONFIG , WDF_DPC_CONFIG ,
WDF_WORKITEM_CONFIG , and WDF_TIMER_CONFIG .
If you set AutomaticSerialization to TRUE , you should select queue-level synchronization.
Choosing an Execution Level
When a driver creates some types of framework objects, it can specify an execution level for the object. The
execution level specifies the IRQL at which the framework will call the object's event callback functions that
handle a driver's I/O requests.
If a driver supplies an execution level, the supplied level affects the callback functions for queue and file objects.
Ordinarily, if the driver is using automatic synchronization, the framework calls these callback functions at IRQL
= DISPATCH_LEVEL. By specifying an execution level, the driver can force the framework to call these callback
functions at IRQL = PASSIVE_LEVEL. The framework uses the following rules when setting the IRQL at which
queue and file object callback functions are called:
If a driver uses automatic synchronization, its queue and file object callback functions are called at IRQL =
DISPATCH_LEVEL unless the driver asks the framework to call its callback functions at IRQL =
PASSIVE_LEVEL.
If a driver is not using automatic synchronization and does not specify an execution level, the driver's
queue and file object callback functions can be called at IRQL <= DISPATCH_LEVEL.
Note that if your driver provides file object callback functions, you will most likely want the framework to call
these callback functions at IRQL = PASSIVE_LEVEL because some file data, such as the file name, is pageable.
To supply an execution level, your driver must specify a value for the ExecutionLevel member of an object's
WDF_OBJECT_ATTRIBUTES structure. The execution level values that your driver can specify are:
WdfExecutionLevelPassive
The framework calls the object's callback functions at IRQL = PASSIVE_LEVEL.
WdfExecutionLevelDispatch
The framework can call the object's callback functions at IRQL <= DISPATCH_LEVEL. (If the driver is using
automatic synchronization, the framework always calls the callback functions at IRQL = DISPATCH_LEVEL.)
WdfExecutionLevelInheritFromParent
The framework obtains the object's ExecutionLevel value from the object's parent.
The default execution level for driver objects is WdfExecutionLevelDispatch . The default execution level for all
other objects is WdfExecutionLevelInheritFromParent .
For more information about the execution level values, see WDF_EXECUTION_LEVEL .
The following table shows the IRQL level at which the framework can call a driver's callback functions for queue
objects and file objects.

IRQ L O F Q UEUE A N D F IL E C A L L B A C K
SY N C H RO N IZ AT IO N SC O P E EXEC UT IO N L EVEL F UN C T IO N S

WdfSynchronizationScopeDevi WdfExecutionLevelPassive PASSIVE_LEVEL


ce

WdfSynchronizationScopeDevi WdfExecutionLevelDispatch DISPATCH_LEVEL


ce

WdfSynchronizationScopeQue WdfExecutionLevelPassive PASSIVE_LEVEL


ue

WdfSynchronizationScopeQue WdfExecutionLevelDispatch DISPATCH_LEVEL


ue
IRQ L O F Q UEUE A N D F IL E C A L L B A C K
SY N C H RO N IZ AT IO N SC O P E EXEC UT IO N L EVEL F UN C T IO N S

WdfSynchronizationScopeNon WdfExecutionLevelPassive PASSIVE_LEVEL


e

WdfSynchronizationScopeNon WdfExecutionLevelDispatch <= DISPATCH_LEVEL


e

You can set the execution level to WdfExecutionLevelPassive or WdfExecutionLevelDispatch for driver,
device, file, queue, timer, and general objects. For other objects, only WdfExecutionLevelInheritFromParent
is allowed.
You should specify WdfExecutionLevelPassive if:
Your driver's callback functions must call framework methods or Windows Driver Model (WDM) routines
that can be called only at IRQL = PASSIVE_LEVEL.
Your driver's callback functions must access pageable code or data. (For example, file object callback
functions typically access pageable data.)
Instead of setting WdfExecutionLevelPassive , your driver can set WdfExecutionLevelDispatch and provide
a callback function that creates work items if it must handle some operations at IRQL = PASSIVE_LEVEL.
Before you decide whether your driver should set an object's execution level to WdfExecutionLevelPassive ,
you should determine the IRQL at which your driver and other drivers in the driver stack are called. Consider the
following situations:
If your driver is at the top of the kernel-mode driver stack, the system typically calls the driver at IRQL =
PASSIVE_LEVEL. The client of such a driver might be a UMDF-based driver or a user-mode application.
Specifying WdfExecutionLevelPassive does not adversely affect the driver's performance, because the
framework does not have to queue your driver's calls to work items that are called at IRQL =
PASSIVE_LEVEL.
If your driver is not at the top of the stack, the system will likely not call your driver at IRQL =
PASSIVE_LEVEL. Therefore, the framework must queue your driver's calls to work items, which are later
called at IRQL = PASSIVE_LEVEL. This process can cause poor driver performance, compared to allowing
your driver's callback functions to be called at IRQL <= DISPATCH_LEVEL.
For DPC objects, and for timer objects that do not represent passive-level timers, note that you cannot set the
AutomaticSerialization member of the configuration structure to TRUE if you have set the parent device's
execution level to WdfExecutionLevelPassive . This is because the framework will acquire the device object's
callback synchronization locks at IRQL = PASSIVE_LEVEL and therefore the locks cannot be used to synchronize
the DPC or timer object callback functions, which must execute at IRQL = DISPATCH_LEVEL. In such a case, your
driver should use framework spin locks in any device, DPC, or timer object callback functions that must be
synchronized with each other.
Also note that for timer objects that do represent passive-level timers, you can set the AutomaticSerialization
member of the configuration structure to TRUE only if the parent device's execution level is set to
WdfExecutionLevelPassive .
Using Framework Locks
2/5/2021 • 2 minutes to read • Edit Online

Sometimes drivers must provide driver-specific synchronization of I/O request-related callback functions, either
in addition to or as a replacement for framework-supplied synchronization. Drivers can use callback
synchronization locks, spin locks, wait locks, and interrupt locks to synchronize driver code.
Callback Synchronization Locks
If you have set up your driver to use the framework's automatic synchronization capability, the framework
acquires a synchronization lock before calling the driver's I/O request-related event callback functions.
These callback synchronization locks, which are associated with framework device objects and queue objects,
can also be acquired by drivers. To acquire a synchronization lock, a driver calls WdfObjectAcquireLock . To
release the lock, the driver calls WdfObjectReleaseLock .
You might want your driver to use the callback synchronization locks if the driver uses the framework's device-
level or queue-level synchronization of I/O request-related callback functions but must synchronize some code
that runs at IRQL = PASSIVE_LEVEL with callback functions that run at IRQL = DISPATCH_LEVEL. This is because
drivers can use automatic synchronization only for callback functions that execute at the same IRQL.
For example, a driver can use automatic synchronization for a work-item object only if the execution level of the
work-item object's parent is WdfExecutionLevelPassive (because a work item's callback function always
executes at IRQL= PASSIVE_LEVEL). Therefore, if a driver specifies WdfExecutionLevelDispatch in the
ExecutionLevel member of a device object's WDF_OBJECT_ATTRIBUTES structure, the driver cannot set the
AutomaticSerialization member of a child work-item object's configuration structure. Instead, the driver must
acquire a callback synchronization lock to synchronize the EvtWorkItem callback functions with the parent
device object's callback functions.
Framework Wait Locks
Use framework wait locks to synchronize access to driver data from code that runs at IRQL = PASSIVE_LEVEL.
Before a driver can use a framework wait lock, it must call WdfWaitLockCreate to create a wait-lock object.
The driver can then call WdfWaitLockAcquire to acquire the lock and WdfWaitLockRelease to release it.
Framework Spin Locks
Use framework spin locks to synchronize access to driver data from code that runs at IRQL <= DISPATCH_LEVEL.
When a driver thread acquires a spin lock, the system sets the thread's IRQL to DISPATCH_LEVEL. When the
thread releases the lock, the system restores the thread's IRQL to its previous level.
A driver that is not using automatic framework synchronization might use a spin lock to synchronize access to a
device object's context space, if the context space is writable and if more than one of the driver's event callback
functions access the space.
Before a driver can use a framework spin lock it must call WdfSpinLockCreate to create a spin-lock object. The
driver can then call WdfSpinLockAcquire to acquire the lock and WdfSpinLockRelease to release it.
For an example use of spin locks, see Synchronizing Cancellation of Sent Requests.
Framework Interrupt Locks
For interrupt objects that support DIRQL interrupt handling, framework interrupt locks are spin locks. After your
driver acquires an interrupt spin lock, the driver executes at the device's DIRQL until it releases the lock. For
more information about using interrupt locks, see Synchronizing Interrupt Code.
For interrupt objects that support passive-level handling, framework interrupt locks are wait locks. After your
driver acquires an interrupt wait lock, the driver executes at IRQL = PASSIVE_LEVEL until it releases the lock. For
more information about passive-level handling, see Supporting Passive Level Interrupts.
Using Kernel-Mode Driver Framework with Non-
PnP Drivers
2/5/2021 • 2 minutes to read • Edit Online

If you are writing a driver for a device that does not support Plug and Play (PnP), the driver must:
Set the WdfDriverInitNonPnpDriver flag in the WDF_DRIVER_CONFIG structure's DriverInitFlags
member.
Provide an EvtDriverUnload event callback function.
Create framework device objects that only represent control device objects.
If your device does not support PnP, your driver does not provide an EvtDriverDeviceAdd callback function.
Instead, the driver must determine if its device is present.
Installing a Non-PnP Driver
2/5/2021 • 2 minutes to read • Edit Online

If your KMDF driver supports a non-Plug and Play (PnP) device on Windows 10, use the same approach as that
shown in the Non-PnP Driver Sample, but remove references to INF files and co-installers. For example, you do
not need the following:

#define NONPNP_INF_FILENAME L"\\nonpnp.inf"


#define WDF_SECTION_NAME L"nonpnp.NT.Wdf"

LoadWdfCoInstaller
UnloadWdfCoInstaller

PFN_WDFPREDEVICEINSTALLEX pfnWdfPreDeviceInstallEx;
PFN_WDFPOSTDEVICEINSTALL pfnWdfPostDeviceInstall;
PFN_WDFPREDEVICEREMOVE pfnWdfPreDeviceRemove;
PFN_WDFPOSTDEVICEREMOVE pfnWdfPostDeviceRemove;

For a non-PnP KMDF driver, simply call the SCM API to create the service. For more info, see Installing a Service.
Guaranteeing Forward Progress of I/O Operations
2/5/2021 • 9 minutes to read • Edit Online

Some drivers, such as storage drivers for the system's paging device, must perform at least some of their
supported I/O operations without failure, to avoid losing critical system data. One potential cause of a driver
failure is a low-memory situation. If the framework or the driver cannot allocate enough memory to handle an
I/O request, one or the other might have to fail the I/O request by completing it with an error status value.
In versions of KMDF prior to version 1.9, the framework always fails an I/O request if it cannot allocate a
framework request object for an I/O request packet (IRP) that the I/O manager has sent to the driver. To provide
drivers the ability to process I/O requests during low-memory situations, versions 1.9 and later of the
framework provide a guaranteed forward progress capability for I/O queues.
This capability enables the framework and the driver to pre-allocate memory for sets of request objects and
request-related driver context buffers, respectively. The framework and driver use this pre-allocated memory
only when the amount of system memory is low.
Features of Guaranteed Forward Progress
By using the framework's guaranteed forward progress for I/O queues, a driver can:
Ask the framework to pre-allocate a set of request objects to use with a specific I/O queue during low-
memory situations.
Provide a callback function that pre-allocates request-specific resources that the driver can use when it
receives pre-allocated request objects from the framework during low-memory situations.
Provide another callback function that allocates driver-specific resources for an I/O request when a low-
memory situation has not been detected. If this callback function's allocation fails because of a low-
memory situation, it can indicate whether the framework should use one of its pre-allocated request
objects.
Specify which I/O requests require the use of pre-allocated request objects. Options include using pre-
allocated objects for all IRPs, using them only if a paging I/O operation is in progress, or having an
additional driver callback function examine each IRP to determine whether to use a pre-allocated object.
If your driver implements guaranteed forward progress for one or more of its I/O queues, the driver will be
better able to successfully process I/O requests during low-memory situations. You can implement guaranteed
forward progress for a device's default I/O queue, and for any I/O queue that your driver configures by calling
WdfDeviceConfigureRequestDispatching .
The framework's guaranteed forward progress capability works for your driver only if both your driver and the
driver's I/O targets implement guaranteed forward progress. In other words, if a driver implements guaranteed
forward progress for a device, all lower-level drivers in the device's driver stack must also implement
guaranteed forward progress.
Enabling Guaranteed Forward Progress for an I/O Queue
To enable guaranteed forward progress for an I/O queue, your driver initializes a
WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY structure and then calls the
WdfIoQueueAssignFor wardProgressPolicy method. If the driver calls
WdfDeviceConfigureRequestDispatching to configure an I/O queue, it must do so before it calls
WdfIoQueueAssignFor wardProgressPolicy .
When the driver calls WdfIoQueueAssignFor wardProgressPolicy , it can specify the following three event
callback functions, all of which are optional:
EvtIoAllocateResourcesForReservedRequest
A driver's EvtIoAllocateResourcesForReservedRequest callback function allocates and stores request-specific
resources for request objects that the framework is reserving for low-memory situations.
The framework calls this callback function each time that it creates a reserved request object. The driver should
allocate request-specific resources for one I/O request, typically by using the reserved request object's context
space.
EvtIoAllocateRequestResources
A driver's EvtIoAllocateRequestResources callback function allocates request-specific resources for immediate
use. It is called immediately after the framework has received an IRP and created a request object for the IRP.
If the callback function's attempt to allocate resources fails, the callback function returns an error status value.
The framework then deletes the newly created request object and uses one of its reserved request objects. In
turn, the driver's request handler uses request-specific resources that its EvtIoAllocateRequestResources callback
function previously allocated.
EvtIoWdmIrpForForwardProgress
A driver's EvtIoWdmIrpForForwardProgress callback function examines an IRP and tells framework whether to
use a reserved request object for the IRP or to fail the I/O request by completing it with an error status value.
The framework calls this callback function only if the framework is unable to create a new request object and
you have indicated (by setting a flag in the driver's WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY
structure) that you want the driver to examine IRPs during low-memory situations. In other words, your driver
can assess each IRP and decide if it is one that must be processed even during low-memory situations.
When your driver calls WdfIoQueueAssignFor wardProgressPolicy , it also specifies the number of reserved
request objects that you want the framework to pre-allocate for low-memory situations. You can choose the
number of request objects that are appropriate for your device and driver. To prevent reduced performance,
your driver should typically specify a number that approximates the number of I/O requests that the driver and
device can handle in parallel.
However, if your driver's call to WdfIoQueueAssignFor wardProgressPolicy and its
EvtIoAllocateResourcesForReservedRequest callback function pre-allocate too many reserved request objects or
too much request-specific resource memory, your driver can actually contribute to the low-memory situations
that you are attempting to handle. You should test the performance of your driver and device, and include low-
memory simulations, to determine the best numbers to choose.
Before WdfIoQueueAssignFor wardProgressPolicy returns, the framework creates and reserves the number
of request objects that the driver has specified. Each time that it reserves a request object, the framework
immediately calls the driver's EvtIoAllocateResourcesForReservedRequest callback function so that the driver
can allocate and save request-specific resources, in case the framework actually uses the reserved request
objects.
When one of the driver's request handlers receives an I/O request from the I/O queue, it can call the
WdfRequestIsReser ved method to determine whether the request object is one that the framework pre-
allocated for low-memory situations. If this method returns TRUE , the driver should use resources that its
EvtIoAllocateResourcesForReservedRequest callback function reserved.
If the framework uses one of its reserved request objects, it returns the object to its set of reserved objects after
the driver completes the request. The framework saves the request object, and any context space that the driver
created by calling WdfDeviceInitSetRequestAttributes or WdfObjectAllocateContext , for reuse if another
low-memory situation occurs.
How the Framework and Driver Support Guaranteed Forward Progress
Following are the steps that the driver and framework perform to support guaranteed forward progress for an
I/O queue:
1. The driver calls WdfIoQueueAssignFor wardProgressPolicy .
In response, the framework allocates and stores the number of request objects that the driver specifies. If
the driver previously called WdfDeviceInitSetRequestAttributes , each allocation includes context
space that WdfDeviceInitSetRequestAttributes specified.
In addition, if the driver has provided an EvtIoAllocateResourcesForReservedRequest callback function,
the framework calls the callback function each time that it allocates and stores a request object.
2. The framework receives an I/O request packet (IRP) that the I/O manager is sending to the driver.
The framework attempts to allocate a request object for the IRP. If the I/O queue that the driver created
for the request type supports guaranteed forward progress, the next step depends on whether the
allocation succeeds or fails:
The request object allocation succeeds.
If the driver provided an EvtIoAllocateRequestResources callback function, the framework calls it. If
the callback function returns STATUS_SUCCESS, the framework adds the request to the I/O queue.
If the callback function returns an error status value, the framework deletes the request object that
it just created and uses one of its pre-allocated request objects. When the driver's request handler
receives the request object, it determines whether the request object was pre-allocated and
therefore whether it should use the driver's pre-allocated resources.
If the driver did not provide an EvtIoAllocateRequestResources callback function, the framework
adds the request to the I/O queue, just as if the driver had not enabled guaranteed forward
progress.
The request object allocation fails.
What the framework does next depends on the value that the driver provided for the
For wardProgressReser vedPolicy member of the
WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY structure. This member informs the
framework when to use a reserved request: always, only if the I/O request is a paging I/O
operation, or only if the EvtIoWdmIrpForForwardProgress callback function indicates that a
reserved request should be used.
In all cases, the driver's request handlers can call WdfRequestIsReser ved to determine whether the
framework has used a reserved request object. If so, the driver should use the request resources that its
EvtIoAllocateResourcesForReservedRequest callback function allocated.
Guaranteed Forward Progress Scenario
You are writing a driver for a storage device that might contain the system's paging file. It is important that read
operations from and write operations to the paging file succeed.
You decide to create separate I/O queues for read and write operations, and to enable guaranteed forward
progress for both of these I/O queues. You decide to create a third I/O queue for all other request types without
enabling guaranteed forward progress.
Your driver stack and device are capable of processing four write operations in parallel, so you set the
TotalFor wardProgressRequests member of the WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY
structure to 4 before calling WdfIoQueueAssignFor wardProgressPolicy .
You decide that guaranteeing forward progress is only important if your driver's device is the paging device, so
your driver sets the For wardProgressReser vedPolicy member of the
WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY structure to
WdfIoFor wardProgressReser vedPolicyPagingIO .
Because your driver requires a framework memory object for each read request and each write request, you
decide that your driver should pre-allocate some memory objects to use for its calls to
WdfIoTargetFormatRequestForRead and WdfIoTargetFormatRequestForWrite in low-memory
situations.
Therefore, the driver provides an EvtIoAllocateResourcesForReservedRequest callback function for the read
queue and another one for the write queue. Each time that the framework calls one of these callback functions,
the callback function calls WdfMemor yCreate and saves the returned object handle for low-memory
situations. Because the callback function receives a handle to a pre-allocated request object, it can parent the
memory object to the request object. (A driver for a DMA device might also pre-allocate framework DMA
objects.)
The request handlers for the read and write queues must determine whether each received request object is one
that the framework reserved for low-memory situations. A request handler can call WdfRequestIsReser ved ,
or it can compare the request object handle with the ones that the EvtIoAllocateResourcesForReservedRequest
callback function received previously.
The driver also provides an EvtIoAllocateRequestResources callback function for the read queue and another one
for the write queue. The framework calls one of these callback functions when it receives a read or write request
from the I/O manager and successfully creates a request object. Each of these callback functions calls
WdfMemor yCreate to allocate a memory object for a request. If the allocation fails, the callback function
returns an error status value to notify the framework that a low-memory situation has just occurred. The
framework, detecting the error return value, deletes the request object that it just created and uses one of its
pre-allocated objects.
This driver does not provide an EvtIoWdmIrpForForwardProgress callback function, because it does not need to
examine individual read or write IRPs before the framework adds them to an I/O queue.
Remember that when a driver implements guaranteed forward progress for a device, all lower-level drivers in
the device's driver stack must also implement guaranteed forward progress.
Specifying Priority Boosts When Completing I/O
Requests
2/5/2021 • 2 minutes to read • Edit Online

When a driver completes an I/O request, it can call WdfRequestCompleteWithPriorityBoost to specify a


value that the system uses to boost the run-time priority of the thread that requested the I/O operation.
If the driver calls WdfRequestComplete or WdfRequestCompleteWithInformation instead of
WdfRequestCompleteWithPriorityBoost , the framework uses a default priority boost value that is based on
the device type. The following table lists the default priority boost values that the framework uses. The device
type and priority boost constants are defined in Wdm.h.

DEVIC E T Y P E DEFA ULT P RIO RIT Y B O O ST

FILE_DEVICE_UNDEFINED IO_NO_INCREMENT

FILE_DEVICE_BEEP IO_NO_INCREMENT

FILE_DEVICE_CD_ROM IO_CD_ROM_INCREMENT

FILE_DEVICE_CD_ROM_FILE_SYSTEM IO_CD_ROM_INCREMENT

FILE_DEVICE_CONTROLLER IO_NO_INCREMENT

FILE_DEVICE_DATALINK IO_NO_INCREMENT

FILE_DEVICE_DFS IO_NO_INCREMENT

FILE_DEVICE_DISK IO_DISK_INCREMENT

FILE_DEVICE_DISK_FILE_SYSTEM IO_DISK_INCREMENT

FILE_DEVICE_FILE_SYSTEM IO_NO_INCREMENT

FILE_DEVICE_INPORT_PORT IO_NO_INCREMENT

FILE_DEVICE_KEYBOARD IO_KEYBOARD_INCREMENT

FILE_DEVICE_MAILSLOT IO_MAILSLOT_INCREMENT

FILE_DEVICE_MIDI_IN IO_SOUND_INCREMENT

FILE_DEVICE_MIDI_OUT IO_SOUND_INCREMENT

FILE_DEVICE_MOUSE IO_MOUSE_INCREMENT

FILE_DEVICE_MULTI_UNC_PROVIDER IO_NO_INCREMENT
DEVIC E T Y P E DEFA ULT P RIO RIT Y B O O ST

FILE_DEVICE_NAMED_PIPE IO_NAMED_PIPE_INCREMENT

FILE_DEVICE_NETWORK IO_NETWORK_INCREMENT

FILE_DEVICE_NETWORK_BROWSER IO_NETWORK_INCREMENT

FILE_DEVICE_NETWORK_FILE_SYSTEM IO_NETWORK_INCREMENT

FILE_DEVICE_NULL IO_NO_INCREMENT

FILE_DEVICE_PARALLEL_PORT IO_PARALLEL_INCREMENT

FILE_DEVICE_PHYSICAL_NETCARD IO_NETWORK_INCREMENT

FILE_DEVICE_PRINTER IO_NO_INCREMENT

FILE_DEVICE_SCANNER IO_NO_INCREMENT

FILE_DEVICE_SERIAL_MOUSE_PORT IO_SERIAL_INCREMENT

FILE_DEVICE_SERIAL_PORT IO_SERIAL_INCREMENT

FILE_DEVICE_SCREEN IO_VIDEO_INCREMENT

FILE_DEVICE_SOUND IO_SOUND_INCREMENT

FILE_DEVICE_STREAMS IO_SOUND_INCREMENT

FILE_DEVICE_TAPE IO_NO_INCREMENT

FILE_DEVICE_TAPE_FILE_SYSTEM IO_NO_INCREMENT

FILE_DEVICE_TRANSPORT IO_NO_INCREMENT

FILE_DEVICE_UNKNOWN IO_NO_INCREMENT

FILE_DEVICE_VIDEO IO_VIDEO_INCREMENT

FILE_DEVICE_VIRTUAL_DISK IO_DISK_INCREMENT

FILE_DEVICE_WAVE_IN IO_SOUND_INCREMENT

FILE_DEVICE_WAVE_OUT IO_SOUND_INCREMENT

FILE_DEVICE_8042_PORT IO_KEYBOARD_INCREMENT

FILE_DEVICE_NETWORK_REDIRECTOR IO_NETWORK_INCREMENT

FILE_DEVICE_BATTERY IO_NO_INCREMENT
DEVIC E T Y P E DEFA ULT P RIO RIT Y B O O ST

FILE_DEVICE_BUS_EXTENDER IO_NO_INCREMENT

FILE_DEVICE_MODEM IO_SERIAL_INCREMENT

FILE_DEVICE_VDM IO_NO_INCREMENT

FILE_DEVICE_MASS_STORAGE IO_DISK_INCREMENT

FILE_DEVICE_SMB IO_NETWORK_INCREMENT

FILE_DEVICE_KS IO_SOUND_INCREMENT

FILE_DEVICE_CHANGER IO_NO_INCREMENT

FILE_DEVICE_SMARTCARD IO_NO_INCREMENT

FILE_DEVICE_ACPI IO_NO_INCREMENT

FILE_DEVICE_DVD IO_NO_INCREMENT

FILE_DEVICE_FULLSCREEN_VIDEO IO_VIDEO_INCREMENT

FILE_DEVICE_DFS_FILE_SYSTEM IO_NO_INCREMENT

FILE_DEVICE_DFS_VOLUME IO_NO_INCREMENT

FILE_DEVICE_SERENUM IO_SERIAL_INCREMENT

FILE_DEVICE_TERMSRV IO_NO_INCREMENT

FILE_DEVICE_KSEC IO_NO_INCREMENT

FILE_DEVICE_FIPS IO_NO_INCREMENT

FILE_DEVICE_INFINIBAND IO_NO_INCREMENT
Supporting PnP and Power Management in Bus
Drivers
2/5/2021 • 2 minutes to read • Edit Online

Some devices are permanently plugged into the system, while others can be plugged in and unplugged while
the system is running. Bus drivers must identify and report the devices that are connected to their bus, and they
must discover and report the arrival and departure of devices in the system.
The devices that a bus driver identifies and reports are called the bus's child devices. The process of identifying
and reporting child devices is called bus enumeration. During bus enumeration, the bus driver creates device
objects for its child devices. For more information about bus enumeration, see Enumerating the Devices on a
Bus.
Bus drivers are essentially function drivers, or rarely a filter driver, that also handle bus enumeration. A bus
driver is typically the function driver for the bus adapter, but it is not the function driver for the child devices that
are connected to the bus.
Bus drivers also have the same PnP and power management responsibilities that function drivers have. For
information about these responsibilities, see Supporting PnP and Power Management in Function Drivers.
Enumerating the Devices on a Bus
2/5/2021 • 2 minutes to read • Edit Online

Bus enumeration is the act of determining which child devices are connected to a parent device. A parent device
is typically a bus adapter, but it can also be a device that supports multiple functions, such as a sound card, for
which each function requires a separate set of drivers.
Kernel-Mode Driver Framework (KMDF) supports two types of bus enumeration:
Static enumeration, which is easy to implement and is ideal if the number and type of child devices is not
system-specific and does not change after the hardware has been plugged in.
Dynamic enumeration, which should be used if the number or type of child devices changes from one
computer to another.
A bus driver can use either or both types of bus enumeration.
For more information about writing a KMDF bus driver, see Bus Driver Development Based on KMDF.
Static Enumeration
2/5/2021 • 2 minutes to read • Edit Online

Static enumeration is a driver's ability to detect and report the existence of devices during system initialization,
with a limited ability to report subsequent changes to the system's configuration.
Bus drivers can use static enumeration if the number and type of devices or functional subunits is
predetermined and permanent, and does not depend on the configuration of the system on which the driver is
running.
For example, a sound card's driver might act as a bus driver and create separate physical device objects (PDOs)
for each of the card's capabilities, such as MIDI, audio, and joystick.
Static Child Lists
The framework enables drivers to support static enumeration by providing static child lists. Each static child list
represents a list of child devices that are connected to a parent device. The bus driver for the parent device must
identify the parent's child devices, add them to the parent device's static child list, and create a PDO for each
child device.
Creating a Static Child List
Each time a driver creates a framework device object that represents a functional device object (FDO) for a
device, the framework creates an empty, static child list for the device.
When the framework calls a bus driver's EvtDriverDeviceAdd callback function, the callback function must call
WdfDeviceCreate to create an FDO for the parent device. For more information about creating an FDO, see
Creating Device Objects in a Function Driver.
The driver must then enumerate the parent device's children, create PDOs for the children, and add the children
to the child list.
Optionally, the driver can call WdfDeviceSetBusInformationForChildren to provide the framework with
information about the bus. Doing so is recommended because it makes it easier for child devices and apps to
identify the bus.
To create a PDO for a detected child device, the bus driver must:
1. Call WdfPdoInitAllocate to obtain a WDFDEVICE_INIT structure.
2. Initialize the WDFDEVICE_INIT structure.
3. Call WdfDeviceCreate to create a framework device object that represents a PDO.
For more information about creating a PDO, see Creating Device Objects in a Bus Driver.
After calling WdfDeviceCreate , the driver must call WdfFdoAddStaticChild to add the child device to the
child list.
Modifying a Static Child List
Because drivers should only use static child lists for device configurations that are predetermined and
permanent, there is little need for a driver to modify a static child list after creating it. If the driver determines
that a child device has become inaccessible, the driver can call WdfPdoMarkMissing . (If a child device remains
accessible but becomes unresponsive and unusable, the driver should set the Failed member of the
WDF_DEVICE_STATE structure to WdfTrue and then call WdfDeviceSetDeviceState .)
Traversing a Static Child List
If you need to retrieve the contents of a static child list, the driver can traverse the list by doing the following:
1. Calling WdfFdoLockStaticChildListForIteration .
2. Calling WdfFdoRetrieveNextStaticChild as many times as necessary.
3. Calling WdfFdoUnlockStaticChildListFromIteration .
Dynamic Enumeration
2/5/2021 • 8 minutes to read • Edit Online

Dynamic enumeration is a driver's ability to detect and report changes to the number and type of devices that
are connected to the system while the system is running.
Bus drivers must use dynamic enumeration if the number or types of devices that are connected to the parent
device depend on a system's configuration. Some of these devices might be always connected to the system,
and some might be plugged in and unplugged while the system is running.
For example, the number and type of devices that are plugged into a system's PCI bus are system-dependent,
but they are permanent unless a user turns off power, opens the case, and adds or removes a device by using a
screwdriver. On the other hand, a user can add or remove USB devices by plugging in or unplugging a cable
while the system is running.
Dynamic Child Lists
The framework enables drivers to support dynamic enumeration by providing framework child-list objects. Each
child-list object represents a list of child devices that are connected to a parent device. The bus driver for the
parent device must identify the parent's child devices, add them to the parent device's child list, and create a
physical device object (PDO) for each child.
Each time a driver creates a framework device object that represents an FDO for a device, the framework creates
an empty, default child list for the device. Your driver can obtain a handle to a device's default child list by calling
WdfFdoGetDefaultChildList . Typically, if you are writing a bus driver that enumerates a device's children, your
driver can add children to the default child list. If you need to create additional child lists, your driver can call
WdfChildListCreate .
Before a driver can use a child list, it must configure the child-list object by initializing a
WDF_CHILD_LIST_CONFIG structure and passing the structure to either
WdfFdoInitSetDefaultChildListConfig , for the default child list, or to WdfChildListCreate , for additional
child lists.
Dynamic Child Descriptions
Each time a bus driver identifies a child device, it must add the child device's description to a child list. A child
description consists of a required identification description and an optional address description.
Identification Description An identification description is a structure that contains information that uniquely
identifies each device that the driver enumerates. The driver defines this structure, but its first member must be
a WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER structure.
Typically, an identification description contains a device's device identification strings, possibly a serial number,
and information about the device's location on the bus, such as a slot number.
The driver can provide the following set of callback functions, which allow the framework to manipulate the
information in an identification description:
EvtChildListIdentificationDescriptionCompare, which compares the contents of two identification
description structures.
EvtChildListIdentificationDescriptionCopy, which copies the contents of one identification description
structure to another.
EvtChildListIdentificationDescriptionDuplicate, which creates a new identification description by
duplicating an existing identification description structure and, if necessary, allocating additional buffers.
EvtChildListIdentificationDescriptionCleanup, which deallocates buffers that were allocated by the
EvtChildListIdentificationDescriptionDuplicate callback function.
Typically, you will need to provide these callback functions if your driver's identification description structures
contain pointers to dynamically allocated buffers. For more information about the purpose of these callback
functions, see their reference pages.
Address Description An address description is a structure that contains information that the driver requires so
that it can access the device on its bus, if the information can change while the device is plugged in. The driver
defines this structure, but its first member must be a WDF_CHILD_ADDRESS_DESCRIPTION_HEADER
structure.
Address descriptions are optional. If a device's address information cannot change between the time the device
is plugged in and the time it is unplugged, all of the device's address information can be stored in an
identification description. For example, USB controllers assign addresses to devices when the devices are
plugged in, and these addresses do not change.
On the other hand, some buses use addressing information that can change. For example, the IEEE 1394 bus
uses a "generation count," which is the number of bus resets that have occurred. Each asynchronous I/O request
to an IEEE 1394 device must include the generation count. Because this address information can change, your
driver must store it in an address description.
The driver can provide the following set of callback functions to manipulate the information in an address
description:
EvtChildListAddressDescriptionCopy, which copies the contents of one address description structure to
another.
EvtChildListAddressDescriptionDuplicate, which creates a new address description by duplicating an
existing address description structure and, if necessary, allocating additional buffers.
EvtChildListAddressDescriptionCleanup, which deallocates buffers that were allocated by the
EvtChildListAddressDescriptionDuplicate callback function.
Typically, you will need to provide these callback functions if your driver's address description structures contain
pointers to dynamically allocated buffers. For more information about the purpose of these callback functions,
see their reference pages.
Adding Devices to a Dynamic Child List
When the framework calls a bus driver's EvtDriverDeviceAdd callback function, the callback function must call
WdfDeviceCreate to create an FDO for the parent device, which is typically a bus adapter. For more
information about creating an FDO, see Creating Device Objects in a Function Driver. The driver must then
enumerate the parent device's children and add the children to a child list.
Optionally, the driver can call WdfDeviceSetBusInformationForChildren to provide the framework with
information about the bus. Doing so is recommended because it makes it easier for child devices and apps to
identify the bus.
To add children to a child list, the driver must call WdfChildListAddOrUpdateChildDescriptionAsPresent
for each child device that it finds. This call informs the framework that a driver has discovered a child device that
is connected to a parent device. When your driver calls
WdfChildListAddOrUpdateChildDescriptionAsPresent , it supplies an identification description and,
optionally, an address description.
After the driver calls WdfChildListAddOrUpdateChildDescriptionAsPresent to report a new device, the
framework informs the PnP manager that the new device exists. The PnP manager then builds a device stack
and driver stack for the new device. As part of this process, the framework calls the bus driver's
EvtChildListCreateDevice callback function. This callback function must call WdfDeviceCreate to create a PDO
for the new device.
Typically, several child devices are connected to a parent, so the bus driver will need to call
WdfChildListAddOrUpdateChildDescriptionAsPresent several times. The most efficient way to do this is
the following:
1. Call WdfChildListBeginScan .
2. Call WdfChildListAddOrUpdateChildDescriptionAsPresent for each child device.
3. Call WdfChildListEndScan .
If you surround your driver's dynamic enumeration with calls to WdfChildListBeginScan and
WdfChildListEndScan , the framework stores all of the changes to the child list, and notifies the PnP manager
of the changes when the driver calls WdfChildListEndScan . At some later time, the framework calls the bus
driver's EvtChildListCreateDevice callback function for each device in the child list. This callback function calls
WdfDeviceCreate to create a PDO for each new device.
When your driver calls WdfChildListBeginScan , the framework marks all previously reported devices as no
longer being present. Therefore, the driver must call
WdfChildListAddOrUpdateChildDescriptionAsPresent for all children that the driver can detect, not just
newly discovered children. To add a single child to a child list, the driver can make a single call to
WdfChildListUpdateAllChildDescriptionsAsPresent without first calling WdfChildListBeginScan .
Updating a Dynamic Child List
There are two common ways to update the information in a dynamic child list:
1. When a parent device receives an interrupt that indicates the arrival or removal of a child, the driver's
EvtInterruptDpc callback function calls WdfChildListAddOrUpdateChildDescriptionAsPresent if a
device has been plugged in or WdfChildListUpdateChildDescriptionAsMissing if a device has been
unplugged.
2. The driver can provide an EvtChildListScanForChildren callback function, which the framework calls each
time the parent device enters its working (D0) state. This callback function should enumerate all child
devices by calling WdfChildListBeginScan ,
WdfChildListAddOrUpdateChildDescriptionAsPresent (or
WdfChildListUpdateAllChildDescriptionsAsPresent ), and WdfChildListEndScan .
You can use one or both of these techniques in your driver.
Traversing a Dynamic Child List
If you want your driver to examine the contents of a child list, it can traverse the list by using one of the
following techniques:
To obtain the contents of each child device description, one at a time, the driver can:
1. Call WdfChildListBeginIteration .
2. Call WdfChildListRetrieveNextDevice , as many times as necessary.
3. Call WdfChildListEndIteration .
When calling WdfChildListBeginIteration , the driver specifies a WDF_RETRIEVE_CHILD_FL AGS -
typed flag that indicates whether the framework should retrieve all device descriptions or only a subset.
When WdfChildListRetrieveNextDevice finds a match, it retrieves the child device's identification and
address descriptions, plus a handle to its device object.
If you need to obtain the address description that is currently contained in a child device description, your
driver can call WdfChildListRetrieveAddressDescription , specifying an identification description. The
framework traverses the child list until it finds a child device with a matching identification description,
and then it retrieves the address description.
If you need to obtain a handle to the framework device object that is associated with a particular child
device, your driver can call WdfChildListRetrievePdo . The framework traverses the child list until it
finds a child device with a matching identification description, and then it returns a device object handle.
Be sure to wrap the call with WdfChildListBeginIteration and WdfChildListEndIteration to protect
the caller from sudden PnP removal of the PDO on another thread.
Accessing a PDO's Identification and Address Descriptions
Your driver can call the following methods to access a PDO's identification description or address description:
WdfPdoRetrieveIdentificationDescription , which retrieves the identification description that is
associated with a PDO.
WdfPdoRetrieveAddressDescription , which retrieves the address description that is associated with a
PDO.
WdfPdoUpdateAddressDescription , which updates the address description that is associated with a
PDO.
Handling re -enumeration requests
Framework-based bus drivers that support dynamic enumeration can receive a request to reenumerate a
particular child device through the REENUMERATE_SELF_INTERFACE_STANDARD interface. For more info,
see Handling Enumeration Requests
Handling Enumeration Requests
2/5/2021 • 2 minutes to read • Edit Online

The PnP manager can request a bus driver to enumerate its children at any time. (If you are familiar with WDM
interfaces, enumeration requests are IRP_MN_QUERY_DEVICE_REL ATIONS requests with a relation type of
BusRelations .) Framework-based drivers do not see these requests. Instead, the framework handles the
requests by using the information that is stored in a device's child list. The driver is responsible for keeping the
child list up-to-date so that the framework can provide correct information when the PnP manager requests an
enumeration.
Framework-based bus drivers that support dynamic enumeration can receive a request to reenumerate a
particular child device. Such a request might be sent by the child device's function driver after the driver detects
a device failure. (The framework supports this type of request by implementing the
REENUMERATE_SELF_INTERFACE_STANDARD interface, which is a standard driver-defined interface that is
defined in wdm.h.)
Framework-based bus drivers that support dynamic enumeration can provide an
EvtChildListDeviceReenumerated callback function, which the framework calls when it receives a reenumeration
request from a child device's driver. If this callback function returns TRUE or does not exist, the framework
marks the child device as no longer being present and informs the PnP manager that the bus driver's child list
has changed. As a result, the PnP manager requests a reenumeration and the framework calls the driver's
EvtChildListCreateDevice callback function, which creates a new PDO for the child device.
Supporting Ejectable Devices
2/5/2021 • 2 minutes to read • Edit Online

Ejectable devices are devices that can be inserted into a docking station and ejected from the docking station.
Typically, an ejectable device's bus power must be disabled before the device can be removed.
If a device is ejectable, the bus driver for the device's bus must set the EjectSuppor ted member in the device's
WDF_DEVICE_PNP_CAPABILITIES structure.
When a bus driver determines that one of its enumerated child devices is about to be ejected, it calls either
WdfPdoRequestEject or WdfChildListRequestChildEject . For example, the bus driver might detect that a
user has pressed an eject button.
When a driver calls WdfChildListRequestChildEject or WdfPdoRequestEject , the PnP manager uses the
orderly removal scenario to inform the device's drivers that the device is being removed. After the framework
has called the EvtDeviceReleaseHardware callback function in the bus driver for the device's bus, the framework
calls the bus driver's EvtDeviceEject callback function, which performs any operations that are necessary to
physically eject the device.
If ejecting your device causes additional devices to also be ejected, your bus driver can maintain a list of ejection
relations. When a user removes your device, the PnP manager informs the drivers of devices in the list that their
devices are also being removed. To maintain a list of ejection relations, a bus driver can use the
WdfPdoAddEjectionRelationsPhysicalDevice , WdfPdoRemoveEjectionRelationsPhysicalDevice , and
WdfPdoClearEjectionRelationsDevices methods.
If a device can be locked in its docking station, the bus driver must set the LockSuppor ted member in the
device's WDF_DEVICE_PNP_CAPABILITIES structure. The bus driver must also provide an EvtDeviceSetLock
callback function, which locks the device to disable ejection or unlocks the device to enable ejection.
State Machines in the Framework
2/5/2021 • 2 minutes to read • Edit Online

To keep track of each device's state, the framework uses a PnP state machine, a power state machine, and a
power policy state machine. The framework creates an instance of each state machine for each device that is
plugged into a system.

NOTE
This functionality is for Microsoft-internal use only.

For drivers that do need to know this information, the framework provides two sets of interfaces:
A set of driver-supplied event callback functions.
The driver can request that the framework call one of the following callback functions whenever one of
the state machines enters or exits a particular state:
EvtDevicePnpStateChange, which the driver registers by calling
WdfDeviceInitRegisterPnpStateChangeCallback .
EvtDevicePowerStateChange, which the driver registers by calling
WdfDeviceInitRegisterPowerStateChangeCallback .
EvtDevicePowerPolicyStateChange, which the driver registers by calling
WdfDeviceInitRegisterPowerPolicyStateChangeCallback .
A set of methods that return the current state of the state machines.
The driver can call one of the following methods to determine the current state of one of the state
machines for a particular device:
WdfDeviceGetDevicePnpState
WdfDeviceGetDevicePowerState
WdfDeviceGetDevicePowerPolicyState
Using Driver-Defined Interfaces
2/5/2021 • 5 minutes to read • Edit Online

Drivers can define device-specific interfaces that other drivers can access. These driver-defined interfaces can
consist of a set of callable routines, a set of data structures, or both. The driver typically provides pointers to
these routines and structures in a driver-defined interface structure, which the driver makes available to other
drivers.
For example, a bus driver might provide one or more routines that higher-level drivers can call to obtain
information about a child device, if that information is not available in the child device's resource list.
For an example of a set of driver-defined interfaces that are documented in the WDK, see USB Routines. Also, see
the framework-based version of the toaster sample.
Creating an Interface
Each driver-defined interface is specified by:
A GUID
A version number
A driver-defined interface structure
Reference and dereference routines
To create an interface and make it available to other drivers, framework-based drivers can use the following
steps:
1. Define an interface structure.
The first member of this driver-defined structure must be an INTERFACE header structure. Additional
members might include interface data and pointers to additional structures or routines that anther driver
can call.
Your driver must provide a WDF_QUERY_INTERFACE_CONFIG structure, which describes the interface
that you have defined.
2. Call WdfDeviceAddQuer yInterface .
The WdfDeviceAddQuer yInterface method does the following:
Stores information about the interface, such as its GUID, version number, and structure size, so the
framework can recognize another driver's request for the interface.
Registers an optional EvtDeviceProcessQueryInterfaceRequest event callback function, which the
framework calls when another driver asks for the interface.
Each instance of a driver-defined interface is associated with an individual device, so drivers typically call
WdfDeviceAddQuer yInterface from within an EvtDriverDeviceAdd or EvtChildListCreateDevice callback
function.
Accessing an Interface
If your driver has defined an interface, another framework-based driver can request access to the interface by
calling WdfFdoQuer yForInterface and passing a GUID, version number, pointer to a structure, and the
structure size. The framework creates an I/O request and sends it to the top of the driver stack.
A driver typically calls WdfFdoQuer yForInterface from within an EvtDriverDeviceAdd callback function.
Alternatively, if the driver must release the interface when the device is not in its working state, the driver can
call WdfFdoQuer yForInterface from within an EvtDevicePrepareHardware callback function and call the
interface's dereference routine from within an EvtDeviceReleaseHardware callback function.
If driver A asks driver B for an interface that driver B has defined, the framework handles the request for driver
B. The framework verifies that the GUID and version represent a supported interface, and that the structure size
that driver A supplied is large enough to hold the interface.
When a driver calls WdfFdoQuer yForInterface , the I/O request that the framework creates travels all the way
to the bottom of the driver stack. If a simple driver stack consists of three drivers - A, B, and C - and if driver A
asks for an interface, both driver B and driver C can support the interface. For example, driver B might fill in
driver A's interface structure before passing the request down to driver C. Driver C can provide an
EvtDeviceProcessQueryInterfaceRequest callback function that examines the interface structure's contents and
possibly modifies them.
If driver A needs to access driver B's interface, and driver B is a remote I/O target (that is, a driver that is in a
different driver stack), driver A must call WdfIoTargetQuer yForInterface instead of
WdfFdoQuer yForInterface .
Using One -Way or Two -Way Communication
You can define an interface that provides one-way communication, or one that provides two-way
communication. To specify two-way communication, your driver sets the Impor tInterface member of its
WDF_QUERY_INTERFACE_CONFIG structure to TRUE .
If the interface provides one-way communication, and if driver A asks for driver B's interface, interface data
flows only from driver B to driver A. When the framework receives driver A's request for an interface that
supports one-way communication, the framework copies the driver-defined interface values into the driver A's
interface structure. It then calls driver B's EvtDeviceProcessQueryInterfaceRequest callback function, if it exists,
so it can examine and possibly modify the interface values.
If the interface provides two-way communication, the interface structure contains some members that driver A
fills in before sending the request to driver B. Driver B can read the parameter values that driver A provided and
make choices, based on those values, about which information to supply to driver A. When the framework
receives driver A's request for an interface that supports two-way communication, the framework calls driver B's
EvtDeviceProcessQueryInterfaceRequest callback function so that it can examine received values and supply
output values. For two-way communication, the callback function is required because the framework does not
copy any interface values to driver A's interface structure.
Maintaining a Reference Count
Each interface must include a reference function and a dereference function, which increment and decrement a
reference count for the interface. The driver that defines the interface specifies the addresses of these functions
in its INTERFACE structure.
When driver A asks driver B for an interface, the framework calls the interface's reference function before
making the interface available to driver A. When driver A has finished using the interface, it must call the
interface's dereference function.
The reference and dereference functions for most interfaces can be no-op functions that do nothing. The
framework provides no-op reference count functions, WdfDeviceInterfaceReferenceNoOp and
WdfDeviceInterfaceDereferenceNoOp , that most drivers can use.
The only time that drivers must keep track of an interface's reference count, and provide real reference and
dereference functions, is when driver A requests an interface from a remote I/O target (that is, a driver that is in
a different driver stack). In this case, driver B (in a different stack) must implement a reference count so that it
can prevent its device from being removed while driver A is using driver B's interface.
If you are designing driver B, which defines an interface, you must decide whether your driver's interface will be
accessed from a different driver stack. (Driver B cannot determine if a request for its interface is from the local
driver stack or from a remote stack.) If your driver will support interface requests from a remote stack, the
driver must implement a reference count.
If you are designing driver A, which accesses the interface on the remote I/O target, the driver must provide an
EvtIoTargetQueryRemove callback function that releases the interface when driver B's device is about to be
removed, an EvtIoTargetRemoveComplete callback function that releases the interface when driver B's device is
surprise-removed, and an EvtIoTargetRemoveCanceled callback function that reacquires the interface if an
attempt to remove the device was canceled.
Supporting Special Files
2/5/2021 • 2 minutes to read • Edit Online

Special files include paging files, dump files, and hibernation files. If the target device for your driver is a storage
device that the system might use for these files, the driver must do the following:
Call WdfDeviceSetSpecialFileSuppor t to enable or disable support for each type of special file. (Each
driver's support for special files is disabled by default.)
A bus driver that enumerates child devices should also call WdfDeviceSetSpecialFileSuppor t for each
child device that can support special files.
Call WdfDeviceAddDependentUsageDeviceObject , if one device is dependent on another device
when supporting special files.
Optionally provide an EvtDeviceUsageNotification or (starting in KMDF 1.11)
EvtDeviceUsageNotificationEx callback function, so the driver will be notified when a special file is created
or removed.
If your driver calls WdfDeviceSetSpecialFileSuppor t for a device, and if a special file is open on the device,
the framework does not allow the PnP manager to remove or stop the device.
After a driver has called WdfDeviceAddDependentUsageDeviceObject , it can call
WdfDeviceRemoveDependentUsageDeviceObject to remove a device's dependency on another device.
Using Control Device Objects
2/5/2021 • 4 minutes to read • Edit Online

A control device object is a framework device object that does not support Plug and Play (PnP) or power
management operations. Drivers can use control device objects to represent software-only virtual devices or
legacy hardware devices (that is, devices that do not provide PnP or power management capabilities).
A driver that creates a control device object also typically creates a symbolic link for the device object.
Applications can send I/O requests to the control device object by passing the symbolic link name to an API
element, such as the Microsoft Win32 CreateFile function.
The framework does not attach control device objects to a device stack. Therefore, when an application sends an
I/O request to a control device object, the I/O manager delivers the request directly to the driver that created the
control device object, instead of to the driver at the top of the stack. (However, an additional driver can call
IoAttachDevice to attach a device object above the control device object. In this case, the additional driver
receives the I/O request first.)
Uses of Control Device Objects
Two typical uses for control devices are:
1. A filter driver for a PnP device, if the driver supports a set of custom I/O control codes for applications to
use.
If an application attempted to send the custom I/O control codes to the top of the driver stack (by using,
for example, the symbolic link name of a device interface), a driver above the filter driver might fail the
I/O request if the driver did not recognize the custom I/O control codes. To avoid this problem, the filter
driver can create a control device object. Applications can use the control device object's symbolic link
name to send I/O control codes directly to the filter driver.
(Note that a better way for the filter driver to avoid the problem is to act as a bus driver and enumerate
child devices that operate in raw mode. In other words, for each device that the filter driver supports, the
driver can create a physical device object (PDO) that does not require a function driver. The driver calls
WdfPdoInitAssignRawDevice and WdfDeviceInitAssignName for each of these devices, and the
application can identify a device by name when it sends a custom I/O control code.)
2. A driver for a device that does not support PnP.
Such a driver must use control device objects, because the device objects for such devices do not reside
in a device stack and do not provide PnP capabilities. For more information about supporting non-PnP
devices, see Using Kernel-Mode Driver Framework with Non-PnP Drivers.
Creating a Control Device Object
To create a control device object, a driver must:
1. Call WdfControlDeviceInitAllocate to obtain a WDFDEVICE_INIT structure.
2. Call object initialization methods, as needed, to initialize the WDFDEVICE_INIT structure. The driver can
call only the following initialization methods:
WdfControlDeviceInitSetShutdownNotification
WdfDeviceInitAssignName
WdfDeviceInitAssignSDDLString
WdfDeviceInitAssignWdmIrpPreprocessCallback
WdfDeviceInitSetCharacteristics
WdfDeviceInitSetDeviceClass
WdfDeviceInitSetExclusive
WdfDeviceInitSetFileObjectConfig
WdfDeviceInitSetIoInCallerContextCallback
WdfDeviceInitSetIoType
WdfDeviceInitSetRequestAttributes
3. Call WdfDeviceCreate , which uses the contents of the WDFDEVICE_INIT structure to create a framework
device object.
4. Complete the following initialization operations:
Create a default I/O queue for the device, if one is needed.
Call WdfDeviceConfigureRequestDispatching , if needed.
Call WdfDeviceCreateSymbolicLink to create a symbolic link name that applications can use to
access the control device.
5. Call WdfControlFinishInitializing .
Rules for Using Control Device Objects
Drivers that create control device objects must obey the following rules:
Drivers cannot pass the control device object's handle to framework methods that enumerate child
devices.
Drivers cannot pass the control device object's handle to framework methods that support device
interfaces.
Drivers can create I/O queues and register request handlers for the queues, but the framework does not
allow the queues to be power-managed.
Drivers can create file objects for control device objects.
Naming a Control Device Object
All control device objects must be named. Typically, your driver will call WdfDeviceInitAssignName to assign
a device name and then call WdfDeviceCreateSymbolicLink to create a symbolic link name that applications
can use to access the object.
If your driver does not call WdfDeviceInitAssignName to assign a device name, the framework automatically
generates a name for control devices--but your driver cannot call WdfDeviceCreateSymbolicLink .
Your driver can call WdfDeviceInitSetDeviceClass to specify a device setup class for a control device. The
device setup class identifies a section of the registry that contains administrator-supplied information about
devices that belong to the setup class. For more information about calling WdfDeviceInitSetDeviceClass , see
Controlling Device Access in Framework-Based Drivers.
Receiving Notification of System Shutdown
Because control device objects do not support PnP, your driver cannot register callback functions that inform the
driver when a device's power state changes. However, the driver can call
WdfControlDeviceInitSetShutdownNotification to register an EvtDeviceShutdownNotification callback
function. This callback function informs the driver when the system is about to lose its power.
Deleting a Control Device Object
Some drivers have to delete their control device objects before the driver unloads, as follows:
If your driver creates control device objects (which do not support PnP or power management), and if the
driver also creates framework device objects that support PnP and power management, the driver must
eventually call WdfObjectDelete at IRQL = PASSIVE_LEVEL to delete the control device objects.
If the driver creates both types of device objects, the operating system cannot unload your driver until the
driver has deleted the control device objects.
However, the driver must not delete the control device objects until after the framework has deleted the
other device objects. To determine when the framework has deleted the other device objects, your driver
should provide EvtCleanupCallback functions for those objects.
If your driver creates control device objects but does not create framework device objects that support
PnP and power management, the driver does not have to delete the control device objects.
In this case, the framework deletes the control device objects after the driver's EvtDriverUnload callback
function returns.
Creating KMDF Miniport Drivers
2/5/2021 • 2 minutes to read • Edit Online

Some miniport drivers can use Kernel-Mode Driver Framework, if the port/miniport architecture allows the
miniport driver to communicate with other drivers by using WDM or framework interfaces. For example, NDIS
miniport drivers with a WDM lower edge can use the framework to implement the lower edge.
If you want your miniport driver to use the framework, the driver must:
Set the WdfDriverInitNoDispatchOverride flag in the DriverInitFlags member of the driver's
WDF_DRIVER_CONFIG structure before calling WdfDriverCreate . Setting this flag enables the port
driver, instead of the framework, to intercept I/O request packets (IRPs) that the I/O manager has directed
to the driver.
Call WdfDeviceMinipor tCreate instead of WdfDeviceCreate to create framework device objects for
the miniport driver's devices. The miniport driver should call WdfDeviceMinipor tCreate when its port
driver informs it that a device is available.
Call WdfObjectDelete to delete the device object that WdfDeviceMinipor tCreate creates, when the
driver determines that the device has been removed. (Because the driver has set the
WdfDriverInitNoDispatchOverride flag, the framework cannot determine when the device is
removed and cannot delete the device object.)
Call WdfDriverMinipor tUnload when the port driver informs the miniport driver that it is about to be
unloaded.
A miniport driver can use the framework only if the underlying device supports Plug and Play (PnP). Miniport
drivers cannot use the framework's control device objects.
Restrictions apply to the device objects that the WdfDeviceMinipor tCreate method creates. For a list of these
restrictions, see WdfDeviceMinipor tCreate .
Creating Pageable Code in a KMDF Driver
2/5/2021 • 2 minutes to read • Edit Online

Pageable code is code that can be written to the computer's paging file when the code is not being used. You can
make part of your driver pageable to reduce its load image and initial load time, and to reduce the amount of
your driver's code that uses the computer's limited nonpaged memory pool.
To help you determine whether pageable code or data is appropriate for your driver, do the following:
1. Identify pageable sections in your driver.
Pageable sections are not loaded into memory until they are needed. For information about how to
create pageable sections in a driver, see Making Drivers Pageable.
2. Make sure that paged driver code does not impede a computer's ability to quickly awaken from a low-
power state.
All device object callback functions that drivers provide are called at IRQL = PASSIVE_LEVEL, which
enables you to make their code pageable (as described in Making Drivers Pageable).
However, you should not make a callback function's code pageable if the framework calls the callback
function when the device leaves a low-power state and returns to its working (D0) state.
If such code is pageable, the code might be written to the paging file before the computer enters a sleep
state. Therefore, the computer will be slower to awaken because your code cannot be reloaded (and
therefore your device cannot become fully operational) until the paging disk's power is restored.
Therefore, the callback functions that are listed in the A Device Returns to Its Working State topic should
not be pageable.
3. Determine whether your driver requires access to pageable data outside the driver, such as files, the
registry, or paged pool, during power transitions.
For information about how to enable and disable a driver's ability to access pageable data during power
transitions, see WdfDeviceInitSetPowerPageable and WdfDeviceInitSetPowerNotPageable .
For information about how to determine when your driver is in a nonpageable state, see
WdfDevStateIsNP .
Introduction to WMI for KMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


Kernel-Mode Driver Framework supports drivers that provide information to Windows Management
Instrumentation (WMI). Such drivers are called WMI data providers because they provide data to WMI clients,
which are applications that have registered to receive information from WMI.
WMI data providers support WMI data blocks, which can represent one or more of the following:
Data items, which contain device-specific data that a driver sends to, or receives from, a WMI client.
Methods (functions) that the driver executes on behalf of a WMI client.
Events that the driver sends to WMI clients that have registered to receive notification of device-specific
events.
WMI data blocks are specified as WMI classes in .mof files. Each WMI data block is identified by a GUID.
All drivers must support any standard WMI data blocks that WMI defines for their device class. These WMI data
blocks are defined in Wmicore.mof.
Your driver can also support WMI data blocks that you define in a .mof file. To learn how to define and publish
customized WMI data blocks, see the following sections:
MOF Syntax for WMI Data and Event Blocks
Designing WMI Data and Event Blocks
Publishing a WMI Schema
WMI Property Sheets
Framework WMI Objects and Callback Functions
The framework defines two objects that drivers can use to implement WMI data providers. The WMI provider
object represents the schema for WMI data blocks that the driver provides. The WMI instance object represents
an instance of a data block that is associated with a particular provider. Drivers communicate with WMI clients
by implementing the following event callback functions that these two objects define:
EvtWmiProviderFunctionControl
Enables and disables the driver's support for collecting WMI data and sending WMI events.
EvtWmiInstanceQueryInstance
Delivers a WMI provider's instance data to a WMI client.
EvtWmiInstanceSetInstance and EvtWmiInstanceSetItem
Set information in a driver's data block to client-supplied values.
EvtWmiInstanceExecuteMethod
Executes a driver-supplied method, at the request of a client.
Sample Drivers that Implement WMI
The FIREFLY, PCIDRV, and Toaster sample drivers are WMI data providers.
Initializing WMI Support in Your Driver
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


To support WMI data blocks, a framework-based driver:
Registers the managed object format (MOF) resource names of any customized WMI data providers that
are not defined in Wmicore.mof.
Creates one or more WMI instance objects to represent the data blocks it can read or write.
Optionally implements one or more event callback functions to supply the WMI data that the driver
provides.
Register each WMI instance object to make it available to WMI clients.
To initialize its WMI support, a KMDF driver follows these steps, typically within its EvtDriverDeviceAdd or
EvtDeviceSelfManagedIoInit callback:
1. A driver that provides a MOF file to support customized WMI data providers must call the
WdfDeviceAssignMofResourceName method to register a MOF resource name before the driver
creates WMI provider objects that represent the data provider.
2. Initialize a WMI provider configuration structure and optionally create a WMI provider object
(WDFWMIPROVIDER).
3. Initialize a WMI instance configuration structure and create a WMI instance object (WDFWMIINSTANCE).
The framework creates a WMI provider by default when a KMDF driver creates its first WMI instance. Therefore,
if the driver requires only one WMI provider, it is not required to call the provider-creation method
(WdfWmiProviderCreate ). However, the driver must fill in the provider configuration structure because this
structure supplies information about the provider that the framework uses when it creates the instance.
If your driver creates a single instance of each WMI data block that it supports, the driver calls
WdfWmiInstanceCreate , passing both a WDF_WMI_PROVIDER_CONFIG structure and a
WDF_WMI_INSTANCE_CONFIG structure. This single call both configures the single framework-provided
WMI provider object and creates a WMI instance object.
If your driver creates multiple instances of its WMI data blocks, the driver must call both
WdfWmiProviderCreate and WdfWmiInstanceCreate
Registering Provider Instances
Before WMI clients can access your driver's WMI data blocks, the driver must register its provider instances with
the system's WMI service. The driver can use either of the following techniques to register a provider instance:
Set the Register member of the provider instance's WDF_WMI_INSTANCE_CONFIG structure to
TRUE .
If your driver sets Register to TRUE , the framework automatically registers the instance the first time
that the device enters its working (D0) state.
Call the WdfWmiInstanceRegister method.
If your driver calls WdfWmiInstanceRegister after calling WdfWmiInstanceCreate , the framework
registers the instance after the device is in its working (D0) state.
The framework automatically deregisters each provider instance when the instance's device is removed (and
before it calls the EvtDeviceSelfManagedIoCleanup event callback function). For information about the order in
which the framework calls a driver's callback functions, see PnP and Power Management Scenarios.
Your driver can deregister an instance at any time by calling WdfWmiInstanceDeregister .
Supporting WMI Data Blocks and Events in Your
Driver
2/5/2021 • 3 minutes to read • Edit Online

[Applies to KMDF only]


Framework-based drivers support WMI data blocks by providing event callback functions. Drivers support WMI
events by calling an object method that sends an event to WMI clients.
Supporting Read/Write WMI Data Blocks
If the information in a WMI data block is both readable and writeable by WMI clients, the driver must provide an
EvtWmiInstanceQueryInstance callback function that services a client's read requests, plus
EvtWmiInstanceSetInstance or EvtWmiInstanceSetItem callback functions (or both) that service a client's write
requests.
If the data block contains methods that the driver executes at the client's request, the driver must also provide an
EvtWmiInstanceExecuteMethod callback function.
If a WMI data block is write-only (that is, WMI clients can write information to the data block but cannot read the
data block), the driver does not provide an EvtWmiInstanceQueryInstance callback function.
Supporting Read-Only WMI Data Blocks
If the information in a WMI data block cannot be modified by a WMI client, the driver does not provide
EvtWmiInstanceSetInstance or EvtWmiInstanceSetItem callback functions. To support requests for the data
block's information from WMI clients, the driver can do either of the following:
Provide an EvtWmiInstanceQueryInstance callback function to copy driver-supplied data into a WMI-
supplied buffer.
Store the data block's information in the WMI instance object's context space, and set the
UseContextForQuer y member of the instance's WDF_WMI_INSTANCE_CONFIG structure to TRUE .
If the driver sets UseContextForQuer y to TRUE , the framework copies the instance object's context space into
a WMI-supplied buffer when a WMI client requests the instance's information. No EvtWmiInstanceXxx callbacks
are required if the driver has only a single WMI instance that provides read-only, fixed-length data from its
object context area.
If a read-only data block contains methods that the driver executes at the client's request, the driver can also
provide an EvtWmiInstanceExecuteMethod callback function.
Supporting Expensive WMI Data Blocks
If your driver collects relatively large amounts of dynamic data to support one of its WMI data blocks, the driver
should do the following:
Declare the data block to be "expensive" by setting the WdfWmiProviderExpensive flag in the Flags
member of the WMI provider object's WDF_WMI_PROVIDER_CONFIG structure.
Provide an EvtWmiProviderFunctionControl callback function that enables and disables data collection
for the data block, or call WdfWmiProviderIsEnabled to determine whether the driver should enable
or disable data collection.
If your driver sets the WdfWmiProviderExpensive flag, the framework calls the
EvtWmiProviderFunctionControl callback function when a WMI client registers to access the data block. The
callback function should enable the driver's ability to collect data. If all WMI clients remove their registrations for
the data block, the framework calls the EvtWmiProviderFunctionControl callback function again so the driver
can stop collecting data.
Supporting WMI Events
A driver can use WMI events to notify WMI clients of exceptional conditions. (You should not use WMI events as
an alternative to logging errors.) Like data items, WMI events are defined in WMI data blocks within managed
object format (.mof) files.
WMI clients register for notification of WMI events. To send an event to registered WMI clients, your driver calls
the WdfWmiInstanceFireEvent method. This method allows the driver to optionally send event-specific data
to the clients.
If the WMI data block that defines the event also contains WMI data items or method items, the driver provides
appropriate WMI callback functions. If a data block defines an event but contains no data or method items, your
driver must set the WdfWmiProviderEventOnly flag in the Flags member of the WMI provider object's
WDF_WMI_PROVIDER_CONFIG structure.
The driver should call WdfWmiInstanceFireEvent only if a WMI client has registered for event notification.
The driver can determine if it should call WdfWmiInstanceFireEvent by either providing an
EvtWmiProviderFunctionControl callback function or calling WdfWmiProviderIsEnabled .
Supporting WMI Event Tracing
Trace events are defined in .mof files, in the same manner as other WMI events. When your driver creates a WMI
provider object for a trace event, it must set the WdfWmiProviderTracing flag in the Flags member of the
provider object's WDF_WMI_PROVIDER_CONFIG structure.
After a provider instance has been registered, the driver can call WdfWmiProviderGetTracingHandle to
obtain a tracing handle. The driver can use the tracing handle as input to the WmiTraceMessage routine.
For more information about event tracing, see:
WMI Event Tracing
WPP Software Tracing
Accessing WDM Interfaces in KMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


Most Kernel-Mode Driver Framework (KMDF) drivers do not need to access Windows Driver Model (WDM)
interfaces directly. This section describes the limited cases when a KMDF driver requires direct access to WDM
data structures, for example to obtain WDM information or manipulate an IRP.

In this section
Obtaining WDM Information
Handling WDM IRPs Outside of the Framework
WDM Interface Restrictions
Obtaining WDM Information
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


The framework provides several object methods that enable your driver to obtain WDM-defined information.
Obtaining WDM Information About the Driver and its Devices
To obtain WDM information about a driver and its devices, the driver can call the following methods:
WdfFdoInitWdmGetPhysicalDevice
Retrieves the DEVICE_OBJECT structure that represents a device's physical device object (PDO). A driver can
call this method before the driver has created a framework device object for the device.
WdfDeviceWdmGetPhysicalDevice
Retrieves the WDM DEVICE_OBJECT structure that represents a device's PDO. A driver can call this method after
it has created a framework device object for the device.
WdfDeviceWdmGetDeviceObject
Returns the WDM device object that is associated with a specified framework device object.
WdfDeviceWdmGetAttachedDevice
Returns the next-lower WDM device object in the device stack.
WdfWdmDeviceGetWdfDeviceHandle
Returns a handle to the framework device object that is associated with a specified WDM device object.
WdfWdmDriverGetWdfDriverHandle
Returns a handle to the framework driver object that is associated with a specified WDM driver object.
Obtaining WDM Information About I/O Requests
To obtain WDM information about I/O requests, a driver can call the following methods:
WdfRequestWdmGetIrp
Returns the WDM IRP structure that is associated with a specified framework request object. (On the other
hand, a driver that receives a WDM IRP outside of the framework can create a framework request object for the
IRP by calling WdfRequestCreateFromIrp .)
WdfRequestGetParameters
Retrieves the parameters that are associated with a specified framework request object. Most of these
parameters come from the request's WDM I/O stack location.)
WdfRequestRetrieveOutputWdmMdl
Retrieves a memory descriptor list (MDL) that represents an I/O request's output buffer.
WdfRequestRetrieveInputWdmMdl
Retrieves an MDL that represents an I/O request's input buffer.
WdfRequestFormatRequestUsingCurrentType
Copies the contents of the calling driver's I/O stack location to the I/O stack location of the driver's local I/O
target.
WdfRequestWdmFormatUsingStackLocation
Sets the contents of the I/O stack location for the driver's local I/O target.
Obtaining WDM Information About I/O Targets
To obtain WDM information about I/O targets, a driver can call the following methods:
WdfIoTargetWdmGetTargetDeviceObject
Returns a pointer to the WDM device object that is associated with a local or remote I/O target.
WdfIoTargetWdmGetTargetFileObject
Returns a pointer to the WDM FILE_OBJECT structure that is associated with a remote I/O target.
WdfIoTargetWdmGetTargetFileHandle
Returns a handle to the file that is associated with a remote I/O target.
WdfIoTargetWdmGetTargetPhysicalDevice
Returns a pointer to the WDM physical device object (PDO) that represents a remote I/O target's device.
Obtaining WDM Information About Interrupts and DPCs
To obtain WDM information about interrupts and deferred procedure calls (DPCs), a driver can call the following
methods:
WdfInterruptWdmGetInterrupt
Returns a pointer to the WDM KINTERRUPT structure that is associated with a specified framework interrupt
object.
WdfDpcWdmGetDpc
Returns a pointer to the WDM KDPC structure that is associated with a specified framework DPC object.
Obtaining WDM Information About USB I/O Targets
To obtain WDM information about USB I/O targets, a driver can call the following method:
WdfUsbTargetPipeWdmGetPipeHandle
Returns the USBD_PIPE_HANDLE-typed handle that is associated with a specified framework pipe object.
Obtaining WDM Information About the Registry
To obtain WDM information about the registry, a driver can call the following method:
WdfRegistr yWdmGetHandle
Returns a WDM handle to the registry key that a framework registry-key object represents.
Obtaining WDM Information About File Objects
To obtain WDM information about file objects, a driver can call the following method:
WdfFileObjectWdmGetFileObject
Returns the WDM FILE_OBJECT structure that is associated with a specified framework file object.
Handling WDM IRPs Outside of the Framework
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


When the I/O manager delivers an I/O request packet (IRP) to a framework-based driver, the framework
intercepts the IRP and then does one of the following:
Processes the IRP. For example, the framework processes IRPs that contain IRP_MJ_PNP and
IRP_MJ_POWER major I/O function codes. While processing these IRPs, the framework might
communicate with the driver by calling the driver's event callback functions.
Creates a framework request object for the IRP and delivers the request object to one of the driver's I/O
queues so that the driver can receive it, typically in a request handler, and process it. The framework
handles read, write, and device I/O control requests in this way.
Passes the IRP to the next-lower driver (if your driver is a filter driver), or completes the IRP with a status
value of STATUS_INVALID_DEVICE_REQUEST (if your driver is not a filter driver) because the IRP contains
an I/O function code that the framework does not support.
Sometimes a driver must handle an I/O function code that the framework does not support.
Rarely, a driver might need to preprocess an IRP before the framework handles it, or the driver might need to
postprocess an IRP after the framework and lower-level drivers have finished processing it.
As part of preprocessing, a driver might need to forward an IRP to a specific I/O queue.
The following topics describe these situations:
Handling an IRP that the Framework Does Not Support
Preprocessing and Postprocessing IRPs
Dispatching IRPs to I/O Queues
Handling an IRP that the Framework Does Not
Support
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


The framework does not support I/O requests that have the following major IRP codes:
IRP_MJ_CREATE_MAILSLOT
IRP_MJ_CREATE_NAMED_PIPE
IRP_MJ_DEVICE_CHANGE
IRP_MJ_DIRECTORY_CONTROL
IRP_MJ_FILE_SYSTEM_CONTROL
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_LOCK_CONTROL
IRP_MJ_QUERY_EA
IRP_MJ_QUERY_INFORMATION
IRP_MJ_QUERY_QUOTA
IRP_MJ_QUERY_SECURITY
IRP_MJ_QUERY_VOLUME_INFORMATION
IRP_MJ_SET_EA
IRP_MJ_SET_INFORMATION
IRP_MJ_SET_QUOTA
IRP_MJ_SET_SECURITY
IRP_MJ_SET_VOLUME_INFORMATION
If the framework receives an IRP that contains one of these I/O function codes, the framework does not process
the IRP. If your driver is a filter driver, the framework passes the IRP to the next-lower driver in the driver stack. If
your driver is not a filter driver, the framework calls IoCompleteRequest to complete the IRP with a status
value of STATUS_INVALID_DEVICE_REQUEST.
If your driver must handle IRPs that contain any of these I/O function codes, the driver must call
WdfDeviceInitAssignWdmIrpPreprocessCallback to register an EvtDeviceWdmIrpPreprocess event
callback function for an I/O function code.
When the driver receives an IRP that contains an I/O function code that the driver has registered an
EvtDeviceWdmIrpPreprocess callback function for, the framework passes the IRP to the callback function. The
callback function must then process the IRP by following the WDM rules for handling IRPs. The driver must call
IoCompleteRequest to complete the IRP, or it must call IoCallDriver to pass the IRP to the next-lower driver.
For an example of an EvtDeviceWdmIrpPreprocess callback function that handles an IRP that the framework
does not support, see the Serial sample driver.
Preprocessing and Postprocessing IRPs
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


If your driver must intercept an I/O request packet (IRP) before or after the framework handles the IRP, the driver
can call WdfDeviceInitAssignWdmIrpPreprocessCallback to register an EvtDeviceWdmIrpPreprocess event
callback function for a major I/O function code and, optionally, for specific minor I/O function codes that are
associated with the major code. Subsequently, the framework calls the driver's EvtDeviceWdmIrpPreprocess
callback function whenever the driver receives an IRP that contains a specified major and minor function code.
The EvtDeviceWdmIrpPreprocess callback function can do whatever is necessary to preprocess the IRP, and then
it must call WdfDeviceWdmDispatchPreprocessedIrp to return the IRP to the framework unless the driver is
handling an IRP that the framework does not support.
After the driver calls WdfDeviceWdmDispatchPreprocessedIrp , the framework processes the IRP in the
same way that it would have if the driver had not provided an EvtDeviceWdmIrpPreprocess callback function. If
the IRP's I/O function code is one that the framework passes to drivers, the driver will receive the IRP again as a
request object.
If the driver needs to postprocess the IRP after a lower-level driver completes the IRP, the driver's
EvtDeviceWdmIrpPreprocess callback function can call IoSetCompletionRoutine to set an IoCompletion
routine before it calls WdfDeviceWdmDispatchPreprocessedIrp .
After your driver calls WdfDeviceInitAssignWdmIrpPreprocessCallback , the framework causes the I/O
manager to add an additional I/O stack location to all IRPs so that the EvtDeviceWdmIrpPreprocess callback
function can set an IoCompletion routine. The callback function must update the IRP's I/O stack location pointer
before it calls WdfDeviceWdmDispatchPreprocessedIrp .
Calling WdfDeviceWdmDispatchPreprocessedIrp
Because the I/O manager adds an additional I/O stack location to the IRP, the EvtDeviceWdmIrpPreprocess
callback function must call IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext (to
set up the next I/O stack location in the IRP) before calling WdfDeviceWdmDispatchPreprocessedIrp .
If your driver is preprocessing an IRP, but not postprocessing the IRP, the driver does not need to set an
IoCompletion routine for the IRP and can call IoSkipCurrentIrpStackLocation , as the following code example
shows.

NTSTATUS
EvtDeviceMyIrpPreprocess(
IN WDFDEVICE Device,
IN OUT PIRP Irp
)
{
//
// Perform IRP preprocessing operations here.
//
...
//
// Deliver the IRP back to the framework.
//
IoSkipCurrentIrpStackLocation(Irp);
return WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
}
If your driver is postprocessing the IRP, the driver must call IoCopyCurrentIrpStackLocationToNext , and then
it must call IoSetCompletionRoutine to set an IoCompletion routine for the IRP, as the following code example
shows.

NTSTATUS
EvtDeviceMyIrpPreprocess(
IN WDFDEVICE Device,
IN OUT PIRP Irp
)
{
//
// Perform IRP preprocessing operations here, if needed.
//
...
//
// Set a completion routine and deliver the IRP back to
// the framework.
//
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
MyIrpCompletionRoutine,
NULL,
TRUE,
TRUE,
TRUE
);
return WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
}

Your driver must not call IoCopyCurrentIrpStackLocationToNext (and therefore must not set an
IoCompletion routine) if the device object handle that the driver's EvtDeviceWdmIrpPreprocess callback function
receives represents a physical device object (PDO), and if the IRP's major function code is IRP_MJ_PNP or
IRP_MJ_POWER. Otherwise, Driver Verifier will report an error.
For more information about when to call IoCopyCurrentIrpStackLocationToNext ,
IoSkipCurrentIrpStackLocation , and IoSetCompletionRoutine , see Passing IRPs down the Driver Stack.
Dispatching IRPs to I/O Queues
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF and UMDF]


A framework-based driver can dynamically specify a target queue for an incoming IRP. To dispatch an IRP to a
specific queue, a driver must call the WdfDeviceWdmDispatchIrpToIoQueue method.
Typically, a driver calls WdfDeviceWdmDispatchIrpToIoQueue from either its EvtDeviceWdmIrpPreprocess
or EvtDeviceWdmIrpDispatch callback function. For best performance, most drivers do not provide both callback
functions.
Note A UMDF driver can supply a EvtDeviceWdmIrpDispatch callback function, but only KMDF drivers can
provide EvtDeviceWdmIrpPreprocess.
If your driver already provides EvtDeviceWdmIrpPreprocess, you can use it to dynamically select a queue. If not,
provide EvtDeviceWdmIrpDispatch and call WdfDeviceWdmDispatchIrpToIoQueue from within that callback
function.
In addition, you should be aware of the following:
An alternate method for dispatching an IRP to an I/O queue is to create a default queue and then from
within the queue's handler, call WdfRequestFor wardToIoQueue . This technique is available starting in
KMDF 1.0 but does not work well with forward progress queues and is in general slower. Consider using
WdfDeviceWdmDispatchIrpToIoQueue instead.
When calling WdfDeviceConfigureWdmIrpDispatchCallback to register a EvtDeviceWdmIrpDispatch
callback function, the driver must set the MajorFunction parameter to one of the following:
IRP_MJ_DEVICE_CONTROL, IRP_MJ_INTERNAL_DEVICE_CONTROL, IRP_MJ_READ, IRP_MJ_WRITE. While
this requirement does not apply to EvtDeviceWdmIrpPreprocess, only IRPs of these types can be
dynamically dispatched to specified queues.
IRPs that go to EvtDeviceWdmIrpPreprocess have an additional stack location. IRPs that go to
EvtDeviceWdmIrpDispatch (without a previous invocation of EvtDeviceWdmIrpPreprocess) do not.
EvtDeviceWdmIrpPreprocess does not facilitate sending driver-defined context information, whereas
EvtDeviceWdmIrpDispatch does.

Dispatching Non-Preprocessed IRPs


To dispatch IRPs from a driver's EvtDeviceWdmIrpDispatch callback function, use the following procedure:
1. From its EvtDriverDeviceAdd callback function, the driver calls
WdfDeviceConfigureWdmIrpDispatchCallback to register a EvtDeviceWdmIrpDispatch callback
function.
If the target is the parent device's I/O queue, a KMDF driver must call
WdfPdoInitAllowFor wardingRequestToParent before it calls WdfDeviceCreate . If a KMDF driver
has also provided a EvtDeviceWdmIrpPreprocess callback function, the framework calls that function first
when an IRP arrives. After the callback function preprocesses the request, it calls
WdfDeviceWdmDispatchPreprocessedIrp to return the IRP to the framework.
2. The framework calls the driver's EvtDeviceWdmIrpDispatch callback function.
3. From within EvtDeviceWdmIrpDispatch, the driver can call either
WdfDeviceWdmDispatchIrpToIoQueue or WdfDeviceWdmDispatchIrp , but not both. A KMDF
driver has the additional option of calling neither of these methods, and instead completing the IRP or
marking it pending.
4. If a KMDF driver has set the WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK flag
and has not enabled guaranteed forward progress for the target I/O queue, the framework then calls the
driver's EvtIoInCallerContext, if provided. After preprocessing the request, the callback function must
either queue it by calling WdfDeviceEnqueueRequest or complete it by calling
WdfRequestComplete .

Dispatching Preprocessed IRPs


To dispatch IRPs from a driver's EvtDeviceWdmIrpPreprocess callback function to a specific I/O queue, use the
following procedure:
1. The driver registers a EvtDeviceWdmIrpPreprocess callback function by calling
WdfDeviceInitAssignWdmIrpPreprocessCallback .
2. The driver calls WdfPdoInitAllowFor wardingRequestToParent if the target is the parent device's I/O
queue.
3. From EvtDeviceWdmIrpPreprocess, call WdfDeviceWdmDispatchIrpToIoQueue with Flags set to
WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP.
4. If the driver has set the WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK flag and has
not enabled guaranteed forward progress for the target I/O queue, the framework then calls the driver's
EvtIoInCallerContext, if provided. After the callback function has finished preprocessing the request, it must
either queue it by calling WdfDeviceEnqueueRequest or complete it by calling WdfRequestComplete .
WDM Interface Restrictions
2/5/2021 • 2 minutes to read • Edit Online

[Applies to KMDF only]


If your framework-based driver accesses WDM interfaces, you must be aware of the following restrictions:
Framework-based drivers must not use the Tail.Overlay.DriverContext member of the IRP structure,
because the framework uses this member.
UMDF 1.x Design Guide
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

This section contains information that applies only to User-Mode Driver Framework (UMDF) versions 1.11 and
earlier.
Windows 8.1 introduces UMDF version 2. For more information, see Getting Started with UMDF.
For more information about which versions of UMDF are available in specific versions of Windows, see UMDF
Version History.

In this section
UMDF Objects and Interfaces
Initializing UMDF Drivers
PnP and Power Management in UMDF Drivers
Processing I/O Requests
Using I/O Targets in UMDF
Accessing Hardware and Handling Interrupts
UMDF Driver Tasks

Additional resources for UMDF version 1


Architecture of the User-Mode Driver Framework
A COM QuickStart for UMDF Developers
UMDF Objects and Interfaces
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The User-Mode Driver Framework (UMDF) is composed of a set of cooperating objects. The UMDF creates and
manages a series of objects exposed to the user-mode device driver. Some of theses objects are created by the
UMDF in response to application-triggered actions, such as an I/O request, while other UMDF objects are
created when the driver calls UMDF interface methods. For example, to create an I/O queue object, the driver
calls the IWDFDevice::CreateIoQueue method.
The following topics describe the core framework objects, the subset of the Component Object Model (COM) on
which they are based, and the UMDF DDI programming model:
Framework Objects
Framework Object Hierarchy
UMDF Based on COM Subset
UMDF DDI Programming Model
Managing the Lifetime of Objects
Framework Objects
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The following table provides basic information about each framework object, links to the object's interface, and
links to more information about the core framework objects.

C A N DRIVER
O B JEC T IN T ERFA O VERRIDEDEFA U C A N DRIVER
O B JEC T N A M E CE P URP O SE DEFA ULT PA REN T LT PA REN T ? OWN?

Driver object IWDFDriver Represents a None No No


driver

Device object IWDFDevice Represents a Driver object No No


device

File object IWDFFile Represents a Device No No, if


file object created by
framework;
Yes, if
created by
driver

Interrupt IWDFInterrupt Represents Device No Yes


object an interrupt object

Queue IWDFIoQueu Represents Device No Yes


object e an I/O object
queue that
receives I/O
requests

Request IWDFIoRequ Represents Device No, if No, if


object est an I/O object created by created by
request framework; framework
Yes, if (for example,
created by redirected
driver requests);
Yes, if
created by
driver
C A N DRIVER
O B JEC T IN T ERFA O VERRIDEDEFA U C A N DRIVER
O B JEC T N A M E CE P URP O SE DEFA ULT PA REN T LT PA REN T ? OWN?

Target object IWDFIoTarge Represents a Device No No, for the


t driver that object default
another target; Yes,
driver sends for all other
requests to targets

USB device IWDFUsbTar Represents a Device No Yes (see


object getDevice device that is object target
connected to object)
USB

USB pipe IWDFUsbTar Represents a Device No Yes (see


object getPipe USB device object target
pipe object)

USB interface IWDFUsbInt Represents a Device No Yes (see


object erface USB device object target
interface object)

Base object IWDFObject Represents a Driver object Yes Yes, if


general base created by
object driver

Memory IWDFMemor Represents a Driver object Yes No, if


object y memory created by
object framework;
Yes, if
created by
driver
Framework Base Object
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework base object is exposed to drivers by the IWDFObject interface. It provides basic functionality that
is common across all framework object types. All framework objects are derived from this root object.
When drivers create framework base objects through a call to the IWDFDriver ::CreateWdfObject method,
they can initially register their IObjectCleanup interfaces so that the framework notifies the driver when the
objects are about to be destroyed. Later, drivers can use the IWDFObject::AssignContext method to change
how they receive notifications on the framework base object instance.
Framework Driver Object
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework driver object is exposed to drivers by the IWDFDriver interface. It is the framework
representation of the driver image loaded in the driver host process. The framework creates a new driver object
for each driver loaded in the driver host process. The IWDFDriver interface is passed to the driver by the
IDriverEntr y::OnInitialize method, which is the main entry point for the user-mode driver.
Framework Device Object
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework device object is exposed to drivers by the IWDFDevice interface. The framework device object is
the framework representation of the device on the system. Each device object has a parent driver object.
When a new device arrives in the system, the framework calls the IDriverEntr y::OnDeviceAdd method to
notify the driver of the arrival and passes the IWDFDriver and IWDFDeviceInitialize interfaces in the call. The
driver can call methods of the IWDFDeviceInitialize interface to initialize the new device. For example, the driver
calls the IWDFDeviceInitialize::RetrieveDeviceProper tyStore method to query for the device information
that is provided as part of device installation. The driver can then call the IWDFDriver ::CreateDevice method
to configure and create the device object.
When drivers create a framework device object, they can register their IPnpCallback,
IPnpCallbackSelfManagedIo, IPnpCallbackHardware, IFileCallbackCleanup, and IFileCallbackClose interfaces. The
framework then notifies the driver when file cleanup and close and Plug and Play (PnP) and power management
(PM) events occur. For more information about supporting PnP and PM, see PnP and Power Management in
UMDF-based Drivers.
Framework File Object
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework file object is exposed to drivers by the IWDFFile interface. It is the framework representation of
the opened device. When an application opens the device through the Microsoft Win32 CreateFile function, the
framework creates a file object to represent the opened device instance. Therefore, the framework file object is
conceptually equivalent to the Win32 handle that is returned from the application's call to CreateFile . The
framework can create multiple file objects associated with a single device. Each file object is created for each
successful call to CreateFile . All I/O operations, like reads and writes, are targeted to a specific file-object
instance.
Note All requests passed to UMDF drivers are associated with file objects. However, requests that are passed to
WDM and KMDF drivers are sometimes not associated with file objects.
A UMDF driver can call the IWDFIoRequest::GetFileObject method to obtain the file object associated with a
request.
When your driver calls GetFileObject , the framework increments the reference count on the interface. Your
driver is responsible for releasing the reference when finished with the interface pointer. To do so, either use a
smart pointer that automatically decrements the reference count when the object goes out of context, or call
Release on the interface when finished with it. For a code example that shows how to use a smart pointer, see
GetFileObject .
Framework I/O Queue Object
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework I/O queue object is exposed to drivers by the IWDFIoQueue interface. It represents an I/O queue,
which is a container for I/O requests. An I/O queue controls the flow of requests into the driver. When an I/O
request arrives, it is placed in the appropriate queue. I/O queue objects are children of UMDF device objects. A
driver can call the IWDFDevice::CreateIoQueue method to create I/O queue objects. In the call to
IWDFDevice::CreateIoQueue , the driver can specify whether the queue is the default queue.
When the driver creates an I/O queue, it specifies a dispatch model that controls the delivery of requests to the
driver. For more information, see Configuring Dispatch Mode for an I/O Queue.
When drivers create I/O queues, they can provide interfaces for callback functions that the framework calls to
notify the driver when events related to the interfaces occur. For more information, see I/O Queue Event
Callback Functions.
Framework I/O Request Object
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework I/O request object is exposed to drivers by the IWDFIoRequest interface. It encapsulates the
details of an I/O operation. All I/O requests are represented as framework I/O request objects. The reflector
notifies the driver host process when the reflector receives an I/O request packet (IRP) as the result of an
application I/O operation, such as, a call to the Microsoft Win32 CreateFile or ReadFile function. The
framework, in response to the reflector notification, constructs a new request object and puts it in the
appropriate I/O queue. The queue configuration and the locking model chosen by the user-mode driver
determine when the request is presented to the driver. For more information, see Configuring Dispatch Mode
for an I/O Queue and Specifying a Callback Synchronization Mode.
Framework I/O Target Object
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework I/O target object is exposed to drivers by the IWDFIoTarget interface. It retrieves information
about an I/O target, which typically represents a lower driver in the stack but can also represent another UMDF
driver or the kernel-mode portion of the stack. The I/O target object provides UMDF drivers a way to send
requests to another device.
UMDF drivers can also use the IWDFIoTargetStateManagement interface to manage and monitor the state of an
I/O target object.
Framework Interrupt Object
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework interrupt object is exposed to drivers by the IWDFInterrupt interface. It represents a hardware
interrupt. Interrupt objects are children of UMDF device objects. A driver can call the
IWDFDevice3::CreateInterrupt method to create an interrupt object.
When drivers create interrupts, they can provide interfaces for callback functions that the framework calls to
notify the driver when events related to the interfaces occur. For more information, see UMDF Interrupt Object
Event Callback Functions.
For more information about interrupt objects, see Handling Interrupts.
Framework Memory Object
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework memory object is exposed to drivers by the IWDFMemory interface. It provides access to a
memory block.
Framework Object Hierarchy
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The following figure shows the parent-child framework object hierarchy.

The lifetime scope of framework objects is determined by their location in the hierarchy and how the objects are
created. The lifetime scope of framework objects falls into one of the following categories:
The framework controls the creation and destruction of the objects.
The framework creates and destroys objects, such as the driver object and device object, in response to
system events. When a user-mode driver calls the IWDFDriver ::CreateDevice method to create the
device object, the driver can optionally register to be notified by the framework before the device object
is destroyed.
The framework creates the object; however, the driver controls when the object is released.
The I/O request object follows this pattern when I/O is presented to the driver. The framework creates the
request object, and the request object's lifetime is valid until the driver calls the
IWDFIoRequest::Complete method.
The driver creates the object and associates the object with another framework object.
Some framework objects are created by a method that is exposed by a parent framework object instance
that the objects are to be associated to for lifetime-management purposes. The
IWDFDevice::CreateIoQueue method is an example of this pattern. If a call to
IWDFDevice::CreateIoQueue succeeds, the newly created I/O queue is associated with the device
instance that the IWDFDevice interface represents. When the parent object is destroyed, the framework
automatically cleans up child instances. Drivers are notified of these events if the drivers register
appropriate callback functions with the framework.
UMDF Based on COM Subset
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework objects and interfaces are based on the Component Object Model (COM) for the following
reasons:
COM is familiar to many applications programmers.
C++ is the preferred language for programming COM applications.
COM interfaces enable logical groupings of functions, so that the device driver interface (DDI) is easy to
understand and navigate.
Using COM enables the DDI to extend and evolve without requiring existing driver DLLs to be
recompiled.
Numerous tools, including Microsoft Visual Studio and active template library (ATL), support COM-based
applications and objects.
The framework uses only a small subset of COM; it does not depend on the entire COM infrastructure and
runtime library. Instead, the framework uses only the query-interface and reference-counting features. Every
framework interface derives from IUnknown and therefore supports the Quer yInterface , AddRef , and
Release methods by default. The AddRef and Release methods manage object lifetime. The Quer yInterface
method enables other components to determine which interfaces the driver supports.
UMDF DDI Programming Model
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework and the UMDF driver communicate through the UMDF DDI. The UMDF DDI is similar to the
KMDF DDI except that the UMDF DDI is based on COM. Therefore, driver writers familiar with KMDF will
understand UMDF.
For each type of framework object, the UMDF defines an interface through which to manipulate instances of the
object. Each interface supports methods and properties. Methods define actions that can be taken on behalf of
the object and properties set and retrieve the characteristics of the object. Some interfaces are implemented by
the framework and others are implemented by the driver. Interfaces that are exposed by a framework object are
of the form IWDF<object>, while the event callback interfaces exposed by a driver are of the form I<object>
<action>, where <object> represents a queue, request, and so on, and <action> indicates what the interface
does. Methods of the callback interfaces begin with "On".
The UMDF driver communicates with the framework's objects through their methods and properties. The
framework communicates with the driver through event notifications, which are callback functions that the
framework can call to notify the driver about specific events. To register callback functions, the driver can call, for
example, the following framework object methods and can pass a pointer to the IUnknown interface associated
with all the interfaces for the callback functions that the driver supports.
IWDFDevice::CreateIoQueue
IWDFDriver ::CreateDevice
IWDFDriver ::CreateWdfObject
As an example of driver to framework communication, consider a device's default I/O queue object. A driver can
call methods, such as IWDFIoQueue::GetState , to retrieve status information about the I/O queue, or
IWDFIoQueue::RetrieveNextRequest to retrieve a request from the I/O queue. A driver can also request for
notifications on the I/O queue by calling the IWDFDevice::CreateIoQueue method to register callback
interfaces, such as IQueueCallbackRead and IQueueCallbackWrite. The methods of these interfaces are
subsequently called by the framework when an application sends read and write requests.
The framework provides any synchronization required across driver callback methods. By default, the
framework synchronizes at device object level; that is, the framework does not concurrently call the event
callback methods at or below the device object level. A driver can override this default by requesting no
synchronization. For more information, see Specifying a Callback Synchronization Mode.
Managing the Lifetime of Objects
2/5/2021 • 3 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

UMDF uses a reference-counting scheme to manage the lifetime of callback objects and framework objects.

Managing References to Driver-Supplied Callback Objects


In most cases, a driver is not required to keep a reference to a callback object. If methods of the callback object
interface are called only by the framework and by objects whose lifetimes depend on the callback object and the
callback object's paired framework object, the driver does not have to keep a reference. In other words, the
driver or framework can safely call methods of object interfaces that are higher up in the object hierarchy.

Managing References to Framework Objects


In UMDF, general COM lifetime principles and the WDF-specific lifetime model determine the lifetime of
framework objects. Your driver must satisfy criteria for both models so that framework objects are freed from
memory at appropriate times.
COM Lifetime Management
In COM, a caller typically keeps a reference to the object while the object is in use, and then the caller releases
the reference when it no longer requires the object. However, a UMDF driver does not need to keep a reference
to a framework object. In fact, the driver can release a framework object reference immediately after the driver
creates the framework object.
For example, UMDF samples release the device object after they call IWDFDriver ::CreateDevice . Although the
reference is released early, the device object continues to exist until device is removed because the WDF object
tree keeps a reference to it.
Because UMDF tracks all framework objects in an object tree, the driver does not need to keep a reference to
framework objects.
However, if your driver keeps a reference to a framework object, the driver must release the reference when it
no longer needs the object. A circular reference remains in place until the driver releases its reference. To avoid
circular references, the driver typically should not keep an explicit reference to a framework object.
If the driver must keep a reference to a framework object, the driver's callback object must also implement the
IObjectCleanup interface. When the driver calls IWDFObject::DeleteWdfObject on the framework object, the
framework object calls its corresponding callback object's IObjectCleanup::OnCleanup method. The
implementation of IObjectCleanup::OnCleanup must release the reference to the framework object to enable
the framework to complete tear down of the framework object.
WDF Lifetime Management
If you are creating an object of a type that allows you to override the default parent, you should select a parent
with a lifetime that matches the lifetime of your object. For more information about default parent objects and if
the driver can override the default parent, see the table in Framework Objects.
If you match object lifetimes, the framework deletes your object when the parent object is deleted. If you do not
match object lifetimes and you want the object to be deleted before the default parent is deleted, you can
explicitly delete the object by calling DeleteWdfObject when the object is no longer needed.
For example, if you create a new request object and then call IWDFDriver ::CreateWdfMemor y to create a
memory object for this request, you can specify the request object as the parent of the new memory object.
Because WDF deletes child objects when the parent object is deleted, the driver does not need to call
DeleteWdfObject to delete the memory object.
However, if there is no parent whose lifetime closely matches your object's lifetime, and if you want the object to
be deleted before the default parent is deleted, you must use explicit deletion. For example, a driver could create
several request objects that are used for a short duration. In this case, the driver can conserve memory by
explicitly deleting the requests when they are no longer needed.
Similarly, if you are creating an object that does not allow you to override the default parent and if you want the
object to be deleted before the default parent is deleted, the driver must explicitly delete the object.
Initializing UMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

Before a UMDF driver for a device is initialized, the driver manager and the reflector are loaded by the operating
system and the driver host process is created. To ensure that a device starts successfully, the driver manager is
loaded and fully initialized by the time the reflector initializes.
When the device is installed, the Plug and Play (PnP) subsystem loads the reflector, if not already loaded. The
reflector then contacts the driver manager to create the driver host process. The framework within the newly
created driver host process then calls the IDriverEntr y::OnInitialize method to initialize the UMDF driver, if
not already initialized.
The framework adds a new device object for each device loaded in the driver host process. The following
sections show an overview and provide details on how the framework adds a new device:
Adding a Device Overview
Adding a Device
Adding a Device Overview
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The following figure shows an overview of how the framework adds a new device:
Adding a Device
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework adds a device object for each device loaded in the driver host process. To add the device, the
framework calls the driver's IDriverEntr y::OnDeviceAdd method and passes the IWDFDriver and
IWDFDeviceInitialize interfaces in the call. The supplied IWDFDeviceInitialize interface is only valid before the
driver calls IWDFDriver ::CreateDevice . The driver can call the following methods of IWDFDeviceInitialize to
perform the following operations:
The driver calls the IWDFDeviceInitialize::RetrieveDeviceProper tyStore method to retrieve the
IWDFNamedPropertyStore interface for the device property store. The driver can use
IWDFNamedProper tyStore to retrieve and set properties for the device.
The driver calls the IWDFDeviceInitialize::SetLockingConstraint method to specify how its callback
functions are called by the framework.
The driver calls the IWDFDeviceInitialize::SetFilter method to enable the device as a filter device.
After the driver uses IWDFDeviceInitialize to initialize the device, the driver passes a pointer to
IWDFDeviceInitialize in a call to the IWDFDriver ::CreateDevice method to create a UMDF device object for
the device. After the framework device object is created, the driver makes calls to the
IWDFDevice::CreateIoQueue method to create read and write I/O queues. In these
IWDFDevice::CreateIoQueue calls, the driver must identify how it receives requests from the I/O queue. For
more information, see Configuring Dispatch Mode for an I/O Queue.
PnP and Power Management in UMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

In this section
PnP and Power Management Interfaces
Power Policy Ownership in UMDF
PnP and Power Management Scenarios in UMDF
PnP and Power Management Interfaces
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

When a new device arrives in the system, the framework calls the IDriverEntr y::OnDeviceAdd method to
notify the UMDF driver of the arrival and passes the IWDFDriver and IWDFDeviceInitialize interfaces in the
call. The driver calls the IWDFDriver ::CreateDevice method to create a framework device object for the
device.
When drivers create a framework device object, they can register the following interfaces so that the framework
notifies the driver—by calling the methods associated with the interfaces—when Plug and Play (PnP) and power
management (PM) events occur.
IPnpCallback
IPnpCallbackSelfManagedIo
IPnpCallbackHardware
IPowerPolicyCallbackWakeFromS0
IPowerPolicyCallbackWakeFromSx
Power Policy Ownership in UMDF
2/5/2021 • 3 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

For each device, one (and only one) of the device's drivers must be the device's power policy owner. The power
policy owner determines the appropriate device power state for a device and sends requests to the device's
driver stack whenever the device's power state should change.
Framework-based drivers do not contain code that requests changes in a device's power state, because the
framework provides that code. By default, whenever the system enters a system sleeping state, the framework
asks the driver for your device's bus to lower the device power state to D3. (Your driver can change the default
behavior so that the framework sets your device's sleep state to D1 or D2, if the device provides wake-up
capabilities.) When the system power returns to its working (S0) state, the framework requests the bus driver to
restore your device to its working (D0) state.
The power policy owner is also responsible for enabling and disabling the following device features:
Your device's ability to enter a low-power (sleeping) state when it is idle and the system remains in its
working (S0) state
Your device's ability to wake itself from a sleeping state when it detects an external event
Your device's ability to wake up the entire system from a system sleeping state when it detects an external
event
If your device supports these idle power-down and system wake-up capabilities, the power policy owner can
also support the framework's IPowerPolicyCallbackWakeFromS0 and IPowerPolicyCallbackWakeFromSx
interfaces, which define a set of power policy event callback functions.
By default, UMDF-based drivers are not power policy owners. The device's kernel-mode function driver is the
default power policy owner. (If there is no kernel-mode function driver and the bus driver has called
WdfPdoInitAssignRawDevice , the bus driver is the power policy owner). If you want your UMDF-based driver
to be the power policy owner for a driver stack, the driver must call
IWDFDeviceInitialize::SetPowerPolicyOwnership , and the kernel-mode default power policy owner must
call WdfDeviceInitSetPowerPolicyOwnership to disable ownership.
In addition, if you are providing a UMDF-based driver for a USB device, and if you want your driver to be the
power policy owner, the driver's INF file must contain an INF AddReg directive that sets the
WinUsbPowerPolicyOwnershipDisabled value in the registry. If this REG_DWORD-sized value is set to any
nonzero number, it disables the WinUSB driver's ability to be the device's power policy owner. The AddReg
directive must be in an INF DDInstall.HW section , as the following example shows.
[MyDriver_Install.NT.hw]
AddReg=MyDriver_AddReg

[MyDriver_AddReg]
HKR,,"WinUsbPowerPolicyOwnershipDisabled",0x00010001,1

The framework does the following work for the power policy owner:
It handles all power policy communication between your driver and the rest of the driver stack. For
example, your driver does not have to request the bus driver to change the device's power state, because
the framework makes the request.
If your driver registers power policy event callback functions, the framework calls them when it is time to
enable or disable the device's ability to wake itself from a low-power state.
If your driver allows users to modify idle and wake settings, the framework provides a user interface in
the form of a property sheet page that Device Manager displays.
For more information about the power policy owner's responsibilities, see the following topics:
Supporting Idle Power-Down in UMDF-based Drivers
Supporting System Wake-Up in UMDF-based Drivers
User Control of Device Idle and Wake Behavior in UMDF
Supporting Idle Power-Down in UMDF Drivers
2/5/2021 • 3 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

Some devices can enter a sleeping state while the system remains in its working state. For such devices, the
framework initiates lowering the device's power after the device has been idle (not used) for a predetermined
(and settable) amount of time.
Some of these devices can also trigger a wake-up signal on the bus when they detect an external event. The bus
driver responds to this signal, and the driver stack restores the device to its working state. (Devices that do not
detect external events remain in a low-power state until the framework asks the bus driver to initiate restoring
the device to its working state.)
If your device can be powered down when it is idle, the power policy owner must perform the following two
steps:
1. Call IWDFDevice2::AssignS0IdleSettings or IWDFDevice3::AssignS0IdleSettingsEx to specify:
The low-power state that the device will enter
The amount of time that the device must remain idle before its power state is lowered
Whether the device can detect an external event and trigger a wake-up signal on the bus
Whether users can control the device's idle settings
Whether the framework can put the device in the D3cold power state when the idle timeout period
expires
If your driver was built with version 1.11 or later of the framework, you can call
IWDFDevice3::AssignS0IdleSettingsEx instead of IWDFDevice2::AssignS0IdleSettings . In addition
to the above functionality, IWDFDevice3::AssignS0IdleSettingsEx allows the driver to specify:
Whether the device's idle power-down capability is enabled or disabled
Whether the device will return to its working (D0) state when the system returns to its working (S0)
state
2. Implement the IPowerPolicyCallbackWakeFromS0 interface and the following event callback functions, if
you need them for your device:
IPowerPolicyCallbackWakeFromS0::OnArmWakeFromS0 , which enables the device hardware
(not the bus) to respond to an external wake-up event.
IPowerPolicyCallbackWakeFromS0::OnDisarmWakeFromS0 , which disables the device's ability
(not the bus's ability) to respond to an external wake-up event.
IPowerPolicyCallbackWakeFromS0::OnWakeFromS0Triggered , which informs the driver that
the bus detected a wake signal.
The framework considers the device to be idle, and starts counting idle time, when all of the following
conditions are met:
None of the power-managed queues created for this device instance have any requests waiting in queue or
dispatched to the driver. If a request was dispatched to the driver and the driver sent it to an I/O target, the
request is still related to the queue and the device will not be considered idle. Requests in non-power–
managed queues are not counted toward device idle.
If the driver previously called IWDFDevice2::StopIdle , the driver has subsequently called
IWDFDevice2::ResumeIdle .
If the power policy owner is a bus driver, none of the child devices of the bus driver are in D0.
If your driver (or a user) enables idle power-down for your device, you might have to use the
IWDFDevice2::StopIdle method. If the device is in its working (D0) state, this method prevents the device from
idling until the driver calls IWDFDevice2::ResumeIdle . If the device is in a low-power state when the driver
calls IWDFDevice2::StopIdle , and if the system is in its working (S0) state, the framework requests the bus
driver to restore the device to its working (D0) state. For more information about when your driver might have
to call IWDFDevice2::StopIdle , see the method's reference page.
If the device can wake itself from a low-power state, the driver for the device's bus participates in waking the
device. The kernel-mode bus driver does whatever is necessary on the bus adapter to enable and disable a
device's ability to wake from a low-power state.
For information about registry entries that control a device's idle capabilities, see User Control of Device Idle and
Wake Behavior in UMDF.
Supporting System Wake-Up in UMDF Drivers
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

While the system is in a low-power state, some devices can detect an external event, such as an incoming
network packet, and then wake the system. For example, if a PCI device has a system wake-up capability, as
indicated in the device's Power Management Capabilities (PMC) register, it wakes the system by raising the
Power Management Event (PME) signal on the PCI bus.
If your device can wake the system from a system-wide low-power state, the IDriverEntr y::OnDeviceAdd
callback function in the power policy owner must perform the following two steps:
1. Call IWDFDevice2::AssignSxWakeSettings to specify:
The low-power state that the device will enter
Whether users can control the device's idle settings
Whether the device's wake capability is enabled or disabled
2. Implement the IPowerPolicyCallbackWakeFromSx interface and the following event callback functions, if
you need them for your device:
IPowerPolicyCallbackWakeFromSx::OnArmWakeFromSx , which enable the device hardware to
respond to an external wake-up event.
IPowerPolicyCallbackWakeFromSx::OnDisarmWakeFromSx , which disables the device's ability
to respond to an external wake-up event.
IPowerPolicyCallbackWakeFromSx::OnWakeFromSxTriggered , which informs the driver that the
bus detected a wake signal.
Bus drivers also participate in waking up the system. The kernel-mode driver for the device's bus does whatever
is necessary on the bus adapter to enable and disable a device's ability to wake from a low-power state.
For information about registry entries that control a device's wake capabilities, see User Control of Device Idle
and Wake Behavior in UMDF.
User Control of Device Idle and Wake Behavior in
UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

If a device has idle power-down or wake-up capabilities, you can decide whether users should be allowed to
enable or disable these capabilities.
Your UMDF-based driver can use the IWDFDevice2::AssignS0IdleSettings method to specify whether users
with registry access can enable or disable a device's idle power-down capability.
Your driver can use the IWDFDevice2::AssignSxWakeSettings method to specify whether users with registry
access can enable or disable a device's wake-up capability.
Both of these methods allow the driver to enable the capability, disable the capability, or give users control of the
capability:
When a driver calls the AssignS0IdleSettings method, it can give users control of a device's idle
capabilities by setting the UserControlOfIdleSettings parameter to IdleAllowUserControl and setting
the Enabled parameter to WdfTrue or WdfUseDefault .
When a driver calls the AssignSxWakeSettings method, it can give users control of a device's wake
capabilities by setting the UserControlOfWakeSettings parameter to WakeAllowUserControl and
setting the Enabled parameter to WdfTrue or WdfUseDefault .
If your driver allows users to modify idle and wake settings, the framework provides a user interface, in the form
of a property sheet page that Device Manager displays so that users can enable or disable the idle and wake
capabilities. (The framework modifies IdleInWorkingState and WakeFromSleepState registry values. Drivers
and their installation files must not read or modify these values.)
If a user modifies a device's settings, the framework updates the device's power state to match the new settings,
if necessary. For example, if the user disables a device's idle power-down capability while the device is already in
a low-power state because it was idle, the framework returns the device to its working state.
If your driver allows users to modify idle and wake settings, the framework enables these settings by default.
Some driver writers might want to initially disable the settings before allowing users to modify them.
Therefore, versions 1.9 and later of the framework provide two driver-definable registry values, named
WdfDefaultIdleInWorkingState and WdfDefaultWakeFromSleepState , which are stored in the device's
Device Parameters\WDF subkey, under the device's hardware key. The values are REG_DWORD-typed, with
"0" indicating the capability is disabled and "1" indicating the capability is enabled.
Your driver's INF file can use an INF AddReg directive to create and set the WdfDefaultIdleInWorkingState
and WdfDefaultWakeFromSleepState registry values. For example, if your driver enables a device's idle
power-down capability, but if the capability must be disabled when the device is installed, the driver's INF file
can set WdfDefaultIdleInWorkingState to "0".
The framework examines the WdfDefaultIdleInWorkingState registry value only if the driver sets the
UserControlOfIdleSettings parameter to IdleAllowUserControl and the Enabled parameter to WdfTrue or
WdfUseDefault when the driver calls the IWDFDevice2::AssignS0IdleSettings method.
The framework examines the WdfDefaultWakeFromSleepState registry values only if the driver sets the
UserControlOfWakeSettings parameter to IWakeAllowUserControl and the Enabled parameter to WdfTrue
or WdfUseDefault when the driver calls the IWDFDevice2::AssignSxWakeSettings method.
PnP and Power Management Scenarios in UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The following PnP and power management scenarios show the sequences in which the framework calls a UMDF
driver's event callback functions:
A User Plugs in a Device
A User Unplugs a Device
A Device Enters a Low-Power State
A Device Returns to Its Working State
The PnP Manager Redistributes System Resources
For information about PnP and power management callback sequences for KMDF drivers, see PnP and Power
Management Callback Sequences.
A User Plugs in a Device (UMDF 1)
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

When a user plugs in a device, the framework calls a UMDF driver's PnP and Power Management callback
methods in the following sequence, starting from the Device Arrived state at the bottom of the figure:

The framework begins by calling the driver’s IDriverEntr y::OnDeviceAdd callback so that the driver can
create a device callback object and a framework device object to represent the device. The framework continues
calling the driver’s callback routines by progressing up through the sequence until the device is operational.
The framework proceeds through this sequence for each UMDF function or filter driver that supports the device,
one driver at a time, starting with the driver that is lowest in the driver stack.
A User Unplugs a Device (UMDF 1)
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

While a system is running, a user can remove a device in one of the following two ways: by orderly removal,
which means that the user informs the system that the device is about to be removed (for example, by using the
Unplug or Eject Hardware program); or by surprise removal, which means that the user unplugs the device
without informing the system. If the bus supports surprise removal (for example, USB), the device's drivers must
be able to handle the device's sudden disappearance.
Orderly Removal
The user requests removal by using the system's Unplug or Eject Hardware program, by disabling the device by
using Device Manager, or by pushing an ejectable device's eject button. The framework allows the device to be
removed or disabled, unless the driver has supplied an IPnpCallback ::OnQuer yRemove callback function,
and the callback function has vetoed the removal.
The following figure shows the sequence of UMDF callbacks in power-down and removal. The sequence starts at
the top of the figure with a device that is in the working power state (D0).

Surprise Removal
In this scenario, a user unplugs a device unexpectedly. In the surprise-removal sequence, UMDF calls the
IPnpCallback ::OnSurpriseRemoval callback to notify the driver that the device has been unexpectedly
removed. This callback is not guaranteed to occur in any particular order with the other callbacks in the removal
sequence.
Generally, the driver should avoid accessing the hardware in the remove path. The reflector times out if an
attempt to access the hardware waits indefinitely. The following figure shows the surprise-removal sequence for
a UMDF driver.
A Device Enters a Low-Power State (UMDF 1)
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

A device leaves its working (D0) state and enters a low-power state if one of the following occurs:
The device is idle (that is, not being accessed) and is capable of entering a low-power idle state while the
system remains in its working (S0) state.
The system's power state has changed from its working (S0) state to a low-power state. (Drivers can call
IWDFDevice2::GetSystemPowerAction to determine the reason for the change in the system's power
state.)
For each UMDF-based function and filter driver that supports the device, the framework does the following, in
sequence, one driver at a time, starting with the driver that is highest in the driver stack:
1. If the driver is using self-managed I/O, the framework calls the driver's
IPnpCallbackSelfManagedIo::OnSelfManagedIoSuspend callback function.
2. The framework stops all of the device's power-managed I/O queues and calls their
IPnpCallbackSelfManagedIo::OnSelfManagedIoStop callback functions (if they exist).
3. If the driver is the device's power policy owner, the framework calls its
IPowerPolicyCallbackWakeFromS0::OnArmWakeFromS0 or
IPowerPolicyCallbackWakeFromSx::OnArmWakeFromSx callback function.
4. The framework calls the driver's IPnpCallback ::OnD0Exit callback function (if it exists).
To see a diagram that shows these steps, see the orderly removal figure in A User Unplugs a Device.
A Device Returns to Its Working State (UMDF 1)
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

A device that is in a low-power state returns to its working state if one of the following occurs:
The device detects an external event and triggers a wake signal on its bus. The kernel-mode bus driver
detects the wake signal.
The device has been idle and a driver calls IWDFDevice2::StopIdle .
The system's power state has changed from a low-power state to its working (S0) state.
In each of these situations, the kernel-mode bus driver restores the device (a child device of the bus) to its
working (D0) state.
For each UMDF-based function and filter driver that supports the device, the framework does the following, in
sequence, one driver at a time, starting with the driver that is lowest in the driver stack:
1. The framework calls the driver's IPnpCallback ::OnD0Entr y callback function (if it exists).
2. If the driver is the device's power policy owner, the framework calls its
IPowerPolicyCallbackWakeFromS0::OnDisarmWakeFromS0 or
IPowerPolicyCallbackWakeFromSx::OnDisarmWakeFromSx callback function.
3. The framework restarts all of the device's power-managed I/O queues and calls their
IQueueCallbackIoResume::OnIoResume callback functions (if necessary).
4. If the driver is using self-managed I/O, the framework calls the driver's
IPnpCallbackSelfManagedIo::OnSelfManagedIoRestar t callback function.
To see a diagram that shows these steps, see A User Plugs in a Device.
The PnP Manager Redistributes System Resources
(UMDF 1)
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

If a user adds a device to a system, and if the device requires system resources that the PnP manager has
already assigned to another device, the PnP manager attempts to reassign resources.
During this process, the PnP manager stops devices and takes them out of their working (D0) states. It then
delivers new resource lists to the devices so that they can restart, using the new resources.
When redistributing resources, the PnP manager will not alter a device's resource assignment if one of the
device's UMDF-based drivers has supplied an IPnpCallback ::OnQuer yStop callback function, and the callback
function has vetoed the reassignment.
Power-Down Sequence
For each UMDF-based function and filter driver that supports the device being stopped, the framework does the
following, in sequence, one driver at a time, starting with the driver that is highest in the driver stack:
1. If the driver is using self-managed I/O, the framework calls the driver's
IPnpCallbackSelfManagedIo::OnSelfManagedIoSuspend callback function.
2. The framework stops all of the device's power-managed I/O queues.
3. The framework calls the driver's IPnpCallback ::OnD0Exit callback function (if it exists).
4. The framework calls the driver's IPnpCallbackHardware::OnReleaseHardware callback function (if it
exists) passing the list of hardware resources that the PnP manager has assigned to the device.
To see a diagram that shows these steps, see the orderly removal figure in A User Unplugs a Device.
Power-Up Sequence
For each UMDF-based function and filter driver that supports the device, the framework does the following, in
sequence, one driver at a time, starting with the driver that is lowest in the driver stack:
1. The framework calls the driver's IPnpCallbackHardware::OnPrepareHardware callback function (if it
exists), passing the list of hardware resources that the PnP manager has assigned to the device.
2. The framework calls the driver's IPnpCallback ::OnD0Entr y callback function (if it exists).
3. The framework restarts all of the device's power-managed I/O queues.
4. If the driver is using self-managed I/O, the framework calls the driver's
IPnpCallbackSelfManagedIo::OnSelfManagedIoRestar t callback function.
To see a diagram that shows these steps, see A User Plugs in a Device.
Processing I/O Requests (UMDF 1)
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

In this section
I/O Request Processing Operation Flow
Sending I/O Requests to Lower Drivers
Obtaining Parameters for I/O Requests
Canceling I/O Requests
Completing I/O Requests
Accessing Data Buffers in UMDF Drivers
Reusing Framework Request Objects
Handling Client Impersonation in UMDF 1.x Drivers
Preventing an Imbalance of Create and Close Notifications to a Driver
I/O Request Processing Operation Flow
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

All I/O operations occur in the context of a file object (that is, all I/O operations occur between calls that an
application makes to the Microsoft Win32 CreateFile and CloseHandle functions). I/O operations are calls that
an application makes to, for example, the Win32 ReadFileEx , WriteFileEx , and DeviceIoControl functions.
The following topics show the flow of operations that occur to and from UMDF drivers as a user I/O transaction
begins, processes, and ends in a single device stack and in a double device stack:
Operation Flow with Single Device Stack
Operation Flow with Double Device Stack
Note All I/O that is initiated by applications is routed through kernel mode as shown in the figures in the
Architecture of the UMDF section, even though the figures in the I/O Request Processing Operation Flow section
do not show this situation.
Operation Flow with Single Device Stack
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The following figure shows the flow of operations that occur to and from the UMDF functional driver in a single
device stack.

Note All I/O that is initiated by applications is routed through kernel mode as shown in the figures in the
Architecture of the UMDF section, even though the preceding figure does not show this situation.
The UMDF driver calls the IWDFIoRequest::GetCreateParameters method only if it requires information
about the file that is associated with the read request. The UMDF driver calls the
IWDFIoRequest::GetReadParameters method only if it requires more information about the read request.
The UMDF driver can call the IWDFIoRequest::Complete method rather than the
IWDFIoRequest::CompleteWithInformation method if specifying the number of bytes that are transferred
in the read operation is not required. The UMDF driver calls Complete or CompleteWithInformation to
signal that the read operation is complete; the application can then access the read data.
Operation Flow with Double Device Stack
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The following figure shows the flow of operations that occur to and from UMDF filter and functional drivers in a
double device stack.

Note All I/O that is initiated by applications is routed through kernel mode as shown in the figures in the
Architecture of the UMDF section, even though the preceding figure does not show this situation.
The UMDF filter and function drivers might also call the IWDFIoRequest::GetCreateParameters method if
they require information about the file that is associated with the read request. The UMDF filter and function
drivers might also call the IWDFIoRequest::GetReadParameters method if they require more information
about the read request.
The UMDF functional driver calls the IWDFIoRequest::Complete or
IWDFIoRequest::CompleteWithInformation method to signal to the filter driver that it is done with the read
operation. The UMDF filter driver might also call methods of the IWDFIoRequestCompletionParams interface if it
requires more information to complete the read request. The UMDF filter driver calls Complete or
CompleteWithInformation to signal that the read operation is complete; the application can then access the
read data.
Sending I/O Requests to Lower Drivers
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

When a driver receives an I/O request that it cannot fully process, the driver typically forwards the received
request to the next lower driver in the stack. The driver calls the IWDFIoRequest::Send method to forward the
request. To forward synchronously, the driver passes the WDF_REQUEST_SEND_OPTION_SYNCHRONOUS flag
in the Flags parameter. Otherwise, the driver forwards the request asynchronously. Before the driver forwards
the request, it should register a completion routine. For more information, see Completing I/O Requests.
Obtaining Parameters for I/O Requests
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

When a driver receives an I/O request, the driver can use the following methods of the IWDFIoRequest interface
to obtain parameters related to the request:
IWDFIoRequest::GetCreateParameters or IWDFIoRequest2::GetCreateParametersEx
IWDFIoRequest::GetDeviceIoControlParameters
IWDFIoRequest::GetReadParameters
IWDFIoRequest::GetWriteParameters
Canceling I/O Requests in UMDF
2/5/2021 • 4 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

A device's in-progress I/O operation (such as a request to read several blocks from a disk) can be canceled by an
application, the system, or a driver. If a device's I/O operation is canceled, the I/O Manager attempts to cancel all
unprocessed I/O requests that are associated with the I/O operation. The device's drivers can register to be
notified when the I/O Manager attempts to cancel I/O requests, and the drivers can cancel the requests that they
own by completing them with a completion status of HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED).
The framework handles some of the cancellation work for framework-based drivers. If a device's I/O operation is
canceled, the framework completes--with a completion status of
HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED)--the following I/O requests that are associated with
the canceled operation:
Undelivered I/O requests that the framework has placed in the driver's default I/O queue.
Undelivered I/O requests that the framework has forwarded to another queue because the driver called
IWDFIoQueue::ConfigureRequestDispatching .
Because the framework cancels these requests, it does not deliver them to the driver.
After the framework has delivered an I/O request to the driver, the driver owns the request and the framework
cannot cancel it. At this point, only the driver can cancel the I/O request, but the framework must notify the
driver that a request should be canceled. Drivers receive this notification by providing an
IRequestCallbackCancel::OnCancel callback function.
Sometimes a driver receives an I/O request from an I/O queue but, instead of processing the request, the driver
requeues the request to the same or another I/O queue for later processing. For example, the framework might
deliver an I/O request to one of the driver's request handlers, and the driver might subsequently call either
IWDFIoRequest::For wardToIoQueue to place the request in a different queue or
IWDFIoRequest2::Requeue to place the request back into the same queue.
In these cases, the framework can cancel the I/O request because the request is in an I/O queue. However, if the
driver has registered an callback function for the I/O queue in which the request resides, the framework calls the
callback function, instead of canceling the request, when the associated I/O operation is being canceled. If the
framework calls the driver's callback function, the driver must cancel the request.
In summary, when an I/O operation is canceled, the framework always cancels all associated I/O requests that
were never delivered to the driver. If the driver receives a request and then requeues it, the framework will
cancel the request (if the request is in the queue) unless the driver provides an callback function for the I/O
queue.
Calling MarkCancelable
A driver can call IWDFIoRequest::MarkCancelable to register an IRequestCallbackCancel::OnCancel
callback function. If the driver has called MarkCancelable , and if the I/O operation associated with the request
is canceled, the framework calls the driver's OnCancel callback function so that the driver can cancel the I/O
request.
A driver should call MarkCancelable if it will own a request for a relatively long time. For example, a driver
might have to wait for a device to respond, or it might have to wait for lower drivers to complete a set of
requests that the driver created when it received a single request.
If a driver does not call MarkCancelable , or if a driver calls IWDFIoRequest::UnmarkCancelable after calling
MarkCancelable , the driver is not aware of the cancellation and therefore handles the request as it typically
would.
Calling IsCanceled
If a driver has not called MarkCancelable to register an OnCancel callback function, it can call
IWDFIoRequest2::IsCanceled to determine if the I/O Manager has attempted to cancel an I/O request. If
IsCanceled returns TRUE , the driver should cancel the request.
For example, a driver that receives a large read or write request that it breaks into several smaller requests
might call IsCanceled after the driver's I/O target completes each of the smaller requests, if the driver has not
called MarkCancelable for the received request.
Canceling the Request
Canceling an I/O request might involve any of the following:
Stopping an in-progress I/O operation.
Not forwarding the request to an I/O target.
Calling IWDFIoRequest::CancelSentRequest to attempt to cancel a request that the driver had
previously submitted to an I/O target.
If a driver is canceling an I/O request for a request object that the driver received from the framework, the driver
must always complete the request by calling IWDFIoRequest::Complete or
IWDFIoRequest::CompleteWithInformation , with a CompletionStatus parameter of
HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED). (If the driver called IWDFDevice::CreateRequest to
create a request object, the driver calls IWDFObject::DeleteWdfObject instead of completing the request.)
Completing I/O Requests in UMDF
2/5/2021 • 4 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

Every I/O request must eventually be completed by a UMDF driver. To complete a request, the driver must call
either the IWDFIoRequest::Complete or IWDFIoRequest::CompleteWithInformation method. When the
driver completes the request, it indicates one of the following scenarios:
The requested I/O operation finished successfully.
The requested I/O operation started but failed before it finished.
The requested I/O operation is not supported or is not valid at the time it was received and therefore
cannot communicate with the device.
The requested I/O operation was canceled.
The driver calls the IWDFIoRequest::CompleteWithInformation method to pass additional information
about the request operation. For example, for a read operation, the driver should provide the number of bytes
read.
To complete an I/O request, the driver must pass the appropriate completion status to the CompletionStatus
parameter in the call to IWDFIoRequest::Complete or IWDFIoRequest::CompleteWithInformation . The
driver uses an HRESULT code to communicate the status of the completed request.
The UMDF driver host process converts the HRESULT code to an NTSTATUS code before it passes the completed
request to the reflector (Wudfrd.sys). The reflector passes the NTSTATUS code to the operating system. The
operating system converts the NTSTATUS code to a Microsoft Win32 error code before it presents the result to
the calling application.
To ensure that your driver's error codes can be converted correctly, you should create error codes by either of
the following techniques:
Use an error code from Winerror.h and apply the HRESULT_FROM_WIN32 macro.
Use an error code from Ntstatus.h and apply the HRESULT_FROM_NT macro.
For more information about these macros, see the Microsoft Windows SDK documentation.
The following example code shows how to complete a request with a suitable error code:
VOID
STDMETHODCALLTYPE
CMyQueue::OnWrite(
__in IWDFIoQueue *pWdfQueue,
__in IWDFIoRequest *pWdfRequest,
__in SIZE_T BytesToWrite
)
{
--------------------
if( BytesToWrite > MAX_WRITE_LENGTH ) {
pWdfRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_MORE_DATA), 0);
return;
}
---------------------
}

When a driver completes a request successfully, it returns S_OK, which is an HRESULT value. Because S_OK is
equivalent to NO_ERROR in Winerror.h and STATUS_SUCCESS in Ntstatus.h, the conversion macros are not
needed.
If Driver Verifier is enabled for the reflector, it identifies an invalid status code and causes a system bugcheck.
Note Driver Verifier for Windows XP incorrectly causes a system bugcheck for Win32 error codes whose
values exceed decimal 1024 (1024L). If your driver runs on Windows XP, please be aware of this issue if you
enable Driver Verifier for the reflector.
If the driver previously sent a request to a lower-level driver, the driver requires notification when the lower-level
driver completes the request. To register for notification, the driver calls the
IWDFIoRequest::SetCompletionCallback method to register the interface for the method that the
framework calls when the lower-level driver completes the request. The driver implements the
IRequestCallbackRequestCompletion::OnCompletion callback function to perform the operations required
to complete the request.
A driver does not complete an I/O request that it has created by calling IWDFDevice::CreateRequest . Instead,
the driver must call IWDFObject::DeleteWdfObject to delete the request object, typically after an I/O target
has completed the request.
For example, a driver might receive a read or write request for an amount of data that is larger than the driver's
I/O targets can handle at one time. The driver must divide the data into several smaller requests and send these
smaller requests to one or more I/O targets. Techniques for handling this situation include:
Calling IWDFDevice::CreateRequest to create a single additional request object that represents a
smaller request.
The driver can send this request synchronously to an I/O target. The smaller request's
IRequestCallbackRequestCompletion::OnCompletion callback function can call
IWDFIoRequest2::Reuse so that the driver can reuse the request and send it to the I/O target again.
After the I/O target completes the last of the smaller requests, the OnCompletion callback function can
call IWDFObject::DeleteWdfObject to delete the driver-created request object and the driver can call
IWDFIoRequest::Complete to complete the original request.
Calling IWDFDevice::CreateRequest to create several additional request objects that represent the
smaller requests.
The driver's I/O targets can process these multiple smaller requests asynchronously. The driver can
register a OnCompletion callback function for each of the smaller requests. Each time that the
OnCompletion callback function is called, it can call IWDFObject::DeleteWdfObject to delete a driver-
created request object. After the I/O target completes all of the smaller requests, the driver can call
IWDFIoRequest::Complete to complete the original request.
Obtaining Completion Information
To obtain information about an I/O request that another driver has completed, a UMDF-based driver can:
Use the IWDFRequestCompletionParams interface to obtain an I/O request's completion status and
other information.
Use the IWDFIoRequestCompletionParams interface to obtain an I/O request's memory buffers.
Use the IWDFUsbRequestCompletionParams interface to obtain memory buffers and other
information related to a request that was sent to a USB target pipe object.
In addition, a UMDF-based driver can use the IWDFIoRequest2::GetStatus method to obtain an I/O request's
current status, either before or after the request has been completed.
Accessing Data Buffers in UMDF 1.x Drivers
2/5/2021 • 11 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

When a driver receives a read, write, or device I/O control request, the request object contains either an input
buffer or an output buffer, or both. (A few device I/O control requests provide two input, two output, or two
input/output buffers.)
Input buffers contain information that the driver needs. For write requests, typically this information is data that
a function driver must send to a device. For device I/O control requests, an input buffer might contain
information that indicates the type of operation that the driver must perform.
Output buffers receive information from the driver. For read requests, typically this information is data that a
function driver receives from a device. For device I/O control requests, an output buffer might receive status or
other information that the I/O control code of the request specified.
The technique that your driver uses to access a request's data buffers can depend on the driver's method for
accessing data buffers for a device. UMDF supports the following buffer access methods:
UMDF versions prior to version 1.9 support only the buffered I/O access method. UMDF-based drivers
that run with those versions of UMDF can use only the buffered I/O method for all read, write, and device
I/O control requests. To access an I/O request's data buffers, UMDF-based drivers must use the
IWDFIoRequest::GetInputMemor y and IWDFIoRequest::GetOutputMemor y object methods.
Beginning with UMDF version 1.9, two access methods: buffered I/O and direct I/O, are available to
UMDF-based drivers. UMDF drivers that are written for UMDF versions 1.9 and later should use the
IWDFIoRequest2::RetrieveInputBuffer , IWDFIoRequest2::RetrieveInputMemor y ,
IWDFIoRequest2::RetrieveOutputBuffer , or IWDFIoRequest2::RetrieveOutputMemor y object
methods to access data buffers.
A third access method, which is called neither buffered nor direct I/O, is not available to UMDF-based drivers,
but UMDF can convert some I/O requests from the "neither" method to a method that the UMDF version
supports.
In most cases, UMDF-based drivers call the same UMDF object methods to access data buffers, whether UMDF
and the driver are using buffered I/O or direct I/O. Direct I/O often provides better performance than buffer I/O
provides.
The following sections of this topic explain:
how to specify a preferred buffer access method and preferred buffer retrieval mode
how UMDF chooses which buffer method and retrieval mode to use
how your driver can obtain the buffer access method that UMDF is using
guidelines for using the buffered, direct, and neither buffered nor direct buffer access methods
Specifying a Preferred Buffer Access Method
UMDF versions 1.9 and later support both the buffered and direct I/O access methods. Drivers can specify the
access method that you prefer to use for all of a device's read, write, and device I/O control requests by calling
IWDFDeviceInitialize2::SetIoTypePreference before calling IWDFDriver ::CreateDevice to create a device
object. For example, if a driver specifies a preference for only the buffered I/O method for read and write
requests for one of its devices, the UMDF driver host process uses the buffered I/O method when it delivers read
and write requests to the driver for that device. If a driver specifies a preference for direct I/O, UMDF can (but
might not) use direct I/O. For more information about when UMDF uses direct I/O, see How UMDF Chooses a
Buffer Access Method for an I/O Request.
For each device that a driver supports, the driver can specify a preference for buffered I/O, for direct I/O, or for
either buffered or direct I/O for the device. The driver can specify one type of access method for read and write
requests and another type of access method for device I/O control requests. If the driver does not specify an
access method preference, UMDF uses the buffered method.
For device I/O control requests, the I/O control code (IOCTL) specifies the buffer access method. (For more
information about how IOCTLs specify an access method, see Defining I/O Control Codes.) However, the access
method that UMDF uses might not match the access method that the IOCTL specifies.
In UMDF versions prior to version 1.9, UMDF always uses the buffered access method for all I/O control
requests.
UMDF versions 1.9 and later use the buffered I/O access method if the IOCTL specifies buffered I/O. If the
IOCTL specifies direct I/O, and if the driver calls IWDFDeviceInitialize2::SetIoTypePreference to
indicate that a preference for direct I/O, UMDF might use direct I/O or it might use buffered I/O, as
described in How UMDF Chooses a Buffer Access Method for an I/O Request. For information about how
UMDF supports IOCTLs that specify the "neither buffered I/O nor direct I/O" method, see Using Neither
Buffered I/O nor Direct I/O in UMDF Drivers.
Specifying a Buffer Retrieval Mode
In UMDF versions prior to version 1.9, UMDF always makes an I/O request's buffers available to the driver (by
copying the buffers into the UMDF driver host process) as soon as UMDF receives the I/O request. This buffer
retrieval mode is called immediate retrieval. If a failure occurs, UMDF completes the I/O request with a failure
status value and does not deliver the I/O request to the driver.
UMDF versions 1.9 and later support both immediate retrieval and deferred retrieval modes. The deferred
retrieval mode postpones copying an I/O request's buffer into the driver host process until the driver attempts
to access the buffer. If a failure occurs, the buffer access functions return an error status value to the driver.
Your driver can specify a buffer retrieval mode when it calls IWDFDeviceInitialize2::SetIoTypePreference for
each device. Use the following rules:
If your driver specifies the direct I/O access method it must also specify the deferred retrieval mode.
Direct I/O only works with deferred retrieval.
All drivers that are written to run with UMDF versions 1.9 and later should specify the deferred retrieval
mode for all I/O requests, whether the driver chooses the buffered or direct I/O access method. Deferred
retrieval provides better performance because it does not access buffers that the driver does not use.
If your driver does not specify a buffer retrieval mode, UMDF uses immediate retrieval.
All UMDF-based drivers in a driver stack must use the same retrieval mode. If some drivers specify immediate
retrieval and some specify deferred retrieval, UMDF uses immediate retrieval.
How UMDF Chooses a Buffer Access Method for an I/O Request
The access method that a driver specifies when it calls IWDFDeviceInitialize2::SetIoTypePreference , might
not be the one that UMDF uses. UMDF uses the following rules to determine which access method to use:
All UMDF-based drivers in a driver stack must use the same method for accessing a device's buffers. If
UMDF determines that some drivers prefer either buffered I/O or direct I/O for a device while other
drivers prefer only buffered I/O for the device, UMDF uses buffered I/O for all drivers. If one or more of a
stack's drivers prefer only buffered I/O while others prefer only direct I/O, UMDF logs an event to the
system event log and does not start the driver stack.
Your driver can call IWDFDevice2::GetDeviceStackIoTypePreference to determine the buffer access
methods that UMDF has assigned to a device's read/write requests and I/O control requests.
In some cases, a driver specifies a preference for direct I/O when it calls
IWDFDeviceInitialize2::SetIoTypePreference , but for best performance, UMDF uses buffered I/O for
one or more of the device's requests. For example, UMDF uses buffered I/O for small buffers if it can copy
the data to the driver's buffer faster than it can map the buffers for direct access.
Optionally, you can set a REG_DWORD-typed DirectTransferThreshold registry value that the
framework uses to determine the smallest buffer size for which the framework will use direct I/O.
Typically, you do not need to provide this registry value because the framework uses a value that
provides the best performance. The DirectTransferThreshold value is located under the device's
Device Parameters\WUDF subkey, which is under the device's hardware key.
The framework uses the following rules to determine the threshold based on the value you provide in
DirectTransferThreshold . The numbers provided assume a PAGE_SIZE of 4096, which is valid except
on Itanium-based systems.
If you set DirectTransferThreshold to any value less than or equal to 8192 (or 2 * PAGE_SIZE ),
the framework sets the threshold to 8192. The framework uses buffered I/O for buffers smaller
than 8192 bytes, and direct I/O for buffers equal to or larger than 8192 bytes.
If you set DirectTransferThreshold to any value greater than 8192, the framework rounds up to
the next exact multiple of PAGE_SIZE . Again, the framework uses buffered I/O for buffers smaller
than the threshold, and direct I/O for buffers equal to or larger than the threshold.
UMDF uses direct I/O only for buffer space that begins and ends on a memory page boundary. If either
the beginning or the end of a buffer does not lie on a page boundary, UMDF uses buffered I/O for that
part of the buffer. In other words, UMDF might use both buffered I/O and direct I/O for a large data
transfer that consists of several I/O requests.
For device I/O control requests, UMDF uses direct I/O only if the I/O control code (IOCTL) specifies direct
I/O and only if all of the device's UMDF-based drivers have called
IWDFDeviceInitialize2::SetIoTypePreference to specify the direct access method.
Drivers use the same set of request object methods to access data buffers, regardless of the buffer access
method. Therefore, most drivers typically do not need to know whether UMDF is using buffered I/O or direct I/O
for an I/O request.
How a Driver Can Obtain the Access Method for an I/O Request
In a few cases, you can improve the device and driver's performance if the access method is known. In such
cases, your driver can call IWDFIoRequest2::GetEffectiveIoType to obtain an I/O request's buffer access
method.
For example, consider a high-throughput device that typically uses direct I/O. Because it is using direct I/O, the
driver must copy application-specified parameters to local driver memory before it validates the parameters, to
ensure that the application does not modify the parameters after validation.
Because the driver might occasionally receive a buffer that uses buffered I/O, and because buffered I/O buffers
have already been copied, the application cannot modify the data and the driver does not have to copy
parameters before validating them. Therefore, the driver should check each request's buffer access method to
determine if it must copy parameters before validating them.
Using Buffered I/O in UMDF Drivers
If your driver is using buffered I/O, UMDF behavior differs depending on the type of request. For read and write
requests, the driver host process creates a single intermediate buffer that the driver can access.
For write requests, the driver host process transfers input information from the calling application's input buffer
before calling the driver stack. Drivers typically read input information from the intermediate buffer and write it
to the device.
For read requests, drivers typically read information from a device and store it in the intermediate buffer. The
driver host process copies the output data from the intermediate buffer to the application's output buffer.
For device I/O control requests, however, the driver host process creates two separate buffers that the driver can
access. Note that this differs from the behavior of WDM and KMDF drivers, for which read, write, and device I/O
control requests sent using buffered I/O result in the driver accessing a single, intermediate buffer. In this case,
the output buffer initially contains nothing, and the driver should not read from it. In addition, any data that the
driver writes to the input buffer is discarded and not returned to the calling application.
For guidelines about when to choose buffered I/O, see WDF_DEVICE_IO_TYPE .
UMDF versions 1.9 and later can support either immediate or deferred retrieval of request buffers. For more
information, see WDF_DEVICE_IO_BUFFER_RETRIEVAL .
A driver that uses the immediate buffer retrieval mode must use IWDFIoRequest::GetInputMemor y and
IWDFIoRequest::GetOutputMemor y to access the buffers.
A driver that uses the deferred buffer retrieval mode can access the buffers by calling
IWDFIoRequest2::RetrieveInputBuffer , IWDFIoRequest2::RetrieveInputMemor y ,
IWDFIoRequest2::RetrieveOutputBuffer , or IWDFIoRequest2::RetrieveOutputMemor y .
Using Direct I/O in UMDF Drivers
If your driver is using direct I/O, the driver host process verifies the accessibility of the buffer space that the
originator of the I/O request (typically a user-mode application) specified, locks the buffer space into physical
memory, and then provides the driver with direct access to the buffer space.
For guidelines about when to choose direct I/O, see WDF_DEVICE_IO_TYPE .
Your driver can access the buffers by calling IWDFIoRequest2::RetrieveInputBuffer ,
IWDFIoRequest2::RetrieveInputMemor y , IWDFIoRequest2::RetrieveOutputBuffer , or
IWDFIoRequest2::RetrieveOutputMemor y .
Using Neither Buffered I/O nor Direct I/O in UMDF Drivers
The buffer access method that is known as the neither buffered I/O nor direct I/O method (or, the "neither"
method, for short) allows drivers to directly access an application's request buffer pointers. UMDF-based drivers
cannot use this access method.
However, the definitions of some device I/O control codes (IOCTLs) specify that the requests use the "neither"
method. Optionally, UMDF can convert the buffer access method of such device I/O control requests to buffered
I/O or direct I/O. Use the following steps:
1. Include the UmdfMethodNeitherAction directive in an INF DDInstall section of your driver's INF file.
You can set the directive's value to indicate that UMDF should pass device I/O control requests that use
the "neither" access method to the driver. (Otherwise, UMDF completes these I/O requests with an error
status value.)
2. Access the I/O request's buffers by using the object methods that UMDF provides for buffered I/O or
direct I/O.
You should enable support of IOCTL requests that use the "neither" method only if you are sure that UMDF can
convert the access method to buffered I/O or direct I/O. For example, if the IOCTL specifies a customized request
that does not follow the buffer specification rules that are described at Buffer Descriptions for I/O Control Codes,
UMDF cannot convert the buffers.
Reusing Framework Request Objects in UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

To improve driver performance, framework-based drivers that create and send many nearly identical
asynchronous requests to an I/O target can reuse request objects instead of creating a new request object for
each request. A driver can reuse a request object after the request has been completed.
If a driver has created a request object by calling IWDFDevice::CreateRequest , it can reuse the request by
calling IWDFIoRequest2::Reuse . A driver can also reuse request objects that it has received from the
framework in its I/O queues.
If your driver provides an IRequestCallbackRequestCompletion::OnCompletion callback function for a
request object that it reuses, the driver must call IWDFIoRequest::SetCompletionCallback after it calls
Reuse .
Handling Client Impersonation in UMDF 1.x Drivers
2/5/2021 • 4 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

UMDF drivers typically run under the LocalService account and cannot access files or resources that require user
credentials, such as protected files or other protected resources. A UMDF driver typically operates on commands
and data that flow between a client application and a device. Therefore, most UMDF drivers do not access
protected resources.
However, some drivers might require access to a protected resource. For example, a UMDF driver might load
firmware into a device from a file that a client application provides. The file might have an access control list
(ACL) that prevents unauthorized users from modifying the file and taking control of the device. Unfortunately,
this ACL also prevents the UMDF driver from accessing the file.
The framework provides an impersonation capability that allows drivers to impersonate the driver's client and
obtain the client's access rights to protected resources.
Enabling Impersonation
Both the UMDF driver's installation package and the client application must enable the framework's
impersonation capability, as follows:
The INF file of the UMDF driver's installation package must include the UmdfImpersonationLevel
directive and set the maximum allowable impersonation level. Impersonation is enabled only if the INF
file includes the UmdfImpersonationLevel directive. For more information about setting the
impersonation level, see Specifying WDF Directives in INF Files.
The client application must set the allowed impersonation level for each file handle. The application uses
the quality of service (QoS) settings in the Microsoft Win32 CreateFile function to set the allowed
impersonation level. For more information about these settings, see the dwFlagsAndAttributes parameter
of CreateFile in the Windows SDK documentation.
Handling Impersonation for an I/O Request
The UMDF driver and framework handle impersonation for an I/O request in the following sequence:
1. The driver calls the IWDFIoRequest::Impersonate method to specify the required impersonation level
and an IImpersonateCallback ::OnImpersonate callback function.
2. The framework checks the requested impersonation level. If the requested level is greater than the level
that the UMDF driver's installation package and the client application allow, the impersonation request
fails. Otherwise, the framework impersonates the client and immediately calls the OnImpersonate
callback function.
The OnImpersonate callback function must perform only the operations that require the requested
impersonation level, such as opening a protected file.
UMDF does not allow a driver's OnImpersonate callback function to call any of the framework's object
methods. This ensures that the driver does not expose the impersonation level to other driver callback functions
or other drivers.
Note In versions 1.0 through 1.7 of UMDF, IWDFIoRequest::Impersonate grants the highest impersonation
level that the client application and INF file allow, even if the impersonation level that the driver requests is
lower. In UMFD versions 1.9 and later, the Impersonate method grants only the impersonation level that the
driver requests.
Passing Credentials down the Driver Stack
When your driver receives a WdfRequestCreate -typed I/O request, the driver might forward the I/O request
down the driver stack to a kernel-mode driver. Kernel-mode drivers do not have the impersonation capability
that IWDFIoRequest::Impersonate provides to UMDF-based drivers.
Therefore, if you want a kernel-mode driver to receive the client's user credentials (rather the credentials of the
driver host process), the driver must set the WDF_REQUEST_SEND_OPTION_IMPERSONATE_CLIENT flag
when it calls IWDFIoRequest::Send to send the create request to the I/O target. The Send method returns an
error code if the impersonation attempt fails, unless the driver also sets the
WDF_REQUEST_SEND_OPTION_IMPERSONATION_IGNORE_FAILURE flag.
The driver does not have to call IWDFIoRequest::Impersonate before it sends the request to the I/O target.
If lower-level drivers also forward the request, the client's impersonation level travels down the driver stack.
Reducing Security Threats
To reduce the chance of an "elevation of privilege" attack, you should:
Try to avoid using impersonation.
For example, to avoid using impersonation to open a file that the driver must use, the client application
can open the file and use I/O operations to send file contents to the driver.
Use the lowest impersonation level that your driver requires.
Set the impersonation level in your driver's INF file as low as possible. If your driver does not require any
impersonation, do not include the UmdfImpersonationLevel directive in the INF file.
Minimize the opportunities for an attacker to exploit your driver.
Your OnImpersonate callback function should contain a small section of code that performs only the
operation that requires impersonation. For example, if your driver accesses a protected file, it requires
impersonation only when it opens the file handle. It does not require impersonation to read from or write
to the file.
Preventing an Imbalance of Create and Close
Notifications to a Driver
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

An upper UMDF driver can use the IWDFDeviceInitialize::AutoFor wardCreateCleanupClose method to


control when the framework automatically forwards create-file, cleanup-file, and close-file notifications to the
next lower driver in the device stack. However, because the upper driver sets
AutoFor wardCreateCleanupClose to automatically forward only on a device level and not on a per-file level,
forwarding must be the same for all files for a device. The framework ensures this forwarding behavior for
cleanup-file and close-file notifications. If the upper driver implements the
IQueueCallbackCreate::OnCreateFile callback function, it must ensure that its forwarding behavior is the
same for all create-file requests and is consistent with the forwarding behavior for cleanup-file and close-file
notifications. Failing to do so might cause lower drivers to receive an unequal amount of calls to their
IQueueCallbackCreate::OnCreateFile method and IFileCallbackCleanup::OnCleanupFile and
IFileCallbackClose::OnCloseFile methods.
To prevent lower drivers from receiving an unequal amount of create-file and close-file notifications, the upper
driver must ensure, in its IQueueCallbackCreate::OnCreateFile callback function, that:
Its forwarding behavior is the same for all files for a device.
Its forwarding behavior is consistent with how it set the flag parameter of
IWDFDeviceInitialize::AutoFor wardCreateCleanupClose . That is:
If the driver set the flag to WdfTrue , the driver must forward all the create-file requests down the
device stack.
If the driver set the flag to WdfFalse , the driver must not forward any of the create-file requests down
the stack.
If the driver set the flag to WdfUseDefault and:
If the driver is a function driver, it must not forward any create-file requests down the stack.
If the driver is a filter driver, it must forward all create-file requests down the stack.
In situations where the driver cannot forward a create-file request, the driver can still generate a new create-file
request for lower drivers by calling the IWDFDevice::CreateWdfFile method to create a new WDF file. The
driver can then complete the original create-file request based on the results of the newly generated create-file
request (that is, from the results of CreateWdfFile ).
Using I/O Targets in UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

When a driver receives an I/O request, the driver might be able to process the request by itself, or it might
require the assistance of other drivers. If the driver requires assistance, it can forward the request to another
driver, or it can create one or more new requests and send them to another driver.
UMDF-based drivers use I/O targets to send I/O requests to another driver. Each I/O target is represented by an
I/O target object. Each I/O target object is primarily a queue. When a driver sends a request to an I/O target, the
framework stores the request in the queue until it can deliver the request to the I/O target.
The framework supports both general I/O targets and specialized I/O targets:
General I/O targets can be used by all UMDF drivers, but they do not support any special, device-specific
data formats.
Specialized I/O targets enable UMDF drivers to send I/O requests that require special, target-specific data
formatting. Currently, the framework provides support for USB I/O targets.
If the framework provides specialized I/O targets that support your device's data format, your driver should use
the specialized I/O targets. Otherwise, the driver should use general I/O targets.
General I/O Targets in UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

General I/O targets, which can be either local or remote, are I/O targets that do not support special, device-
specific data formats, such as USB request blocks. Before drivers send data to a general I/O target, they must put
data into a write buffer in a format that the I/O target and device can interpret. Likewise, when drivers read data
from a general I/O target, the drivers must be able to interpret the contents of data buffers that they receive
from the target.
Local I/O Targets
Drivers often send I/O requests to the next-lower driver in the driver stack. Therefore, each UMDF-based driver
has a default I/O target for each device, which is the device's next-lower driver. The default I/O target for the
lowest-level UMDF-based driver is the kernel-mode reflector.
Sometimes a UMDF-based driver must send I/O requests to a file-handle-based I/O target, such as a file or a
network socket. Therefore, the framework also provides file-handle-based I/O target objects.
Both the default I/O target and file-handle-based I/O targets are called local I/O targets, because UMDF-based
drivers use these targets to send I/O requests to devices that the driver stack supports.
Remote I/O Targets
Occasionally, a driver must send an I/O request to a different driver stack. Therefore, the framework also
provides remote I/O targets, which consist of all of the I/O targets except local I/O targets.
A remote I/O target might be a device that the driver stack does not support, a file on that device, or a device
interface for that device.
The following sections describe how to initialize and use a general I/O target:
Initializing a General I/O Target in UMDF
Sending I/O Requests to a General I/O Target in UMDF
Controlling a General I/O Target's State in UMDF
Obtaining Information About a General I/O Target in UMDF
Initializing a General I/O Target in UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The steps that your driver uses to initialize a general I/O target depend on whether the I/O target is local or
remote.
Initializing a local I/O target
Local I/O targets include a device's default I/O target and file-handle-based I/O targets.
The framework initializes a driver's default I/O target for a device when the driver calls the
IWDFDriver ::CreateDevice method. To retrieve the IWDFIoTarget interface that enables the driver to access
the device's default I/O target, the driver calls the IWDFDevice::GetDefaultIoTarget method.
Most drivers send requests only to their default I/O target.
If a UMDF driver must send I/O requests to a handle-based interface, such as a network socket interface, the
driver must create a file-handle-based I/O target object. To create a file-handle-based I/O target object, the
driver must do the following:
1. Call the Quer yInterface method of the device's IWDFDevice interface to retrieve a pointer to the
IWDFFileHandleTargetFactory interface.
2. Obtain a Win32 handle to a file, named pipe, or socket by calling the Win32 CreateFile ,
CreateNamedPipe , or socket function.
3. Call the IWDFFileHandleTargetFactor y::CreateFileHandleTarget method to create a file-handle-
based I/O target object for the file, pipe, or socket.
For a code example that shows how to retrieve the IWDFFileHandleTargetFactory interface, obtain a Win32
handle, and create a file-handle-based I/O target object, see the code example at
IWDFFileHandleTargetFactor y::CreateFileHandleTarget .
After the driver creates the file-handle-based I/O target, the driver can send I/O requests to the I/O target.
Initializing a Remote I/O Target
Before your driver can use a remote I/O target, it must create a remote target object and open the target, as
follows:
1. Call IWDFDevice2::CreateRemoteTarget to create a remote target object.
2. Call either IWDFRemoteTarget::OpenFileByName (for files) or
IWDFRemoteTarget::OpenRemoteInterface (for device interfaces) to open the target for I/O
operations.
Sending I/O Requests to a General I/O Target in
UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

A UMDF driver can send I/O requests to general I/O targets either synchronously or asynchronously.
If a driver sends I/O requests synchronously, a driver thread sends the requests one at a time. The thread waits
for each request to complete before it sends the next one. This process is simpler than sending the I/O requests
asynchronously. The driver can send I/O requests synchronously if it does not send many requests and if system
or device performance is not reduced while the driver waits for each I/O request.
If a driver sends I/O requests asynchronously, a driver thread sends each request as soon as the request is ready
to be sent, without waiting for previously sent requests to finish. If the driver must handle many I/O requests in
short periods of time, the driver probably cannot wait for each request to complete before sending the next
request. Otherwise, the driver might lose data or the performance of its devices and, possibly, of the entire
system might be reduced.
Before a UMDF driver can send an I/O request to an I/O target, the driver must format the request. The following
table lists the methods that the driver can call to format I/O requests. The driver can use these methods to
format a request that the driver received in one of its I/O queues or that the driver created.

M ET H O D P URP O SE

IWDFIoRequest::FormatUsingCurrentType Formats a request that the driver received from the


framework so that the driver can send the request,
unmodified, to the target

IWDFIoTarget::FormatRequestForIoctl Formats a device control request

IWDFIoTarget::FormatRequestForRead Formats a read request

IWDFIoTarget::FormatRequestForWrite Formats a write request

IWDFIoTarget2::FormatRequestForFlush Formats a request to flush buffers.

IWDFIoTarget2::FormatRequestForQuer yInformat Formats a request to obtain file information.


ion
M ET H O D P URP O SE

IWDFIoTarget2::FormatRequestForSetInformation Formats a request to set file information.

To send the I/O request to the I/O target, the driver calls the IWDFIoRequest::Send method. To send the I/O
request synchronously, the driver passes the WDF_REQUEST_SEND_OPTION_SYNCHRONOUS flag to the Flags
parameter. Otherwise, the driver sends the I/O request asynchronously. If the driver sends the I/O request
asynchronously, the driver typically requires notification when another driver completes the request. The driver
should define a IRequestCallbackRequestCompletion::OnCompletion callback function and register it by
calling the IWDFIoRequest::SetCompletionCallback method. For more information, see Completing I/O
Requests.
A driver that calls IWDFIoRequest::Send to send an I/O request can attempt to cancel the request later by
calling the IWDFIoRequest::CancelSentRequest method. If the driver cancels an I/O request that the driver
received from the framework, the driver must always complete the request by calling the
IWDFIoRequest::Complete or IWDFIoRequest::CompleteWithInformation method with the
CompletionStatus parameter set to STATUS_CANCELLED. If the driver created the request object, the driver calls
IWDFObject::DeleteWdfObject instead of completing the request.
Controlling a General I/O Target's State in UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework defines the following states for general I/O targets:
Star ted
The I/O target is open (that is, available to the UMDF driver) and the driver can send I/O requests to it. The
framework delivers the requests to the appropriate driver.
Stopped
The I/O target is open, but the UMDF driver cannot send I/O requests to the I/O target unless the driver passes
the WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE flag to the Flags parameter in a call to the
IWDFIoRequest::Send method.
The framework stops delivering requests to the appropriate driver.
Closed for Quer y-Remove
The I/O target is temporarily closed because its device might soon be removed.
Closed
The I/O target is closed and cannot be started or stopped.
Deleted
The I/O target's device has been removed.
The WDF_IO_TARGET_STATE enumeration defines the values that represent these states.
Local I/O Target States
The framework automatically opens and starts local I/O targets.
If necessary, the driver can call IWDFIoTargetStateManagement::Stop to temporarily stop a local I/O target
and call IWDFIoTargetStateManagement::Star t to restart it. For example, the driver might stop a local I/O
target if it detects a temporary error condition and then restart the I/O target if the error condition is corrected.
If a local I/O target's device is removed, the framework automatically stops and closes the I/O target and cancels
all I/O requests that are in the target's queue. The framework notifies the driver that the device is no longer
available by calling device object event callback functions. For more information about these callback functions,
see PnP and Power Management Scenarios in UMDF.
Drivers can call IWDFIoTargetStateManagement::GetState to obtain the current state of a local I/O target.
Remote I/O Target States
Drivers must call IWDFRemoteTarget::OpenFileByName or IWDFRemoteTarget::OpenRemoteInterface
to open remote I/O targets. When a driver opens a remote I/O target, the framework automatically starts the I/O
target.
If necessary, the driver can call IWDFRemoteTarget::Stop to temporarily stop a remote I/O target and call
IWDFRemoteTarget::Star t to restart it.
If a remote I/O target's device is removed, the framework automatically stops and closes the I/O target and
cancels all I/O requests that are in the target's queue, unless the driver registers the following event callback
functions:
IRemoteTargetCallbackRemoval::OnRemoteTargetQuer yRemove
Informs the driver that a remote I/O target's device might be removed. Your driver must call
IWDFRemoteTarget::CloseForQuer yRemove if you want the driver to allow removal of the device.
IRemoteTargetCallbackRemoval::OnRemoteTargetRemoveComplete
Informs the driver that a remote I/O target's device has been removed. This callback function must call
IWDFRemoteTarget::Close .
IRemoteTargetCallbackRemoval::OnRemoteTargetRemoveCanceled
Informs the driver that an attempt to remove a remote I/O target's device has been canceled. If you want the
driver to continue to use the target, the driver must call IWDFRemoteTarget::Reopen . Typically, a driver calls
Reopen from within the OnRemoteTargetRemoveCanceled callback function, but Reopen can instead be
called after OnRemoteTargetRemoveCanceled returns.
Drivers can call IWDFRemoteTarget::GetState to obtain the current state of a remote I/O target.
Obtaining Information About a General I/O Target
in UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

To obtain information about an I/O target, a UMDF driver can call the following methods that the I/O target
object defines:
IWDFIoTarget::GetTargetFile
Returns the framework file object that is associated with the I/O target.
IWDFIoTargetStateManagement::GetState
Returns state information for a local I/O target.
IWDFRemoteTarget::GetState
Returns state information for a remote I/O target.
USB I/O Targets in UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

Each universal serial bus (USB) device, and each pipe that a USB device interface supports, has a separate I/O
target. I/O that the USB device processes is sent to the device's I/O target. I/O that a specific pipe processes is
sent to that pipe's I/O target.

In this section
Choosing a Driver Model for a USB Device
USB-Specific UMDF 1.x Interfaces
Working with USB Devices in UMDF 1.x Drivers
Working with USB Interfaces in UMDF 1.x Drivers
Working with USB Pipes in UMDF 1.x Drivers
File Creation by a USB I/O Target
Calling WinUSB from UMDF
Choosing a Driver Model for a USB Device
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

For information about how to determine what type of driver you need for your USB device, see Choosing a
driver model for developing a USB client driver.
USB-Specific UMDF 1.x Interfaces
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

A USB device can have one or more configurations. Each configuration can have one or more interfaces. Each
interface is associated with one or more alternate settings, and each alternate setting defines one or more
endpoints. An endpoint represents a buffer on the device hardware.
A pipe is a software abstraction of a connection between the host controller and an endpoint in the current
alternate setting. A pipe can be a target for I/O, and is exposed in UMDF by the IWDFUsbTargetPipe interface.
The USB-specific UMDF interfaces are built on top of the WinUSB architecture. By design, WinUSB allows access
only to the first configuration of a multiple configuration device. Therefore, the WinUSB interface does not
expose the ability to submit a select-configuration request. Consequently, the I/O target functionality in UMDF
does not support selecting any device configuration other than the first.
The USB-specific UMDF interfaces have an object hierarchy that is similar to that of the general USB model. A
UMDF driver creates a target device object, which is exposed by the IWDFUsbTargetDevice interface. The driver
can then use methods of IWDFUsbTargetDevice to access USB interfaces, which are exposed by instances of
IWDFUsbInterface. The driver can call IWDFUsbInterface methods to manipulate settings and endpoints.
The following table shows the USB-specific UMDF interface hierarchy:

USB - SP EC IF IC UM DF IN T ERFA C E DERIVED F RO M

IWDFUsbTargetDevice IWDFIoTarget

IWDFUsbInterface IWDFObject

IWDFUsbTargetPipe IWDFIoTarget

The IWDFUsbTargetDevice and IWDFUsbTargetPipe interfaces derive from the IWDFIoTarget interface and,
therefore, expose I/O target objects. The IWDFUsbInterface interface does not derive from IWDFIoTarget
(IWDFUsbInterface derives from the IWDFObject interface) and, therefore, does not expose an I/O target object.
Any I/O sent to discover and manipulate interface details is sent to the target device.
For step-by-step directions on writing a simple UMDF-based USB client driver, see How to write your first USB
client driver (UMDF).
To learn about the source code required for a UMDF-based USB client driver, see Understanding the USB client
driver code structure (UMDF).
Working with USB Devices in UMDF 1.x Drivers
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework represents each USB device as a framework USB device object. A UMDF driver must create a
framework USB device object before the driver can access the framework's support for USB I/O targets. UMDF
provides USB device object methods that enable a UMDF driver to:
Create a UMDF-USB device object
Obtain device information
Send a control transfer
Set power policy
Creating a UMDF -USB Device Object
To use the framework's USB I/O target capabilities, a UMDF driver must first obtain a pointer to the
IWDFUsbTargetFactory interface. To obtain the pointer, the driver must call the Quer yInterface method of the
device's IWDFDevice interface. The following code example shows how to call Quer yInterface to obtain the
pointer:

hr = pdevice->QueryInterface(IID_IWDFUsbTargetFactory, (LPVOID*)&ppUsbTargetFactory);

The driver must next call the IWDFUsbTargetFactor y::CreateUsbTargetDevice method to create a USB I/O
target object for the device. After the driver creates the USB I/O target, the driver can send requests to the I/O
target. Typically, drivers call IWDFUsbTargetFactor y::CreateUsbTargetDevice from within an
IPnpCallbackHardware::OnPrepareHardware callback function.
After the driver calls IWDFUsbTargetFactor y::CreateUsbTargetDevice , the driver can obtain USB device
information (for example, USB descriptors for the device, USB interfaces, and interface endpoints). The USB
descriptors are described in the USB specification.
Obtaining UMDF -USB Device Information
After a UMDF driver calls the IWDFUsbTargetFactor y::CreateUsbTargetDevice method to create a UMDF-
USB target device object, the driver can call the following methods that the USB target device object defines for
obtaining information about a USB device:
IWDFUsbTargetDevice::RetrieveDescriptor
Obtains a device's USB device descriptor.
IWDFUsbTargetDevice::GetNumInterfaces
Obtains the number of USB interfaces that the device supports.
IWDFUsbTargetDevice::RetrieveUsbInterface
Obtains a pointer to a IWDFUsbInterface interface that exposes one of the USB interfaces that the device
supports.
IWDFUsbTargetDevice::RetrieveDeviceInformation
Retrieves capability information that is associated with a USB device.
IWDFUsbTargetDevice::RetrievePowerPolicy
Retrieves a WinUsb power policy.
IWDFUsbTargetDevice::GetWinUsbHandle
Obtains the WinUsb interface handle that is associated with the I/O target device object.
Sending a Control Transfer to a UMDF -USB Device Object
A UMDF driver can call the IWDFUsbTargetDevice::FormatRequestForControlTransfer method to format
an I/O request that describes a standard, device-class-specific, or vendor-specific USB control transfer. The driver
can then call the IWDFIoRequest::Send method to send the request synchronously or asynchronously.
Setting Power Policy for a UMDF -USB Device
A UMDF driver can call the IWDFUsbTargetDevice::SetPowerPolicy method to set the power policy that is
used by WinUsb for a USB device. The power policy for a USB device effects changes to power management
states for the device.
Working with USB Interfaces in UMDF 1.x Drivers
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework represents each USB interface as a framework USB interface object. When a UMDF driver creates
a framework USB device object, the framework creates a framework USB interface object for each USB interface
that the device supports.
Most USB devices have only one interface, and the interface has only one alternative setting. Drivers for such
devices typically do not need to use the object methods that the framework's USB interface object defines.
If a UMDF driver supports USB devices that provide multiple interfaces or alternate settings, interface object
methods enable the driver to:
Obtain interface information.
Select an alternate setting for a USB interface.
Obtaining UMDF -USB Interface Information
After a UMDF driver has called the IWDFUsbTargetFactor y::CreateUsbTargetDevice method to create a
UMDF-USB target device object, the driver can call the IWDFUsbTargetDevice::GetNumInterfaces method to
obtain the number of USB interfaces that the device supports. Next, the driver can make calls to the
IWDFUsbTargetDevice::RetrieveUsbInterface method to obtain pointers to the IWDFUsbInterface interfaces
that expose the USB interfaces that the device supports. Then the driver can call the following methods that each
USB interface object defines for obtaining information about the USB interface:
IWDFUsbInterface::GetInterfaceNumber
Obtains the USB interface number that is associated with a USB interface object.
IWDFUsbInterface::GetInterfaceDescriptor
Obtains that USB interface descriptor that is associated with one of the alternate settings of a USB interface.
IWDFUsbInterface::GetNumEndPoints
Obtains the number of endpoints (also known as pipes) that are associated with one of the alternate settings of
a USB interface.
IWDFUsbInterface::GetConfiguredSettingIndex
Obtains an index value that identifies the alternate setting that is currently selected for a USB interface.
IWDFUsbInterface::RetrieveUsbPipeObject
Retrieves a pointer to the IWDFUsbTargetPipe interface that exposes the framework pipe object that is
associated with a specified USB device interface and pipe index.
IWDFUsbInterface::GetWinUsbHandle
Obtains the WinUsb interface handle that is associated with a USB interface.
Selecting an Alternate Setting for a UMDF -USB Interface
The UMDF driver can call the IWDFUsbInterface::SelectSetting method to select an alternate setting for one
of the USB interfaces that the device supports.
The device's alternate settings must be numbered contiguously, starting with zero.
Impor tant Selecting a setting invalidates any information about the interface and endpoints. Therefore, the
driver should obtain this information again. The driver must also discard any USB pipe objects that it previously
retrieved and recreate them.
Working with USB Pipes in UMDF 1.x Drivers
2/5/2021 • 3 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The framework represents each pipe in a USB interface as a framework USB pipe object. When a driver
configures a USB device, the framework creates a framework USB pipe object for each pipe in each selected
interface. Pipe object methods enable a driver to:
Obtain pipe information.
Read from a pipe.
Write to a pipe.
Stop, flush, or reset a pipe.
Set pipe policy.
Handle pipe errors.
Obtaining UMDF -USB Pipe Information
After a UMDF driver calls the IWDFUsbInterface::RetrieveUsbPipeObject method to obtain a pointer to the
IWDFUsbTargetPipe interface for a USB pipe object, the driver can call the following methods that the USB pipe
object defines for obtaining information about the USB pipe:
IWDFUsbTargetPipe::GetInformation
Retrieves information about a USB pipe and its endpoint.
IWDFUsbTargetPipe::GetType
Returns the type of a USB pipe.
IWDFUsbTargetPipe::IsInEndPoint
Determines whether a USB pipe is connected to an input endpoint.
IWDFUsbTargetPipe::IsOutEndPoint
Determines whether a USB pipe is connected to an output endpoint.
IWDFUsbTargetPipe::RetrievePipePolicy
Retrieves a WinUsb pipe policy.
Reading from a UMDF -USB Pipe
To read data from a USB input pipe, your driver can use either (or both) of the following techniques:
Read data synchronously.
To read data synchronously from a USB input pipe, a UMDF driver first calls the
IWDFIoTarget::FormatRequestForRead method to build a read request. Then the driver calls the
IWDFIoRequest::Send method, specifying the WDF_REQUEST_SEND_OPTION_SYNCHRONOUS flag, to
send the request synchronously.
Read data asynchronously.
To read data asynchronously from a USB input pipe, a UMDF driver first calls the
IWDFIoTarget::FormatRequestForRead method to build a read request. Then the driver calls the
IWDFIoRequest::Send method without specifying the WDF_REQUEST_SEND_OPTION_SYNCHRONOUS
flag.
Read data synchronously and continuously.
A continuous reader is a framework-supplied mechanism that ensures a read request is always available
to a USB pipe. This mechanism guarantees that the driver is always ready to receive data from a device
that provides an asynchronous, unsolicited input stream. For example, a driver for a network interface
card (NIC) might use a continuous reader to receive input data.
To configure a continuous reader for an input pipe, the driver's
IPnpCallbackHardware::OnPrepareHardware callback function must call the
IWDFUsbTargetPipe2::ConfigureContinuousReader method. This method queues a set of read
requests to the device's I/O target.
Also, the driver's IPnpCallback ::OnD0Entr y callback function must call
IWDFIoTargetStateManagement::Star t to start the continuous reader and the driver's
IPnpCallback ::OnD0Exit callback function must call IWDFIoTargetStateManagement::Stop to stop
the continuous reader.
Each time that data is available from the device, the I/O target will complete a read request and the
framework will call one of two callback functions:
IUsbTargetPipeContinuousReaderCallbackReadComplete::OnReaderCompletion if the I/O target
successfully read the data, or
IUsbTargetPipeContinuousReaderCallbackReadersFailed::OnReaderFailure if the I/O target
reports an error.
After a driver has called IWDFUsbTargetPipe2::ConfigureContinuousReader , the driver cannot use
IWDFIoRequest::Send to send I/O requests to the pipe unless the driver's
IUsbTargetPipeContinuousReaderCallbackReadersFailed::OnReaderFailure callback function is
called and returns FALSE .
Continuous readers are supported in UMDF versions 1.9 and later.
Writing to a UMDF -USB Pipe
To write data to a USB output pipe, a UMDF driver can first call the IWDFIoTarget::FormatRequestForWrite
method to build a write request. Then the driver can call the IWDFIoRequest::Send method to send the
request asynchronously.
Stopping, Flushing, and Resetting a UMDF -USB Pipe
A UMDF driver can call the following methods to stop, flush, or reset a USB pipe:
IWDFUsbTargetPipe::Abor t
Synchronously sends a request to stop all pending transfers on a USB pipe.
IWDFUsbTargetPipe::Flush
Synchronously sends a request to discard any data that WinUsb saved when the device returned more data than
the client requested.
IWDFUsbTargetPipe::Reset
Synchronously sends a request to reset a USB pipe.
Setting Policy for a UMDF -USB Pipe
A UMDF driver can call the IWDFUsbTargetPipe::SetPipePolicy method to control the behavior that is used
by WinUsb for a USB pipe (for example, time-outs, handling short packets, and other behaviors).
Handling Pipe Errors
If your driver's USB target completes an I/O request with an error status value, your driver should do the
following:
1. Call IWDFIoTargetStateManagement::Stop with the WdfIoTargetCancelSentIo flag set. This call
stops the pipe and cancels any additional I/O requests that the driver has sent to the USB target, if the
target has not completed the requests.
2. Call IWDFUsbTargetPipe::Abor t to send an abort request to the pipe.
3. Call IWDFUsbTargetPipe::Reset to send a reset request to the pipe.
4. Call IWDFIoTargetStateManagement::Star t to restart the pipe.
5. Resend the I/O request that failed, and all I/O requests that followed the failed request.
File Creation by a USB I/O Target
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

During its initialization, the USB I/O target creates an intra-stack file object, which represents a default session
that the USB I/O target keeps open. For more information about an intra-stack file object, see Creating a File
Object to Handle I/O. The USB I/O target or its USB pipe target children use this file object to send any I/O that
they originate (for example, I/O to obtain the USB configuration descriptor).
The driver can use this intra-stack file object in format functions (for example, the driver can pass a pointer to
this file object to the pFile parameter in a call to the IWDFIoTarget::FormatRequestForRead method) if the
driver must send I/O on this file object's default session. To obtain the intra-stack file object, the driver can call
the IWDFIoTarget::GetTargetFile method.
This intra-stack file object is closed when the I/O target is disposed of either explicitly, when the driver calls the
IWDFObject::DeleteWdfObject method on the I/O target, or implicitly, when the I/O target's parent is
disposed of.
If any I/O remains outstanding on this intra-stack file object at the time of device removal, this file object will fail
to close, and UMDF will generate a driver stop. For more information, see Creating and Using Driver-Created
File Objects.
Calling WinUSB from UMDF
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

A UMDF driver can call WinUSB Functions directly if the driver cannot use the USB-specific UMDF interfaces to
perform a specific operation. To call WinUSB Functions, the driver must first obtain a WinUSB interface handle
by calling IWDFUsbTargetDevice::GetWinUsbHandle or IWDFUsbInterface::GetWinUsbHandle . A
WinUSB interface handle is used to define the first interface in the selected configuration.
For more information, see How to Access a USB Device by Using WinUSB Functions.
Accessing Hardware and Handling Interrupts
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

Starting in UMDF 1.11, UMDF drivers can retrieve hardware resources that the system has assigned to the
device, directly read or write to device registers that the system has assigned and mapped to memory space or
I/O port space, and connect and service hardware interrupts.

In this section
Enabling Hardware Access
Finding and Mapping Hardware Resources in UMDF 1.x Drivers
Reading and Writing to Device Registers in UMDF 1.x Drivers
Handling Interrupts
Enabling Hardware Access
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

To enable hardware access, a UMDF driver must set the UmdfDirectHardwareAccess INF directive to
AllowDirectHardwareAccess .
For more information about INF directives in UMDF, see Specifying WDF Directives in INF Files.
Finding and Mapping Hardware Resources in
UMDF 1.x Drivers
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

If you are using UMDF version 2.0 or later, see Finding and Mapping Hardware Resources.
A UMDF 1.x driver receives hardware resources in its IPnpCallbackHardware2::OnPrepareHardware
callback method. The driver uses the IWDFCmResourceList interface to review the translated resource list and
identify memory-mapped registers, I/O ports, and interrupts.
The driver iterates through the resource list by calling IWDFCmResourceList::GetCount and
IWDFCmResourceList::GetDescriptor .
If the driver receives memory-mapped registers, the driver must call IWDFDevice3::MapIoSpace to map the
registers before it can access them. Typically, a driver maps its registers in its
IPnpCallbackHardware2::OnPrepareHardware method. The driver unmaps the registers in its
IPnpCallbackHardware2::OnReleaseHardware callback by calling IWDFDevice3::UnmapIoSpace . Note
that mapping is not needed for I/O ports.
For an example that shows how a driver finds and maps memory-mapped register resources, see
IWDFDevice3::MapIoSpace .
Reading and Writing to Device Registers in UMDF
1.x Drivers
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

Starting in UMDF version 1.11, the framework provides a set of routines to access registers in memory space
and I/O port space. The UMDF register/port access routines are very similar to the HAL routines used by kernel-
mode drivers. After a driver has mapped registers as described in Finding and Mapping Hardware Resources in
a UMDF Driver, the driver uses the READ/WRITE_REGISTER_Xxx routines to read and write to individual
registers. For I/O ports, the driver calls the READ/WRITE_PORT_Xxx routines.
This example shows how to write to a memory-mapped register.

VOID
CMyQueue::WriteToDevice(
__in IWDFDevice3* pWdfDevice,
__in UCHAR Value
)
{
//
// Write the UCHAR value at offset 2 from register base
//
WRITE_REGISTER_UCHAR(pWdfDevice,
(m_MyDevice->m_RegBase)+2,
Value);
}

By default, UMDF internally uses system calls to access the registers mapped either in memory space or in I/O
port space. A register in I/O port space is always accessed through a system call. However, when accessing
memory-mapped registers, a UMDF driver can cause the framework to map the memory-mapped registers into
user-mode address space by setting the INF directive UmdfRegisterAccessMode to
RegisterAccessUsingUserModeMapping . Some drivers may need to do this for performance reasons. See
Specifying WDF Directives in INF Files for a complete list of UMDF INF directives.
The driver should use the READ/WRITE_REGISTER_Xxx routines even if it has mapped registers into user-mode.
These routines validate driver input and ensure that the driver doesn't request access to invalid locations. Rarely,
a driver may need to access user-mode mapped registers directly, without using these routines. To do so, a
driver retrieves the user-mode mapped address by calling
IWDFDevice3::GetHardwareRegisterMappedAddress on the mapped base address. Because UMDF doesn't
validate read and write accesses performed in this way, this technique is not recommended for register access.
Handling interrupts in UMDF drivers
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

Starting in UMDF version 1.11, UMDF drivers can handle hardware interrupts. UMDF supports both line-based
(both level-triggered and edge-triggered) and message-signaled (MSI) interrupts.
Line-based, level-triggered interrupts are available starting in Windows 8. MSI and line-based, edge-triggered
interrupts are available on all operating systems that UMDF 1.11 supports.
Framework-based drivers manage hardware interrupts by using framework interrupt objects.

In this section
Creating an Interrupt Object
Enabling and Disabling Interrupts
Servicing an Interrupt
Using Work Items
Synchronizing Interrupt Code
Deleting an Interrupt Object
Creating an Interrupt Object (UMDF 1)
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

A UMDF driver that handles a device's hardware interrupts must create a framework interrupt object for each
interrupt that each device can support.
Typically, a driver creates framework interrupt objects in IDriverEntr y::OnDeviceAdd . However, you can also
create interrupt objects in IPnpCallbackHardware2::OnPrepareHardware .
To create a framework interrupt object, your driver must initialize a WUDF_INTERRUPT_CONFIG structure
and pass it to the IWDFDevice3::CreateInterrupt method. This method registers the following driver-supplied
event callback functions:
OnInterruptEnable
Enables a hardware interrupt.
OnInterruptDisable
Disables a hardware interrupt.
OnInterruptIsr
The interrupt service routine (ISR) for the interrupt.
OnInterruptWorkItem
The worker routine for the interrupt.
Optionally, the driver can call IWDFInterrupt::SetPolicy or IWDFInterrupt::SetExtendedPolicy to specify
additional interrupt parameters.
The framework calls the driver's IDriverEntr y::OnDeviceAdd callback function before the Plug and Play (PnP)
manager has assigned system resources, such as interrupt vectors, to the device. After the PnP manager assigns
resources, the framework stores interrupt resources in the device's interrupt object. (Drivers that don't support
Plug and Play cannot use interrupt objects.)
Message-signaled interrupts (MSIs) are supported in Windows Vista and later versions of the operating system.
To enable the operating system to support MSIs for your device, your driver's INF file must set some values in
the registry. For information about how to set these values, see Enabling Message-Signaled Interrupts in the
Registry.
If a device can support a certain number of MSI messages, the PnP manager will try to assign that number of
messages to the device. If the PnP manager cannot assign all of the messages that the device can support, it will
assign only one message to the device.
Your driver should create a framework interrupt object for each interrupt vector or MSI message that the device
can support. If the PnP manager doesn't grant the device all of the interrupt resources that the device can
support, the extra interrupt objects won't be used, and their callback functions won't be called.
Enabling and Disabling Interrupts (UMDF 1)
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

If your driver handles device interrupts, it must provide OnInterruptEnable and OnInterruptDisable callback
functions that enable and disable the interrupts. These callback functions must do whatever is necessary to
enable and disable a device's interrupt mechanism.
If your driver must perform additional operations that are related to enabling or disabling interrupts, the driver
can also provide IPnpCallbackHardwareInterrupt::OnD0Entr yPostInterruptsEnabled and
IPnpCallbackHardwareInterrupt::OnD0ExitPreInterruptsDisabled callback functions.
The framework calls the driver's OnInterruptEnable and
IPnpCallbackHardwareInterrupt::OnD0Entr yPostInterruptsEnabled callback functions each time the
device enters its working (D0) state, after the framework has called the driver's OnD0Entr y callback function.
The framework calls the driver's IPnpCallbackHardwareInterrupt::OnD0ExitPreInterruptsDisabled and
OnInterruptDisable callback functions each time the device leaves its working state, before the framework calls
the driver's OnD0Exit callback function. For more information about when the framework calls a driver's
callback functions, see PnP and Power Management in UMDF-based Drivers.
You must not assume that a device will use the same interrupt resources each time the framework calls your
driver's OnInterruptEnable callback function. Sometimes the PnP manager redistributes system resources, and it
might assign new interrupt resources to your device.
The driver can call IWDFInterrupt::GetInfo to determine a device's interrupt resources. The driver can call
IWDFInterrupt::GetDevice to determine the device that an interrupt object belongs to.
To enable and disable interrupts directly, the driver can call the interrupt object's IWDFInterrupt::Enable and
IWDFInterrupt::Disable methods, which call the driver's OnInterruptEnable and OnInterruptDisable event
callback functions. However, most drivers should just allow the framework to call the OnInterruptEnable and
OnInterruptDisable callback functions at the proper times.
Servicing an Interrupt (UMDF 1)
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

Servicing an interrupt consists of two steps:


1. Saving volatile information (such as register contents) quickly, in an interrupt service routine.
2. Processing the saved volatile information in a workitem routine.
When a device generates a hardware interrupt, the framework calls the driver's interrupt service routine (ISR),
which framework-based drivers implement as an OnInterruptIsr callback function.
The OnInterruptIsr callback function, which runs at PASSIVE_LEVEL, must quickly save interrupt information,
such as register contents, queue a workitem to process the data further, and return from the ISR to allow
servicing of other interrupts if the interrupt line is shared. Because the UMDF driver's ISR runs at
PASSIVE_LEVEL, handling PCI line-based interrupts is not recommended. These interrupts are typically shared
between multiple devices, some of which might not accept ISR delays. However, you can handle PCI MSI
interrupts in a UMDF driver. These interrupts have edge semantics and are not shared.
Typically, the OnInterruptIsr callback function schedules a workitem to process the saved information later.
Framework-based drivers implement workitem routines as OnInterruptWorkItem callback functions.
Most drivers use a single OnInterruptWorkItem callback function for each type of interrupt. To schedule
execution of an OnInterruptWorkItem callback function, a driver must call
IWDFInterrupt::QueueWorkItemForIsr from within the OnInterruptIsr callback function.
If your driver creates multiple framework queue objects for each device, you might consider using a separate
workitem object and OnWorkItem callback function for each queue. To schedule execution of an OnWorkItem
callback function, the driver must first create one or more workitem objects by calling
IWdfDevice3::CreateWorkItem , typically from the driver's IDriverEntr y::OnDeviceAdd callback function.
Then the driver's OnInterruptIsr callback function can call IWDFWorkItem::Enqueue .
Drivers typically complete I/O requests in their OnInterruptWorkItem or OnWorkItem callback functions.
For an example of a UMDF driver that handles interrupts, see the SpbAccelerometer sample driver, available
starting in the Windows 8 WDK.
Using Work Items
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

A work item is a task that a driver performs in an OnWorkItem event callback function. These functions run
asynchronously.
UMDF drivers commonly use work items if an OnInterruptIsr must perform additional processing without
delaying the execution of the interrupt service request (ISR) because the interrupt line may be shared by
multiple devices.
Typically, a driver's OnInterruptIsr callback function creates a work-item object and adds it to the system's work-
item queue. Subsequently, a threadpool thread dequeues the object and calls the work item's OnWorkItem
callback function.

Setting Up a Work Item


To set up a work item, your driver must:
1. Create the work item.
Your driver calls IWDFDevice3::CreateWorkItem to create a work-item object and to identify an
OnWorkItem callback function that will process the work item.
2. Store information about the work item.
Typically, drivers use the context memory of the work-item object to store information about the task that
the OnWorkItem callback function should perform. When the OnWorkItem callback function is called, it
can retrieve the information by accessing this context memory. For information about how to allocate
and access context memory, seeIWDFObject::AssignContext .
3. Add the work item to the system's work-item queue.
Your driver calls IWDFWorkItem::Enqueue , which adds the driver's work item to the work-item queue.
When your driver calls IWDFDevice3::CreateWorkItem , it may optionally supply a parent object (for example
a device object or a queue object). When the system deletes that object, it also deletes any existing work items
that are associated with the object.

Using the WorkItem Callback Function


After the work item has been added to the work-item queue, it remains in the queue until a system worker
thread becomes available. The system worker thread removes the work item from the queue and then calls the
driver's OnWorkItem callback function, passing the work-item object as input.
Typically, the OnWorkItem callback function performs the following steps:
1. Obtains driver-supplied information about the work item by accessing the context memory of the work-item
object.
2. Performs the task that you specified. If necessary, the callback function can call
IWDFWorkItem::GetParentObject to determine the work item's parent object.
3. If the driver will requeue the work item, indicates that the handle to the work item is now available for reuse.
A few drivers might need to call IWDFWorkItem::Flush to flush their work items from the work-item queue. If
a driver calls the Flush method, the method does not return until a worker thread has removed the specified
work item from the work-item queue and called the driver's OnWorkItem callback function, and the
OnWorkItem callback function has subsequently returned after processing the work item.
Synchronizing Interrupt Code (UMDF 1)
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

All driver code that accesses the interrupt data buffer must be synchronized so that only one routine accesses
the data at a time.
You can synchronize interrupt code by using either manual interrupt locking or automatic callback serialization.

Manual Interrupt Locking


UMDF acquires the interrupt lock before calling the OnInterruptIsr, OnInterruptDisable, or OnInterruptEnable
callbacks.
If a driver needs to synchronize any code using the interrupt lock, it calls
IWDFInterrupt::AcquireInterruptLock and IWDFInterrupt::ReleaseInterruptLock . For example, a driver
acquires and releases the interrupt lock in its OnInterruptWorkItem callback routine by using these methods.
However, in I/O dispatch callbacks (such as OnRead and OnWrite ), the driver first calls
IWDFInterrupt::Tr yToAcquireInterruptLock to decide whether to queue a work item or do the work in same
thread to avoid potential deadlock. For an example of a deadlock scenario that can be caused by calling
IWDFInterrupt::AcquireInterruptLock from an arbitrary thread context, see the Remarks section of
IWDFInterrupt::AcquireInterruptLock .
If IWDFInterrupt::Tr yToAcquireInterruptLock returns TRUE , the driver has acquired the interrupt lock in the
same thread. In this case, the driver performs the work that required that lock, and then calls
ReleaseInterruptLock . If IWDFInterrupt::Tr yToAcquireInterruptLock returns FALSE , the driver queues a
work item and performs the work in its OnWorkItem callback. In this case, the work item must not use
automatic serialization.

Using Automatic Serialization


A UMDF driver can request automatic callback synchronization by calling
IWDFDeviceInitialize::SetLockingConstraint with the LockType parameter set to WdfDeviceLevel .
The driver then sets the AutomaticSerialization member of its WUDF_INTERRUPT_CONFIG structure to
TRUE before calling CreateInterrupt .
As a result, UMDF serializes the driver's OnInterruptWorkItem callbacks with I/O queue, request cancellation,
and file object callback routines. In this scenario, UMDF uses the callback lock instead of a per-interrupt object
lock.
Deleting an Interrupt Object
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

If the driver creates an interrupt object by calling IWDFDevice3::CreateInterrupt , the driver does not need to
delete the interrupt object. The framework deletes the interrupt object automatically because the interrupt object
is a child object of the framework device object.
The framework uses the following rules:
If the driver calls CreateInterrupt from its OnPrepareHardware callback method, the framework
deletes the interrupt object after the driver returns from its OnReleaseHardware callback.
If the driver calls CreateInterrupt from its OnDeviceAdd callback method, the framework deletes the
interrupt object when the device is removed.
Optionally, the driver can call IWDFObject::DeleteWdfObject to delete an interrupt object at any time.
Because a driver cannot create a new interrupt object outside of OnDeviceAdd or OnPrepareHardware ,
manual deletion of the object should not be used unless the driver must remove the object before the
framework deletes it.
UMDF Driver Tasks
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

In this section
Using Device Interfaces in UMDF Drivers
Creating Callback Objects
Specifying a Callback Synchronization Mode
I/O Queue Event Callback Functions
Configuring Dispatch Mode for an I/O Queue
Combining Dispatch and Synchronization Modes
Creating a File Object to Handle I/O
Using the Registry in UMDF 1.x Drivers
Supporting Kernel-Mode Clients in UMDF 1.x Drivers
Viewing UMDF Objects
Determining Why a UMDF Driver Consumes an Excessive Amount of Memory
Summary of Debugger Extensions in Wudfext.dll
Using Device Interfaces in UMDF Drivers
2/5/2021 • 3 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

A device interface is a symbolic link to a Plug and Play (PnP) device that an application can use to access the
device. A user-mode application can pass the interface's symbolic link name to an API element, such as the
Microsoft Win32 CreateFile function. To obtain a device interface's symbolic link name, the user-mode
application can call SetupDi functions. For more information about SetupDi functions, see SetupDi Device
Interface Functions.
Each device interface belongs to a device interface class. For example, a driver stack for a CD-ROM device might
provide an interface that belongs to the GUID_DEVINTERFACE_CDROM class. One of the CD-ROM device's
drivers would register an instance of the GUID_DEVINTERFACE_CDROM class to inform the system and
applications that a CD-ROM device is available. For more information about device interface classes, see
Introduction to Device Interfaces.
Registering a Device Interface
To register an instance of a device interface class, a UMDF-based driver can call
IWDFDevice::CreateDeviceInterface from within its IDriverEntr y::OnDeviceAdd callback function. If the
driver supports multiple instances of the interface, it can assign a unique reference string to each instance.
Enabling and Disabling a Device Interface
If creation succeeds, the framework automatically enables and disables the interface based on the device's PnP
state.
In addition, a driver can disable and re-enable a device interface as necessary. For example, if a driver
determines that its device has stopped responding, the driver can call
IWDFDevice::AssignDeviceInterfaceState to disable the device's interfaces and prohibit applications from
obtaining new handles to the interface. (Existing handles to the interface are not affected.) If the device later
becomes available, the driver can call IWDFDevice::AssignDeviceInterfaceState again to re-enable the
interfaces.
Receiving Requests to Access a Device Interface
When an application requests access to a driver's device interface, the framework calls the driver's
IQueueCallbackCreate::OnCreateFile callback function. The driver can call IWDFFile::RetrieveFileName to
obtain the name of the device or file that the application is accessing. If the driver specified a reference string
when it registered the device interface, the operating system includes the reference string in the file or device
name that IWDFFile::RetrieveFileName returns.
Creating Device Events
Your UMDF-based driver can create device-specific, custom events (called device events) by calling
IWDFDevice::PostEvent . A driver that has registered to use any of the device's interfaces can receive
notifications of a device's custom events. UMDF-based drivers receive such notifications by providing an
IRemoteInterfaceCallbackEvent::OnRemoteInterfaceEvent callback function.
Custom events are unique to the device. Both the developer of the driver that creates the event and the
developer of the driver that receives the event must understand the meaning of the event.
Accessing Another Driver's Device Interface
If you want your UMDF-based driver to send I/O requests to a device interface that another driver provides, you
can create a remote I/O target that represents the device interface.
First, your driver must register to receive a notification when a device interface is available. Use the following
steps:
1. When your driver calls IWDFDriver ::CreateDevice , the driver can provide an
IPnpCallbackRemoteInterfaceNotification interface. The
IPnpCallbackRemoteInterfaceNotification::OnRemoteInterfaceArrival callback function of this
interface informs your driver when device interfaces are available.
2. After your driver calls IWDFDriver ::CreateDevice , it can call
IWDFDevice2::RegisterRemoteInterfaceNotification for each device interface that the driver will
use.
Subsequently, the framework calls the driver's
IPnpCallbackRemoteInterfaceNotification::OnRemoteInterfaceArrival callback function each time that a
specified device interface becomes available. The callback function can call
IWDFRemoteInterfaceInitialize::GetInterfaceGuid and
IWDFRemoteInterfaceInitialize::RetrieveSymbolicLink to determine which device interface has arrived.
Your driver's IPnpCallbackRemoteInterfaceNotification::OnRemoteInterfaceArrival callback function
should typically do the following:
1. Call IWDFDevice2::CreateRemoteInterface to create a remote interface object, optionally providing
IRemoteInterfaceCallbackEvent and IRemoteInterfaceCallbackRemoval interfaces.
2. Call IWDFDevice2::CreateRemoteTarget to create a remote target object, optionally providing an
IRemoteTargetCallbackRemoval interface.
3. Call IWDFRemoteTarget::OpenRemoteInterface to connect the device interface to the remote target.
If the device interface is one that the SWENUM software device enumerator creates, your driver must call
OpenRemoteInterface from a work item. (For example, see the QueueUserWorkItem function in the
Windows SDK.)
Now the driver can format and send I/O requests to the remote I/O target.
In addition to the IPnpCallbackRemoteInterfaceNotification::OnRemoteInterfaceArrival callback
function, a UMDF-based driver can provide two additional callback functions to receive notifications of device
interface events:
The IRemoteInterfaceCallbackRemoval::OnRemoteInterfaceRemoval callback function notifies the
driver when a device interface is removed.
The IRemoteInterfaceCallbackEvent::OnRemoteInterfaceEvent callback function notifies the driver
when a device's custom events arrive.
Creating Callback Objects
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

A UMDF driver can create callback objects, which consist of context data and interface methods. The framework
accesses the driver's callback objects through the driver's callback interface methods.
The following figure shows how driver-implemented callback objects correspond to framework objects.

A UMDF driver can create several types of callback objects, including the following:
Driver callback object
The framework uses the driver callback object to initialize the driver and notify the driver of the arrival of
a new device.
Device callback object
The driver uses the device callback object to store device context and to handle the cleanup and closing of
file objects and Plug and Play (PnP) and power management (PM) events.
Queue callback object
The driver uses the queue callback object to process I/O.
The following figure shows how a UMDF driver creates a device callback object.

The following topics contain code examples that show how to create a callback object:
Creating Callback Objects Example
Defining Callback Objects Example
Associating Callback Interfaces Example
Creating Callback Objects Example
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The following code example shows how a driver creates a device callback object in the implementation of its
IDriverEntr y::OnDeviceAdd method and then passes a pointer to the device callback interface in its call to the
IWDFDriver ::CreateDevice method to create the device.

HRESULT CMyDriver::OnDeviceAdd(
IWDFDriver* pDriver,
IWDFDeviceInitialize* pDeviceInit
) {
IUnknown *pDeviceCallback = NULL;
...
HRESULT hr;
// Create callback object
hr = CMyDevice::CreateInstance( &pDeviceCallback,
pDeviceInit,
completionPort );
...
// Create WDF device
hr = pDriver->CreateDevice( pDeviceInit,
pDeviceCallback,
&pIWDFDevice );
...
}
Defining Callback Objects Example
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The following code example shows how a driver inherits from the IPnpCallbackHardware interface to define a
device callback object.

class CMyDevice :
// Callback interface exposed to the framework
public IPnpCallbackHardware
{// The following data members make up the context
private:
HANDLE m_CompletionPort;
WINUSB_INTERFACE HANDLE m_UsbHandle;
UCHAR m_BulkOutPipe;
ULONG m_BulkOutMaxPacket;
...
// The following methods make up the callback interfaces
public:
virtual HRESULT stdcall OnPrepareHardware(
IWDFDevice* pDevice
);
STDMETHOD( OnReleaseHardware )( IWDFDevice *pDevice );

// Method used to create a device callback object


static HRESULT CreateInstance(
IUnknown **ppUnknown,
IWDFDeviceInitialize *pDeviceInit,
HANDLE CompletionPort
);
...
};
Associating Callback Interfaces Example
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The following code example shows how a driver implements a create-instance method that the driver uses to
create the device callback object. The driver allocates the callback context and associates the supplied
IUnknown with one or more callback interfaces. The framework can subsequently use Quer yInterface to
discover the callback interfaces supported by the driver.

static HRESULT CreateInstance(


IUnknown **ppUnknown,
IWDFDeviceInitialize *pDeviceInit,
HANDLE CompletionPort
) {
...
// Allocate the callback context
CMyDevice *pMyDevice = new CMyDevice();
...
HRESULT hr;
// Discover the callback interface
hr = pMyDevice->QueryInterface(
__uuidof(IUnknown),
(void **) ppUnknown
);
...
return hr;
}
Specifying a Callback Synchronization Mode
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The driver can specify how its callback functions are called by the framework. The driver specifies a
synchronization (or locking) mode for a device before it calls the IWDFDriver ::CreateDevice method to create
a device object for the device. To specify synchronization mode, the driver should call the
IWDFDeviceInitialize::SetLockingConstraint method. The driver receives a pointer to the
IWDFDeviceInitialize interface when its IDriverEntr y::OnDeviceAdd method is called to add the device to the
system.
The driver can specify one of the following values from the WDF_CALLBACK_CONSTRAINT enumeration type in
the LockType parameter of IWDFDeviceInitialize::SetLockingConstraint to identify the locking mode. The
type of constraint (or locking) specified depends on how much parallelism the hardware device can exploit and
how much the driver can handle.

VA L UE M EA N IN G

None (0) Indicates that no callback functions into the driver are
synchronized.

WdfDeviceLevel (1) Indicates that all queue callback functions into the driver
are synchronized.

Note If the driver does not call IWDFDeviceInitialize::SetLockingConstraint to specify a value, the
framework sets the default value of this property to WdfDeviceLevel .
Constraints apply only to queue callback functions and not to Plug and Play (PnP) and power management
callback functions. Queue callback functions include the following:
Automatic dispatch callback functions, such as, IQueueCallbackRead::OnRead and
IQueueCallbackWrite::OnWrite . For more information, see I/O Queue Event Callback Functions.
Queue state change callback functions, such as, IQueueCallbackStateChange::OnStateChange .
Request cancellation callback functions, such as, IRequestCallbackCancel::OnCancel .
File cleanup and close callback functions, such as, IFileCallbackCleanup::OnCleanupFile and
IFileCallbackClose::OnCloseFile .
Request completion callback functions (IRequestCallbackRequestCompletion::OnCompletion ) are not
queue callback functions. Therefore, they are not synchronized.
I/O Queue Event Callback Functions
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

When drivers create I/O queues, or configure default I/O queues, they can register the following interfaces so
that the framework notifies the driver--by calling the methods associated with the interfaces--when events
related to the interfaces occur. For more information about I/O queues and creating and configuring I/O queues,
see Framework I/O Queue Object.
IQueueCallbackCreate
IQueueCallbackDeviceIoControl
IQueueCallbackRead
IQueueCallbackWrite
IQueueCallbackDefaultIoHandler
Configuring Dispatch Mode for an I/O Queue
2/5/2021 • 3 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

When I/O requests from applications arrive, the framework places each request in the appropriate I/O queue.
How and when the requests are delivered to the driver depend on how the driver configures dispatching for the
I/O queue and on how the driver specifies callback-function synchronization. The I/O queue also interacts with
the PnP and power management subsystem of UMDF to hold I/O requests in the queue until the device reaches
the proper state.
Note The dispatch mode for the I/O queue is not related to the synchronization mode. The I/O queue's
dispatch configuration controls the number of requests that the driver can accept for processing at any given
time, while synchronization controls the simultaneous execution of event callback functions that are presenting
or canceling requests. However, several modes of operation are created by combining dispatch and
synchronization modes.
The driver configures dispatching for an I/O queue when the driver calls the IWDFDevice::CreateIoQueue
method to configure the default queue or to create a secondary queue. The driver can specify one of the values
from the WDF_IO_QUEUE_DISPATCH_TYPE enumeration type in the DispatchType parameter of
IWDFDevice::CreateIoQueue to identify the dispatch mode. An I/O queue object can support the following
dispatch modes:
Sequential
The sequential dispatch mode is specified using the WdfIoQueueDispatchSequential value. In this
dispatch mode, a queue in the processing state raises events so that a driver only processes one request
at a time. The queue defers any additional requests until the driver finishes processing its current request
or calls the IWDFIoRequest::For wardToIoQueue method to requeue the request. When the current
request completes or is forwarded, the queue raises an event to provide the next request.
Parallel
The parallel dispatch mode is specified using the WdfIoQueueDispatchParallel value. In this dispatch
mode, a queue in the processing state raises events as soon as I/O requests are ready for the driver.
When the driver receives an I/O request, the driver can process the I/O request in one of the following
ways:
The driver calls either the IWDFIoRequest::Complete or
IWDFIoRequest::CompleteWithInformation method to complete the I/O request immediately. A
driver completes the I/O request immediately if the I/O request is invalid, cannot ever be serviced, or
can be completed by copying data from a buffer or cache that has the data.
The driver calls the IWDFIoRequest::For wardToIoQueue method to requeue the I/O request.
The driver calls the IWDFIoRequest::Send method to pass the I/O request to a lower-level driver.
Manual
The manual dispatch mode is specified using the WdfIoQueueDispatchManual value. In this dispatch
mode, the I/O queue does not automatically notify the driver when requests arrive at the queue. The
driver must call the IWDFIoQueue::RetrieveNextRequest method to retrieve requests manually from
the queue. This is a polling model.
In UMDF versions 1.9 and later, if your driver is using the manual dispatch mode, it can call
IWDFIoRequest2::Requeue to return an I/O request to the head of the I/O queue from which the driver
obtained it. After calling IWDFIoRequest2::Requeue , the driver's next call to
IWDFIoQueue::RetrieveNextRequest retrieves the requeued request.
For all dispatch modes, the I/O queue object receives and tracks the request until the driver handles the request
or the request is canceled.
If the driver configures the queue for serial or parallel dispatching, the framework notifies the driver of a request
through the callback functions that are registered by the driver when the driver creates the queue or configures
the default queue. For more information, see I/O Queue Event Callback Functions.
Combining Dispatch and Synchronization Modes
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

Combining a particular queue dispatch mode with a synchronization mode provides the mode of operation, as
shown in the following diagram.
Creating a File Object to Handle I/O
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

When an application opens a file handle, the I/O manager creates a file object. The framework in turn creates a
framework file object to represent the I/O manager's file object.
Unless the driver sets the UmdfFileObjectPolicy directive to AllowNullAndUnknownFileObjects , UMDF
requires each I/O request to be associated with a file object. For more information about this directive, see
Specifying WDF Directives in INF Files.
If your UMDF driver sends I/O that is independent of the application to the next driver in the stack (for example,
during device initialization or to get notification of device events), the driver must create its own file object to
associate with the request.
The following sections describe the differences between driver-created file objects and application-created file
objects, and how the driver creates and uses a file object.
Driver-Created Versus Application-Created File Objects
Creating and Using Driver-Created File Objects
Driver-Created Versus Application-Created File
Objects
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

When an application opens a handle to a device, the framework calls your driver's
IQueueCallbackCreate::OnCreateFile method and supplies a pointer to the IWDFFile interface for the file
object that is associated with the device. Any I/O requests that the application sends to the opened handle are
associated with the created file object. When such requests arrive, the framework calls the appropriate method
from one of the driver-supplied UMDF Queue Object Interfaces. The driver can then call
IWDFIoRequest::GetFileObject to determine the file object associated with the request. The driver can call
AssignContext on the file object to associate context that is specific to the I/O session.
The following table shows calls the application makes and the resulting notifications that the driver receives.

A P P L IC AT IO N IN IT IAT ES DRIVER REC EIVES

A call to the Microsoft Win32 CreateFile function. A call to its IQueueCallbackCreate::OnCreateFile


method.

A call to the Win32 ReadFileEx, WriteFileEx, or A call to its IQueueCallbackRead::OnRead ,


DeviceIoControl function. IQueueCallbackWrite::OnWrite , or
IQueueCallbackDeviceIoControl::OnDeviceIoCont
rol method.

A call to the Win32 CloseHandle function for the last A call to its IFileCallbackCleanup::OnCleanupFile
open handle to the file object. method.
The driver cancels or completes all I/O requests that are
associated with the file object.
After the driver returns from the cleanup notification,
UMDF cancels any pending I/O requests.
After cleanup completes and UMDF cancels pending I/O
requests, the driver receives a call to its
IFileCallbackClose::OnCloseFile method.

A system component may issue a create request on behalf of a Universal Windows app. If the driver needs to
determine the process ID of the app that issued the create request, it can call the
IWDFFile3::GetInitiatorProcessId method.

Driver-created file objects


If your driver needs to create and send an I/O request independent of the application to the next driver in the
stack (the default I/O target), the driver must call IWDFDevice::CreateWdfFile to retrieve a pointer to a
IWDFDriverCreatedFile interface. In this case, the next driver receives the same notifications that your driver
receives when the application generates the request.
The following table shows calls your driver makes and the resulting notifications to the next driver in the stack.

DRIVER IN IT IAT ES N EXT DRIVER IN T H E STA C K REC EIVES

A call to the IWDFDevice::CreateWdfFile method. A call to its IQueueCallbackCreate::OnCreateFile


method.
The file object that UMDF creates represents an I/O
session between the device and the next device in the
stack.

A call to the IWDFDevice::CreateRequest method. A call to its IQueueCallbackRead::OnRead ,


IQueueCallbackWrite::OnWrite , or
A call to format the request (for example, a call to the IQueueCallbackDeviceIoControl::OnDeviceIoCont
IWDFIoTarget::FormatRequestForIoctl method). rol method.
A call to the IWDFIoRequest::Send method.

A call to the IWDFDriverCreatedFile::Close method. A call to its IFileCallbackCleanup::OnCleanupFile


method.
The driver cancels or completes all I/O requests that are
associated with the file object.
After the driver returns from the cleanup notification,
UMDF cancels any pending I/O requests.
After cleanup completes and UMDF cancels pending I/O
requests, the driver receives a call to its
IFileCallbackClose::OnCloseFile method.

For the next device in the stack, no difference exists between the file object that is created by an application and
the file object that is created by a higher-layer device.
Creating and Using Driver-Created File Objects
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

If your driver needs to create and send an I/O request that is independent of the application to the next driver in
the stack (the default I/O target), the driver must create and close its own file objects.
Creating a File Object
Your driver must call the IWDFDevice::CreateWdfFile method to create a file object for the driver's use. When
the driver calls IWDFDevice::CreateWdfFile , the framework sends a create request to the next driver in the
stack. The next driver in the stack could be in kernel mode or in user mode.
This create-file request processing is different in the Windows Driver Model (WDM). In WDM, a call to the
ZwCreateFile function causes a create IRP to go to the top of the kernel-mode stack. The following figure
shows create-file request processing in UMDF versus WDM:

By calling IWDFDevice::CreateWdfFile , the driver can create a file object and then send I/O requests during
device start, before the whole stack has started.
The next driver in the stack must determine if it can handle the create-file request or if it must forward the
request further down the stack.
After calling IWDFDevice::CreateWdfFile , a driver cannot cancel the create operation.

Using the File Object


To send an asynchronous read request to the next driver stacked below it, your driver can use the following
pattern.
1. Call IWDFDevice::CreateWdfFile to create the file object.
2. Call IWDFDevice::GetDefaultIoTarget to retrieve the interface representing the lower level driver.
3. Call IWDFDevice::CreateRequest to create an unformatted IWDFIoRequest object.
4. Call IWDFIoRequest::SetCompletionCallback to register a IRequestCallbackRequestCompletion
interface for the OnCompletion method that the framework calls when an I/O request completes.
5. Call IWDFIoTarget::FormatRequestForRead , providing a pointer to the IWDFDriverCreatedFile
interface in the pFile parameter.
6. Call IWDFIoRequest::Send to send the request.

Closing the File Object


The driver that called IWDFDevice::CreateWdfFile must later call IWDFDriverCreatedFile::Close .
Typically, your driver calls IWDFDriverCreatedFile::Close either from its
IPnpCallbackHardware::OnReleaseHardware or
IPnpCallbackSelfManagedIo::OnSelfManagedIoCleanup callback method.
When the driver calls IWDFDriverCreatedFile::Close , the framework calls the next driver's
IFileCallbackCleanup::OnCleanupFile method. In this method, the next driver must cancel or complete all
pending I/O requests that are associated with the file object. The framework then cancels any I/O requests
created by the driver that called IWDFDevice::CreateWdfFile . The framework does not cancel any I/O
requests that lower drivers in the stack may have associated with the file object. It is the driver's responsibility to
cancel any such requests. The file object only closes after all I/O requests associated with it have completed.
Next, the framework calls the next driver's IFileCallbackClose::OnCloseFile method. At this point, the
framework guarantees that the next driver will not receive additional I/O requests for this file object.
After the framework calls OnCloseFile , it destroys the IWDFFile interface that represents the file object.
If driver-created file objects remain after the driver's device-removal methods (for example
IPnpCallbackHardware::OnReleaseHardware and
IPnpCallbackSelfManagedIo::OnSelfManagedIoCleanup ) return, the framework generates a driver stop.
For information about troubleshooting this problem, see Determining Why UMDF Indicates Outstanding Files at
Device Removal Time.
Using the Registry in UMDF 1.x Drivers
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

UMDF-based drivers can read and write values in the registry by using interfaces of the property store object.
UMDF-based drivers can access four types of registry keys. Drivers can create, read, and write subkeys and
values under these keys. The following types of registry keys are available to UMDF-based drivers:
Hardware keys
The PnP manager creates a hardware key, or device key, for each device, in which it stores the device's
unique identification information.
Your driver can retrieve and modify some of the property values under the hardware key. The location of
the stored values depends on the method that you use to access them.
Property values that were created using PropertyStore methods are stored in the \Device Parameters
subkey, under the hardware key. To access these properties, your driver calls one of the following
methods to obtain a property store interface.
IWDFDevice::RetrieveDeviceProper tyStore
Obtains a pointer to an IWDFNamedProper tyStore interface.
IWDFDeviceInitialize::RetrieveDeviceProper tyStore
Obtains a pointer to an IWDFNamedProper tyStore interface.
IWDFProper tyStoreFactor y::RetrieveDeviceProper tyStore
Obtains a pointer to an IWDFNamedProper tyStore2 interface. You can use the SubkeyPath parameter
to specify values under a driver-created subkey, such as \Device
Parameters\ DriverServiceName\subkey.
Drivers have read-only access to values within the \Device Parameters subkey, and cannot access
\Device Parameters\WDF or \Device Parameters\WUDF .
Property values that were created using the Unified Device Property model are stored in the \Proper ties
subkey, under the hardware key.
To access these properties, your driver calls
IWDFUnifiedProper tyStoreFactor y::RetrieveUnifiedDeviceProper tyStore to obtain a property
store interface. Then the driver can use the IWDFUnifiedProper tyStore interface to modify and retrieve
current settings of device properties.
Software keys
A driver's software key is also called its driver key because the registry contains a software key for each
driver. The registry contains a list of all of the device classes, and each driver's software key resides under
its device class entry. The system stores information about each driver under its software key.
Your driver can call IWDFProper tyStoreFactor y::RetrieveDeviceProper tyStore to obtain read or
write access to values under its software key. The driver can read and write driver-specific information
that is not associated with specific devices.
Device interface keys
The registry contains keys for all of the device interface classes that drivers have created. Under each of
these keys is an entry for each instance of the device interface class that a driver has registered.
If your driver has registered an instance of a device interface class, it can read and write values under the
registry's entry for that instance by calling
IWDFProper tyStoreFactor y::RetrieveDeviceProper tyStore . The driver can read and write instance-
specific information about the device interface.
The DEVICEMAP key
The registry contains a HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP key that some drivers for
older technologies, such as serial and parallel ports, use. If your driver supports a technology that uses
the DEVICEMAP key, the driver can access subkeys and values under the key by calling
IWDFProper tyStoreFactor y::RetrieveDeviceProper tyStore .
After a driver has called one of the RetrieveDeviceProper tyStore methods to open a registry subkey, the
driver can use methods exposed by IWDFNamedProper tyStore , IWDFNamedProper tyStore2 , or
IWDFUnifiedProper tyStore to create, read, and write values under a subkey. The
IWDFNamedProper tyStore2 interface also enables drivers to delete values.
For more information about registry keys for drivers, see Overview of Registry Trees and Keys.
Supporting Kernel-Mode Clients in UMDF 1.x
Drivers
2/5/2021 • 6 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

WARNING
Also see Supporting Kernel-Mode Clients in UMDF 2.x.

UMDF versions 1.9 and later allow UMDF drivers to support kernel-mode clients. A kernel-mode client can be
either of the following:
A kernel-mode driver that exists above a UMDF driver in a device's driver stack.
A kernel-mode driver for one device stack, which supports one device, opens a handle to another device,
and the latter device's driver stack contains a UMDF driver.
In other words, a UMDF driver that supports kernel-mode clients can receive I/O requests from a kernel-mode
driver. The kernel-mode driver can forward I/O requests that it has received from a user-mode application, or
can create new I/O requests and send them to the user-mode driver.
To determine if your UMDF driver must support kernel-mode clients, you must understand the driver stack to
which your driver will be added, and where in that stack your driver will reside. You must also determine
whether a driver from another stack might send I/O requests to your driver's device.
Your driver must support kernel-mode clients if:
A kernel-mode driver can be located directly above your UMDF driver in a driver stack. For example, a
kernel-mode filter driver might reside directly above a UMDF-based function driver.
A kernel-mode driver from another stack can send I/O requests to your driver's device. For example, your
driver might create a symbolic link that a kernel-mode driver in another stack can use to open a handle to
your driver's device. The kernel-mode driver can then send I/O requests to the device.
How to support kernel-mode clients in a UMDF driver
A UMDF driver can receive I/O requests from a kernel-mode driver only if the UMDF driver has enabled support
for kernel-mode clients. Furthermore, if a device installation attempts to load kernel-mode drivers above a
UMDF driver in the device's driver stack, the framework allows the drivers to load only if the UMDF driver has
enabled support for kernel-mode clients.
To enable a UMDF driver's support for kernel-mode clients, the INF file of the UMDF driver must include a
UmdfKernelModeClientPolicy directive in its INF DDInstall.WDF section. If the INF file of the UMDF driver does
not include this directive, UMDF does not allow a kernel-mode driver that is installed above the UMDF driver to
run.
The framework provides two methods that are useful to drivers that support kernel-mode clients. A driver can
call the IWDFIoRequest2::GetRequestorMode method to determine whether an I/O request came from
kernel mode or user mode. If the I/O request came from user mode, the driver can call
IWDFIoRequest2::IsFromUserModeDriver to determine whether the request came from an application or
another user-mode driver.
Restrictions on kernel-mode drivers
A UMDF driver can process I/O requests from a kernel-mode driver only if the kernel-mode driver meets the
following requirements:
The kernel-mode driver must be running at IRQL = PASSIVE_LEVEL when it sends the I/O request.
Unless the driver has set the UmdfFileObjectPolicy INF directive to
AllowNullAndUnknownFileObjects , each I/O request that a kernel-mode driver sends to a user-mode
driver must have an associated file object. The framework must have previously been notified that the I/O
manager created the file object. (Such notification causes the framework to call the user-mode driver's
IQueueCallbackCreate::OnCreateFile callback function, but that callback function is optional.)
The I/O request cannot contain an IRP_MJ_INTERNAL_DEVICE_CONTROL function code.
The I/O request's buffers must not contain pointers to additional information, because the user-mode
driver cannot dereference the pointers.
If the I/O request contains an I/O control code that specifies the "neither" buffer access method, the
kernel-mode driver must send the I/O request in the process context of the application that created the
I/O request. For more information about how to support the "neither" method in a UMDF-base driver, see
Using Neither Buffered I/O nor Direct I/O in UMDF Drivers.
The UMDF driver might modify an I/O request's output data, in user mode. Therefore, the kernel-mode
driver must validate any output data that it receives from the user-mode driver.
The kernel-mode client should typically validate the Information value that a UMDF driver passes to
IWDFIoRequest::CompleteWithInformation . If the client is a KMDF driver, it can call
WdfRequestGetCompletionParams to obtain this information in an IO_STATUS_BLOCK structure.
Typically, the framework does not validate the information value that a UMDF driver passes to
IWDFIoRequest::CompleteWithInformation . (This parameter usually specifies the number of
transferred bytes.) The framework validates the information value only for output buffers, and only for
the buffered I/O data access method. (For example, the framework verifies that the number of transferred
bytes does not exceed the output buffer size of a read operation, if the access method is buffered I/O.)
Handling return status values in a UMDF 1.x driver
Passing return status values from user-mode to kernel-mode requires special attention, as follows:
UMDF version 1 drivers typically receive HRESULT-typed return values, while KMDF and WDM-based
kernel-mode drivers typically receive NTSTATUS-typed values. If a UMDF 1.x driver completes an I/O
request, and if the driver has a kernel-mode client, the driver's call to IWDFIoRequest::Complete or
IWDFIoRequest::CompleteWithInformation should specify an HRESULT value that the driver
generates from an NTSTATUS value. In general, UMDF 1.x drivers should use the HRESULT_FROM_NT
macro (defined in Winerror.h) to return status to a kernel-mode client. The following example shows how
to use this macro when completing a request.

hr = HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW)
request->Complete(HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW);
return hr;
To return a specific HRESULT value to a kernel-mode client, the following callbacks must use the
HRESULT_FROM_NT macro:
IPnpCallback ::OnQuer yRemove
IPnpCallback ::OnQuer yStop
IPnpCallbackHardware::OnPrepareHardware
IPnpCallbackHardware::OnReleaseHardware
To use the NTSTATUS values that are defined in ntstatus.h, a UMDF 1.x driver must include these two lines
before including any additional headers.

#define UMDF_USING_NTSTATUS
#include <ntstatus.h>

Do not use the HRESULT_FROM_NT macro to convert STATUS_SUCCESS from an NTSTATUS value to an
HRESULT value. Just return S_OK, as shown in the following example.

request->Complete(S_OK);

The framework completes some I/O requests on behalf of UMDF drivers. Sometimes the framework does
not convert HRESULT-typed return values into equivalent NTSTATUS values, so the framework might pass
an HRESULT-typed completion status to a kernel-mode client.
Because of this situation, kernel-mode clients should not use the NT_ERROR macro when testing an I/O
request's completion status, because the NT_ERROR macro does not return TRUE for HRESULT error
values. Kernel-mode drivers should use the NT_SUCCESS macro when testing an I/O request's
completion status.
Kernel-mode client support in earlier UMDF versions
For UMDF versions earlier than version 1.9, a driver's INF file can include an INF AddReg directive to create a
REG_DWORD-sized UpperDriverOk registry value under the WUDF subkey of the device's hardware key.
If the UpperDriverOk registry value is set to a nonzero number, the framework allows kernel-mode drivers to
load above the user-mode driver. The kernel-mode drivers can forward I/O requests from user-mode
applications to the UMDF driver, but kernel-mode drivers cannot send I/O requests that are created in kernel
mode to the UMDF driver.
For UMDF versions 1.9 and later, the UpperDriverOk registry value is obsolete and supported only for existing
drivers. New drivers should use the UmdfKernelModeClientPolicy directive.
Viewing UMDF Objects
2/5/2021 • 3 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

This topic describes how you can use the Wudfext.dll debugger extensions to view information about objects
used by a User-Mode Driver Framework (UMDF) version 1 driver.
Starting with UMDF version 2, you should instead use the Wdfkd.dll debugger extensions. For more info, see
Windows Driver Framework Extensions (Wdfkd.dll).
You can perform the following steps to view information about UMDF version 1 objects:
1. Use one of the following UMDF debugger extensions to view device stacks that are in the host process:
!wudfext.umdevstacks
!wudfext.umdevstack as shown in the following example:
!wudfext.umdevstack <dev-stack-addr>
The information includes driver objects and device objects for each driver. Currently, UMDF allows
only one device stack in a host process so there is no difference between the outputs of these two
extensions.
2. View the complete object tree by using the !wudfext.wudfobject UMDF debugger extension, as in the
following example:
!wudfext.wudfobject <IWDFDriver*> 1
3. Use the !wudfext.wudfdevice UMDF debugger extension as shown in the following example to
determine the Plug and Play (PnP) and power-management state of the device:
!wudfext.wudfdevice <IWDFDevice*>
4. Perform the following steps to determine the queues that are associated with the device:
a. Use the !wudfext.wudfdevicequeues UMDF debugger extension to view the queues that are
associated with the device. This extension shows queue properties, queue state, and driver-owned
requests.
b. Use the !wudfext.wudfqueue UMDF debugger extension as shown in the following example to
obtain information about each queue:
!wudfext.wudfqueue <IWDFIoQueue*>
5. Use the !wudfext.wudfrequest UMDF debugger extension to obtain information about a particular
request. This information includes the underlying user-mode I/O request packet (IRP). From the user-
mode IRP information, you can determine where the request is currently being processed in the stack.
You can also use the !wudfext.umirp UMDF debugger extension to obtain this user-mode IRP
information.
6. Determine all I/O targets by:
a. Using the !wudfext.wudfobject UMDF debugger extension to view the child objects of the device
object. I/O target objects are child objects of the device object.
b. Using the !wudfext.wudfiotarget UMDF debugger extension as shown in the following example
to view information about each I/O target object:
!wudfext.wudfiotarget <IWDFTarget*>
This extension shows the target's state and the list of sent requests.
There is currently no UMDF debugger extension that allows you to view all I/O targets.
7. Use the following UMDF debugger extensions to view information about file objects:
!wudfext.wudfrequest or !wudfext.umirp
Use the !wudfext.wudfrequest or the !wudfext.umirp UMDF debugger extension to view files that are
child objects of device objects.
!wudfext.wudffile
Use the !wudfext.wudffile UMDF debugger extension as shown in the following example to view
information about a framework file:
!wudfext.wudffile <IWDFFile*>
!wudfext.umfile
Use the !wudfext.umfile UMDF debugger extension as shown in the following example to view
information about a UMDF intra-stack file (that is, a file object that a driver in the stack created as
opposed to a file object that was created by an application or by a driver in another stack):
!wudfext.umfile <addr>
In some cases, there might not be a corresponding framework file, and user-mode IRP information might
include a UMDF intra-stack file.
Information that !wudfext.umfile displays includes any IRPs that are queued to the UMDF intra-stack
file. Only driver-created files track user-mode IRPs that are queued to those files. For application-created
files, the I/O manager tracks the kernel-mode IRPs.
!wudfext.umdevstacks and !wudfext.umdevstack
Use the output from the !wudfext.umdevstacks and !wudfext.umdevstack UMDF debugger
extensions to view outstanding UMDF intra-stack files that correspond to driver-created files.
Determining Why a UMDF Driver Consumes an
Excessive Amount of Memory
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

This topic describes how you can use the Wudfext.dll debugger extensions in conjunction with a User-Mode
Driver Framework (UMDF) version 1 driver to determine why a UMDF driver consumes an excessive amount of
memory.
Starting with UMDF version 2, you should instead use the Wdfkd.dll debugger extensions. For more info, see
Windows Driver Framework Extensions (Wdfkd.dll).
To investigate memory usage, use the following steps:
1. View the outstanding object in the object tree by using the !wudfext.wudfobject UMDF debugger
extension.
The !wudfext.wudfobject extension displays information about a WDF object, which includes its parent
and child relationships. If you set bit 0 of the Flags parameter to 1 (0x01), !wudfext.wudfobject
performs a recursive dump of the object tree that is rooted at the object that you passed. To view the
complete object tree, use the following example command:
!wudfext.wudfobject <IWDFDriver*> 1
2. Determine if you see more outstanding objects than you expect.
Your driver might eventually leak these objects (for more information about leaking WDF objects, see
Determining If a Driver Leaks Framework Objects).
These objects might be in the object tree and would therefore eventually be freed. However, they are
being accumulated unnecessarily. These objects might require:
Corrections to their parent objects.
Explicit deletion by using the IWDFObject::DeleteWdfObject method.
Summary of Debugger Extensions in Wudfext.dll
2/5/2021 • 2 minutes to read • Edit Online

WARNING
UMDF 2 is the latest version of UMDF and supersedes UMDF 1. All new UMDF drivers should be written using UMDF 2.
No new features are being added to UMDF 1 and there is limited support for UMDF 1 on newer versions of Windows 10.
Universal Windows drivers must use UMDF 2.
For more info, see Getting Started with UMDF.

The Windows Driver Kit (WDK) includes a debugger extension library, named WudfExt.dll, which is located in the
%DDKROOT%\bin subdirectory. This topic describes the debugger extension commands in WudfExt.dll, which
you can use to debug User-Mode Driver Framework (UMDF) version 1.x drivers.
To debug UMDF drivers starting in UMDF version 2.0, you must instead use the Wdfkd.dll debugger extension
library. For more info, see Windows Driver Framework Extensions (Wdfkd.dll) .
For a complete description of each command in WudfExt.dll, see User-Mode Driver Framework Extensions
(Wudfext.dll). For more information about all available debugger extension libraries, see the documentation that
is supplied with the Windows Debugging package.
To load the WudfExt.dll debugger extension library, enter the following command at the debugger's command
prompt:
!load WudfExt.dll
The following table summarizes the extension commands that the WudfExt.dll extension library provides.

EXT EN SIO N DESC RIP T IO N

!help Shows all debugger extensions that WudfExt.dll supports

!umdevstacks Shows all the device stacks in the host process

!umdevstack Shows information about a device stack in the host


process

!umirps Shows the list of pending I/O request packets in the


host process

!umirp Shows information about a user-mode I/O request


packet

!wudfdriverinfo Shows information about a UMDF driver

!wudfdevicequeues Shows all the I/O queues for a device


EXT EN SIO N DESC RIP T IO N

!wudfqueue Shows information about an I/O queue

!wudfrequest Shows information about an I/O request

!wudfobject Shows information about a WDF object as well as its


parent and child relationships

!wudfdevice Shows Plug and Play (PnP) and power-management


state systems for a device

!wudfdumpobjects Shows the list of outstanding WDF objects; used to


determine any leaked objects when the driver unloads

!wudfiotarget Shows information about an I/O target, including its


state and list of sent requests

!wudffile Shows information about a framework file

!umfile Shows information about a UMDF intra-stack file

!wudffilehandletarget Shows information about a file-handle-based I/O target

!wudfusbtarget Shows information about a USB I/O target

!wudfusbinterface Shows information about a USB interface object

!wudfusbpipe Shows information about a USB pipe object

!wudfrefhist Shows reference count history for a framework object

You might also like