DDK驱动开发笔记
- 格式:doc
- 大小:291.50 KB
- 文档页数:4
ddk学习中遇到的问题和解决方法/lweiyan/blog/item/8b9d22091fd8c9c73ac763f6.html2009年05月16日星期六 17:55关于Driver Studio 3.2 的安装详解经过对VC、WINDDK、Driver Studio这三个软件反复的安装,终于可以使Driver Studio能在VC环境下正常编译了。
俗话说久病成医,遇到的问题多了,自然就有了很多解决问题的方法,现在拿出来和大家一起分享一下。
1、分别安装VC、WINDDK、Driver Studio,为:VC-〉WINDDK-〉 Driver Studio。
其实顺序也可以变一下的,笔者曾试过VC-〉 Driver Studio -〉WINDDK,没问题的,但最好按建议顺序安装;2、注意安装DDK时,建议将例子等全部安装,否则Driver Studio编译时会提示缺少头文件;3、在VS2005环境下,安装Driver Studio时会有对话框弹出,单击Ignore按钮,解决办法会在后面详细说明;4、选择“DriverStudio->DDK Build Setting”,在“DDK Root Directory”选项中选入DDK目录,例如“C:\WINDDK\2600”。
为了防止每次启动VC来编译WDM时,都要设置DDK目录,可以在“控制面板”的“系统”-〉“高级”-〉“环境变量E”设置中,添加一个值为C:\WINDDK\2600的系统变量BASEDIR;5、用VC打开“…\DriverStudio\DriverWorks\source\VdwLibs.dsw”,用 Driver Studio进行编译,如果编译成功就OK了,然后可以进行驱动的开发了。
6、利用DriverWizard向导对所要开发的驱动类型进行正确配置,生成所需要的驱动工程框架。
安装DriverStudio3.2 过程中出现DSDDKEnv8.dll failed to register错误的解决方法原因:与VS2005集成时会发生此错误。
基于DDK的PCI设备驱动程序设计作者:赵彬,田泽,陈佳来源:《电脑知识与技术》2011年第07期摘要:该文以基于PCI9056的某项目设备板卡为例,介绍WDM驱动程序和PCI总线协议,分析利用DDK开发WDM驱动程序的主要例程,实现了识别板卡及测试板卡功能。
关键词:WDM;PCI;DDK;设备驱动程序中图分类号:TP333文献标识码:A 文章编号:1009-3044(2011)07-1534-03Designed of PCI Device Driver Based on DDKZHAO bin1, TIAN Ze1, CHEN Jia2(1.Xi'an Shiyou University, Xi'an 710065, China; 2. Xidian University, Xi'an 710072, China)Abstract: This paper takes a PCI device as an example, describes WDM drivers and PCI bus protocols. And introducing a method of WDM driver design base on DDK(Driver Development Kit), realizing identification and testing function.Key words: WDM; PCI; DDK; device driver因为某项目的需求,需要在PC机上调试一PCI设备,在Windows系统下实现主机通过PLX9056桥芯片对PCI设备的访问,但前提条件是当操作系统装载驱动程序正确的情况下。
如果驱动程序装载不正常,主机首先就不能够识别PCI设备;如果驱动程序运行不正常,用户就不能正确的访问PCI设备。
因此,PCI驱动程序是实现主机识别板卡以及正确访问设备的关键。
现在介绍在windows XP下开发虚拟串口的方法。
可以开发一个虚拟串口,将读写请求传递给USB驱动,这样就可以利用现成的串口调试工具向USB设备读取了。
1、DDK串口开发框架DDK对串口驱动提供了专门接口。
只要编写的驱动满足这些接口,并按照串口标准的命名方法,不管是真实的串口设备,还是虚拟设备,Windows操作系统都会认为这个设备是一个标准的串口设备。
用标准的串口调试工具都可以与这个设备进行通信。
1、1 串口驱动的入口函数本章的实例程序是在HelloWDM驱动的基础上修改而来,入口函数依然是DriverEntry,在DriverEntry函数中指定各种IRP的派遣函数,以及AddDevice 例程、卸载例程等。
[cpp]view plaincopy1./************************************************************************2.* 函数名称:DriverEntry3.* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象4.* 参数列表:5. pDriverObject:从I/O管理器中传进来的驱动对象6. pRegistryPath:驱动程序在注册表的中的路径7.* 返回值:返回初始化驱动状态8.*************************************************************************/9.#pragma INITCODE10.extern"C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,11. IN PUNICODE_STRING pRegistryPath)12.{13. KdPrint(("Enter DriverEntry\n"));14.15. pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;16. pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;17. pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloWDMDispatchControlp;18. pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloWDMCreate;19. pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloWDMClose;20. pDriverObject->MajorFunction[IRP_MJ_READ] = HelloWDMRead;21. pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMWrite;22. pDriverObject->DriverUnload = HelloWDMUnload;23.24. KdPrint(("Leave DriverEntry\n"));25.return STATUS_SUCCESS;26.}其中在AddDevice例程中,需要创建设备对象,这些都是和以前的HelloWDM驱动程序类似。
一准备DDK版本:Windows DDK 3790IDE:Visual Studio 2005二用DDK环境编译驱动这种编译驱动的办法是DDK文档中所提倡的办法。
此种方法需要编写一个编译脚本文件,在这个脚本中描述了DDK驱动程序的源文件、用到的lib文件和include路径名、编译输出的目录和文件名等信息。
编写此类脚本对于Windows程序员可能比较陌生,尤其是当源文件较多时,编写脚本文件可能显得更如麻烦。
在源程序的相同目录下创建两个文件makefile和Sources,这两个文件都是文本文件,内容如下。
Makefile这个文件不要修改## DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source# file to this component. This file merely indirects to the real make file# that is shared by all the driver components of the Windows NT DDK#!INCLUDE $(NTMAKEENV)\makefile.defSources这个文件参考实际情况修改!if "$(DDK_TARGET_OS)"=="Win2K"TARGETNAME=Passthru_2000!elseif "$(DDK_TARGET_OS)"=="WinXP"TARGETNAME= Passthru _XP!elseif "$(DDK_TARGET_OS)"=="WinNET"TARGETNAME= Passthru _03Server!endifTARGETPATH=objTARGETTYPE=DRIVERC_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNDIS_WDM=1!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K"## The driver is built in the Win2K build environment#C_DEFINES=$(C_DEFINES) -DNDIS40_MINIPORT=1C_DEFINES=$(C_DEFINES) -DNDIS40=1!else## The driver is built in the XP or .NET build environment# So let us build NDIS 5.1 version.#C_DEFINES=$(C_DEFINES) -DNDIS51_MINIPORT=1C_DEFINES=$(C_DEFINES) -DNDIS51=1!endif# Uncomment the following to build for Win98/SE/WinMe# This causes several APIs that are not present in Win9X to be# ifdef'ed out.# C_DEFINES=$(C_DEFINES) -DWIN9X=1PRECOMPILED_INCLUDE=precomp.hPRECOMPILED_PCH=precomp.pchPRECOMPILED_OBJ=precomp.obj!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K"TARGETLIBS=$(DDK_LIB_PATH)\ndis.lib \$(DDK_LIB_PATH)\ntstrsafe.lib!elseTARGETLIBS=$(DDK_LIB_PATH)\ndis.lib!endifUSE_MAPSYM=1INCLUDES=SOURCES=\miniport.c \passthru.c \passthru.rc \protocol.c \PTEXTEND.C \filter.c前7行说明此驱动的名称,这里用到了宏来控制不同操作系统版本的编译所需的文件,$(DDK_TARGET_OS)是从外面的命令行传递进来的。
接触windows驱动开发有一个月了,感觉Windows驱动编程并不像传说中的那么神秘。
为了更好地为以后的学习打下基础,记录下来这些学习心得,也为像跟我一样致力于驱动开发却苦于没有门路的菜鸟朋友们抛个砖,引个玉。
我的开发环境:Windows xp 主机+ VMW ARE虚拟机(windows 2003 server系统)。
编译环境:WinDDK6001.18002。
代码编辑工具:SourceInsight。
IDE:VS2005/VC6.0。
调试工具:WinDBG,DbgView.exe, SRVINSTW.EXE上面所有工具均来自互联网。
对于初学者,DbgView.exe和SRVINSTW.EXE是非常简单有用的两个工具,一定要装上。
前者用于查看日志信息,后者用于加载驱动。
下面从最简单的helloworld说起吧。
Follow me。
驱动程序的入口函数叫做DriverEntry(PDRIVER_OBJECT pDriverObj,PUNICODE_STRING pRegisgryString)。
两个参数,一个是驱动对象,代表该驱动程序;另一个跟注册表相关,是驱动程序在注册表中的服务名,暂时不用管它。
DriverEntry 类似于C语言中的main函数。
它跟main的差别就是,main完全按照顺序调用的方法执行,所有东西都按照程序员预先设定的顺序依次发生;而DriverEntry则有它自己的规则,程序员只需要填写各个子例程,至于何时调用,谁先调,由操作系统决定。
我想这主要是因为驱动偏底层,而底层与硬件打交道,硬件很多都是通过中断来与操作系统通信,中断的话就比较随机了。
但到了上层应用程序,我们是看不到中断的影子的。
说到中断,驱动程序中可以人为添加软中断,__asm int 3或者Int_3();前者是32位操作系统用的,后者是64位用的。
64位驱动不允许内嵌汇编。
下面是我的一个helloworld的源码:注意第16行的宏。
Windows驱动程序开发笔记一、WDK与DDK环境最新版的WDK 微软已经不提供下载了这里:https:/// 可以下并且这里有好多好东东!不要走进一个误区:下最新版的就好,虽然最新版是Windows Driver Kit (WDK) 7_0_0,支持windows7,vista 2003 xp等但是它的意思是指在windows7操作系统下安装能编写针对windows xp vista的驱动程序,但是不能在xp 2003环境下安装Windows Driver Kit (WDK) 7_0_0这个高版本,否则你在build的时候会有好多好多的问题.上文build指:首先安装好WDK/DDK,然后进入"开始"->"所有程序"->"Windows Driver Kits"->"WDK XXXX.XXXX.X" ->"Windows XP"->"x86 Checked Build Environment"在弹出来的命令行窗口中输入"Build",让它自动生成所需要的库如果你是要给xp下的开发环境还是老老实实的找针对xp的老版DDK吧,并且xp无WDK 版只有DDK版build自己的demo 有个常见问题: 'jvc' 不是内部或外部命令,也不是可运行的程序。
解决办法:去掉build路径中的空格。
二、下载 WDK 开发包的步骤1、访问Microsoft Connect Web site站点2、使用微软 Passport 账户登录站点3、登录进入之后,点击站点目录链接4、在左侧的类别列表中选择开发人员工具,在右侧打开的类别:开发人员工具目录中找到Windows Driver Kit (WDK) and Windows Driver Framework (WDF)并添加到您的控制面板中5、添加该项完毕后,选择您的控制面板,就可以看到新添加进来的项了。
通常驱动程序的调试都是用ddk在cmd中完成的。
这部分我暂时略过。
下面先介绍如何设置vc++6.0在Visual Studio 6.0集成环境中开发设备驱动程序的方法。
在Windows上,Windows DDK提供的开发环境是基于命令行的,操作起来极为不便,而Visual Studio 6.0给我们提供了非常友好易用的集成环境,让我们有如虎添翼之感。
那么,能否利用Visual Studio的集成环境来开发驱动程序呢?答案是可以的。
通过对Visual Studio集成环境的简单设置,创建好自己的驱动开发集成环境就可以了。
1,第一:安装Vc++6.0,我装的是英文版,中文版应该也可以,不过我没试。
第二:安装winXP DDK,注意,安装目录中间不能有空格,比如D:\Program Files不行,我直接装在了D盘,装完后设置环境变量DDKROOT为安装目录D:\WINDDK\2505。
2,创建一个目录,作为开发目录,我是利用<<PCI设备开发宝典>>的光盘中的工程文件PCI9052Demo,直接考到E盘,所以,工作目录下是E:\PCI9052Demo3,工作目录下创建一个批处理文件MakeDrvr.bat,内容如下:@echo offif "%1"=="" goto usageif "%3"=="" goto usageif not exist %1\bin\setenv.bat goto usagecall %1\bin\setenv %1 %4%2cd %3build -b -w %5 %6 %7 %8 %9goto exit:usageecho usage MakeDrvr DDK_dir Driver_Drive Driver_Dir free/checked [build_options] echo eg MakeDrvr %%DDKROOT%% F: %%WDMWorkshop%% free -cef:exit解释以下:1% 是DDK_dir,也就是ddk的安装目录2% 是Driver_Drive,是你工作目录所在的盘符,这里是E:3% 是Driver_Dir,是你工作目录的路径,这里是E:\PCI9052Demo4% 是编译模式,checked表示调试模式,free表示发行模式,这里是出问题的地方,后面再说。
用NT DDK开发协议驱动程序王大伟杨凯锋胡熠洪佩琳摘要:本文针对基于Windows NT平台的协议驱动程序的开发方法进行讨论,并给出一个开发实例进行具体说明。
关键词:协议驱动程序、DDK、NDIS一.协议驱动程序简介微软公司为Windows系列平台上的网络驱动程序开发者专门制定了NDIS规范(Network Driver Interface Specification)。
根据NDIS规范,Windows NT平台上的网络驱动程序主要有三类:网卡驱动程序、中介协议驱动程序和上层协议驱动程序。
网络驱动程序的层次结构参见参考文献【1】。
网卡驱动程序位于驱动程序层次的最底层,它直接管理硬件,屏蔽底层物理硬件的细节,向上层驱动程序提供一个抽象的服务接口。
协议驱动程序加载在网卡驱动程序之上,利用网卡驱动程序提供的服务实现各种网络协议的功能。
协议驱动程序可以在其上边界实现TDI(Transport Driver Interface)接口为网络用户提供服务。
譬如分配分组,从用户应用程序把数据拷贝到分组中,然后调用NDIS提供的函数把分组发送给下层驱动程序。
它在下边界提供一个协议接口,接收并解释从下层驱动程序接收到的分组。
微软公司为开发者编写驱动程序提供了DDK(Device DriverKit)工具包。
根据不同的平台分为NT DDK和Windows 95 DDK。
在DDK中,包含了依据NDIS规范开发网络驱动程序的工具。
关于DDK的介绍,以及用DDK开发驱动程序的步骤参见参考文献【1】。
二.协议驱动程序的结构协议驱动程序包括驱动程序对象和驱动程序所提供的入口函数集合。
一个协议驱动程序必须绑定到小端口网卡驱动程序或者中介驱动程序(此时相当于一个虚拟的小端口网卡驱动程序)之上,它可以绑定到一个或者多个底层驱动程序之上。
协议驱动程序在其下边界提供一系列的ProtocolXxx接口函数,并通过NDIS发送和接收网络分组。
DDK驱动开发笔记1、windows驱动分为NT式驱动和WDM式驱动,前者为非即插即用,后者为即插即用驱动。
需要头文件分别为NTDDK.h和WDM.h2、驱动的入口函数均为extern "C" NTSTA TUS DriverEntry(IN PDRIVER_OBJECTpDriverObject, IN PUNICODE_STRING pRegistryPath),它由I/O管理器负责调用,前参数为传递进来的驱动对象,后参数为Unicode字符串,指向此驱动的注册表。
3、驱动程序向windows的I/O管理器注册一些回调函数,回调函数是由程序员定义的函数,由操作系统负责调用,只要把地址告诉操作系统即可如:pDriverObject->DriverUnload=HelloDDKUnload;4、使用CreateDevice函数创建驱动设备对象如:CreateDevice(pDriverObject);返回NTSTATUS类型5、KdPrint是一个宏,用于打印输出信息,在Checked中会使用DbgPrint代替,在Free版本中无效果,用法和TRACE一致。
6、Windows的设备管理是使用线性链表进行管理,每一个节点记录了设备对象的地址,每次要对指定驱动进行操作,就必须先遍历设备对象链表。
7、设备对象函数NextDevice域记录下一个设备对象的地址,IoDeleteDevice用于删除设备对象如:IoDeleteDevice(pDevExt->pDevice),IoDeleteSymbolicLink用于删除设备符号链接。
8、DDK环境编译驱动源程序,需要使用两个自己创建的脚本makefile和Sources,最好使用二进制文本格式,makefile的内容固定为:!INCLUDE $(NTMAKEENV)\makefile.def。
sources文件记录了驱动的名称、驱动类型、编译输出目录、include目录、指定源文件。
编译好的文件会再工程目录的objchk_wxp_x86\i386文件夹里生成.sys文件。
9、对于使用其他编译环境,只能使用VS编译环境,vc6编译环境只能支持到win2000的DDK。
10、配置VS+DDK+DDKWizard:11、使用DriverMonitor安装驱动,对于NT驱动,在设备管理器中默认是隐藏的(可更改),本软件用于测试驱动。
12、WDM中使用AddDevice回调函数创建设备对象并由PNP(即插即用plug and play)管理器调用,然后设置对IRP_MJ_PNP的IRP(I/O Request Packages)的回调函数,对PNP的IRP处理是WDM和NT驱动的重大区别之一。
在WDM程序中,大部分卸载工作放在对IRP_MN_REMOVE_DEVICE的IRP的处理函数中处理。
13、在WDM的驱动程序中,创建设备对象需要驱动程序向系统注册一个称作AddDevice的例程,由PNP调用如:NTSTATUS HelloAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject); 对象->AddDevice=HelloAddDevice;14、WDM驱动的安装需要使用INF文件安装,其中编译的时候其Sources文件有所不同。
要安装WDM驱动,要先为驱动程序编写一个inf文件,该文件描述了驱动的操作硬件设备信息和驱动的一些信息,并存放在源文件的同一目录下。
Inf的信息是提供给SDK使用的。
15、安装WDM驱动,由于该驱动是一个虚拟设备,因此需要使用添加硬件的方式使用inf安装。
快速安装的话可以使用DriverStudio的EzDriverInstaller工具直接安装。
16、Windows系统的设计思想采用CS架构,内核到硬件之间使用HAL(硬件抽象层)作为过渡。
Native API穿越了用户层和内核层。
为能将其他操作系统程序移植到windows上才采用了子系统的设计模式。
17、Windows API分为三类:USER函数(窗口控件)、GDI函数(绘图)、KERNEL函数(其他有关内核操作的一些进程、线程之类的操作)。
在运行应用程序的时候,系统都会把这三种DLL装载到内存中(user32.dll\gdi32.dll\kernel.dll)。
user32和gdi32模块是在内核模式下实现的,所以图形效率非常高。
18、除了WIN32其他子系统都不是WINDOWS的纯正系统。
有OS/2子系统(苹果)、POSIX子系统(UNIX),WOW子系统(是使低bit的win程序在高bit的win上运行)、VDW子系统(Virtual DOS Machine),但这些系统都要调用win32的特定api才能运行,属于一个虚拟机概念。
19、Windows API是调用Native API的,对应的函数都是在API函数前加Nt,如NtCreateFile(由I/O管理器调用),Native API是用户模式通往内核模式的大门,它通过软件中断方式进入内核模式,并调用内核的系统服务。
Native API没有文档,适当时候可以使用,不推荐。
20、Windows规定,将4G的虚拟内存分成两部分,0~0x7fffffff为用户模式地址,以上为内核模式地址。
21、I/O管理器,用来发出IO请求,让用户发出的IO请求独立与设备,使用IRP的请求形式,把操作的参数内容存进缓冲区再读到内存中,IRP被传递到具体的设备驱动程序中,驱动程序完成IRP并返回到用户程序中,实际上,I/O管理器担当着用户模式代码和设备驱动程序之间的接口。
22、配置管理程序,它用来记录计算机软硬件的配置信息,使用叫“注册表”的数据库保存数据,驱动程序根据表中信息进行加载操作。
23、内核为执行组件提供最基本的支持,负责提供进程和线程的调度,通过自旋锁(spinlock)提供多CPU同步支持。
功能:对内核对象的支持、对线程的调度、对多处理器同步的支持、中断处理函数的支持、对错误陷阱的支持、对其他硬件特殊功能的支持。
24、Windows与微内核:微内核可以看做是组件化内核,每个组件都独立运行,降低模块间的耦合性,单一内核是可以看做所有组件都与一个中央内核有联系而存在高耦合性,linux就是典型的单内核系统。
Windows是单内核与微内核并存的系统(由user32和gdi32可以由内核模式实现说明)。
25、Windows为了简化对不同设备的操作,实现对不同设备的统一接口,将所有设备以普通文件看待,都用操作文件的办法去操作设备。
26、DbgView可以用于监听内核和win32上层程序的调试信息(免费)。
比WinDbg好用。
27、设备驱动程序的动态加载由服务控制管理程序(server control manage,SCM)系统组件完成,其实就是修改注册表实现。
操作是四个步骤:为NT驱动创建新的服务、开启此项服务、关闭此项服务、删除N T驱动所创建的服务。
28、SCM函数:A、SC_HANDLE OpenSCManager(…):打开SCM管理器用于SCM的初始化B、B OOL CloseServiceHandle(…):关闭SCM管理器用于SCM的清除工作C、S C_HANDLE CreateService(…):创建SCM管理器句柄,或说创建服务,所有操作都基于此进行D、SC_HANDLE OpenService(…):打开服务E、BOOL ControlService(…):控制服务,发送控制码进行操作服务。
29、使用VC提供的一个附加工具GUIDGEN.exe可以产生一组新的GUID,工具在Microsoft Visual Studio\Common\Tools里。
30、驱动对象DRIVER_OBJECT由I/O管理器负责加载,由DriverEntry对其进行初始化。
Typedef struct _DRIVER_OBJECT{…};驱动对象可以对应多个设备对象,在系统中是使用链表存储驱动对象。
31、设备对象DEVICE_OBJECT,在系统中使用链表存储设备对象。
在驱动程序中尽量避免全局变量的使用,因为全局变量设计不容易同步问题,可以将全局变量存放在设备扩展里。
32、设备扩展:设备对象记录“通用”设备的信息,而另外一些“特殊”信息记录在设备扩展里。
设备扩展由程序员指定内容和大小,由I/O管理器创建并保存在非分页内存中。
在驱动程序中,尽量避免使用全局函数,因为全局函数往往导致函数的不可重入性。
重入性指在多线程的程序中,多个函数并行运行,函数的运行结果不会根据函数的调用先后顺序而导致不同。
解决的办法是,将全局变量以设备扩展的形式存储,并加以适当的同步保护措施。
由于设备扩展是驱动程序专用的,它的结构必须在驱动程序的头文件中定义。
33、设备扩展定义:在设备扩展仲,记录以上几个信息,以备其他回调函数或者派遣函数使用。
使用的时候,只需从驱动设备中获取,类似以下代码:34、WinObj.exe和DeviceTree.exe用于观察驱动对象和设备对象。
它由windows内核专家编写。
35、WDM模型中完成一个设备的操作,至少有PDO和FDO两个设备对象共同完成,两者的关系是附加与“被附加”的关系。
WDM程序负责创建FDO,PDO由总线驱动创建,FDO创建后被附加到PDO上。
当FDO附加在PDO上的时候,PDO设备对象的子域AttachedDevice会记录FDO的位置。
PDO被称作底层\下层驱动,FDO被称作高层\上层驱动。
通过函数IoAttachDeviceToDeviceStack实现FDO附加到PDO上。
36、内存管理37、要指定某个例程和某个全局变量是载入分页内存还是非分页内存,需要做如下定义:#define PAGEDCODE code_seg(“PAGE”)#define LOCKEDCODE code_seg()#define INITCODE code_seg(“INIT”)#define PAGEDCODE data_seg(“PAGE”)#define LOCKEDCODE data_seg()#define INITCODE data_seg(“INIT”)如果将某个函数载入到分页内存中,我们需要在函数的实现中加入代码:#pragma PAGEDCODEVOID SomeFunction(){PAGED_CODE();//内容}PAGED_CODE宏会检验函数是否运行低于DISPATCH_LEVEL的中断请求级,等于或高于这个请求级将产生一个断言用来防止蓝屏。