The Windows WDF (Windows Driver Framework) is a driver development architecture introduced by Microsoft, designed to simplify the kernel driver development process and enhance system stability. WDF drivers are divided into KMDF (Kernel-Mode Driver Framework) and UMDF (User-Mode Driver Framework). KMDF provides an object-oriented interface for kernel-mode drivers, such as Device Objects, Queue Objects, Request Objects, and so on. KMDF encapsulates complex logic such as PnP (Plug and Play), power management, and I/O queues, allowing developers to focus solely on implementing device-related functionality.
UMDF allows drivers to run in user mode, improving system security and stability (for example, USB device drivers). As a subset of KMDF, UMDF provides similar PnP and power management interfaces but does not support low-level interactions such as DMA operations and hardware interrupt handling, which must be managed by KMDF.
By standardizing the driver development process, WDF significantly lowers the development threshold and maintenance costs for device drivers, becoming a core support framework for the Windows hardware ecosystem. This article will demonstrate how to write a WDF driver by creating a simple WDF driver for a PCI device.
Before starting the experiment, you need to set up the Windows driver development environment. The main development environment includes:
Visual Studio 2019 (or a later version), and you also need to install the WDK (Windows Driver Kit). The WDK version must strictly match the SDK version (for example, WDK 10.0.19041.685 must be paired with SDK 19041 to work correctly). The testing environment needs to enable test signing mode by executing the command cmd bcdedit /set testsigning on, and then restart the test machine.
You do not need to write a WDF driver from scratch; Visual Studio provides templates for WDF drivers that generate some framework code for you. You only need to modify and add your own code to this framework, which will help developers, especially beginners, to speed up development efficiency.
First, create a new project in Visual Studio, selecting the KMDF project template.
Configure this new project by filling in the project name and location.
After creating the project, you will see the following structure in the Solution Explorer of VS. The header and source files for the driver have already been generated, along with a PciTestDriver.inf file. The .inf file is the core configuration file for installing the driver, serving purposes such as hardware identification and resource allocation.
For now, we will not concern ourselves with the generated driver source code. Instead, let’s modify the PciTestDriver.inf file to allow us to install this driver on a specific PCI device. The only modification needed is to change the HW ID; we will fill in the Vendor ID and Device ID of the PCI device we want to install this driver for in the format “PCI\VEN_xxxx&DEV_xxxx” in the red box below.

Then, select the x64 Release or Debug version in VS for compilation. After compiling, a directory named x64 will appear under the solution directory, containing the compiled driver files.

We will skip the process of signing the driver for now and will introduce this part separately later.
Copy the compiled pcitestdriver.cat, pcitestdriver.inf, and pcitestdriver.sys (the executable program of the driver) to the test machine.
Installing the driver is simple; just right-click on the pcitestdriver.inf file and select Install.

After the driver is installed, we can see the corresponding device node in the Device Manager. Since we did not modify the driver class in the .inf file (the default is Samples Class), this device node appears under the Samples category. Through the device properties, we can see that the device is located on PCI bus 0, with a device number of 11 and a function number of 0 (BDF is 0:11.0).

By checking the Resources tab in the device properties, we can see that the OS has already allocated BAR and IRQ resources for this PCI device.

So far, we have “written” a very simple PCI device driver. Although this driver currently has no actual functionality, it can already be loaded onto the corresponding PCI device. In the future, we will gradually add more features to this driver.