Click Here to Install Silverlight*
United StatesChange|All Microsoft Sites
Windows Hardware Developer Central 
|WHDC China|WHDC Japan|WHDC Korea|WHDC Taiwan|WHDC Site Map|RSS 2.0|Atom 1.0
* * Looking for drivers or help with your PC?

If every driver writer would just...

Updated: September 16, 2004
On This Page
Donald Burn: ...recognize these 10 simple rulesDonald Burn: ...recognize these 10 simple rules
Tim Roberts: ...convince his or her employer that driver source code should be shared, we would have an enormous pool of valuable, real-world experience to draw fromTim Roberts: ...convince his or her employer that driver source code should be shared, we would have an enormous pool of valuable, real-world experience to draw from
Stephan Wolf: ...insert sanity checks everywhereStephan Wolf: ...insert sanity checks everywhere

Donald Burn: ...recognize these 10 simple rules

1. Learning driver development is hard
The Windows driver environment has a steep learning curve and evolves quickly. A new driver developer needs professional training. An experienced developer should go to conferences and read articles and whitepapers to stay on top of the improvements.

2. Driver development is software engineering
Good driver development uses software engineering principles. A developer cannot just throw some code into a sample driver and expect to produce a high quality driver. A driver needs specifications for functionality and testing. Coding a driver should reflect good development practices.

3. It is not just the Win9x computer model anymore
Too many times developers ignore the scope of the Windows system when developing a driver. Windows drivers and their supporting programs must consider 64-bit processors, multi-processing, memory greater than 4 GB, headless systems, multi-user systems, and hot-plug devices.

4. Use the latest tools
Microsoft constantly upgrades the DDK with new samples, documentation, and tools. Additionally, each new version of Windows has additional validation for drivers. Use the latest DDK and test on the latest OS.

5. Find bugs at compile time
A driver should compile cleanly with /W4 and PREfast before being loaded for testing. When appropriate, enable DEPRECATE_DDK_FUNCTIONS. Drivers should use the C_ASSERT macro to test compile time conditions. Consider using Lint for further checks. Finally, run all INF files through ChkInf.

6. Take advantage of runtime checking
The driver should run cleanly under the Driver Verifier with all options enabled, Call Usage Verifier, and the Checked Build of Windows. A good driver will have extensive ASSERTs and conditional validity checks built into it.

7. No one can test too much
Allot more time for testing than for development. A driver needs testing at many levels: incorporate unit testing, driver tests, and system level testing. Take advantage of the tests from Microsoft, but plan to write driver-specific tests.

8. Use profiling, code coverage, and code reviews
Profile the completed driver and correct any hotspots. Use a code coverage tool and then inspect the output to see if all significant code was tested. Finally, using the data from profiling and coverage, hold a code review to find potential problems before the driver gets to the customer.

9. Plan for maintenance and modifications
Take advantage of WPP software tracing to provide diagnostic capabilities in the driver. Consider a WinDBG extension to display complex data structures in a driver. Finally, recognize that the actual driver implementation needs to be documented for support.

10. Bugs will happen
Even the best developers have bugs. Make sure that the development team whose code caused a problem knows of the problem so it does not happen again. Finally, driver developers leverage existing code. Be sure that you fix the bug in all drivers based on that code.

Tim Roberts: ...convince his or her employer that driver source code should be shared, we would have an enormous pool of valuable, real-world experience to draw from

This is a pipe dream, of course. Every company believes their world-changing hardware is completely unique and worthy of protection under lock and key, but it is a shame nonetheless. Windows DDK programming is very much a "word of mouth" adventure: "Fred was able to get streaming working by connecting his pins to the KsFrammis filter; we should try it." Without the operating system source code as an ultimate reference, we are forced to use trial-and-error to try to understand what lies beneath. Because driver source is so well-protected, we all have to rediscover this information ourselves, over and over. That's an enormous waste of resources.

Stephan Wolf: ...insert sanity checks everywhere

Isolating the origin of a bug is one of the most challenging tasks for a driver writer. However, it turns out that most bugs result from invalid assumptions that the programmer made about the state of the driver at certain code points.

Unfortunately, unusual driver states usually do not immediately lead to remarkable system behavior. It may take a while before such a bug takes effect. At the time the system crashes, the code originally causing the bug might no longer be executing.

I believe one can easily identify the bigger part of all driver bugs from debug output that the driver prints whenever it detects an unusual situation. You should therefore place sanity checks in your code whenever some state change might have happened. For instance:

On return from each function call, validate its return value. Also validate the state of any variables that the function call should or might have changed.

At the entry to each function, validate the arguments passed to it.

A well-known technique for adding sanity checks is the ASSERT() macro. However, ASSERT() will break into the debugger when the assertion fails, and also only applies to checked driver builds and is thus not available for production drivers.

Of course, for performance reasons I also do not want all sanity checks to be present in a production driver. But I still want some of them. I therefore use macros for all debug output, which I can expand to white space on a free build, for instance:

if ((pVirt = MmAllocateNonCachedMemory(NumberOfBytes)) == NULL) {
	WARNING(("Out of memory (size=%ul).\n", NumberOfBytes));
	return (NULL);
VERBOSE(("Successfully allocated %ul bytes.\n", NumberOfBytes));

If I want VERBOSE() to be a no-op in my production driver, I define the macros as follows:

#ifdef DBG
#define VERBOSE(x)	DbgPrint x
#define VERBOSE(x) 
#define WARNING(x)	DbgPrint x

Notice the missing parentheses for the call to DbgPrint() here; they are provided as the extra parentheses around the message text and parameters in the example above.

For a more detailed example of how debug macros can be defined efficiently, see the "…\inc\…\minidrv.h" header file in the DDK.

How would you rate the usefulness of this content?
Poor Outstanding

© 2017 Microsoft Corporation. All rights reserved. Contact Us |Terms of Use |Trademarks |Privacy & Cookies