Window XP驱动开发(十) 驱动程序的基本结构

转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家提出意见,一起讨论!

 参考书籍<>

一、数据结构

1、驱动对象(DRIVER_OBJECT)

 

每个驱动程序会有唯一的驱动对象与之对应,且这个驱动对象是在驱动加载时,

被内核中的对象管理程序所创建的。

 

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;  // 每个驱动程序会有一个或多个设备对象。其中每个
								  // 设备对象都有一个指向下一个驱动对象,最后一个设备对象指向空。
								  // 此处的DeviceObject指赂驱动对象的第一个设备对象。
								  // 通过DeviceObject就可以遍历驱动对象里的所有设备对象。
								  // 设备对象是由程序员自己创建的,而而OS完成。
								  // 在驱动卸载时,遍历每个设备对象,并将其删除。
    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; // 驱动程序的名字,该串一般为\Driver\[驱动程序名称 ]

    //
    // The following section is for registry support.  Thise is a pointer
    // to the path to the hardware information in the registry
    //

    PUNICODE_STRING HardwareDatabase;  // 记录的是设备的硬件数据库键名。
									   // 这里同样用UNICODE字符串记录。
									   // 一般为\REGISTRY\MACHINE\HARDWAR\DESCRIPTORION\SYSTEM

    //
    // 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;  // 记录StartIO例程的函数地址
    PDRIVER_UNLOAD DriverUnload;    // 指向驱动卸载时所用的回调函数地址
    PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; 

} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT; 


2、 设备对象(DEVICE_OBJECT)

每个驱动程序会创建一个或多个设备对象,用DEVICE_OBJECT数据结构表示,每个设备对象都会有一个指针指向下一个设备对象,因此形成一个设备链。

 

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; // 指向下一个设备对象。这里指出的是,如果有更高一层的驱动附加
										   // 到这个驱动时,AttachedDevice指向的就是那个更高一层的驱动
    struct _IRP *CurrentIrp;               // 在使用StartIO例程时,此域指向的是当前IRP结构。  
    PIO_TIMER Timer;
    ULONG Flags;                           // 是一个32位的无符号整型。
    ULONG Characteristics;                      // See ntioapi:  FILE_...
    __volatile PVPB Vpb;
    PVOID DeviceExtension;
    DEVICE_TYPE DeviceType;                // 设备的类型。
    CCHAR StackSize;                       // 在多层驱动情况下,驱动与驱动之间会形成类似堆栈的结构,
										   // IRP会依次从最高层传递到最低层。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;

typedef struct _DEVICE_OBJECT *PDEVICE_OBJECT; 




//
// The following structure is pointed to by the SectionObject pointer field
// of a file object, and is allocated by the various NT file systems.
//

typedef struct _SECTION_OBJECT_POINTERS {
    PVOID DataSectionObject;
    PVOID SharedCacheMap;
    PVOID ImageSectionObject;
} SECTION_OBJECT_POINTERS;


 

 

 

 

 

===========================================================================================================

设备对象的结构如下图:

 

3、设备扩展

设备对象记录“通用”设备的信息,而另外一些“特殊”信息记录在设备扩展中。各个设备扩展由程序员定义,每个设备的设备扩展也不尽相同。

设备扩展由I/O管理器创建的。并保存在非分页的内存中。

在设备扩展中会记录下列内容:

(1)设备对象的反向指针

(2)设备状态或驱动环境信息

(3)中断对象指针

(4)控制器对象指针

 

 二、驱动的基本结构

1、NT式驱动的基本结构
1、1  驱动加载过程与驱动入口函数(DriverEntry)

参考我的另一篇博客: http://blog.csdn.net/chenyujing1234/article/details/7565364

 

1、2  创建设备对象

会调用IoCreateDevice函数

IoCreateDevice(
    __in  PDRIVER_OBJECT DriverObject,  // 驱动对象的指针。
    __in  ULONG DeviceExtensionSize,    // 指定设备扩展的大小,I/O管理器会根据这个大小
										// 在内存中创建设备扩展,并与驱动对象关联。
    __in_opt PUNICODE_STRING DeviceName,// 设置设备对象的名字。
    __in  DEVICE_TYPE DeviceType,       
    __in  ULONG DeviceCharacteristics,	// 设备设备对象的特征
    __in  BOOLEAN Exclusive,            // 设置设备对象是否为内核算模式下使用
    __out
    __drv_out_deref(
        __drv_allocatesMem(Mem)
        __drv_when((((inFunctionClass$("DRIVER_INITIALIZE"))
             ||(inFunctionClass$("DRIVER_DISPATCH")))),
             __drv_aliasesMem)
        __on_failure(__null))
    PDEVICE_OBJECT *DeviceObject        // I/O管理器负责创建这个设备对象,并返回对象的地址。
    );


设备名称用UNICODE字符串指定,且字符串必须是"\Device\[设备名]"的形式。

在Windows下的所有设备都是以类似的名字命令的。

当然也可以不指定设备名字。如果在IoCreateDevice没指定设备名字,I/O管理器会自动分配一个数字作为设备的设备名。

eg: \Device\00000001

如果指定了设备名,只能被内核模式下的其他驱动所识别。但在用户模式下的应用程序无法识别这个设备。

让应用程序能识别设备有两种方法:

(1)通过符号链接找到设备。(常用)

(2)通过设备接口找到设备。

符号链接可以理解为设备对象起了一个“别名”。设备对象的名称只能被内核模式的驱动识别,

而别名也可以被用户模式下的APP识别.

eg: 常说的C盘,指向的“C:”的符号链接,其真实对象是“\Device\HarddiskVolume1“

创建符号链接的函数是

NTSTATUS
IoCreateSymbolicLink(
    __in PUNICODE_STRING SymbolicLinkName,
    __in PUNICODE_STRING DeviceName
    );

 

2、WDM式驱动的基本结构

WDM驱动结构请参考我的另一篇文章

http://blog.csdn.net/chenyujing1234/article/details/7568029

 

WDM驱动的DriverEntry与NT式驱动的DriverEntry有以下几个不同:

(1)增加了对AddDevice函数的设置。

因为NT驱动是主动加载设备的,也就是一旦加载驱动就创建设备。

而WDM驱动是被动加载设备的。OS必须加载PDO后,调用驱动的AddDevice例程,

AddDevice负责创建FDO,并附加到PDO上。

(2)必须加入IRP_MJ_PNP的派遣回调函数。

它主要负责计算机中即插即用的处理。

 

具体的回调函数可以参照我的文章

http://blog.csdn.net/chenyujing1234/article/details/7580315

 

 

 

你可能感兴趣的:(window,xp)