DRIVER_OBJECT
每一个驱动对象代表一个被加载的内核模式驱动镜像,一个指向驱动对象的指针是驱动的DriverEntry、AddDevice的一个输入参数。并且作为Reinitialize到Unload函数可选参数,如果这些函数存在的话。
驱动程序对象是部分不透明。驱动程序编写者必须了解驱动程序对象的初始化,以及了解驱动无法加载时如何卸载它,以下驱动程序对象的成员都可以访问驱动程序。
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
//
// The following links all of the devices created by a single driver
// together on a list, and the Flags word provides an extensible flag
// location for driver objects.
//
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
//
// The following section describes where the driver is loaded. The count
// field is used to count the number of times the driver has had its
// registered reinitialization routine invoked.
//
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
//
// The driver name field is used by the error log thread
// determine the name of the driver that an I/O request is/was bound.
//
UNICODE_STRING DriverName;
//
// The following section is for registry support. Thise is a pointer
// to the path to the hardware information in the registry
//
PUNICODE_STRING HardwareDatabase;
//
// The following section contains the optional pointer to an array of
// alternate entry points to a driver for "fast I/O" support. Fast I/O
// is performed by invoking the driver routine directly with separate
// parameters, rather than using the standard IRP call mechanism. Note
// that these functions may only be used for synchronous I/O, and when
// the file is cached.
//
PFAST_IO_DISPATCH FastIoDispatch;
//
// The following section describes the entry points to this particular
// driver. Note that the major function dispatch table must be the last
// field in the object so that it remains extensible.
//
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
PDEVICE_OBJECT DeviceObject
指向被驱动创建的设备对象。当驱动调用IoCreateDevice成功时,这个成员自动的更新。一个驱动可以使用这个成员和NextDevice成员遍历由驱动创建的设备对象列表。
PDRIVER_EXTENSION DriverExtension
指向驱动的扩展,唯一可以访问驱动扩展成员是DriverExtension->AddDevice,在它当中,驱动的DriverEntry函数保存了驱动AddDevice函数,即插即用管理器检测到一个新设备时此函数被调用。
typedef struct _DRIVER_EXTENSION {
//
// Back pointer to Driver Object
//
struct _DRIVER_OBJECT *DriverObject;
//
// The AddDevice entry point is called by the Plug & Play manager
// to inform the driver when a new device instance arrives that this
// driver must control.
//
PDRIVER_ADD_DEVICE AddDevice;
//
// The count field is used to count the number of times the driver has
// had its registered reinitialization routine invoked.
//
ULONG Count;
//
// The service name field is used by the pnp manager to determine
// where the driver related info is stored in the registry.
//
UNICODE_STRING ServiceKeyName;
//
// Note: any new shared fields get added here.
//
} DRIVER_EXTENSION, *PDRIVER_EXTENSION;
-
PUNICODE_STRING HardwareDatabase
指向注册表硬件配置信息的
路径:
\Registry\Machine\Hardware
PFAST_IO_DISPATCH FastIoDispatch
指向一个定义驱动的快速I/O(fast I/O)入口点。这个成员只用于FSDs和网络传输驱动。
PDRIVER_INITIALIZE DriverInit
DriverEntry函数的入口点,它是由I/O管理器设置的。
PDRIVER_STARTIO DriverStartIo
驱动程序StartIo函数的入口点。如果有,当驱动初始化时DriverEntry函数中被设置。如果驱动没有StartIo函数,则此成员为NULL。
PDRIVER_UNLOAD DriverUnload
驱动程序Unload函数的入口点,如果有,当驱动初始化时DriverEntry函数中被设置。如果驱动没有Unload程序,则此成员为NULL。
一个指向驱动的Dispatchxxx函数的指针数组(分发(dispatch)表)。这个数组的索引值是IRP主功能码(IRP major function code)对应的RP_MJ_XXX值。每个驱动必须为IRP_MJ_XXX请求设置这个数组中的入口点的驱动句柄。更多的信息见Writing Dispatch Routines。
分发函数被声明为DRIVER_DISPATCH类型,如下:
DRIVER_DISPATCH DispatchXxx;
回调函数实现为:
_Use_decl_annotations_
NTSTATUS DispatchXxx(
struct _DEVICE_OBJECT *DeviceObject,
struct _IRP *Irp
)
{
// Function body
}
DRIVER_DISPATCH函数类型在Wdm.h头文件中定义。
备注
每个内核模式驱动的初始化函数应该命名为DriverEntry,系统才能将自动加载驱动。如果这个函数命名为其他的,驱动程序编写者必须为初始化函数定义链接。否则系统加载器或者I/O管理器无法找到驱动传输地址。这个名字其他命名表彰可以有驱动编写者权衡选择。
驱动程序必须在被传递给DriverEntry例程时,驱动程序加载的驱动程序对象设置其DispatchXxx入口点。一个设备驱动必须设置一个或更多DispatchXxx入口点用于IRP_MJ_XXX处理一些设备请求。一个高级的驱动必须为IRP_MJ_XXX设置一个或更多的DispatchXxx入口点,它必须通过对底层设备驱动程序。否则,如果驱动对象没有设置DispatchXxx,则驱动无法发送任何IRP_MJ_XXX的IRPs。
DriverEntry函数也要设置AddDeivce、StartIo、或者Unload入口点。
当驱动程序从注册表中获取硬件配置信息时,HardwareDatabase字符串可以被使用。驱动给出一个只读权限用于访问该字符串。
DriverEntry函数的RegistryPath输入参数指向\Registry\Machine\System\CurrentControlSet\Services\DriverName,在此路径下有驱动程序DriverName标识。