DebugPrint.c | DebugPrint code |
DebugPrint.h | DebugPrint header |
Wdm1.rc | Version resource |
GUIDs.h | GUID definition |
Ioctl.h | IOCTL definition |
resource.h | Visual Studio resource editor header |
Wdm1free.inf | Free build installation instructions |
Wdm1checked.inf | Checked build installation instructions |
Table 4.5 Wdm1 build files
SOURCES | |
makefile.inc | Post build steps for makefile |
makefile | Standard makefile |
MakeDrvr.bat | |
build.log | |
build.err | |
build.wrn |
The code includes some directives to the compiler that need some explaining.
The
The
Only routines that run at PASSIVE_LEVEL IRQL can be paged from memory. All the dispatch routines in the Wdm1 driver operate at PASSIVE_LEVEL so they can be put in the PAGE segment. Routines that are not given a segment are never paged from memory.
If writing C code, you can use the alloc_text pragma instead to set the code segment of named routines.
The Wdm1.h header file is included in all the source files. Wdm1.h first includes the main DDK header file for WDM projects, wdm.h. If you were writing NT style drivers, you would use the similar ntddk.h. You may find that you need to include some other DDK header files for particular types of drivers.
Next, a device extension structure is defined. This structure is where a driver can hold any information it needs about a device (more on this later).
The GUIDs.H header defines a Globally Unique Identifier (GUID) for the Wdm1 device interface. The next chapter shows how this GUID is used by Win32 user mode applications to find Wdm1 devices. I used the
Finally, the IOCTL.H header defines the IOCTL codes that Wdm1 supports. These are explained in Chapter 7.
Init.cpp contains the driver entry point. Listing 4.5 shows this routine, which must be called DriverEntry and use C linkage.
The Plug and Play Manager locates the correct driver and calls DriverEntry to initialize the driver (at PASSIVE_IRQL). In DriverEntry, the main job is to store a series of call back routine pointers in the passed DriverObject. This DRIVER_OBJECT structure is used by the operating system to store any information relevant to the driver. A separate structure is used later to store information about each device.
In Wdm1, DriverEntry sets a whole series of callback routines. These routines are called by the kernel when a device is added and when IRPs need to be sent to the driver. The WdmUnload routine, later in Init.cpp, does nothing at this stage.
Finally, DriverEntry returns an NTSTATUS value of STATUS_SUCCESS. Almost all driver routines have to return a NTSTATUS value, from the list in the NTSTATUS.H DDK header file. Note that these error codes do not correspond to Win32 error codes. The kernel does the necessary mapping between the two types of error code.
Listing 4.5 DriverEntry routine
extern 'C'
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
NTSTATUS status = STATUS_SUCCESS;
//…
// Export other driver entry points…
DriverObject->DriverExtension->AddDevice = Wdm1AddDevice;
DriverObject->DriverUnload = Wdm1Unload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = Wdm1Create;