I am a little confused about the unloading process for Stream Minidrivers. Is there any information you can give me about this?
Unloading Stream Minidrivers
One of the key architectural features of Windows Driver Model is the class/minidriver architecture. Functionality that is common to a class of devices resides in the class driver, and minidrivers that are subordinate to the class driver need only implement device specific functionality.
A perfect example of the class/minidriver relationship is that of the stream class driver and its minidrivers. On its upper edge, the stream class driver exposes an interface that allows application code to access streams of audio, video, or other data in an abstract fashion. It arbitrates the data formats, transmission rate, and other properties of streaming data to be moved between producers and consumers within the system. A stream minidriver, of which there may be many in the system, typically controls a hardware device that produces or consumes one or more data streams. Each minidriver controls one or more devices, and each device may supply one or more data streams.
Like all WDM drivers, stream minidrivers are Plug and Play, meaning that they can be loaded and unloaded dynamically. However, since the upper edge of the minidriver is geared to the stream class, as opposed to the conventional IRP based interface of other WDM drivers, the Plug and Play behavior of stream minidrivers is unique, and not completely documented.
One unusual aspect of a stream minidriver relates to the unloading of the driver. Normally, a WDM driver sets up an unload routine in its driver object for the purpose of receiving notification of being unloaded. The system calls this entry point when the driver is unloaded, usually as a result of all a driver's devices having been removed from the system.
Similarly, a stream minidriver receives notifications from the class driver whenever one of the devices under control of the minidriver is removed. The class driver instructs the minidriver to deallocate resources associated with the particular device that is no longer present.
However, this notification does not necessarily indicate that the minidriver is about to be unloaded, because it may be controlling multiple instances of a particular device type.
The conventional strategy of setting an unload routine in the driver object in order to detect unloading fails for stream minidrivers unless special precautions are taken. The reason is that when the minidriver registers with the class driver (by calling StreamClassRegisterAdapter), the class driver overwrites the address of the unload routine stored in the minidriver's driver object. You might think that the class driver does this in order to ensure that the class driver is notified should the minidriver be unexpectedly unloaded, but a disassembly of the function inserted by the class driver appears to be just a stub. Possibly the class driver simply needs to ensure that the minidriver is unloadable, and disregards the possibility that the minidriver may require notification of unloading.
While the reasons for this behavior of the stream class driver are not obvious, dealing with it is not difficult. First of all, if your DriverEntry function does nothing but register with the class driver, you may not need any unload notification at all. However, if you allocate any memory in DriverEntry, or if you need to call destructors of objects allocated in the global scope, then you will have to defer setting the unload routine until after the minidriver registers with the class driver. At this point, it is a good idea to store away the address of the function that the class driver writes into the minidriver's driver object, so that your unload routine can call it for safety's sake. It's conceivable that at some time in the future, the class driver may do something useful in that routine.
Versions of the DriverWorks stream classes prior to version 2.2 failed to take into account that the stream class driver overwrote the minidriver's unload routine at registration time. This has now been corrected, thanks to one of our very observant users who pointed out the problem to us