You are on page 1of 571

Table of Contents

What's New for WDF Drivers


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
Using WDF to Develop a Driver
WDF Architecture
Writing a Simple WDF Driver
Sample KMDF Drivers
Sample UMDF Drivers
Sample Toaster Driver Programming Tour
Developing Drivers with the Windows Driver Foundation: Reference Book
Framework Library Versioning
KMDF Version History
UMDF Version History
WDF 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
Framework Object Creation Errors
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
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
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
Power Management for I/O Queues
Using Self-Managed I/O
Handling Requests to Stop a Device
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
Driver Access to Hardware
Reporting Device Failures
Creating WDF HID Minidrivers
Framework File Objects
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
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
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
Handling Client Impersonation in UMDF Drivers
Host Process Timeouts in UMDF
Supporting Kernel-Mode Clients in UMDF Drivers
Using Activity Identifiers
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
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
Synchronization Techniques
Using Automatic Synchronization
Using Framework Locks
WDF Support Objects
Using Memory Buffers
Memory Buffer Life Cycle
Using Timers
Using String Objects
Using Framework Work Items
Using Device Interfaces
Using the Registry in WDF Drivers
Introduction to Registry Keys for Drivers
Using Framework Registry-Key Objects
Accessing the Unified Device Property Model
Security Issues for KMDF Drivers
Controlling Device Access in KMDF Drivers
Handling 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
Handling DMA Operations in KMDF Drivers
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
Supporting WMI in KMDF Drivers
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
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
Building, Installing, and Testing
Building and Loading a WDF Driver
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
Debugging WDF Drivers
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
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 (KMDF and UMDF)
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
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 DMA
Porting WMI
Requests That KMDF Does Not Support
Installation Procedure
Summary of KMDF and WDM Equivalents
WDM Equivalents for WDF Buffer Pointers
WDM IRPs and WDF Event Callback Functions
Additional Topics for KMDF Drivers
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
UMDF 1.x Design Guide
UMDF Objects and Interfaces
Framework Objects
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
PnP and Power Management Scenarios in UMDF
Processing I/O Requests
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
Using I/O Targets in UMDF
General I/O Targets in UMDF
USB I/O Targets in 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
UMDF Driver Tasks
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
What's New for WDF Drivers in Windows 10
4/26/2017 • 6 min to read • Edit Online

This topic summarizes the new features and improvements for Windows Driver Frameworks (WDF) drivers in
Windows 10.
Windows 10, version 1703 includes Kernel-Mode Driver Framework (KMDF) version 1.21 and User-Mode Driver
Framework (UMDF) version 2.21.
You can use these framework versions to build drivers for:
Windows 10 (all SKUs)
Windows Server 2016
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 Redstone 2


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
http://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
http://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 New support for source-level debugging of WDF code in Windows 10,
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 New Performance Tools for WDF Drivers in Windows 10 and 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
4/26/2017 • 2 min 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
4/26/2017 • 4 min 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 easly
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 IDriverEntry interface (UMDF 1.11 and earlier) or the DriverEntry 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
4/26/2017 • 2 min 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 LocalService 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
4/26/2017 • 1 min 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, 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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.

FEATURE RELATED INFORMATION

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 UMDF) Supporting Functional Power States

Access to WDM objects 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
WdfIoTargetSendInternalIoctlOthersSynchronousl
y
Sending I/O Requests Asynchronously
WdfIoTargetFormatRequestForInternalIoctl
WdfIoTargetFormatRequestForInternalIoctlOthers

Remove lock opt-in for I/O requests WdfDeviceInitSetRemoveLockOptions

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)
4/26/2017 • 1 min 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 WdfMemoryCreate. 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
4/26/2017 • 4 min 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 IDriverEntry) is IObjectCallbackXxx, while in UMDF 2 the
naming convention for driver-supplied routines is EvtObjectXxx. For example, the
IDriverEntry::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 IDriverEntry interface. In its IDriverEntry::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 DriverEntry and EvtDriverDeviceAdd. In its DriverEntry 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
Using WDF to Develop a Driver
4/26/2017 • 3 min 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 DriverEntry 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 DriverEntry 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
4/26/2017 • 1 min 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 WdfObjectAction, 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 WdfObjectGetValue and WdfObjectSetValue, and properties that can fail are named
WdfObjectRetrieveValue and WdfObjectAssignValue. 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
4/26/2017 • 1 min 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 DriverEntry 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 DriverEntry 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.
Sample KMDF Drivers
4/26/2017 • 2 min to read • Edit Online

This topic lists the Kernel-Mode Driver Framework (KMDF) sample drivers that you can download from the
Windows driver samples repository 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.
RAMDISK
Demonstrates a software-only driver.
For more information about this sample, see the RAMDisk Storage 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
4/26/2017 • 1 min to read • Edit Online

This topic lists available User-Mode Driver Framework (UMDF) sample drivers that you can download from the
Windows driver samples repository on GitHub.
Windows 8.1 driver samples can be downloaded from the Windows Hardware Dev Center.

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
4/26/2017 • 8 min 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.

TERM 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_HEAD
ER structure.
TERM DESCRIPTION

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_HEAD
ER structure. Address descriptions are optional. This
sample does not use address descriptions.

To add children to a child list, the driver calls [**WdfChildListAddOrUpdateChildDescriptionAsPresent**]


(https://msdn.microsoft.com/library/windows/hardware/ff545591) 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**]


(https://msdn.microsoft.com/library/windows/hardware/ff545591) 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*]
(https://msdn.microsoft.com/library/windows/hardware/ff540828) callback function. This callback function must
call [**WdfDeviceCreate**](https://msdn.microsoft.com/library/windows/hardware/ff545926) 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
4/26/2017 • 1 min 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 links:
Electronic or printed format
Preview or read entire content with a Safari subscription
Framework Library Versioning
4/26/2017 • 1 min 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.
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
4/26/2017 • 3 min 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:

INCLUDED IN THIS VERSION


KMDF VERSION RELEASE METHOD OF WINDOWS DRIVERS USING IT RUN ON

1.21 Windows 10, version Windows 10, version Windows 10 version


1703 WDK 1703 (Creators Update, 1703
Redstone 2)

1.19 Windows 10, version Windows 10, version Windows 10 version


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

1.17 Windows 10, version Windows 10, version Windows 10 version


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

1.15 Windows 10 WDK Windows 10, version Windows 10, version


1507 (Threshold 1) 1507, 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

1.7 Windows Server 2008 Windows Vista with Windows 2000 and later
WDK Service 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 2015 to build drivers that run on
Windows 7 and later.
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.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_FLAGS
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:
WdfDeviceAllocAndQueryPropertyEx
WdfDeviceAssignProperty
WdfDeviceInitSetIoTypeEx
WdfDeviceQueryPropertyEx
WdfFdoInitAllocAndQueryPropertyEx
WdfFdoInitQueryPropertyEx
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
WdfInterruptReportActive
WdfInterruptReportInactive
WdfInterruptTryToAcquireLock
WdfIoQueueStopAndPurge
WdfIoQueueStopAndPurgeSynchronously
WdfIoTargetPurge
WdfUsbTargetDeviceCreateIsochUrb
WdfUsbTargetDeviceCreateUrb
WdfUsbTargetDeviceCreateWithParameters
WdfUsbTargetDeviceQueryUsbCapability
Added EvtDeviceUsageNotificationEx.
Added IdleTimeoutType and ExcludeD3Cold members to
WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS.
Added ReportInactiveOnPowerDown 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
WdfPdoInitAllowForwardingRequestToParent
WdfPdoInitAssignContainerID
WdfPreDeviceInstallEx
WdfRequestForwardToParentDeviceIoQueue
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_CLASS 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
4/26/2017 • 5 min 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.

UMDF Versions and Operating Systems


The following table shows the release history of the UMDF library:

INCLUDED IN THIS VERSION DRIVERS USING IT CAN RUN


UMDF VERSION RELEASE METHOD OF WINDOWS ON

2.21 Windows 10, version Windows 10, version Windows 10 version


1703 WDK 1703 (Creators Update, 1703
Redstone 2)

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

2.17 Windows 10, version Windows 10, version Windows 10 version


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

2.15 Windows 10 WDK Windows 10, version Windows 10, version


1507 (Threshold 1) 1507, 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 Windows 8 Windows Vista and later


(WDK) 8

1.9 Windows 7 WDK Windows 7 Windows XP and later

1.7 Windows Server 2008 Windows Vista with Windows XP and later
WDK Service 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 2015 to build drivers that run on
Windows 7 and later.
For information about the new features for UMDF drivers in Windows 10, see What's New for WDF Drivers.
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
WdfDeviceAllocAndQueryInterfaceProperty
WdfDeviceAssignInterfaceProperty
WdfDeviceGetDeviceStackIoType
WdfDeviceGetHardwareRegisterMappedAddress
WdfDeviceMapIoSpace
WdfDevicePostEvent
WdfDeviceQueryInterfaceProperty
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:
WdfDeviceAllocAndQueryPropertyEx
WdfDeviceAssignProperty
WdfDeviceInitSetIoTypeEx
WdfDeviceQueryPropertyEx
WdfFdoInitAllocAndQueryPropertyEx
WdfFdoInitQueryPropertyEx
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 WdfUsbTargetDeviceQueryUsbCapability:
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
IWDFUnifiedPropertyStore
IWDFUnifiedPropertyStoreFactory
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
WDF Objects
4/26/2017 • 1 min to read • Edit Online

This section describes common characteristics of framework objects and how a Windows Driver Frameworks
(WDF) driver uses object-based interfaces to call methods, register callback routines, set and retrieve property data,
and manage object reference counts.

In this section
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
Framework Object Creation Errors
Introduction to Framework Objects
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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
4/26/2017 • 3 min 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_DECLARE_CONTEXT_TYPE macro or the
WDF_DECLARE_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_DECLARE_CONTEXT_TYPE or the WDF_DECLARE_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
6/2/2017 • 1 min 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_DECLARE_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
4/26/2017 • 1 min 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
4/26/2017 • 3 min 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.
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
4/26/2017 • 2 min 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.

CAN DRIVER
OVERRIDE
DEFAULT DEFAULT
NAME HANDLE PURPOSE PARENT PARENT? MODE REFERENCE

Child-list WDFCHIL Represent Device No KM WDF Child-


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

Collection WDFCOL Represent Driver Yes KM/UM WDF


object LECTION s an object Collection
object Object
collection. Reference

Common WDFCOM Represent DMA No KM WDF


buffer MONBUF sa enabler Common
object FER common object Buffer Object
buffer. Reference

Device WDFDEVI Represent Driver No KM/UM WDF Device


object CE s a device. object Object
Reference

DMA WDFDMA Enables a Device Yes KM WDF DMA


enabler ENABLER driver to object Object
object use the Reference
framewor
k's DMA
capabilitie
s.

DMA WDFDMA Represent DMA No KM WDF DMA


transactio TRANSAC s a DMA enabler Object
n object TION transactio object Reference
n.
CAN DRIVER
OVERRIDE
DEFAULT DEFAULT
NAME HANDLE PURPOSE PARENT PARENT? MODE REFERENCE

DPC WDFDPC Represent None Yes KM WDF DPC


object sa Object
deferred Reference
procedure
call.

Driver WDFDRIV Represent None No KM/UM WDF Driver


object ER s a driver. Object
Reference

File object WDFFILE Represent Device No KM/UM WDF File


OBJECT s a file. object Object
Reference

General WDFOBJE Represent Driver Yes KM/UM WDF General


object CT sa object Object
general Reference
object.

Interrupt WDFINTE Represent Device Yes KM/UM WDF


object RRUPT sa object Interrupt
hardware Object
interrupt Reference
resource.

I/O target WDFIOTA Represent Device Yes KM/UM WDF I/O


object RGET s a driver object Target Object
to which Reference
another
driver
sends I/O
requests.

Lookaside WDFLOO Represent Driver Yes KM WDF Memory


-list object KASIDE sa object Object
lookaside Reference
list.

Memory WDFMEM Represent Driver Yes KM/UM WDF Memory


object ORY sa object Object
memory Reference
buffer.

Queue WDFQUE Represent Device Yes KM/UM WDF Queue


object UE s an I/O object Object
queue Reference
that
receives
I/O
requests.
CAN DRIVER
OVERRIDE
DEFAULT DEFAULT
NAME HANDLE PURPOSE PARENT PARENT? MODE REFERENCE

Registry WDFKEY Represent Driver Yes KM/UM WDF Registry


key object sa object Key Object
registry Reference
key.

Request WDFREQ Represent None, if Yes, if KM/UM WDF Request


object UEST s an I/O created created Object
request. by by driver. Reference
framewor
k. Driver
object, if
created
by driver.

Resource WDFCMR Represent Driver No KM/UM WDF


list object ESLIST sa object Resource
resource Object
list. Reference

Resource WDFIORE Represent Resource No KM WDF


range list SLIST s a logical requireme Resource
object configurat nts list Object
ion. object Reference

Resource WDFIORE Represent Driver No KM WDF


requireme SREQLIST sa object Resource
nts list resource Object
object requireme Reference
nts list.

Spin-lock WDFSPIN Represent Driver Yes KM/UM WDF


object LOCK s a spin object Synchronizati
lock. on Methods

String WDFSTRI Repesents Driver Yes KM/UM WDF String


object NG a Unicode object Object
string. Reference

Timer WDFTIME Represent None Yes KM/UM WDF Timer


object R s a timer. Object
Reference

USB WDFUSB Represent Device No KM/UM WDF USB


device DEVICE s a device object Reference
object connected
to a USB.
CAN DRIVER
OVERRIDE
DEFAULT DEFAULT
NAME HANDLE PURPOSE PARENT PARENT? MODE REFERENCE

USB WDFUSBI Represent USB No KM/UM WDF USB


interface NTERFAC s a USB device Reference
object E device object
interface.

USB pipe WDFUSBP Represent USB No KM/UM WDF USB


object IPE s a USB interface Reference
device object
pipe.

Wait-lock WDFWAIT Represent Driver Yes KM/UM WDF


object LOCK s a wait object Synchronizati
lock. on Methods

WMI WDFWMI Represent WMI No KM WDF WMI


instance INSTANCE s an provider Reference
object instance object
of a WMI
data
block.

WMI WDFWMI Represent Device No KM WDF WMI


provider PROVIDE s a WMI object Reference
object R data
block.

Work- WDFWOR Represent None Yes KM/UM WDF Work-


item KITEM s a work Item Object
object item. Reference
Framework Object Creation Errors
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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.
Creating a Framework Device Object
4/26/2017 • 1 min 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
4/26/2017 • 3 min 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 WdfFdoInitQueryProperty or
WdfFdoInitAllocAndQueryProperty to obtain this information. New drivers targeting Windows 8.1 and
later can call WdfFdoInitQueryPropertyEx and WdfFdoInitAllocAndQueryPropertyEx.
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 WdfFdoInitOpenRegistryKey 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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.
Power Policy Ownership
4/26/2017 • 2 min 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
4/26/2017 • 3 min 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.

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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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 to
IdleAllowUserControl or WakeAllowUserControl, respectively, and the Enabled member to WdfTrue or
WdfUseDefault, in the appropriate settings structure.
Supporting Functional Power States
4/26/2017 • 1 min 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.

WHEN TO USE/HOW TO
TYPE KMDF SUPPORT UMDF SUPPORT IMPLEMENT

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
WdfDeviceAssignS0Idl
eSettings with
IdleTimeoutType =
SystemManagedIdleTi
mout or
SystemManagedIdleTi
moutWithHint.
WHEN TO USE/HOW TO
TYPE KMDF SUPPORT UMDF SUPPORT IMPLEMENT

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
WdfDeviceAssignS
0IdleSettings with
IdleTimeoutType =
SystemManagedIdl
eTimout.
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
4/26/2017 • 4 min 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 WdfInterruptReportInactive 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 WdfInterruptReportInactive, re-enable inactive interrupts by calling
WdfInterruptReportActive from either ComponentActiveConditionCallback or ComponentIdleStateCallback.
Supporting Multiple-Component Devices with Single
or Multiple Functional Power States
4/26/2017 • 1 min 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
PoFxStartDevicePowerManagement. 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
4/26/2017 • 4 min 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:

REQUEST TYPE COMPONENTS NEEDED

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
WdfIoQueueStart 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
4/26/2017 • 1 min 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 PoFxReportDevicePoweredOn 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 PoFxReportDevicePoweredOn from its next EvtDeviceD0Entry callback.
2. In EvtDeviceD0Entry, if the flag is set, the driver clears the flag and calls PoFxReportDevicePoweredOn.
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 PoFxReportDevicePoweredOn and then
unregisters with the power framework.
Supporting Idle Power-Down on Multiple-
Component Devices
4/26/2017 • 1 min 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
PoFxReportDevicePoweredOn.
Power Management for I/O Queues
4/26/2017 • 3 min 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
4/26/2017 • 3 min 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
4/26/2017 • 2 min 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 WdfDeviceSetSpecialFileSupport 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.
PnP and Power Management Scenarios
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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 DriverEntry 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
4/26/2017 • 3 min 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 WdfDeviceSetSpecialFileSupport 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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 WdfDeviceSetSpecialFileSupport 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
4/26/2017 • 1 min to read • Edit Online

The following topics show the sequence in which the framework calls a KMDF 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
For information about UMDF callback sequences, see PnP and Power Management Scenarios in UMDF.
Power-Up Sequence for a Function or Filter Driver
4/26/2017 • 1 min 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 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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.
Surprise-Removal Sequence
4/26/2017 • 1 min 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.
Driver Access to Hardware
4/26/2017 • 1 min 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.

EVENT CALLBACKS FUNCTIONSFOR FRAMEWORK DEVICE OBJECTS IS HARDWARE ACCESSIBLE?

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

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


EVENT CALLBACKS FUNCTIONSFOR FRAMEWORK DEVICE OBJECTS IS HARDWARE ACCESSIBLE?

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.


Reporting Device Failures
4/26/2017 • 1 min to read • Edit Online

There are two 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.
For both methods, the framework effectively removes 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 WdfDeviceFailedAttemptRestart and WdfDeviceFailedNoRestart.
UMDF A UMDF driver must set this value to WdfDeviceFailedNoRestart.
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 WdfDeviceFailedNoRestart.
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
4/26/2017 • 2 min 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
4/26/2017 • 5 min 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 AutoForwardCleanupClose 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.
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.
Framework Queue Objects
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 3 min 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 WdfIoQueueStart 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 4 min 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
WdfIoQueueStart.
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
WdfRequestForwardToIoQueue.

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 WdfRequestForwardToIoQueue or
WdfRequestForwardToParentDeviceIoQueue, 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
4/26/2017 • 2 min 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
4/26/2017 • 1 min 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 WdfIoQueueStart 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
4/26/2017 • 6 min 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 WdfIoQueueStart.

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 WdfRequestForwardToIoQueue 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.
Framework Request Objects
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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
WdfRequestForwardToIoQueue 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 WdfRequestForwardToIoQueue to requeue each request to an additional queue.
If your driver calls WdfRequestForwardToIoQueue 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 WdfRequestForwardToIoQueue 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 WdfPdoInitAllowForwardingRequestToParent before it
creates a child device and then call WdfRequestForwardToParentDeviceIoQueue to requeue a request from
the child's I/O queue to a parent queue. If a driver usesWdfPdoInitAllowForwardingRequestToParent and
WdfRequestForwardToParentDeviceIoQueue, 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
4/26/2017 • 4 min 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
4/26/2017 • 4 min 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 WdfRequestForwardToIoQueue (or
WdfRequestForwardToParentDeviceIoQueue) 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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
4/26/2017 • 1 min 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)
4/26/2017 • 9 min 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
WdfRequestRetrieveInputMemory or WdfRequestRetrieveOutputMemory, depending on whether this is a
read or write request. The driver can then retrieve a pointer to the buffer by calling WdfMemoryGetBuffer. To
read and write the buffer, the driver calls WdfMemoryCopyFromBuffer or WdfMemoryCopyToBuffer.
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
WdfRequestRetrieveInputMemory or WdfRequestRetrieveOutputMemory. The driver can then retrieve a
pointer to the buffer by calling WdfMemoryGetBuffer. To read and write the buffer, the driver calls
WdfMemoryCopyFromBuffer or WdfMemoryCopyToBuffer.
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 WdfMemoryGetBuffer 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
4/26/2017 • 4 min 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
4/26/2017 • 1 min 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.
Handling Client Impersonation in UMDF Drivers
4/26/2017 • 4 min 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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
4/26/2017 • 1 min 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.
Using I/O Targets
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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.

METHOD PURPOSE

WdfIoTargetSendReadSynchronously Sends a read request

WdfIoTargetSendWriteSynchronously Sends a write request

WdfIoTargetSendIoctlSynchronously Sends a device control request

WdfIoTargetSendInternalIoctlSynchronously Sends an internal device control request

WdfIoTargetSendInternalIoctlOthersSynchronously Sends a non-standard internal device control request

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
4/26/2017 • 1 min 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.

METHOD PURPOSE

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
4/26/2017 • 3 min 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 WdfIoTargetStart
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
WdfIoTargetStart 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
WdfIoTargetCloseForQueryRemove 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
4/26/2017 • 1 min 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.
WdfIoTargetQueryTargetProperty or WdfIoTargetAllocAndQueryTargetProperty
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
4/26/2017 • 1 min 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
4/26/2017 • 4 min 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:
WdfUsbTargetDeviceQueryUsbCapability
Determines whether the host controller and USB driver stack support a specific capability. Before calling
WdfUsbTargetDeviceQueryUsbCapability, 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.
WdfUsbTargetDeviceQueryString
Copies a Unicode string to a driver-supplied buffer.
WdfUsbTargetDeviceAllocAndQueryString
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:
WdfUsbTargetDeviceResetPortSynchronously
Synchronously sends a request to reset a device's USB port.
WdfUsbTargetDeviceCyclePortSynchronously (KMDF only)
Synchronously sends a request to power-cycle a device's USB port.
WdfUsbTargetDeviceFormatRequestForCyclePort (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
4/26/2017 • 1 min 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
4/26/2017 • 5 min 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 WdfIoTargetStart 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:
WdfUsbTargetPipeAbortSynchronously
Synchronously sends a request to stop a USB pipe.
WdfUsbTargetPipeFormatRequestForAbort
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 WdfUsbTargetPipeAbortSynchronously, or call WdfUsbTargetPipeFormatRequestForAbort
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 WdfIoTargetStart.
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 WdfUsbTargetDeviceResetPortSynchronously.
3. Restart the pipes.
Call WdfIoTargetStart 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.
Synchronization Techniques
4/26/2017 • 1 min to read • Edit Online

This section describes how a Windows Driver Frameworks (WDF) driver can customize the framework's built-in
callback synchronization, or use manual locks to control when the framework calls the driver's callback routines.

In this section
Using Automatic Synchronization
Using Framework Locks
Using Automatic Synchronization
4/26/2017 • 10 min 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 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.

OBJECT TYPE SYNCHRONIZED CALLBACK FUNCTIONS

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.

IRQL OF QUEUE AND FILE CALLBACK


SYNCHRONIZATION SCOPE EXECUTION LEVEL FUNCTIONS

WdfSynchronizationScopeDevic WdfExecutionLevelPassive PASSIVE_LEVEL


e

WdfSynchronizationScopeDevic WdfExecutionLevelDispatch DISPATCH_LEVEL


e

WdfSynchronizationScopeQueue WdfExecutionLevelPassive PASSIVE_LEVEL

WdfSynchronizationScopeQueue WdfExecutionLevelDispatch DISPATCH_LEVEL

WdfSynchronizationScopeNone WdfExecutionLevelPassive PASSIVE_LEVEL

WdfSynchronizationScopeNone WdfExecutionLevelDispatch <= DISPATCH_LEVEL


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. (In fact, if your driver's client runs in user mode, the driver is always called at IRQL =
PASSIVE_LEVEL even if you do not specify WdfExecutionLevelPassive.)
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
4/26/2017 • 2 min 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.
WDF Support Objects
4/26/2017 • 1 min to read • Edit Online

The topics in this section describe how a Windows Driver Frameworks (WDF) driver uses memory buffers, timers,
string objects, work items, and other support functionality that the framework provides.

In this section
Using Memory Buffers
Memory Buffer Life Cycle
Using Timers
Using String Objects
Using Framework Work Items
Using Device Interfaces
Using the Registry in WDF Drivers
Security Issues for KMDF Drivers
Using Memory Buffers
4/26/2017 • 3 min 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:
WdfMemoryCreate, which creates a memory object and allocates a memory buffer of a specified size.
WdfMemoryCreatePreallocated, which creates a memory object for a preallocated buffer.
WdfMemoryCreateFromLookaside, 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
WdfRequestRetrieveInputMemory and WdfRequestRetrieveOutputMemory. 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 WdfMemoryGetBuffer.
To move data into or out of a memory object's buffer, your driver calls either WdfMemoryCopyFromBuffer or
WdfMemoryCopyToBuffer. These object methods check the source and destination sizes and prevent buffer
overrun errors.
If your driver creates a memory object by calling WdfMemoryCreatePreallocated, it can subsequently assign a
different buffer to the memory object by calling WdfMemoryAssignBuffer.
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 WdfMemoryCreateFromLookaside.
Each time the driver calls WdfMemoryCreateFromLookaside, 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
WdfMemoryCreateFromLookaside, 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.
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
4/26/2017 • 5 min 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
WdfMemoryCreatePreallocated, 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
4/26/2017 • 4 min 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 WdfTimerStart, 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.
A driver might call WdfTimerStart 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.

PERIOD, IN MS STANDARD TIMER HIGH RESOLUTION TIMER

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
4/26/2017 • 1 min 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 WdfRegistryQueryString, 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
4/26/2017 • 4 min 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.
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.
Using Device Interfaces
4/26/2017 • 4 min 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 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 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, the framework automatically enables all of a device's
interfaces when the device enters its working state and disables the interfaces when the device leaves its working
state. If the driver specified a physical device object (PDO) when it called WdfDeviceCreateDeviceInterface, the
framework re-enables the device's interfaces if a disabled device is re-enabled.
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 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
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;
}

```

1. 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
Using the Registry in WDF Drivers
4/26/2017 • 1 min to read • Edit Online

Driver writers typically use the Microsoft Windows registry to store and retrieve configuration information about
their driver and its devices. The framework defines a registry-key object that drivers should use to access registry
keys and values.

In this section
Introduction to Registry Keys for Drivers
Using Framework Registry-Key Objects
Accessing the Unified Device Property Model
Introduction to Registry Keys for Drivers
4/26/2017 • 1 min 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. For Kernel-Mode Driver
Framework (KMDF) drivers, this key is located in the HKLM\SYSTEM\CurrentControlSet\Services tree,
under the driver's service name. For User-Mode Driver Framework (UMDF) drivers, this key is located in the
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services 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 DriverEntry routine, it passes the driver a path to the driver's Services
tree. Your driver must pass this path to WdfDriverCreate. Subsequently, the driver can obtain the path by
calling WdfDriverGetRegistryPath, and the driver can open its Parameters key by calling
WdfDriverOpenParametersRegistryKey.
For more information about the Parameters key, see The HKLM\SYSTEM\CurrentControlSet\Services Tree.
Software key
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 WdfFdoInitOpenRegistryKey and WdfDeviceOpenRegistryKey to open its software
key.
For more information about software keys, see The HKLM\SYSTEM\CurrentControlSet\Control Tree.
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. The PnP manager
stores each device's unique identification information under the device's hardware key.
Your driver can call WdfFdoInitOpenRegistryKey and WdfDeviceOpenRegistryKey to open a device's
hardware key.
For more information about hardware keys, see The HKLM\SYSTEM\CurrentControlSet\Enum Tree.
Your driver's INF file can contain INF AddReg directives that set registry values. INF files typically use INF
DDInstall.HW sections to set information under a device's hardware key.
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:
Overview of Registry Trees and Keys
Using the Registry in a Driver
Using Framework Registry-Key Objects
4/26/2017 • 2 min 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 WdfRegistryOpenKey. If the key does not exist, the driver must call
WdfRegistryCreateKey, 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:
WdfRegistryQueryMemory
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.
WdfRegistryQueryMultiString
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.
WdfRegistryQueryString
Retrieves the string data that is currently assigned to a string-typed value name and assigns the string to a
specified framework string object.
WdfRegistryQueryUnicodeString
Retrieves the string data that is currently assigned to a string-typed value name and copies the string to a specified
UNICODE_STRING structure.
WdfRegistryQueryULong
Retrieves the unsigned long word (REG_DWORD) data that is currently assigned to a value name and copies the
data to a specified location.
WdfRegistryQueryValue
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.
WdfRegistryAssignMemory
Assigns data that is contained in a memory buffer to a specified value name in the registry.
WdfRegistryAssignMultiString
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.
WdfRegistryAssignString
Assigns a string to a specified value name in the registry. The string is contained in a framework string object.
WdfRegistryAssignUnicodeString
Assigns a specified Unicode string to a specified value name in the registry.
WdfRegistryAssignULong
Assigns a specified unsigned long word value to a specified value name in the registry.
WdfRegistryAssignValue
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 WdfRegistryRemoveValue. To remove a key, the driver must call
WdfRegistryRemoveKey.
To obtain WDM information about the registry, a driver can call WdfRegistryWdmGetHandle, 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 WdfRegistryClose or WdfObjectDelete to
close the key and delete the registry-key object.
Accessing the Unified Device Property Model
4/26/2017 • 1 min 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:
WdfDeviceAllocAndQueryPropertyEx
WdfDeviceAssignProperty
WdfDeviceQueryPropertyEx
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
WdfDeviceXxxProperty method.
WdfFdoInitAllocAndQueryPropertyEx
WdfFdoInitQueryPropertyEx
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 WdfXxxQueryProperty 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 WdfXxxQueryProperty again. Therefore, drivers should call WdfXxxQueryProperty inside a
loop that executes until the return status is not STATUS_BUFFER_TOO_SMALL.
It is best to use WdfXxxQueryProperty only if the required buffer size is known and unchanging, because in that
case the driver has to call WdfXxxQueryProperty only once. If the required buffer size is unknown or varies, the
driver should call WdfXxxAllocAndQueryProperty.

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:
WdfDeviceAllocAndQueryInterfaceProperty
WdfDeviceAssignInterfaceProperty
WdfDeviceQueryInterfaceProperty
To retrieve or modify a device interface property, a KMDF driver must call IoGetDeviceInterfacePropertyData
or IoSetDeviceInterfacePropertyData directly.
Security Issues for KMDF Drivers
4/26/2017 • 1 min to read • Edit Online

Like all kernel-mode drivers, framework-based drivers must be reliable and secure.
This section includes:
Controlling Device Access in Framework-Based Drivers
Controlling Device Access in KMDF Drivers
4/26/2017 • 3 min 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 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.
Handling Hardware Interrupts
4/26/2017 • 1 min to read • Edit Online

The topics in this section describe how a Windows Driver Frameworks (WDF) driver creates framework interrupt
objects to service hardware interrupts, and how your driver synchronizes access to interrupt data buffers.

In this section
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
Creating an Interrupt Object
4/26/2017 • 3 min 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
4/26/2017 • 1 min to read • Edit Online

If your driver handles device interrupts, it must provide 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
4/26/2017 • 1 min 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 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
4/26/2017 • 4 min 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
6/2/2017 • 6 min 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(
&memoryDescriptor,
&intReport,
&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;
}

//
// Retrive 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);

//
//
// 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 WdfInterruptTryToAcquireLock 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 WdfInterruptTryToAcquireLock 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 WdfInterruptTryToAcquireLock.
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
4/26/2017 • 2 min 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
4/26/2017 • 3 min 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_FLAGS 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++)


{
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.
Handling DMA Operations in KMDF Drivers
4/26/2017 • 1 min to read • Edit Online

[Applies to KMDF only]


This section describes how a Kernel-Mode Driver Framework (KMDF) driver converts I/O requests into direct
memory access (DMA) operations. KMDF supports bus-master and system-mode DMA.

In this section
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
Supporting System-Mode DMA
Canceling DMA Transactions
Reserving DMA Resources
Testing DMA in KMDF Drivers
For information on how support DMA operations in WDM drivers, see DMA Programming Techniques.
Introduction to DMA in Windows Driver Framework
4/26/2017 • 1 min 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.
Framework DMA Objects
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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
4/26/2017 • 2 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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 WdfCommonBufferGetAlignedVirtualAddress 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
4/26/2017 • 2 min 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
4/26/2017 • 2 min 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
4/26/2017 • 1 min 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_FLAGS
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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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.
Supporting WMI in KMDF Drivers
4/26/2017 • 1 min to read • Edit Online

[Applies to KMDF only]


The topics in this section describe how a Kernel-Mode Driver Framework (KMDF) driver registers as a WMI data
provider, responds to requests for instance data, and sends events to registered WMI clients.

In this section
Introduction to WMI for KMDF Drivers
Initializing WMI Support in Your Driver
Supporting WMI Data Blocks and Events in Your Driver
Introduction to WMI for KMDF Drivers
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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
4/26/2017 • 3 min 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
UseContextForQuery member of the instance's WDF_WMI_INSTANCE_CONFIG structure to TRUE.
If the driver sets UseContextForQuery 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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 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:
WdfRegistryWdmGetHandle
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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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
4/26/2017 • 2 min 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 WdfRequestForwardToIoQueue. 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
WdfPdoInitAllowForwardingRequestToParent 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_FORWARD_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 WdfPdoInitAllowForwardingRequestToParent if the target is the parent device's I/O queue.
3. From EvtDeviceWdmIrpPreprocess, call WdfDeviceWdmDispatchIrpToIoQueue with Flags set to
WDF_FORWARD_IRP_TO_IO_QUEUE_PREPROCESSED_IRP.
4. If the driver has set the WDF_FORWARD_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
4/26/2017 • 1 min 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.
Handling Hardware Resources
4/26/2017 • 1 min 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
4/26/2017 • 3 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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 WdfIoResourceListInsertDescriptor 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
WdfIoResourceRequirementsListInsertIoResList.
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
4/26/2017 • 1 min 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
WdfIoResourceRequirementsListInsertIoResList, 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 WdfIoResourceListInsertDescriptor, to add a resource
descriptor.
Creating a Resource List for a Boot Configuration
4/26/2017 • 1 min 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 WdfCmResourceListInsertDescriptor 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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 CmResourceTypeMemory, 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
4/26/2017 • 1 min 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 (CmResourceTypeMemory) 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 (CmResourceTypeMemory), 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 Library 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 (CmResourceTypePort, 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
4/26/2017 • 2 min to read • Edit Online

After a driver has mapped registers as described in Finding and Mapping Hardware Resources, a KMDF driver uses
the HAL Library 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&#39;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;
}
Building, Installing, and Testing
4/26/2017 • 1 min 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
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
4/26/2017 • 2 min to read • Edit Online

This topic describes how to select a target operating system and framework version for a driver project in Visual
Studio. It also describes the co-installer and how to determine if you should include this component in your driver
package.

Which framework version should I use?


If your driver needs to run only on Windows 8.1, use Kernel-Mode Driver Framework (KMDF) version 1.13 or User-
Mode Driver Framework (UMDF) version 2.0.
If your driver must work on operating systems earlier than Windows 8.1, we recommend that you use KMDF or
UMDF version 1.11.
You can use the Windows Driver Kit (WDK) that ships with Windows 8.1 to build KMDF 1.9, 1.11, and 1.13 drivers,
as well as UMDF 1.9, 1.11, and 2.0 drivers.

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:
Change the Project Configuration setting in the Configuration Manager to an appropriate value (such as
Win7 Debug).
Change the KMDF_VERSION_MINOR or UMDF_VERSION_MINOR value in the Driver Model Settings to an
appropriate value (such as 11).
For detailed information about KMDF and UMDF versions, see KMDF Version History and UMDF Version History.

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


If you build a driver for Windows 8.1 using KMDF 1.13 or UMDF 2.0, you do not need to include a co-installer,
custom installer, or reference in the INF file.
If your driver must work on operating systems earlier than Windows 8.1, we recommend that you use KMDF or
UMDF version 1.11, and that you include Microsoft-supplied framework updates in your driver package.
The 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.

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: FxDriverEntry. MSBuild sets the stub's FxDriverEntry 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 FxDriverEntry 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 DriverEntry
routine.
Redistributable Framework Components
4/26/2017 • 1 min to read • Edit Online

This topic describes the Microsoft-supplied redistributable framework updates that are included as part of the
Windows Driver Kit (WDK) for Windows 8.1, and how to determine which ones to add to your driver package.
To determine if you need to include any framework updates at all in your driver package, see Building and Loading
a WDF Driver. If you don't, skip this topic.

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. You can find a sample of
such an application in the WDK, in the src\general\installwdf directory.
In the latter case, no INF entries are needed.

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


When you build your driver in Visual Studio, MSBuild places the co-installer in the resulting Package directory,
along with the driver's .sys and INF files.
The full set of redistributable framework update files is located in %programfiles%\windows kits\<WDK
version>\redist\wdf.
This directory contains the following files, for x86 and x64:
WdfCoinstaller01009.dll, wdfcoinstaller01011.dll (co-installers for KMDF 1.9/1.11).
WUDFUpdate_01009.dll, WUDFUpdate_01011.dll (co-installers for UMDF).
winusbcoinstaller.dll, winusbcoinstaller2.dll (co-installers for WinUSB 1.5/1.9).
WinUSB_1.9.msu – WinUSB version 1.9 update, also available as KB971286.
kmdf-1.11-Win-6.0.msu, kmdf-1.11-Win-6.1.msu - Windows Update package for KMDF 1.11 for Windows Vista
(v6.0) / Windows 7 (v6.1).
umdf-1.11-Win-6.0.msu, umdf-1.11-Win-6.1.msu – Windows Update package for UMDF 1.11 for Windows
Vista (v6.0) / Windows 7 (v6.1).

Co-installer Naming and Versioning


The co-installer is named WdfCoInstallerMMmmm.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
4/26/2017 • 2 min 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:
KmdfService = 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:
KmdfLibraryVersion = 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_Device.NT.Wdf]
KmdfService = MyDevice, MyDevice_wdfsect
[MyDevice_wdfsect]
KmdfLibraryVersion = 1.0
....
....
=============== End of MyDevice.inf ===============
Using the UMDF Co-installer
4/26/2017 • 3 min 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
4/26/2017 • 2 min 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 Properties. In the Property Pages for the package,
click Configuration Properties, and then StampInf.
You can also manually run the Stampinf tool, which is located in the bin subdirectory of the WDK.
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)
4/26/2017 • 1 min 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. 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.
For general information about testing your driver using Microsoft Visual Studio and the Windows Driver Kit (WDK),
see Testing a Driver.
Troubleshooting KMDF and UMDF Driver Installation
4/26/2017 • 3 min to read • Edit Online

The framework's co-installer creates debugging messages. You can see these messages in a debugger if you are
running a checked build of Windows.
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&#39;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
4/26/2017 • 1 min 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
IDriverEntry::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 UmdfService and
UmdfServiceOrder 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 UmdfServiceOrder entry.
The first parameter specifies the lowest UMDF driver in the device stack. To install a lower filter driver,
simply reverse the arguments for UmdfServiceOrder.
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
4/26/2017 • 2 min 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
AddService directive in an INF DDInstall.Services 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 AddService 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 AddService directive.
The following code example, taken from the WUDFVhidmini sample, shows an AddService 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 AddService directive references an service-install-section similar to the following code example. The
ServiceType entry specifies 1 or 0x00000001, which indicates that the INF installs support for one or more
devices. The StartType entry specifies when to start the driver. The ErrorControl entry specifies the level of error
control that the driver provides. The ServiceBinary 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 AddService 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 StartName 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
4/26/2017 • 9 min 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.Services 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 in the following list:
UmdfService = <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. The sectionName parameter
references the UMDF-service-install section. A valid INF file typically requires at least one UmdfService
directive. However, if a UMDF driver is part of the operating system, a UmdfService directive for the UMDF
driver is not required. Therefore, a valid INF file might not have any UmdfService directives, although most
INF files have one UmdfService directive for each UMDF driver.
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.
UMDF versions 1.11 and later support the UmdfHostProcessSharing directive.
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:
Connecting a UMDF Driver to GPIO I/O Pins
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.
UMDF versions 1.11 and later support the UmdfDirectHardwareAccess directive.
UmdfHostPriority = <PriorityHigh>
Starting in UMDF version 2.15, 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 = <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.
UMDF versions 1.11 and later support the UmdfRegisterAccessMode directive.
UmdfServiceOrder = <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 UmdfService 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 UmdfServiceOrder directive must be present
in any given WDF-specific DDInstall section. That is, the UmdfServiceOrder directive cannot be imported by
using the Include and Needs directives.
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 = <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 = <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 = <AllowKernelModeClients | RejectKernelModeClients>


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.
UMDF versions 1.9 and later support the UmdfKernelModeClientPolicy directive. 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.
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.
UMDF versions 1.11 and later support the UmdfFileObjectPolicy directive.
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.
UMDF versions 1.11 and later support the UmdfFsContextUsePolicy directive.

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 = <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 = <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 = <{CLSID}>
Note This directive is available in UMDF versions 1.11 and earlier.
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 = <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\Services
On Windows 8.1 and earlier, 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
Using Device Pooling in UMDF Drivers
4/26/2017 • 2 min 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 IDriverEntry::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 IDriverEntry::OnInitialize and IDriverEntry::OnDeinitialize methods once
for each device stack.
The framework calls the driver’s IDriverEntry::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 IDriverEntry::OnInitialize and IDriverEntry::OnDeinitialize methods only
once.
The framework calls the driver’s IDriverEntry::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
4/26/2017 • 1 min 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 SetupDiXxx functions to retrieve a Plug and Play device property. For example, the
UMDF Sample Driver for OSR USB Fx2 Learning Kit calls SetupDiGetDeviceRegistryProperty to
retrieve the GUID for the device's bus type. Note A UMDF driver cannot safely call many of the
SetupDiXxx 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
4/26/2017 • 1 min 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
6/2/2017 • 1 min 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
4/26/2017 • 4 min 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
4/26/2017 • 3 min 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\Services 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\Services 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
6/2/2017 • 3 min 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 recommend running Application Verifier (AppVerif.exe) on WUDFHost.exe while testing or debugging your
UMDF driver. Use the following command, 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\Services\<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\Services\*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\Services 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\Services 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
4/26/2017 • 2 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
Debugging WDF Drivers
4/26/2017 • 1 min to read • Edit Online

The topics in this section describe techniques and tools that you can use to debug a Kernel-Mode Driver
Framework (KMDF) or User-Mode Driver Framework (UMDF) driver.

In this section
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
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 (KMDF and UMDF)
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
Videos: Debugging KMDF Drivers
Videos: Debugging UMDF Drivers
Accessing UMDF Metadata in WER Reports
6/2/2017 • 4 min 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.
INDEX NAME VALUES

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:
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:
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.
INDEX NAME VALUES

5 Operation Contains one of the following


enumeration values:
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.

INDEX NAME VALUES

0 EventClass The framework sets this value to


UnhandledException.
INDEX NAME VALUES

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.

INDEX NAME VALUES

0 EventClass The framework sets this value to


VerifierFailure.
INDEX NAME VALUES

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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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 (referred to as a free build environment or a checked build
environment in Windows 7 and earlier). 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.
Bug Checks from KMDF Drivers
4/26/2017 • 1 min 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_VIOLATION.
Your driver can create a bug check by calling WdfVerifierKeBugCheck.
Debugging Power Reference Leaks in WDF
6/2/2017 • 1 min 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\Services\<Driver Service Name>\Parameters\Wdf
For a UMDF driver:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services\<Driver Service
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
4/26/2017 • 2 min 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\Services\
<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
4/26/2017 • 3 min 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
4/26/2017 • 2 min 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
4/26/2017 • 1 min to read • Edit Online

This topic describes how you can analyze why the reflector terminated the driver host process (WUDFHost.exe).
The most common reason for the reflector to terminate the host process is the expiration of UMDF host process
timeouts.

Using Dump Files


For many crashes, dump file details are sufficient to determine why the termination occurred. To review dump file
information, follow these steps:
1. Locate the latest .dmp file in the %windir%\system32\LogFiles\WUDF directory.
Note Starting in UMDF 2.15, the log directory is %ProgramData%\Microsoft\WDF.
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.

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, 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
4/26/2017 • 2 min 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 ChkINF 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 HostProcessDbgBreakOnStart registry entry by using the
WDF Verifier control application (WdfVerifier.exe). By enabling HostProcessDbgBreakOnStart, 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 HostProcessDbgBreakOnStart 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 IDriverEntry::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::OnD0Entry 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
4/26/2017 • 1 min 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
6/2/2017 • 5 min to read • Edit Online

You can use the following configurations to debug a User-Mode Driver Framework (UMDF) driver. All
configurations involve two machines, a host and a target. You run Microsoft Visual Studio and the Windows Driver
Kit (WDK) to build the driver on the host computer, and then install and test your driver on the target machine.
Use Visual Studio to copy ("deploy") the driver to the target and start a user-mode debugging session within
Visual Studio on the host.
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.
You can use the latter two configurations together, running both a user-mode debugger on the target and a
kernel-mode debugger on the host.

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.
Enable Driver Verifier. Open a Command Prompt window (Run as administrator). Type verifier to open
the Driver Verifier Manager.
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 UMDF version 1.11.
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.

Using Visual Studio with F5 to attach automatically (user-mode


debugging)
Before you can use Visual Studio with the WDK to debug a driver on a test computer, you must first set up and
configure your test machine. For information on how to do this, see Deploying a Driver to a Test Computer.
After you have configured your test computer, use Visual Studio on the host computer to set breakpoints in your
driver. When you press F5, Visual Studio builds the driver, deploys it to the target computer, and starts a user-
mode debugging session.
When you deploy a UMDF driver using this technique, Visual Studio turns on UMDF debug mode for that driver.
By default, debug mode means that:
The driver starts in its own dedicated host process. Device pooling is turned off.
Devices are not automatically restarted after a driver crash, and error reporting is disabled.
The framework does not enforce the timeouts described in Host Process Timeouts in UMDF.
If the UMDF host process or the framework verifier detects an invalid operation, UMDF breaks into the user-
mode debugger.
You can use debug mode to debug a UMDF driver even if driver installation requires a reboot. You can also debug
user-mode drivers that start before the user logs in, for example biometrics, smartcard, or input.

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 HostProcessDbgBreakOnStart 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
HostProcessDbgBreakOnDriverStart or HostProcessDbgBreakOnDriverLoad to 0x80000000 to specify no
timeout, but break into the kernel debugger.
In UMDF 1.11 or later, before breaking into the kernel debugger, the reflector automatically switches the process
context to that of the host process. As a result, you can use UMDF debugger extension commands immediately,
without first issuing the .process command to change the process context.
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 HostProcessDbgBreakOnDriverStart and
HostProcessDbgBreakOnDriverLoad. (When HostProcessDbgBreakOnDriverStart 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 (KMDF
and UMDF)
4/26/2017 • 7 min to read • Edit Online

This topic describes the registry values that a Windows Driver Frameworks (WDF) driver can set. It applies to
Kernel-Mode Driver Framework (KMDF) drivers and User-Mode Driver Framework (UMDF) drivers starting with
UMDF version 2.
The following registry values can exist 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.
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.
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.
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.)
DbgWaitForSignalTimeoutInSec (REG_DWORD)
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.
This value is available in framework versions 1.11 and later.
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.
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.
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.)
ForceLogsInMiniDump (REG_DWORD)
Set to a nonzero value to cause the framework to include information from its event logger in crash dump files.
TraceDelayTime (REG_DWORD)
For Microsoft Windows 2000 only, set to a nonzero value to introduce a delay during initialization of WPP
software tracing. The value is specified in milliseconds and a useful value is 1000 (1 second). Without this delay,
the first part of the WPP trace might be missed.
EnhancedVerifierOptions (REG_DWORD)
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_VIOLATION 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_VIOLATION 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.
This value is available in framework versions 1.9 and later.
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. 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 available in framework versions 1.9 and later.

KMDF
For a KMDF driver, the following registry value can exist under the
HKLM\SYSTEM\CurrentControlSet\Control\Wdf\Kmdf\Diagnostics registry key. For a UMDF driver, the
following registry value can exist under the
HKLM\System\CurrentControlSet\Control\Wdf\Umdf\Diagnostics registry key. The driver might need to
create the optional Diagnostics subkey.
DbgPrintOn (REG_DWORD)
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.

UMDF
You can also set the following registry values in HKLM\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\WUDF\Services\{193a1820-d9ac-4997-8c55-be817523f6aa}. These values affect all
UMDF drivers on the system.
*HostProcessDbgBreakOnStart* (REG_DWORD)
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 HostProcessDbgBreakOnStart is set (0x80000000), the framework makes a single
attempt to break into the kernel-mode debugger. For example:

Value 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.

*HostProcessDbgBreakOnDriverLoad* (REG_DWORD)
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 HostProcessDbgBreakOnStart.
Specifying HostProcessDbgBreakOnStart 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.
You can also set these registry values by using the WDF Verifier tool (WdfVerifier.exe) that is included in the
WDK. For information on using this tool with UMDF drivers, see Managing UMDF Verifier Settings with WDF
Verifier.
These additional values are located in HKLM\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\WUDF\DebugMode:
DebugModeFlags (REG_DWORD)

VALUE DESCRIPTION
VALUE DESCRIPTION

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.
DebugModeBinaries (REG_MULTI_SZ)
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.
You can also set the following value in HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF:
HostFailKdDebugBreak (REG_DWORD)
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.
For changes to UMDF registry values to take effect, you must reboot the computer.
Summary of Debugger Extensions in Wdfkd.dll
4/26/2017 • 4 min 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:

EXTENSION DESCRIPTION FRAMEWORKS

!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.
EXTENSION DESCRIPTION FRAMEWORKS

!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.wdfforwardprogress Displays information about the KMDF


guaranteed forward progress
capabilities of an I/O queue.

!wdfkd.wdfgetdriver Displays the driver name. KMDF


UMDF 2
EXTENSION DESCRIPTION FRAMEWORKS

!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.wdfmemory 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
EXTENSION DESCRIPTION FRAMEWORKS

!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.wdftraceprtdebug 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.
EXTENSION DESCRIPTION FRAMEWORKS

!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
4/26/2017 • 2 min 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.
If HostFailKdDebugBreak is set, 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.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
4/26/2017 • 4 min 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 Properties. In the Property Pages for the driver, click Configuration Properties, and then
Wpp Tracing. On the General menu, set Run WPP Tracing to Yes.
Navigate to Properties->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 DriverEntry:

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 DriverEntry
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\Services\
<YourDriver>\Parameters\Wdf
For KMDF:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\<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
6/2/2017 • 5 min 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.
Click here to view
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.

1. Reboot the computer.


2. In an elevated command prompt, enter the following command.
Wpr.exe -Start WdfPerfTraceProviders.wprp
This command enables the ETW provider for WDF. The computer starts recording a trace.
Note As in step 2, Wpr.exe and WdfPerfTraceProviders.wprp 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.

1. Exercise your scenario of interest.


2. Stop the ETW trace session: Wpr.exe -Stop MyPerfTrace.etl
3. 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.
If you captured a trace on Windows 10 Mobile, you'll need to copy MyPerfTrace.etl from the target device to a
computer that has Wpa.exe. You can use the TShell tool to do this.
Related topics
Windows Performance Analyzer
Using WPP Software Tracing in KMDF Drivers
6/2/2017 • 1 min 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 DriverEntry 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
Properties. In the Property Pages for the driver, click Configuration Properties, 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

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
6/2/2017 • 4 min 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 Properties. In the Property Pages for the driver, click Configuration Properties, 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
4/26/2017 • 1 min 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.
To find the step-by-step procedure followed in the video, see New support for source-level debugging of WDF
code in Windows 10.
Click here to view
Video: Accessing driver IFR logs without a debugger
4/26/2017 • 1 min 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.
Click here to view
Send comments about this topic to Microsoft
Videos: Debugging KMDF Drivers
4/26/2017 • 1 min 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
4/26/2017 • 3 min 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.
Click here to view
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


Click here to view
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
Click here to view
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


Click here to view
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


Click here to view
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


Click here to view
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


Click here to view
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.
Porting a Driver from WDM to WDF
4/26/2017 • 1 min 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 DriverEntry 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
4/26/2017 • 2 min 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
4/26/2017 • 4 min 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
4/26/2017 • 8 min 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 (DriverEntry), 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 DriverEntry 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 DriverEntry 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
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 IoStartPacket and IoStartNextPacket 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
4/26/2017 • 2 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min to read • Edit Online

In both WDM and framework-based drivers, the DriverEntry function is the primary entry point. The function
prototype is the same in both models. In a WDM driver, the system calls DriverEntry 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 FxDriverEntry function upon loading the driver. This internal function initializes the
framework and then calls the driver’s DriverEntry function. DriverEntry 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_INIT( &config,
ToasterEvtDeviceAdd );
status = WdfDriverCreate(
DriverObject
RegistryPath
WDF_NO_OBJECT_ATTRIBUTES
&config
WDF_NO_HANDLE
);

return STATUS_SUCCESS;
}

DriverEntry 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 DriverEntry routine. The reason is the same: only a few drivers use the pointer to the driver object.
Porting AddDevice to EvtDriverDeviceAdd
4/26/2017 • 4 min 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:

KMDF CALLBACK WDM 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

EvtDeviceDisableWakeAtBus IRP_MN_WAIT_WAKE
Additional WdfPdoInitXxx methods enable the driver to specify device-specific data, such as device IDs.
Porting Interrupts
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 5 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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:

KMDF METHOD ACTION

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
WdfIoTargetSendInternalIoctlOthersSynchronously

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 IoForwardIrpSynchronously but does not call


IoCallDriver; driver must call WdfRequestSend.

WdfRequestSend Similar to IoForwardIrpSynchronously 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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.
Installation Procedure
4/26/2017 • 1 min to read • Edit Online

Kernel-Mode Driver Framework (KMDF) and User-Mode Driver Framework (UMDF) drivers are installed by using
INF files, just as WDM drivers are. However, framework-based drivers must use the appropriate co-installer and
must add information about the additional service that is required for KMDF or UMDF.
For implementation details, see Building, Installing, and Testing.
Summary of WDF and WDM Equivalents
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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)
WdfRequestRetrieveOutputMemory
WdfRequestRetrieveInputBuffer
WdfRequestRetrieveInputWdmMdl (KMDF only)
WdfRequestRetrieveInputMemory
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 WdfRequestRetrieveOutputXxx 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.

FUNCTION BUFFERED I/O DIRECT I/O

WdfRequestRetrieveOutputBuffer Irp->AssociatedIrp.SystemBuffer MmGetSystemAddressForMdlSafe


(Irp->MdlAddress)

WdfRequestRetrieveOutputWdmMdl Builds a memory descriptor list (MDL) Irp->MdlAddress


(KMDF only) for Irp->AssociatedIrp.SystemBuffer
and returns the MDL.

WdfRequestRetrieveOutputMemory Returns a WDFMEMORY object. Call Returns a WDFMEMORY object. Call


WdfMemoryGetBuffer on this object WdfMemoryGetBuffer on this object
to get Irp- 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 WdfRequestRetrieveInputXxx 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.

FUNCTION BUFFERED I/O DIRECT I/O

WdfRequestRetrieveInputBuffer Irp->AssociatedIrp.SystemBuffer MmGetSystemAddressForMdlSafe


(Irp->MdlAddress)
FUNCTION BUFFERED I/O DIRECT I/O

WdfRequestRetrieveInputWdmMdl Builds an MDL for Irp- Irp->MdlAddress


(KMDF only) >AssociatedIrp.SystemBuffer and
returns the MDL.

WdfRequestRetrieveInputMemory Returns a WDFMEMORY object. Call Returns a WDFMEMORY object. Call


WdfMemoryGetBuffer on this object WdfMemoryGetBuffer on this object
to get Irp- 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:

FUNCTION BUFFERED I/O DIRECT I/O

WdfRequestRetrieveInputBuffer Irp->AssociatedIrp.SystemBuffer MmGetSystemAddressForMdlSafe


(Irp->MdlAddress)

WdfRequestRetrieveInputWdmMdl Builds an MDL for Irp- Builds an MDL for Irp-


(KMDF only) >AssociatedIrp.SystemBuffer and >AssociatedIrp.SystemBuffer and
returns the MDL. returns the MDL.

WdfRequestRetrieveInputMemory Returns a WDFMEMORY object. Call Returns a WDFMEMORY object. Call


WdfMemoryGetBuffer on this object WdfMemoryGetBuffer on this object
to get Irp- to get
>AssociatedIrp.SystemBuffer. MmGetSystemAddressForMdlSafe
(Irp->MdlAddress).

WdfRequestRetrieveOutputBuffer Irp->AssociatedIrp.SystemBuffer MmGetSystemAddressForMdlSafe


(Irp->MdlAddress)

WdfRequestRetrieveOutputWdmMdl Builds a memory descriptor list (MDL) Irp->MdlAddress


(KMDF only) for Irp->AssociatedIrp.SystemBuffer
and returns the MDL.

WdfRequestRetrieveOutputMemory Returns a WDFMEMORY object. Call Returns a WDFMEMORY object. Call


WdfMemoryGetBuffer on this object WdfMemoryGetBuffer on this object
to get Irp- to get
>AssociatedIrp.SystemBuffer. MmGetSystemAddressForMdlSafe
(Irp->MdlAddress).
WDM IRPs and WDF Event Callback Functions
4/26/2017 • 4 min 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.

MAJOR IRP CODE WDF EVENT CALLBACK FUNCTION

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)
MAJOR IRP CODE WDF EVENT CALLBACK FUNCTION

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_MJ_PNP MINOR CODE KMDF CALLBACKS

↓IRP_MN_CANCEL_REMOVE_DEVICE None

↓IRP_MN_CANCEL_STOP_DEVICE None

↑IRP_MN_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification
IRP_MJ_PNP MINOR CODE KMDF CALLBACKS

↓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_RELATIONS (bus, removal, and EvtDeviceRelationsQuery


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_MJ_PNP MINOR CODE KMDF CALLBACKS

↓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_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_MJ_PNP MINOR CODE KMDF CALLBACKS

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_MJ_POWER MINOR CODE FRAMEWORK CALLBACKS

↓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)


Additional Topics for KMDF Drivers
4/26/2017 • 1 min to read • Edit Online

This section contains information that applies only to Kernel-Mode Driver Framework (KMDF).

In this section
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
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
Using Kernel-Mode Driver Framework with Non-PnP
Drivers
4/26/2017 • 1 min 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
4/26/2017 • 1 min to read • Edit Online

If your driver does not support a Plug and Play (PnP) device, your driver package must include an INF file that
contains an INF DDInstall.CoInstallers section and INF DDInstall.WDF section that are described in Using the
KMDF Co-installer.
In addition, you must provide an installer that loads your driver and the framework's co-installer. The co-installer
provides WdfPreDeviceInstall, WdfPreDeviceInstallEx, WdfPostDeviceInstall, WdfPreDeviceRemove, and
WdfPostDeviceRemove functions that the driver's installer must call.
For an example of how to write an installer for a non-PnP driver, see the installer that is included with the NONPNP
sample.
Guaranteeing Forward Progress of I/O Operations
4/26/2017 • 9 min 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
WdfIoQueueAssignForwardProgressPolicy method. If the driver calls
WdfDeviceConfigureRequestDispatching to configure an I/O queue, it must do so before it calls
WdfIoQueueAssignForwardProgressPolicy.
When the driver calls WdfIoQueueAssignForwardProgressPolicy, 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 WdfIoQueueAssignForwardProgressPolicy, 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 WdfIoQueueAssignForwardProgressPolicy 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 WdfIoQueueAssignForwardProgressPolicy 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
WdfRequestIsReserved 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 WdfIoQueueAssignForwardProgressPolicy.
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
ForwardProgressReservedPolicy 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 WdfRequestIsReserved 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
TotalForwardProgressRequests member of the WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY structure to
4 before calling WdfIoQueueAssignForwardProgressPolicy.
You decide that guaranteeing forward progress is only important if your driver's device is the paging device, so
your driver sets the ForwardProgressReservedPolicy member of the
WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY structure to
WdfIoForwardProgressReservedPolicyPagingIO.
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 WdfMemoryCreate 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 WdfRequestIsReserved, 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
WdfMemoryCreate 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
4/26/2017 • 1 min 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.

DEVICE TYPE DEFAULT PRIORITY BOOST

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
DEVICE TYPE DEFAULT PRIORITY BOOST

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

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
DEVICE TYPE DEFAULT PRIORITY BOOST

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

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
DEVICE TYPE DEFAULT PRIORITY BOOST

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
4/26/2017 • 1 min 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
4/26/2017 • 1 min 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
4/26/2017 • 2 min 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
4/26/2017 • 7 min 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_FLAGS-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.
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 Enumeration Requests
4/26/2017 • 1 min 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_RELATIONS 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
4/26/2017 • 1 min 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 EjectSupported 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 LockSupported 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
4/26/2017 • 1 min 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.
Very few drivers need to be aware of the state of a device's state machines. However, for the 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
4/26/2017 • 5 min 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 WdfDeviceAddQueryInterface.
The WdfDeviceAddQueryInterface 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
WdfDeviceAddQueryInterface 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 WdfFdoQueryForInterface 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 WdfFdoQueryForInterface 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
WdfFdoQueryForInterface 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 WdfFdoQueryForInterface, 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 WdfIoTargetQueryForInterface instead of WdfFdoQueryForInterface.
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 ImportInterface 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
4/26/2017 • 1 min 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 WdfDeviceSetSpecialFileSupport 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 WdfDeviceSetSpecialFileSupport 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 WdfDeviceSetSpecialFileSupport 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
4/26/2017 • 4 min 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 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
4/26/2017 • 1 min 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 WdfDeviceMiniportCreate instead of WdfDeviceCreate to create framework device objects for the
miniport driver's devices. The miniport driver should call WdfDeviceMiniportCreate when its port driver
informs it that a device is available.
Call WdfObjectDelete to delete the device object that WdfDeviceMiniportCreate 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 WdfDriverMiniportUnload 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 WdfDeviceMiniportCreate method creates. For a list of these
restrictions, see WdfDeviceMiniportCreate.
Creating Pageable Code in a KMDF Driver
4/26/2017 • 1 min 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.
UMDF 1.x Design Guide
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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.

CAN DRIVER
OVERRIDEDEFAUL
OBJECTNAME OBJECTINTERFACE PURPOSE DEFAULTPARENT TPARENT? CAN DRIVER 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 object No No, if created


file by
framework;
Yes, if
created by
driver

Interrupt IWDFInterrupt Represents Device object No Yes


object an interrupt

Queue object IWDFIoQueu Represents Device object No Yes


e an I/O queue
that receives
I/O requests

Request IWDFIoRequ Represents Device object No, if created No, if created


object est an I/O by by
request framework; framework
Yes, if (for example,
created by redirected
driver requests);
Yes, if
created by
driver
CAN DRIVER
OVERRIDEDEFAUL
OBJECTNAME OBJECTINTERFACE PURPOSE DEFAULTPARENT TPARENT? CAN DRIVER OWN?

Target object IWDFIoTarge Represents a Device object No No, for the


t driver that default
another target; Yes,
driver sends for all other
requests to targets

USB device IWDFUsbTar Represents a Device object No Yes (see


object getDevice device that is target object)
connected to
USB

USB pipe IWDFUsbTar Represents a Device object No Yes (see


object getPipe USB device target object)
pipe

USB interface IWDFUsbInte Represents a Device object No Yes (see


object rface USB device target object)
interface

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 created


object y memory by
object framework;
Yes, if
created by
driver
Framework Base Object
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
IDriverEntry::OnInitialize method, which is the main entry point for the user-mode driver.
Framework Device Object
5/9/2017 • 1 min 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 IDriverEntry::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::RetrieveDevicePropertyStore 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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 QueryInterface, AddRef, and Release methods by
default. The AddRef and Release methods manage object lifetime. The QueryInterface method enables other
components to determine which interfaces the driver supports.
UMDF DDI Programming Model
5/9/2017 • 2 min 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
5/9/2017 • 3 min 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::CreateWdfMemory 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
5/9/2017 • 1 min 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 IDriverEntry::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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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 IDriverEntry::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::RetrieveDevicePropertyStore method to retrieve the
IWDFNamedPropertyStore interface for the device property store. The driver can use
IWDFNamedPropertyStore 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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 IDriverEntry::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
5/9/2017 • 3 min 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
5/9/2017 • 3 min 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
5/9/2017 • 1 min 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 IDriverEntry::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
5/9/2017 • 2 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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 IDriverEntry::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
5/9/2017 • 1 min 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::OnQueryRemove 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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::OnD0Entry 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::OnSelfManagedIoRestart callback function.
To see a diagram that shows these steps, see A User Plugs in a Device.
The PnP Manager Redistributes System Resources
5/9/2017 • 1 min 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::OnQueryStop 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::OnD0Entry 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::OnSelfManagedIoRestart callback function.
To see a diagram that shows these steps, see A User Plugs in a Device.
Processing I/O Requests
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 4 min 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::ForwardToIoQueue 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
5/9/2017 • 4 min 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
5/9/2017 • 11 min 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::GetInputMemory and IWDFIoRequest::GetOutputMemory 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::RetrieveInputMemory,
IWDFIoRequest2::RetrieveOutputBuffer, or IWDFIoRequest2::RetrieveOutputMemory 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::GetInputMemory and
IWDFIoRequest::GetOutputMemory to access the buffers.
A driver that uses the deferred buffer retrieval mode can access the buffers by calling
IWDFIoRequest2::RetrieveInputBuffer, IWDFIoRequest2::RetrieveInputMemory,
IWDFIoRequest2::RetrieveOutputBuffer, or IWDFIoRequest2::RetrieveOutputMemory.
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::RetrieveInputMemory, IWDFIoRequest2::RetrieveOutputBuffer, or
IWDFIoRequest2::RetrieveOutputMemory.
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
5/9/2017 • 1 min 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
5/9/2017 • 4 min 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
5/9/2017 • 1 min 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::AutoForwardCreateCleanupClose 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 AutoForwardCreateCleanupClose 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::AutoForwardCreateCleanupClose. 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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 QueryInterface 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 IWDFFileHandleTargetFactory::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
IWDFFileHandleTargetFactory::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
5/9/2017 • 2 min 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.

METHOD PURPOSE

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::FormatRequestForQueryInformation Formats a request to obtain file information.


METHOD PURPOSE

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
5/9/2017 • 2 min 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:
Started
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 Query-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::Start 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::Start 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::OnRemoteTargetQueryRemove
Informs the driver that a remote I/O target's device might be removed. Your driver must call
IWDFRemoteTarget::CloseForQueryRemove 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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-SPECIFIC UMDF INTERFACE DERIVED FROM

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
5/9/2017 • 2 min 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 QueryInterface method of the
device's IWDFDevice interface. The following code example shows how to call QueryInterface to obtain the
pointer:

hr = pdevice->QueryInterface(IID_IWDFUsbTargetFactory, (LPVOID*)&ppUsbTargetFactory);

The driver must next call the IWDFUsbTargetFactory::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 IWDFUsbTargetFactory::CreateUsbTargetDevice from within an
IPnpCallbackHardware::OnPrepareHardware callback function.
After the driver calls IWDFUsbTargetFactory::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 IWDFUsbTargetFactory::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
5/9/2017 • 2 min 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 IWDFUsbTargetFactory::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.
Important 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
5/9/2017 • 3 min 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::OnD0Entry callback function must call
IWDFIoTargetStateManagement::Start 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::Abort
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::Abort to send an abort request to the pipe.
3. Call IWDFUsbTargetPipe::Reset to send a reset request to the pipe.
4. Call IWDFIoTargetStateManagement::Start 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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 IDriverEntry::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 IDriverEntry::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
5/9/2017 • 1 min 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::OnD0EntryPostInterruptsEnabled and
IPnpCallbackHardwareInterrupt::OnD0ExitPreInterruptsDisabled callback functions.
The framework calls the driver's OnInterruptEnable and
IPnpCallbackHardwareInterrupt::OnD0EntryPostInterruptsEnabled callback functions each time the device
enters its working (D0) state, after the framework has called the driver's OnD0Entry 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
5/9/2017 • 1 min 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 IDriverEntry::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
5/9/2017 • 2 min 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
5/9/2017 • 1 min 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::TryToAcquireInterruptLock 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::TryToAcquireInterruptLock 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::TryToAcquireInterruptLock 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 3 min 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 IDriverEntry::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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
IDriverEntry::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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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 QueryInterface 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
5/9/2017 • 1 min 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 IDriverEntry::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.

VALUE MEANING

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
5/9/2017 • 1 min 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
5/9/2017 • 3 min 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::ForwardToIoQueue 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::ForwardToIoQueue 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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
5/9/2017 • 2 min 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 is specific to the I/O session.
The following table shows calls the application makes and the resulting notifications that the driver receives.

APPLICATION INITIATES DRIVER RECEIVES

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::OnDeviceIoControl
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 INITIATES NEXT DRIVER IN THE STACK RECEIVES

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::OnDeviceIoControl
IWDFIoTarget::FormatRequestForIoctl method). 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
5/9/2017 • 2 min 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
5/9/2017 • 2 min 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::RetrieveDevicePropertyStore
Obtains a pointer to an IWDFNamedPropertyStore interface.
IWDFDeviceInitialize::RetrieveDevicePropertyStore
Obtains a pointer to an IWDFNamedPropertyStore interface.
IWDFPropertyStoreFactory::RetrieveDevicePropertyStore
Obtains a pointer to an IWDFNamedPropertyStore2 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 \Properties
subkey, under the hardware key.
To access these properties, your driver calls
IWDFUnifiedPropertyStoreFactory::RetrieveUnifiedDevicePropertyStore to obtain a property store
interface. Then the driver can use the IWDFUnifiedPropertyStore 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 IWDFPropertyStoreFactory::RetrieveDevicePropertyStore 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 IWDFPropertyStoreFactory::RetrieveDevicePropertyStore.
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
IWDFPropertyStoreFactory::RetrieveDevicePropertyStore.
After a driver has called one of the RetrieveDevicePropertyStore methods to open a registry subkey, the driver
can use methods exposed by IWDFNamedPropertyStore, IWDFNamedPropertyStore2, or
IWDFUnifiedPropertyStore to create, read, and write values under a subkey. The IWDFNamedPropertyStore2
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
5/9/2017 • 6 min 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 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::OnQueryRemove
IPnpCallback::OnQueryStop
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
5/9/2017 • 3 min 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
5/9/2017 • 1 min 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
5/9/2017 • 1 min 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.

EXTENSION DESCRIPTION

!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


EXTENSION DESCRIPTION

!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