1:驱动对象:
每个驱动都有一个驱动对象与之对应,且这个驱动对象是在驱动加载时,被内核中的对象管理器创建的.其中pDriverObject是作为驱动的一个实例被内核(确切的说是IO管理器)加载.定义如下:
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size; //每个驱动程序都有一个或者多个设备对象.每个设备对象都有一个指针指向下一个设备对象.最后一个设备对象指向空.形成一个设备链.在驱动卸载的时候,要遍历每个设备对象.并将其删除.
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName;//驱动名称.UNICODE字符串.一般为:/Driver/[驱动程序名称]
PUNICODE_STRING HardwareDatabase;//硬件数据库键名一般为:/REGISTRY/MACHINE/HARDWARE/DESCRIPTION/SYSTEM
PFAST_IO_DISPATCH FastIoDispatch;//文件驱动中的派遣函数.
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;//StartIO例程的函数地址.用于串行化操作.
PDRIVER_UNLOAD DriverUnload;//驱动卸载时的回调函数地址
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];//是一个函数指针数组.每个成员记录一个指针.每个指针指向一个函数.这些函数就是IRP的派遣函数
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT; // ntndis
pRegistryPath为此驱动的注册表路径.
2:设备对象:定义如下:
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
LONG ReferenceCount;
struct _DRIVER_OBJECT *DriverObject;//驱动对象.
struct _DEVICE_OBJECT *NextDevice;//下一个设备对象.同属于一个驱动对象的设备对象.通过链表枚举每个设备对象.
struct _DEVICE_OBJECT *AttachedDevice;//指向更高一层的驱动.
struct _IRP *CurrentIrp;//使用StartIO例程时,此域指向当前IRP结构
PIO_TIMER Timer;
ULONG Flags; // See above: DO_...
ULONG Characteristics; // See ntioapi: FILE_...
PVPB Vpb;
PVOID DeviceExtension;
DEVICE_TYPE DeviceType;
CCHAR StackSize;
union {
LIST_ENTRY ListEntry;
WAIT_CONTEXT_BLOCK Wcb;
} Queue;
ULONG AlignmentRequirement;
KDEVICE_QUEUE DeviceQueue;
KDPC Dpc;
//
// The following field is for exclusive use by the filesystem to keep
// track of the number of Fsp threads currently using the device
//
ULONG ActiveThreadCount;
PSECURITY_DESCRIPTOR SecurityDescriptor;
KEVENT DeviceLock;
USHORT SectorSize;
USHORT Spare1;
struct _DEVOBJ_EXTENSION *DeviceObjectExtension;
PVOID Reserved;
} DEVICE_OBJECT;
3:设备扩展对象.
每个设备都会指定一个设备扩展对象.保存在非分页内存中.是程序员自己定义的结构体.在驱动程序中,应该尽量避免全局变量的使用.因为全局对象涉及到同步的问题.解决办法.把全局对象存放在设备扩展对象中.
驱动入口函数:
* 函数名称:DriverEntry
* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
* 参数列表:
pDriverObject:从I/O管理器中传进来的驱动对象
pRegistryPath:驱动程序在注册表的中的路径
* 返回 值:返回初始化驱动状态
extern "C" NTSTATUS DriverEntry (
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath )
DriverEntry对驱动进行初始化.由系统进程[System]调用.系统进程在系统启动时就已经被创建了.该函数返回NTSTATUS类型(32位无符号长整形).其中0-0x7FFFFFFF为正确状态.而0x80000000-0xFFFFFFFF为错误状态.
创建设备对象:
* 功能描述:初始化设备对象
* 参数列表:
pDriverObject:从I/O管理器中传进来的驱动对象
* 返回 值:返回初始化状态
NTSTATUS
IoCreateDevice(
IN PDRIVER_OBJECT DriverObject,//驱动对象的指针
IN ULONG DeviceExtensionSize,//设备扩展大小
IN PUNICODE_STRING DeviceName OPTIONAL,//设备对象的名字.UNICODE字符串.必须是/Device/[设备名]的形式 //在windows下,所有的设备都是类似命名.如系统的C盘,D盘分别被命名为"/Device/HarddiskVolume1"和"/Device/HarddiskVolume2".如果不指定设备名称.则系统以"Device/00000001","Device/00000002"依次命名
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject
);
符号链接:
NTSTATUS
IoCreateSymbolicLink(
IN PUNICODE_STRING SymbolicLinkName,
//符号链接.内核模式下,符号链接是以"/??/"或者是"/DosDevice/"开头的.如C:盘就是"/??/C:"或者"/DosDevice/C:"而在用户模式下则是以"//./"开头的.如C:盘就是"//./C:"
IN PUNICODE_STRING DeviceName
);
如果指定了设备名.也就是IoCreateDevice中的DeviceName由程序员自己定义,那么该设备只能被内核模式下的其他驱动所识别.但是用户模式下的应用程序无法识别这个设备.为了让用户模式下的程序也能识别这个设备.要指定符号链接.还有一种方法就是通过设备接口找到设备.如系统的C盘,D盘分别被命名为"/Device/HarddiskVolume1"和"/Device/HarddiskVolume2"那么"C:"就是符号链接
驱动卸载:
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
pDriverObject:驱动对象
* 返回 值:返回状态
VOID
IoDeleteDevice(
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
IoDeleteSymbolicLink(
IN PUNICODE_STRING SymbolicLinkName
);
pDriverObject->DriverUnload.删除入口函数中创建的设备对象.如果有多个设备对象.则需要遍历设备对象链表.最后删除符号链接.