This column is dedicated to disseminating information on the various Gotchas and annoyances that crop up during Windows driver development. Where possible we'll provide a workaround, as well as identify which versions of the DDK and the operating systems exhibit these problems. Also, some Gotchas are restricted to particular driver models, such as Network, Video, Audio, etc., which will be identified. In addition to Gotchas, we'll also periodically cover some advanced techniques that do not require an entire article to describe, as well as the occasional pearl of wisdom.

If you have any Gotchas that you would like to share, please send them to Gotchas@wd-3.com. We don't promise to use anything you send us -- or even to read everything you send -- but if we do use your suggestion, we’ll give you credit (if we didn’t think of it first, or if you slip Brian a sawbuck) making you instantly famous and the object of adoration by millions (well OK, maybe you’ll still just be adored only by your mother -- but you’ve got to start somewhere).

 

Driver Model

All

Title

RtlDeleteRegistryValue incorrectly documented

Annoyance

High

Description

RtlDeleteRegistryValue is used to delete a key in the registry. The DDK states the following:

Note that if RelativeTo is set to RTL_REGISTRY_HANDLE, the following occurs:

  • On Windows 98/Me and Windows NT 4.0, the routine closes the specified handle before returning.
  • On Windows 2000 and later versions of the NT-based operating system, the routine leaves the handle open

This is incorrect; Windows 2000 will close the handle, but Windows XP and later will not

Workaround

Call ZwClose to close the handle if running on Windows 2000

Versions

Win2K

 

Driver Model

All

Title

RtlQueryRegistryValues may bugcheck

Annoyance

High

Description

If RtlQueryRegistryValues is called with a table entry whose Flags field does not have RTL_QUERY_REGISTRY_REQUIRED set AND whose DefaultType is not 0 (REG_NONE) AND the value being queried does not exist in the registry, the system will bugcheck.

Workaround

Set DefaultType to be 0 (REG_NONE)

Versions

Win2K, WinXP, WS2003

 

Driver Model

Application

Title

DLL and Thread Local Storage

Annoyance

Low

Description

If a DLL implements one or more thread local storage variables by using __declspec (thread) AND the DLL is loaded using LoadLibrary, then any attempt to access any of the thread local storage variables will cause an access violation.  If the same DLL is loaded as a result of some program (or another DLL for that matter) being linked to it, then all is OK.

Workaround

To get around this problem, use the TlsAlloc, TlsFree, TlsGetValue, and TlsSetValue functions from within the DllMain; this is not as clean but will work when the DLL is loaded using LoadLibrary.

Versions

Win2K, WinXP, WS2003

 

Driver Model

All

Title

Writing drivers using C++

Annoyance

Low

Description

It is possible to write device drivers using C++, but with the following restrictions:

  1. C++ exception handling is not available in kernel-mode
  2. STL is not natively available in the kernel
  3. Global new and delete missing
  4. Support for initialization of static or global objects is missing

Workaround

You’ll have to write it all yourself. Here is an article on how you might go about supporting static and global initializers: http://msdn.microsoft.com/msdnmag/issues/01/01/hood/

Versions

Win2K, WinXP, WS2003

 

Driver Model

All

Title

Including firmware in driver executable

Annoyance

Low

Description

More and more devices require firmware to be downloaded by its device driver. Storing the firmware in an external file (in the \Windows\System32\Drivers directory!) allows for the firmware to be easily upgraded. However, if the firmware file is missing, then the device is unusable. Also, some devices rarely – if ever – have their firmware updated. In both cases, it would be nice to include the firmware in the driver’s executable – but without having to convert the binary into some hokey ASCII representation. Surprisingly enough, this is supported – but with one catch.

Workaround

To include a firmware file (or any other type of file) into your driver’s executable, specify the name of the file in your resources.rc file, in the following format: resource-name resource-type file-name, for example:

MyWidget Firmware \firmware\WidgetFirmware.bin

The resource compiler will grab the firmware file and place it in the resource PSECT (Program Section), which the linker will combine with other resource PSECTs into the .rsrc image section in the executable. All the image sections in the driver’s executable are loaded into kernel memory when the driver is loaded, so the driver will then have to search through its .rsrc (resource) image section for the firmware resource.

Remember the ‘catch’ I mentioned earlier? Well, the catch is that the .rsrc image section has the Discardable bit set, which, like the INIT image section (containing DriverEntry), will be deallocated after DriverEntry returns back to the I/O manager. This leaves you with two options:

  1. Copy the firmware into another buffer within DriverEntry
  2. Clear the Discardable bit in the image section

Clearly, changing the Discardable bit is the simplest choice. This requires a change to your linker options. Ever notice the following linker option:

-SECTION:INIT,d

Ever wonder what it does? It sets the Discardable bit on the INIT image section (and clears all other bits). Well, if you were to add the following line to your linker options, the resource section would not be deallocated when DriverEntry returned:

-SECTION:.rsrc,r

Now, all you have to do is locate your firmware resource in the resource section. The beginning of the driver in memory is Driver_obj->DriverStart. From there, locate the offset to the resource section in the image directory. Once you have the resource section, search the resource tree for your named resource.

Versions

Win2K, WinXP, WS2003

 

Driver Model

All

Title

Messing with system data structures

Annoyance

Low

Description

More and more, I see driver writers messing around with undocumented system data structures. While I don’t advocate this, if you’re going to do it, then at least do it safely. The problem is synchronizing access to these structures safely – especially on a multiprocessor system. At any time, the system may be “in the middle” of its own access to these structures. So, what we need is guaranteed atomic access to these structures – but we generally don’t have access to the spinlock protecting them.

Workaround

Well, there are no guarantees in life, but in this case, we can come pretty close. In a nutshell, we want to prevent all the CPUs on the system from doing anything until we finish accessing the system data structure. To do this, allocate an array of DPC objects (one for each CPU on the system), specify the CPU that the DPC is to run on using KeSetTargetProcessorDpc, and queue up the DPCs using KeInsertQueueDpc. When a DPC runs, raise IRQL to 31, and spin while waiting for all the other CPUs to run their DPC. When all CPUs are spinning at IRQL 31, one CPU will perform the access. When the access is complete, the other CPUs are notified, causing them to exit their spin loops, go back to IRQL 2, and then exit the DPC.

Versions

All