If
The Wdm1 device extension is now available through the FDO
Wdm1AddDevice now attaches the Wdm1 device to the device stack using IoAttachDeviceToDeviceStack, which must be called at PASSIVE_LEVEL[11]. The FDO and the given PDO are passed to this function. It returns a pointer to yet another device object that is also stored in the Wdm1 device extension. All this shenanigans are explained in the Plug and Play chapters.
Finally, two bits in the FDO
The Wdm1 driver must delete its FDO if it receives a
Device Names
The Wdm1 AddDevice code calls IoCreateDevice to create a Wdm1 device object. There are two ways to provide a name that is available to Win32 programs. The old way is to provide an explicit symbolic link name. The newfangled approach is to use a device interface to identify the devices that support a defined API.
The
You must create a symbolic link to make the kernel device name available to Win32. To do this the old way, call
Explicit device names created using this technique usually have a device number at the end. By convention, kernel device name numbers increment from zero, while symbolic link names increment from one.
The best way to illustrate device naming is using the
Windows provides symbolic links 'C0M1', 'COM2', etc., to make these serial ports available to Win32. Symbolic links appear in the ?? folder in
The ?? folder used to be called DosDevices, which you might come across in some old documentation.
Figure 5.2
The Wdm1 driver could have given its first device object a kernel name of device Wdm1device0 and called IoCreateSymbolicLink to create a symbolic link with the name ??Wdm1dev1. A Win32 program would then have been able to open \.Wdm1dev1 using CreateFile.
Note that C strings represent each character as '\', so you would have to pass ' \\.\Wdm1dev1' to
If this technique is used, you must keep track of how many devices are in use, so you can generate the correct names. If you use a global variable to keep the device count, you must use it carefully to ensure that simultaneous accesses do not corrupt its value. Achieve this using the
Explicit kernel and symbolic link names are used most often in NT style drivers, which create devices in their
You can use the
Device Interfaces
The Wdm1 driver uses a
The device interface that each Wdm1 device exposes is the set of commands that a Win32 programmer can use to access the device. A Wdm1 device responds to Win32
The Wdm1 driver's job is to implement a memory buffer that is shared by all the Wdm1 devices. Any writes extend the buffer, if necessary. Reads do not extend the buffer. Four IOCTLs are supported: Zero buffer, remove buffer, get buffer size, and get buffer.
One benefit of device interfaces is that another driver could be written that also implements the Wdm1 API. As long as it does this faithfully, there is no reason why a Win32 program should notice the difference between the new driver and Wdm1.
While it seems unlikely that the Wdm1 device interface will be copied by others, this technique is very useful for other types of drivers. For example, audio miniport drivers should implement the IMiniport COM interface. This is identified using the IID_IMiniport GUID and means that the driver implements two functions,
Implementing a device interface for Wdm1 devices is straightforward. First, a new 16-byte GUID must be generated using the
Generating GUIDs
To get a suitable new GUID, run the
Microsoft says that all GUIDs that
If you need to allocate a series of identifiers, press the
Figure 5.3
The definition of WDM1_GUID in GUIDs.h is shown in Listing 5.3. There is a final twist in the tail for GUID definitions. One of the driver modules, Pnp.cpp in Wdm1, must have the following preprocessor directive before including GUIDs.h to formally declare WDM1_GUID.[12]
#define INITGUID
Listing 5.3 WDM1_GUID definition in GUIDs.h
// Wdm1 device interface GUID
// {C0CF0640-5F6E-11d2-B677-00C0DFE4C1F31
DEFINE_GUID(WDM1_GUID, 0xc0cf0640, 0x5f6e, 0x11d2, 0xb6, 0x77, 0x0, 0xc0, 0xdf, 0xe4, 0xc1, 0xf3);
Device Interface Registration
Wdm1 does not give a kernel device name to its device object and does not use IoCreateSymbolicLink to create a device name accessible to Win32 programs. Instead, the Wdm1 AddDevice routine calls IoRegisterDeviceInterface to register its interface as shown in Listing 5.4. It does this after creating its device but before attaching it to the device stack. IoRegisterDeviceInterface creates a Win32 symbolic link name connection to the Wdm1 device object. This is stored in the device extension
The Wdm1AddDevice code checks the return value from IoRegisterDeviceInterface. If this call fails, it tidies up properly by deleting the FDO and returning the status error code.
The final step is to enable the device interface by calling IoSetDeviceInterfaceState, at IRQL PASSIVE_LEVEL In subsequent drivers, the device interface is only enabled when the PnP