4.3. Device Object and Device Context Area
The first task of the ToasterEvtDeviceAdd callback is to initialize the context area and attributes for the WDFDEVICE object. The context area for this device object is a structure of type FDO_DATA, which is defined as follows in the header file toaster.h:
typedef struct _FDO_DATA
{
WDFWMIINSTANCE WmiDeviceArrivalEvent;
BOOLEAN WmiPowerDeviceEnableRegistered;
TOASTER_INTERFACE_STANDARD BusInterface;
} FDO_DATA, *PFDO_DATA;
WDF_DECLARE_CONTEXT_TYPE_WITH(FDO_DATA, ToasterFdoGetData)
As the example shows, the header file defines the context area and then invokes the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro. This macro creates an accessor method that is associated with a context type. Thus, when the ToasterEvtDeviceAdd function is called, the accessor method ToasterFdoGetData has already been created to read and write a context area of type FDO_DATA.
To associate the named context area with an object,
the driver must initialize the object’s attribute structure with
information about the context area. The ToasterEvtDeviceAdd function invokes the WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE macro to do this:
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes,
FDO_DATA);
This macro performs the following tasks:
Initializes fdoAttributes, which is a WDF_OBJECT_ATTRIBUTES structure.
Sets pointers to the name and length of the context area and to the context area itself in the WDF_OBJECT_ATTRIBUTES structure.
The variable fdoData, of type PFDO_DATA, is defined to hold a pointer to the context area.
Next, the driver creates the WDFDEVICE object by calling WdfDeviceCreate, passing as parameters the addresses of the WDFDEVICE_INIT and WDF_OBJECT_ATTRIBUTES structures and a location to receive a handle to the create object:
status = WdfDeviceCreate(&DeviceInit, &fdoAttributes,
&hDevice);
The framework allocates the WDFDEVICE_INIT
structure, which is opaque to the driver writer. This object supports
several methods that a driver can use to initialize device and driver
characteristics, including the type of I/O that the driver supports,
the device name, and a security descriptor definition language (SDDL)
string for the device, among others. (These settings correspond to the
device characteristics fields of the WDM device object, which is
familiar to WDM driver writers.) By default, KMDF sets the I/O type to
buffered I/O. This default, along with all the others, is appropriate for the Simple Toaster, so the driver does not call any methods on this object.
WdfDeviceCreate creates a WDFDEVICE
object that is associated with an underlying WDM device object,
connects the device object to the device stack, and sets the
appropriate flags and attributes. It returns a handle to the WDFDEVICE object in hDevice.
After creating the device object, the driver gets a pointer to the context area by calling the accessor method ToasterFdoGetData:
fdoData = ToasterFdoGetData(hDevice);
The ToasterEvtDeviceAdd function does not use the returned pointer; this statement appears only for demonstration purposes.
4.4. Device Interface
Every device that a user-mode application or system
component opens must have an interface. A device interface can be
created in any of three ways:
A user-mode installation application can create the interface using SetupDi function.
An INF can create the interface by including a DDInstall.Interfaces section.
The driver can create the interface by calling WdfDeviceCreateInterface.
The following shows how the Simple Toaster driver creates an interface:
status = WdfDeviceCreateDeviceInterface (
hDevice,
(LPUID) &GUID_DEVINTERFACE_TOASTER,
NULL
);
If (!NT_SUCCESS (status)) {
KdPrinte(("WdfDeviceCreateDeviceInterface failed"
"0x%x\n", status));
return status;
}
The
driver passes a handle to the device object, a pointer to a Globally
Unique Identifier (GUID), and a pointer to an optional string. The GUID
identifies the interface and is defined in the driver.h
header file. The string enables the driver to distinguish two or more
devices of the same interface class (that is, two or more devices that
have identical GUIDs). The Simple Toaster driver passes NULL for the string.