Last reviewed and updated: 10 August 2020
You’re probably here looking at OSR.COM because you need to learn how to write or debug Windows drivers. But if you’ve never written a driver for Windows before and you have a given task to accomplish (like supporting a particular piece of hardware or intercepting access to files), your first question is likely to be: Where do I start? Where can I find a good introduction to Windows drivers? Are there any tutorials on writing Windows drivers that will be helpful to me?
One problem is that the world of Windows drivers is extremely varied. You would write a device driver to support a specific piece of hardware, perhaps a USB device or a PCIe device. You would write a Filter Manager Minifilter driver to implement on-access scanning of files (such as anti-virus products), activity monitors, and file replication, deduplication, or backup solutions. While these are both “Windows drivers” they don’t have much in common with each other.
Fortunately, we’re here to help you figure things out.
Believe it or not, one of the most commonly asked questions we receive here at OSR is “How do I write a driver for Windows?” You’d think the answer would be simple. And sometimes it is. But, all too often, the answer is not only non-obvious, it’s fraught with complexity.
The answers to the question, “How do I write a driver for my device on Windows” come in three categories:
- What you need to know
- What development tools (and stuff) you need
- What driver model to use
We’ll describe each of these in individual sections, below.
What You Need To Know
The things you need to know fall into two categories:
- Personal background about the Windows operating system and devices that’ll allow you to readily learn about how to write Windows drivers.
- Technical information about the hardware device you need to write your driver for (if you’re writing a driver for a hardware device).
Items in the first category, personal background knowledge, are actually pretty simple. To be able to write drivers for Windows and not just frustrate yourself, you need to have at least general knowledge of computer operating systems and Windows in particular. You probably know most of what you need if you took a general OS Concepts class when you were in school. If you understand about devices, registers, interrupts, virtual memory, scheduling, multi-threaded programming, reentrancy, and concurrency issues… you’re more than half-way to being a driver developer. You can pick-up the Windows-specific information you need from doing a bit of reading. Please don’t skip this step. We spend almost two days in the 5-day driver seminar we teach here at OSR just discussing Windows OS and I/O subsystem architecture. So, it’s important.
Also, if you’re not familiar with programming on Windows systems from a user perspective (maybe you’ve been working in Linux all your life) it would also be helpful to know a bit about Windows I/O fundamentals. Things like CreateFile, ReadFile, WriteFile, and asynchronous (that is “overlapped”) I/O.
If you need to brush-up on your OS concepts, would like to know more about Windows OS concepts in particular, or you’d like to learn more about how I/O is performed in Windows, we have some reading suggestions in the Sidebar labeled Understanding Windows OS and I/O Concepts. Doing that reading should set you up well for your task for writing Windows drivers.
How do you learn basic OS concepts and Windows architecture? There are a couple of good books to which we regularly refer our students. These are:
Windows Internals 7th Edition — Part 1
(Yosifovich, Ionescu, Russinovich, and Solomon) (Microsoft Press)
This is the basic description of Windows OS Architecture. Everyone in the world of Windows has read it at some time. When you read the following chapters, you may just skip the exercises shown or try a few if they sound interesting to you… it’s your choice. –
- Chapter 1: Concepts and Tools (whole chapter)
- Chapter 2: System Architecture (whole chapter)
- Chapter 3: System Mechanisms (Up to but not including section entitled Advanced Local Procedure Calls)
Windows System Programming 4th Edition
(Johnson M. Hart) (Addison-Wesley Microsoft Technology Series)
If you’re going to write device drivers, it probably makes sense to understand something about how to write Windows programs. If you’ve worked on Unix, and you’ve never written a program on a Windows system, this book will give you a lot of the information you’ll need.
- Chapter 1: Getting Started With Windows (whole chapter)
- Chapter 2: Using the Windows File System and Character I/O (whole chapter)
- Chapter 4: Exception Handling (whole chapter)
- Chapter 14: Asynchronous Input/Output and Completion Ports
One other thing you’ll need to know in terms of personal background is something about the hardware architecture that’s typical of the platform on which your hardware will be running. Whether the device you’re writing the driver for will run on PC (desktop to server) systems or used exclusively in an ARM SoC system, knowing something about the hardware environment – such as common buses and hardware concepts – that are unique to that platform would be valuable. You don’t need to know a lot. We’re not saying you need to be a hardware designer. We’re just saying knowing, for example, the basic concepts of PCIe or USB or SPI or whatever bus your device connects to will help speed you on your way as you write your driver.
About Your Hardware
If you’re writing a driver to support a hardware device on Windows, you’ll need the hardware specifications for the device you’ll be supporting. The information you need usually takes the form of a “data sheet” (which is often more like a book than a single sheet of paper) that describes the register-level interface to your device. Your hardware designer can give this to you. You need the specifics of your device, by the way. If the device you’ll be writing your driver for is implemented using some sort of PLD like an FPGA, don’t let your hardware designer simply point you off to the hardware spec for the PLD device (hardware designer waves her hand at you while saying: “Oh, we’re using an Arria II GX. Just go to Altera’s web site and download what you need. Bye.”). You need to know how the designer has implemented the register interface using the chosen PLD device, not the specs for the PLD itself.
Development Tools (and Stuff) You Need
In recent history, the tools used for Windows driver development have undergone nothing short of a revolution. Gone (well, mostly) are the days when you had to use special mystic project files and compile and link your code from the command line. Today, Windows driver development is fully integrated with Visual Studio.
Visual Studio + Windows Driver Kit
At the current time (May 2020, Windows 10 is the current version), the most recent version of the tools for Windows driver development is Visual Studio 2019. You can even use Visual Studio 2019 Community Edition. That means the “free for anybody to use” version of Visual Studio will work for driver development.
Once you have Visual Studio installed on your development machine, you’ll also need to install the Windows Driver Kit (WDK) add-in that supports driver development. This is a separate, but free (yay!), download from Microsoft (no MSDN subscription necessary). Search “Download the WDK” using your search engine of choice. Visual Studio and the WDK together provide everything you need to create driver projects, and to compile, link, and even debug Windows drivers. After you’ve successfully installed
Visual Studio and the WDK together provide everything you need to create driver projects, and to compile, link, and even debug Windows drivers. After you’ve successfully installed Visual Studio and the WDK, you can very easily build a simple driver demo project. You don’t even need any hardware! Just select “New Project” and within Visual C++ select the Windows Driver project category. Within this category select Kernel Mode Driver (KMDF). Click OK and Visual Studio will generate a simple starter or demo driver project for you that doesn’t require any specific hardware. This driver will successfully build, and can even be installed on a test machine. Yup, it really is that simple.
Ah, test machines. That’s probably something we should discuss. Driver development on Windows requires two Windows systems. One system where you run Visual Studio, do your development, and run the debugger. And a second, separate, system on which you run your driver. The Windows kernel debugger, running on your Development System, controls your Target System (where the driver you’re developing is running) via a remote connection that can be either be the network or a serial port (there are other options, but they are less common or “have issues”).
If you think about it, this makes good sense: Driver and hardware errors can quite easily destabilize or even crash a system. So you certainly don’t want to be running your new and potentially buggy driver on the same system on which you’re editing your source code files and doing your development.
In many cases, the second system can be a virtual machine. Using a virtual machine is acceptable when you’re writing a driver (such as a filter driver or a Filter Manager file system Minifilter) that doesn’t directly access any hardware. But if your driver talks to real hardware, you’ll need a real, physical, second machine to use as your Target System. This is generally good practice even when you’re building a device driver for something like a USB device, when the VM host you’re using allows you to assign access to the device exclusively to a given VM.
Debugging: You Want to Use WinDbg
We mentioned the Windows kernel debugger. This debugger is named WinDbg (which almost everyone pronounces as “wind bag”, by the way). The debugger is included in the Windows Driver Kit and is automatically installed on your system when you install the WDK. It’s the debugger you’ll use as part of developing and testing your driver. It’s very similar to the user-mode debugger in Visual Studio, and has most of the same features.
There are several options available for using WinDbg for debugging your driver. One option is to use WinDbg directly within Visual Studio, through the interface provided by the WDK. While this pretty much works, here at OSR we don’t recommend this. Our experience is that trying to use WinDbg from within Visual Studio creates more complications than it’s currently worth. Instead, we recommend that you run WinDbg directly from your development machine, outside of Visual Studio. This allows you to use Visual Studio for driver development, which is what it’s best at, and use WinDbg directly for debugging, which is what WinDbg is best at.
Before you can use WinDbg to debug your driver, you’ll need to enable kernel debugging on the target system (if you’re writing a kernel-mode driver). Fortunately, it’s easy and very well documented (thank you, WDK doc writers). Search “Setting Up Kernel-Mode Debugging Manually” in your search engine of choice for the steps.
One quick note about debugging. Do not, under any circumstances, try to develop your driver without setting up WinDbg. For some reason, there are folks who’ve been fooled into thinking they can use something like the Microsoft DebugView utility, which allows DbgPrint statements (the kernel-mode equivalent of printf or OutputDebugString) from your driver to be viewed on your system, as their sole tool for driver development. While DebugView can be useful at times, we can guarantee that it is no substitute for having a debugger that allows you to set breakpoints, single step, and change the contents of structure fields and local variables. While setting up WinDbg for the first time can sometimes be annoying, we promise you it’ll be worth your effort in the long run. Yay, WinDbg!
Getting Your Driver Onto Your Test Machine
If you play around with the WDK and Visual Studio a bit, you might notice that the WDK adds features to Visual Studio for “deployment” and “testing” for your driver. Ignore this. Please. It’s soooo much easier just to copy your driver to your test machine on your own than trying to reliably get the WDK to do this for you from within Visual Studio.
The first time (and ONLY the first time) you copy your driver onto your Test Machine, install it using the INF file. After that, when you want to update your driver, just copy the new driver executable (the driver’s .SYS file) over the old one (drivers are traditionally stored in \Windows\System32\Drivers). Then disable and re-enable your device using Windows Device Manager. When you re-enable your device, the new version of your driver will be loaded. If you have trouble copying your new driver directly over your old one, rename the old driver (rename myDriver.sys myDriver.OLD) and then copy the new one. This is what we do at OSR (or we use “.kdfiles -m” in WinDbg, which is also a great trick).
This is another one of those things where you’re just going to have to trust me, and thank me later.
Getting Debug Messages
Also: You’ll notice the WDF template drivers (and most of the WDK sample drivers as well) output debug information using something called WPP Tracing. WPP Tracing is fine… but it’s really designed for collecting driver info from the field, once your driver has been released. During development, you will be MUCH happier if you just use DbgPrint… which just writes output directly to the WinDbg Command Windows (like printf or OutputDebugString). Once you’ve got your driver working, if you decide you want to be able to collect trace information from your driver after release, it’s pretty easy to convert your DbgPrint statements to WPP Tracing. That’s what we teach our students to do, and it’s what we do here at OSR.
If this doesn’t immediately work, fear not! You have to enable DbgPrint output on your target machine. It’s super easy: See the instructions here.
The final thing you’ll definitely want are the Windows Driver Kit Samples. These are example drivers, provided by Microsoft, that demonstrate how to write drivers of various kinds. They’re just like the typical sample code you download from just about anywhere: They are very useful and highly instructive, even if some of the code provided isn’t always exactly “the best.” Samples are provided for all sorts of hardware drivers, filter drivers, and software-only drivers. Heck, they even give you the source code to a few of the drivers that are part of the Windows OS… including sources for the FAT file system.
The samples are hosted on GitHub (yes, really) and available for download. Search “Windows driver samples github” from your search engine of choice. You can download specific samples individually, or you can download the entire ZIP archive (about 140MB when we last checked, including more than 160 sample drivers). We recommend you download the complete archive. Take your time and look through the samples. This will be time well spent.
So… now you have the background info you need, and you have all the stuff you need to develop Windows drivers. What’s the next step?
What Driver Model to Use
The actual development of a Windows driver starts with choosing what “driver model” to use for your driver’s implementation. Many folks find this step confusing. A driver model is an overall driver organization, including a set of APIs and entry points, which you’ll use when you write your code. Unlike some other operating systems that support a small number of driver models (“block” and “character”, for example) Windows has a wide number of driver models. The best driver model to choose is based on as many as three things. These are:
- The type of driver you’re writing: Hardware device, filter, or some other kind.
- If you’re writing a driver for a hardware device, the category (storage controller, sound card, graphics adapter, network card) of device.
- Developer preference
Now hear this: The choice of a driver model is the most important decision you’ll make about how your driver will be developed. And it’s a place where many people make the wrong decision and “go off the rails” – making their project much harder than it needs to be. So take some time to make this decision. Don’t simply Google around and find some trash example lying on a web site somewhere and start to hack it. Make the decision thoughtfully.
General Purpose Models
Broadly speaking, there are two Windows driver models that apply for general use, and some Windows driver models that apply to specific devices. For example, if you’re writing a driver for a local area network card, Windows has a specific model that is tailored specifically for this use and makes it maximally convenient to implement this type of driver. Likewise, if you’re writing a driver that supports streaming audio or streaming video, Windows has a specific model for these types of drivers. These are only two simple examples. Windows has specific models for lots of other device types as well.
Lacking a specific model for your device type, you can use one of the general-purpose models. The first general-purpose model is the Windows Driver Model (WDM). WDM is the old, historic, model for writing Windows drivers. Nobody should use this model anymore for writing new Windows drivers. Seriously. Nobody. It’s hard to use and filled with “traps” that have evolved over years to support backward compatibility guarantees. Trying to write a new WDM driver in the 21st Century will do nothing but make you hate life. Don’t do it. Enough said?
Much preferred over WDM is the Windows Driver Foundation (WDF). This is the second general-purpose driver model that Windows supports. WDF is a modern, pleasant, and (dare I say it) almost easy to use method for writing Windows drivers. Unless there’s a specific model that Microsoft recommends for the device, filter, or software-only driver you need to write, you’ll want to use WDF.
One interesting thing about WDF is that it actually comes in three flavors, called Frameworks:
- Kernel Mode Driver Framework – KMDF
- User Mode Driver Framework V1 – UMDF V1.x
- User Mode Driver Framework V2 – UMDF V2.0 (only applies to Windows 8.1 and later)
KMDF is the Kernel Mode Driver Framework. This is the model you’ll almost certainly want to use now and in the near future for any general-purpose Windows driver development project.
You’ll notice that there are two WDF Frameworks that allow you to write drivers in user-mode. Writing drivers in user mode is good, because if there’s a bug in your driver (let’s say, you deference a null pointer) your user-mode driver won’t crash the system the way it would if you wrote your driver in kernel mode. That’s certainly a very good thing, and contributes to nothing but customer satisfactions. So, why didn’t we recommend using UMDF for writing your drivers?
Using UMDF today is a bit of a problem. UMDF V1 is the older model. It’ll support devices running on Windows versions as old as Windows XP. But UMDF V1 uses an odd, difficult, programming pattern that’s based on COM (yes, the Component Object Model… that COM). Add to that the fact that UMDF V1 has been put in “end of life” status by Microsoft, and you get a model that most people will want to avoid.
UMDF V2.0 is actually a pretty terrific driver model. It uses 99% the same syntax as KMDF, but it runs in user mode, thus contributing to overall system stability. So why don’t we recommend using UMDF V2.0 today? Because UMDF V2.0 is currently only supported on Windows 8.1 or later. To be absolutely clear, this means that if you write a UMDF V2 driver, that driver can only be installed on systems that are running Windows 8.1 or more recent versions of Windows. In short, unless you only need to support Windows 8.1 or more recent systems, UMDF V2 isn’t really a viable choice. On the other hand, if you do only need to support Windows 8.1 or later (I don’t know, maybe you’re writing a driver for some sort of embedded system) then UMDF V2.0 could be a very good choice indeed.
Choosing the Best Model for Your Project
Confused? It wouldn’t be surprising if you are. We told you many people find this driver model stuff confusing. Fortunately, there are some simple rules that can help you decide the best driver model for your use. Here are those rules:
- Writing a driver for a hardware device? Check the Windows Hardware Certification Requirements for the type of device that you’ll be supporting. To do this, search for “Windows Hardware Certification Requirements: Devices”. If the type of device you’ll be supporting is listed, the Certification Requirements document will almost always specify the driver model you must use. Note that this guidance applies even if you don’t plan to apply for Windows Hardware Certification for your device and driver. The Certification Requirements will almost always point you in the direction of the best, easiest, most modern, and most supportable driver model that applies to your type of device.
- Writing a filter driver for a device? A filter driver in Windows is a type of driver that monitors I/O operations going to a given device/driver in the system and intercepts those I/O operations. The purpose for intercepting those I/O operations might be to track them, measure them, or modify them. If you’re writing a filter for file systems (like for an antivirus product) or networks (such as you would write for a firewall product), there are specific driver models defined for these uses.
- Writing a driver that intercepts file system operations? This type of driver might be used for antivirus scanning, creating a hierarchical storage system, or even for file deduplication, replication or backup. In this case, you want to write a Filter Manager Minifilter driver. This is a special model designed precisely for these purposes.
- Writing a software-only driver? For example, maybe you need to write a driver that collects data in kernel-mode. In this case, you probably want to write a software-only driver. Using what’s called the “legacy NT model” is probably your best option. But you also have the option of using KMDF for this type of driver.
- Are you writing a media-based or network-based file system? Stop reading now. You almost certainly do not want to write a Windows file system. It’s really difficult. We know, because it’s one of the things we’ve done over the years here at OSR. Send us email. We’ll see if we can talk you out of it, and if not we’ll point you in the right direction. Seriously. No charge.
- None of the previous steps pointed you to a specific model? Do you need to support systems older than Windows 8.1? If you only need to support Windows 8.1 or later, the best model for you to use is probably UMDF 2.0. If you need to support systems older than Windows 8.1, then your best choice of driver model is probably KMDF.
There are a number of factors that contribute to the decision of which driver model is best for you. You can read more about this on MSDN. Search for the page titled “Choosing a driver model”. For the reasons we described above, we recommend for the present time you ignore Microsoft’s advice about preferring UMDF. UMDF V2.0 will be a great choice when it supports the majority of systems in the field (either because Microsoft decides to support UMDF 2 on systems older than Windows 8.1 or everyone is running Windows 8.1 or later). But until that time, everywhere you see UMDF recommended we suggest you choose KMDF instead.
You’ve Chosen a Model: Now What?
Once you understand the driver model to use, you have to figure out how to write a driver using that model. The WDK documentation is pretty good (and getting better all the time), it’s not exactly a good tutorial for beginners. The available books on Windows driver development are either lacking in practical detail, wrong, out of date, or all three. While you could learn on your own, with trial and error and help from news groups, this is where we here at OSR can help!
You might have gathered from this article that driver development isn’t much like application programming. It doesn’t readily lend itself to grabbing an example, learning just enough to modify it, and then call it done. So, why spend the time and effort (it will be weeks, at least) trying to learn this discipline on your own when you have an expert resource you can use?
Seriously consider taking an OSR seminar. We teach all of our most popular seminars (WDF, Internals and Software Drivers, Kernel-Mode Debugging and Crash Analysis, and even Windows file system Minifilters) multiple times a year at locations all over the world, including about once every month at our own training center. Invest a week of your time, and a few dollars of your company’s money, and avoid the annoyance of learning by trial-and-error. At an OSR seminar, you’ll learn from real developer/instructors who have written dozens (if not literally hundreds) of real, shipping, production Windows drivers. They’ve made just about every possible mistake, so they can help you avoid those same issues. At a OSR seminar, you’ll get started on the right path and avoid many of the pitfalls that are common to new driver developers.
About Online Examples and Samples
Remember what we said earlier, that writing a Windows driver (any type of driver) is quite a bit more complicated than writing an application? It’s hard to take a sample and start hacking it into becoming your solution. And, when you do choose a sample from which to start, you need to choose that sample carefully or you won’t end up with a decent solution.
Sadly, it’s been our experience that (except for Microsoft’s own WDK samples on GitHub) most of the online samples that you’ll find are badly out of date, badly designed, or really terribly implemented. Sorry, but it’s the truth. CodeProject and Stack Overflow have their place… but that place is unfortunately not the world of Windows drivers. So, when it comes to samples, please stick to the current WDK samples that live on GitHub. It’ll almost certainly save you lots of annoyance.
Questions? Where Do You Get Help?
You might be pleased to discover that there’s a vibrant, and helpful, online community for driver developers, where you can post questions here and get answers. Check out the OSR Developer Community.
That’s how you get started writing Windows drivers. Learn a bit about Windows architecture, get the tools, and choose a model for your driver. Maybe take one of our seminars… we think that’d be a good idea, too. Of course, there are lots of things we haven’t discussed in this short article. We haven’t discussed how to install your driver (you write something called an INF file), specific techniques for driver development with any of the models, or strategies for debugging your code. We talk about these types of things regularly in The NT Insider (our free journal on Windows internals and software development issues) — Sign up (for free) and we’ll let you know each time it’s published.
We hope the above has been useful, and provided a place to start. Happy driver writing!