Figure 4   Function Pointers Supplied by DriverEntry

Pointer Member (DriverObject->xxx)
Brief Description
DriverExtension->AddDevice
Initialize to handle a new device
DriverInit
Initialize driver
DriverStartIo
Begin processing the next queued request
DriverUnload
Cleanup when driver unloaded after all of its devices are removed
MajorFunction[IRP_MJ_xxx]
Handle I/O request of type xxx


Figure 5   Driver.H and AddDevice

DRIVER.H


 #ifndef DRIVER_H
 #define DRIVER_H
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 #include <wdm.h>
 
 #ifdef __cplusplus
 } // extern "C"
 #endif
 
 #define arraysize(p) (sizeof(p)/sizeof((p)[0]))
 
 typedef struct tagDEVICE_EXTENSION {
     PDEVICE_OBJECT DeviceObject;            
     PDEVICE_OBJECT LowerDeviceObject;       
     UNICODE_STRING ifname;                  
     LONG usage;                             
     KEVENT evRemove;                        
     PULONG idle;                            
     BOOLEAN started;                        
     BOOLEAN enabled;                        
     BOOLEAN iospace;                        
     BOOLEAN mappedport;                     
     BOOLEAN removing;                       
     DEVICE_POWER_STATE power;               
     ULONG nports;                           
     PUCHAR base;                            
     PKINTERRUPT InterruptObject;            
     PUCHAR buffer;                          
     ULONG nbytes;                           
     ULONG numxfer;                          
     } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
 
 #define SIMPLE_IDLE_CONSERVATION    30
 #define SIMPLE_IDLE_PERFORMANCE     600
 
 NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status, IN ULONG info);
 VOID DpcForIsr(IN PKDPC Dpc, IN PDEVICE_OBJECT fdo, IN PIRP Irp, 
     IN PVOID Context);
 NTSTATUS ForwardAndWait(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
 BOOLEAN LockDevice(IN PDEVICE_EXTENSION pdx);
 BOOLEAN LockDevice(IN PDEVICE_OBJECT fdo);
 NTSTATUS OnRequestComplete(IN PDEVICE_OBJECT fdo, IN PIRP Irp, 
     IN PKEVENT pev);
 NTSTATUS SendDeviceSetPower(IN PDEVICE_OBJECT fdo, 
     IN DEVICE_POWER_STATE state, ULONG context);
 VOID SetPowerState(IN PDEVICE_OBJECT fdo, IN DEVICE_POWER_STATE state);
 VOID RemoveDevice(IN PDEVICE_OBJECT fdo);
 NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST list);
 VOID StopDevice(PDEVICE_OBJECT fdo);
 VOID StartIo(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
 void UnlockDevice(IN PDEVICE_EXTENSION pdx);
 void UnlockDevice(IN PDEVICE_OBJECT fdo);
 
 // I/O request handlers
 
 NTSTATUS RequestCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
 NTSTATUS RequestClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
 NTSTATUS RequestControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
 NTSTATUS RequestPnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
 NTSTATUS RequestPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
 NTSTATUS RequestWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
 
 // {3d93c5c0-0085-11d1-821e-0080c88327ab}
 
 #ifndef FAR
 #define FAR
 #endif 
 
 DEFINE_GUID(GUID_SIMPLE, 0x3d93c5c0, 0x0085, 0x11d1, 0x82, 0x1e, 0x00,
     0x80, 0xc8, 0x83, 0x27, 0xab);
 
 #endif // DRIVER_H
DRIVERENTRY.CPP (Excerpt)

 NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT pdo)
     {                           // AddDevice
     NTSTATUS status;
     PDEVICE_OBJECT fdo;
     status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL,
         FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
     if (!NT_SUCCESS(status))
         return status;
     
     PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
     pdx->DeviceObject = fdo;
     pdx->usage = 1;             // locked until RemoveDevice
     KeInitializeEvent(&pdx->evRemove, NotificationEvent, FALSE);
 
     status = IoRegisterDeviceInterface(pdo, &GUID_SIMPLE, NULL,
         &pdx->ifname);
     if (!NT_SUCCESS(status))
         {                       // unable to register interface
         IoDeleteDevice(fdo);
         return status;
         }                       // unable to register interface
     IoSetDeviceInterfaceState(&pdx->ifname, TRUE);
 
     pdx->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);
     fdo->Flags &= ~DO_DEVICE_INITIALIZING;
     IoInitializeDpcRequest(fdo, DpcForIsr);
     fdo->Flags |= DO_BUFFERED_IO;
     pdx->power = PowerDeviceD0; // device starts in full power state
 
     pdx->idle = PoRegisterDeviceForIdleDetection(pdo, 
         SIMPLE_IDLE_CONSERVATION, SIMPLE_IDLE_PERFORMANCE, PowerDeviceD3);
 
     return STATUS_SUCCESS;
     }                           // AddDevice

Figure 7   Test Program for SIMPLE.SYS


 // TEST.CPP
 
 #include <windows.h>
 #include <stdio.h>
 #include <winioctl.h>
 #include <setupapi.h>
 #include "SimpleIoctl.h"
 
 // {3d93c5c0-0085-11d1-821e-0080c88327ab}
 #include <initguid.h>
 DEFINE_GUID(GUID_SIMPLE, 0x3d93c5c0, 0x0085, 0x11d1, 0x82, 0x1e, 0x00,
             0x80, 0xc8, 0x83, 0x27, 0xab);
 
 #define Not_VxD
 #include "myvxd.h"
 
 void main(int argc, char* argv[])
     {                           // main
     HDEVINFO info = SetupDiGetClassDevs((LPGUID) &GUID_SIMPLE, NULL, NULL, 
                                         DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
     if (info == INVALID_HANDLE_VALUE)
         {
         printf("Error %d trying to open enumeration handle for " "GUID_SIMPLE\n", 
                GetLastError());
         exit(1);
         }
 
     SP_INTERFACE_DEVICE_DATA ifdata;
     ifdata.cbSize = sizeof(ifdata);
     if (!SetupDiEnumInterfaceDevice(info, NULL, (LPGUID) &GUID_SIMPLE,
                                     0, &ifdata))
         {
         printf("Error %d trying to enumerate interfaces\n",
                GetLastError());
         SetupDiDestroyDeviceInfoList(info);
         exit(1);
         }
 
     DWORD needed;
     SetupDiGetInterfaceDeviceDetail(info, &ifdata, NULL, 0, &needed, NULL);
     PSP_INTERFACE_DEVICE_DETAIL_DATA detail = 
         (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc(needed);
     if (!detail)
         {
         printf("Error %d trying to get memory for interface detail\n",
                GetLastError());
         SetupDiDestroyDeviceInfoList(info);
         exit(1);
         }
 
     detail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
     if (!SetupDiGetInterfaceDeviceDetail(info, &ifdata, detail, needed,
                                          NULL, NULL))
         {
         printf("Error %d getting interface detail\n", GetLastError());
         free((PVOID) detail);
         SetupDiDestroyDeviceInfoList(info);
         exit(1);
         }
 
     char name[MAX_PATH];
     strncpy(name, detail->DevicePath, sizeof(name));
     free((PVOID) detail);
     SetupDiDestroyDeviceInfoList(info);
 
     HANDLE hfile = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, 
                               OPEN_EXISTING, 0, NULL);
     if (hfile == INVALID_HANDLE_VALUE)
         {
         printf("Error %d trying to open %s\n", GetLastError(), name);
         exit(1);
         }
 
         //The code above is a partial listing of Test.cpp.  The complete
         //listing will be published in the second article of this two part
         //series.  In addition the entire listing is available on the MSJ
         //web site, http://microsoft.com/msj .
 
     }