每个驱动程序对象表示加载的内核模式驱动程序的图像。 I/O 管理器分配 DRIVER_OBJECT 结构,并将其作为输入参数传递给驱动程序的 DriverEntry、 AddDevice 和可选的 Reinitialize 例程及其 Unload 例程(如果有)。
驱动程序对象部分不透明。 驱动程序编写器必须了解驱动程序对象的某些成员,才能初始化驱动程序,并在驱动程序可卸载时卸载该驱动程序。 驱动程序对象的以下成员可供驱动程序访问。
语法
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;
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch;
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT, *PDRIVER_OBJECT;
成员
Type
指定驱动程序对象的对象类型标识符。 I/O 管理器在分配驱动程序对象时设置此字段。 驱动程序不应使用此字段或修改此字段。
Size
指定驱动程序对象结构的大小(以字节为单位)。 I/O 管理器在分配驱动程序对象时设置此字段。 驱动程序不应使用此字段或修改此字段。
DeviceObject
指向驱动程序创建的设备对象链接列表中的第一个设备对象的指针。 此字段将单个驱动程序创建的所有设备链接在列表中。 驱动程序成功调用 IoCreateDevice 时,I/O 管理器会自动更新此成员。 驱动程序可以使用此成员和DEVICE_OBJECT的 NextDevice 成员遍历驱动程序创建的所有设备对象的完整列表。 这在驱动程序卸载期间特别有用,以确保正确清理所有设备对象。
Flags
包含描述驱动程序的各种属性和状态的系统定义标志。 此字段为驱动程序对象提供可扩展的标志位置。 这些标志由 I/O 管理器和其他系统组件设置和维护。 驱动程序不应直接修改此字段。
DriverStart
指向在系统内存中加载驱动程序映像的基虚拟地址。 此地址表示内核地址空间中驱动程序代码部分的开头。 加载驱动程序时,I/O 管理器将设置此值。
DriverSize
指定内存中驱动程序映像的大小(以字节为单位)。 此值表示加载的驱动程序的总内存占用量,包括代码、数据和其他部分。 加载驱动程序时,I/O 管理器将设置此值。
DriverSection
指向驱动程序的节对象,该对象表示内存管理器中的驱动程序映像。 这是内存管理器和加载程序内部使用的不透明系统结构。 驱动程序不应访问或修改此成员。
DriverExtension
指向驱动程序扩展的指针。 驱动程序扩展的唯一可访问成员是 DriverExtension->AddDevice,驱动程序的 DriverEntry 例程存储驱动程序的 AddDevice 例程。
DriverName
包含驱动程序的 Unicode 字符串名称。 错误日志线程使用此字段来确定 I/O 请求或绑定到的驱动程序的名称。 这通常是 \Driver\DriverName 形式的,其中 DriverName 对应于注册表中的驱动程序的服务名称。 I/O 管理器基于驱动程序的注册表配置设置此值。
HardwareDatabase
指向注册表中硬件配置信息的 \Registry\Machine\Hardware 路径的指针。
FastIoDispatch
指向定义驱动程序快速 I/O 入口点 的FAST_IO_DISPATCH 结构的指针。 此可选指针指向驱动程序的备用入口点数组,以支持“快速 I/O”。 使用单独的参数直接调用驱动程序例程,而不是使用标准 IRP 调用机制来执行快速 I/O。 请注意,这些函数只能用于同步 I/O,以及缓存文件时。 此成员仅由文件系统驱动程序(FSD)和网络传输驱动程序使用。
DriverInit
驱动程序 DriverEntry 例程的入口点地址。 I/O 管理器将此字段设置为在加载驱动程序时指向驱动程序的初始化函数。 这是将驱动程序加载到内存中时调用的第一个函数,负责初始化驱动程序对象并设置调度例程。
DriverStartIo
驱动程序 StartIo 例程(如果有)的入口点,驱动程序初始化时由 DriverEntry 例程设置。 如果驱动程序没有 StartIo 例程,则此成员 NULL。
DriverUnload
驱动程序 Unload 例程(如果有)的入口点,驱动程序初始化时由 DriverEntry 例程设置。 如果驱动程序没有 Unload 例程,则此成员 NULL。
MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]
一个调度表,其中包含驱动程序 DispatchXxx 例程的入口点数组。 数组的索引值是表示每个 IRP 主函数代码IRP_MJ_XXX 值。 此主要函数调度表必须是对象中的最后一个字段,使其保持可扩展。 每个驱动程序必须在此数组中为驱动程序处理 IRP_MJ_XXX 请求设置入口点。 有关详细信息,请参阅 编写调度例程。
为了帮助 驱动程序代码分析,静态驱动程序验证程序(SDV)和其他验证工具,每个 DispatchXxx 例程都使用DRIVER_DISPATCH类型声明,如以下代码示例所示:
DRIVER_DISPATCH DispatchXxx;
然后,按如下所示实现回调例程:
_Use_decl_annotations_
NTSTATUS
DispatchXxx(
struct _DEVICE_OBJECT *DeviceObject,
struct _IRP *Irp
)
{
// Function body
}
DRIVER_DISPATCH函数类型在 Wdm.h 头文件中定义。 若要在运行代码分析工具时更准确地识别错误,请务必将 _Use_decl_annotations_ 批注添加到函数定义中。
_Use_decl_annotations_ 批注可确保使用应用于头文件中DRIVER_DISPATCH函数类型的批注。 有关函数声明要求的详细信息,请参阅 使用 WDM 驱动程序的函数角色类型来声明函数。 有关 _Use_decl_annotations_的信息,请参阅 批注函数行为。
言论
每个内核模式驱动程序的初始化例程都应命名为 DriverEntry ,以便系统会自动加载驱动程序。 如果此例程的名称是其他名称,驱动程序编写器必须定义链接器初始化例程的名称;否则,系统加载程序或 I/O 管理器找不到驱动程序的传输地址。 可以由驱动程序编写者自行决定选择其他标准驱动程序例程的名称。
驱动程序必须在加载驱动程序时将其 DispatchXxx 入口点设置为传递到 DriverEntry 例程的驱动程序对象中。 设备驱动程序必须为 IRP_MJ_XXX 设置一个或多个 DispatchXxx 入口点, 需要处理同一类型的设备的任何驱动程序。 高级驱动程序必须为必须传递到基础设备驱动程序的所有 IRP_MJ_XXX 设置一个或多个 DispatchXxx 入口点。 否则,驱动程序不会为其在驱动程序对象中设置 DispatchXxx 例程的任何 IRP_MJ_XXX 发送 IRP。 有关需要处理不同类型的基础设备的驱动程序 IRP_MJ_XXX 集的详细信息,请参阅 IRP 主要函数代码。
DriverEntry 例程还设置驱动程序的 AddDevice、StartIo 和/或 Unload 入口点(如果有)。
设备驱动程序可以使用 HardwareDatabase 字符串在加载驱动程序时从注册表获取硬件配置信息。 为驱动程序提供对此字符串的只读访问权限。
RegistryPathDriverEntry 例程的输入指向 \Registry\Machine\System\CurrentControlSet\Services\DriverName 键,其中 DriverName 的值项标识驱动程序。 此注册表项包含驱动程序的服务配置,包括如下值:
- 启动:何时应加载驱动程序(启动、系统、自动、需求或禁用)
- 类型:服务类型(内核驱动程序、文件系统驱动程序等)
- ErrorControl:如果驱动程序无法加载,系统应如何响应
- ImagePath:驱动程序二进制文件的路径
驱动程序可以在其服务 密钥的参数子 项下存储其他配置数据。 至于输入驱动程序对象中的 HardwareDatabase,将为驱动程序提供对此字符串的只读访问权限。
驱动程序对象中的未记录成员应被视为不可访问。 依赖于对象成员位置或访问未记录成员的驱动程序可能无法在一段时间内保持可移植性且与其他驱动程序互作。
要求
| 要求 | 价值 |
|---|---|
| 标头 | wdm.h (包括 Wdm.h、Ntddk.h、Ntifs.h) |