array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 Windows驱动开发WDM (1) - 基本结构 - 爱码网

驱动对象(DRIVER_OBJECT)

每个驱动程序会有唯一的驱动对象与之对应,并且这个驱动对象是在驱动加载的时候,被内核中的对象管理程序所创建的。

驱动对象用DRIVER_OBJECT来表示,内核对一个驱动只加载一个实例。对于DRIVER_OBJECT的说明,详见:http://msdn.microsoft.com/en-us/library/windows/hardware/ff544174(v=vs.85).aspx

说明一下其中的一个成员:DeviceObject。

MSDN上面是这么定义:

PDEVICE_OBJECT DeviceObject

Pointer to the device objects created by the driver. This member is automatically updated when the driver callsIoCreateDevice successfully. A driver can use this member and theNextDevice member ofDEVICE_OBJECT to step through a list of all the device objects that the driver created.

DeviceObject指向驱动对象的第一个设备对象。DeviceObject->NextDevice指向下一个设备对象,最后一个设备对象的NextDevice指向空。比如第一次调用IoCreateDevice的时候,DriverObject->DeviceObject指向第一个设备对象(DeviceObject->NextDevice=NULL),再调用一次IoCreateDevice创建第二个设备成功后,DriverObject->DeviceObject->NextDevice会指向第二个设备对象。

设备对象都是由驱动程序创建的,而非操作系统创建,当驱动被卸载的时候,需要遍历每个设备对象,并将其删除。

 

设备对象(DEVICE_OBJECT)

每个驱动会创建一个或者多个设备对象,用DEVICE_OBJECT表示。每个设备对象都有一个指针指向下一个设备对象,因此形成一个设备链。设备链的第一个设备是由DRIVER_OBJECT的DeviceObject指定。

参考:http://msdn.microsoft.com/en-us/library/windows/hardware/ff543147(v=vs.85).aspx

需要说明的是:

1. NextDevice,指向下一个设备对象,注意这里指的下一个对象是同属于一个驱动对象的设备。也就是说这个设备链是指同一个驱动对象的设备链。

2. AttachedDevice,这里指的是更高一层驱动的设备对象。比如另外一个驱动附加到本驱动,那么AttachedDevice指的是那个驱动里面的第一个设备对象。

 

设备扩展 (DEVICE_EXTENSION)

DEVICE_OBJECT里面记录一些通用信息,但是大多数情况下,驱动程序需要额外记录一些信息,这个时候就需要设备扩展了。

设备扩展是由程序员指定内容和大小,由I/O管理器创建的,并且保存在非分页内存中

在驱动程序中,尽量不要使用全局变量,数据可以保存在设备扩展里面。

 

WDM驱动的基本结构

从Windows2000以后,微软引入了新的驱动模型:WDM。WDM是建立在NT驱动模型之上的。

WDM驱动一般分为2种设备对象:

1. 物理设备对象(Physical Device Object,PDO)

2. 功能设备对象(Function Device Object,FDO)

比如:当用户插入USB盘的时候,总线驱动会创建PDO,然后提示用户加载FDO,如果操作系统已经提供了相应的驱动,那么操作系统会自动加载这个驱动。如果没有,则需要用户去安装相应的驱动。

在FDO和PDO之间,可以创建过滤驱动。

1. 位于FDO下面的,称之为下层过滤驱动;

2. 位于FDO上面的,称之为上层过滤驱动。

简单画了一个示意图:

Windows驱动开发WDM (1) - 基本结构

过滤驱动不是必须的,在WDM中,基本上可以说PDO和FDO是必须的。AttachedDevice指向上层驱动的设备对象。

 

入口程序DriverEntry

跟NT驱动一样,WDM驱动的入口函数也是DriverEntry。WDM驱动需要额外设置2个派遣函数:

1. AddDevice

2. IRP_MJ_PNP

跟NT驱动不同,NT驱动一旦加载就创建设备,而WDM驱动是操作系统加载PDO以后,调用驱动的AddDevice例程,然后在AddDevice例程里面创建FDO,并且附加到PDO之上。

 

驱动程序的垂直层次结构

DeviceObject->AttachedDevice指向上层设备,如上面的图示。但是设备对象里面不能记录下一层驱动的设备对象(NextDevice指的是同一个驱动里面的下一个设备对象),这时就可以通过设备扩展来记录。

通过AttachedDevice和设备扩展,我们可以遍历整个设备对象堆栈,包括从上到下和从下到上。

 

驱动程序的水平层次结构

《windows驱动技术开发详解》里面将同一个驱动创建出来的设备对象的关系称之为水平层次,我觉得还是蛮形象的。

水平层次的第一个设备对象是由它的驱动对象所指定(DRIVER_OBJECT::DeviceObject)。每一个设备对象可以通过NextDevice找到水平层次(同一个驱动对象)的下一个设备对象。

比如插入2块同样型号的网卡。插入第一个网卡的时候,系统会创建一个PDO,并且加载相应的FDO,插入第二个网卡的时候,系统创建另外一个PDO,并且加载相应的FDO。那么这两个PDO之间就是同一个水平层次,这两个FDO也处于同一个水平层次。

 

相关文章: