The Skeleton
driver is designed for use as a basis for UMDF driver development. By
customizing the existing code and adding some of your own code, you can
create a driver for your specific device. The following tasks are
required:
Customize the exports.
Customize the Sources file.
Customize the INF file.
Customize the Comsup.cpp file.
Add device-specific code to the Driver.cpp file.
Add device-specific code to the Device.cpp file.
For most drivers, you can use the following files from the Skeleton unchanged:
Resource.h
Makefile
ComSup.cpp and ComSup.h, which supply basic support for COM
DllSup.cpp, which supports basic DLL functions
1. Customize the Exports File
The file Exports.def lists the library and function names that the DLL exports. To customize this file, replace the value in the LIBRARY statement with the name of the binary file that contains the DLL. For example:
Your driver must export the DLLGetClassObject function, so you can leave the EXPORTS area unchanged.
2. Customize the Sources File
The Sources file defines environment variables and
settings that are required to build the driver. It is input to the
generic makefile that is supplied with the samples. To create a makefile
to build your own driver, you do not edit the generic makefile.
Instead, you edit the Sources file.
To customize the Sources file:
Change the TARGETNAME statement to include the name for your driver. For example:
Change the SOURCES statement to include the source files for your driver. For example:
SOURCES=\
MyDevice.rc \
dllsup.cpp \
comsup.cpp \
driver.cpp \
device.cpp \
Change the NTTARGETFILES statement to include the INF files and any other miscellaneous files for your driver. For example:
NTTARGETFILES=$(OBJ_PATH)\$(0)\UMDFSkeleton_Root.inf\
$(OBJ_PATH)\$(0)\UMDFSkeleton_OSR.inf
3. Customize the INX File
The INX file contains the INF
that is used to install the driver. To use this file as a basis for
your own driver’s installation, you must change a variety of settings.
The following list outlines the types of required changes:
Change the [Manufacturer] section to include the name of your company and the [Manufacturer.NT$ARCH$] section to include the name and location of your driver.
Change the [SourceDisksFiles] section to include the name of your DLL.
If your driver is a filter driver, change the [DDInstall.Services]
section to install the reflector as the top filter driver in the kernel
mode device stack. If your driver is a function driver, the [DDInstall.Services] section should install the reflector as the service for the device.
Change the [DDInstall.Wdf] section to install your driver as a service and list it in the UMDFServiceOrder directive.
If your driver performs impersonation, add the UMDF-Impersonation directive that specifies the maximum impersonation level for the driver.
In the [UMDFServiceInstall] section, change the name of the binary to the name of your driver binary and specify your driver’s class ID in the DriverCLSID directive.
In the UMDriverCopy section, specify the name of your DLL.
In the [Strings] section, change the strings to specify the name of your company, installation medium, and so forth.
Additional changes might be required depending on the
type of device that your driver supports or whether yours is a
software-only driver.
4. Customize the Comsup.cpp File
If you change the name of the driver class to something different from CMyDriver, you must change the following line in CClassFactory::CreateInstance to reflect the new class name:
hr = CMyDriver::CreateInstance(&driver);
5. Add Device-Specific Code to Driver.cpp
In the driver.cpp file, you should add code to the OnDeviceAdd
method to initialize your device and to change any device-specific
settings. For example, if your driver must read settings from the
registry before initializing the device, it should do so in OnDeviceAdd.
The CreateInstance, AddRef, Release, and QueryInterface methods from the Skeleton driver should suffice for most drivers.
4.8.6. Add Device-Specific Code to Device.cpp
The file Device.cpp is where you must do the most work. The Skeleton
sample does not support an actual device, so it implements very few of
the interfaces and callback objects that are required for the typical
device.
In the Initialize
method, you should set the locking constraint for your driver. The
locking constraint determines whether your driver’s callback methods can
be called concurrently or whether only one such method at a time can be
active. Note, however, that the locking model applies strictly to the
number of callback methods that are concurrent; it does not limit the
number of I/O requests that can be active in your driver at one time.
If your driver is a filter driver, you should indicate that in the Initialize method as well, by calling the SetFilter method of the IDeviceInitialize interface.
In the Configure method, you create the I/O queues for the driver. Because the Skeleton
driver does not handle actual I/O requests, it does not set up any
queues. Most drivers, however, implement one or more queues through
which UMDF dispatches I/O requests. To create a queue, the driver calls
the IWdfDevice::CreateIoQueue method
and specifies how the queue dispatches requests to the driver: in
parallel as soon as they arrive, sequentially (one at a time), or only
when the driver calls a method on the queue to request one. The driver
then calls IWdfIoQueue::ConfigureRequestDispatching to specify the types of requests that should be directed to the queue. The driver must also implement methods in the IQueueCallbackXxx, IRequestCallbackXxx, and IFileCallbackXxx interfaces as appropriate to handle the requests that are directed to its queues.
Finally, a driver that supports a Plug and Play device typically must implement the IPnPCallback interface and possibly the IPnPCallbackHardware and IPnPCallbackSelfManagedIo interfaces as well.
You should also either update the header file Internal.h or add your own device-specific header file with any additional definitions pertinent to your device-specific code.