windows 环境下的程序设计

92
Windows Windows 环环环环环环环环 环环环环环环环环 Instructor: Hengming Zou, Ph.D. In Pursuit of Absolute Simplicity 环环环环 环环环环

Upload: jarah

Post on 10-Jan-2016

78 views

Category:

Documents


5 download

DESCRIPTION

Windows 环境下的程序设计. Instructor: Hengming Zou, Ph.D. In Pursuit of Absolute Simplicity 求于至简,归于永恒. Windows 环境下的程序设计. 1. Windows 应用程序设计模式 2. 结构化异常处理 3. 动态链接库 4. Windows 驱动程序模型 5. WDM 驱动程序编程实例 6. 开发 WDM 驱动程序的一般方法. Windows 应用程序设计模式. Windows 应用程序是特意为在 Windows 环境中运行而编写的应用程序 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Windows 环境下的程序设计

WindowsWindows 环境下的程序设计环境下的程序设计Instructor: Hengming Zou, Ph.D.

In Pursuit of Absolute Simplicity 求于至简,归于永恒

Page 2: Windows 环境下的程序设计

22

Windows环境下的程序设计

1. Windows 应用程序设计模式 2. 结构化异常处理 3. 动态链接库 4. Windows驱动程序模型 5. WDM驱动程序编程实例 6. 开发 WDM驱动程序的一般方法

Page 3: Windows 环境下的程序设计

33

Windows 应用程序设计模式

Windows 应用程序是特意为在 Windows 环境中运行而编写的应用程序

以窗口为核心的用户界面、以事件驱动为动力的程序运行机制、以及将程序代码与用户界面分开处理的程序开发手段,构成了 Windows应用程序特有的设计模式

Page 4: Windows 环境下的程序设计

44

Win32 API

Windows 应用程序总是在常规的用户态下运行 操作系统核心组件则对外界表现出中立的性质,它们不实现

用户界面,甚至不提供编程接口,系统服务调用对应用程序而言是不公开的

Windows操作系统依靠一组用户态环境子系统,作为应用程序与操作系统核心之间的接口

Page 5: Windows 环境下的程序设计

55

Win32 API

Win32子系统是 Windows 操作系统的固有的子系统,这个子系统能够提供应用程序运行所需要的窗口管理、图形设备接口、媒体控制、内存管理等各项服务功能,这些功能以函数库的形式组织在一起,这就是 Win32应用程序编程接口,简称为 Win32 API

Win32子系统负责将 API调用转换成 Windows操作系统的系统服务调用

Page 6: Windows 环境下的程序设计

66

Win32 API

Windows 应用程序与操作系统的关系

Windows应用程序

Win32子系统

子系统 用户态

核心态系统服务

Windows应用程序

硬件层

Page 7: Windows 环境下的程序设计

77

Win32 API

USER32.DLL:负责处理用户接口 GDI32.DLL:负责在图形设备上执行绘图操作 KERNEL32.DLL:操作系统核心功能服务 COMCTL32.DLL:通用控件库 COMDLG32.DLL:公共对话框 SHELL32.DLL:用户界面外壳 DIBENG.DLL:图形引擎 NETAPI32.DLL:网络

Page 8: Windows 环境下的程序设计

88

Win32 API

标准 Win32 API函数分类:– 系统服务– 通用控件库– 图形设备接口– 网络服务– 用户接口– 系统 Shell

– Windows 系统信息

Page 9: Windows 环境下的程序设计

99

Windows应用程序设计模式

窗口 目的是保证用户能够同时访问大多数应用程序 应用程序使用窗口来显示输出或接收用户的输入 应用程序只有通过窗口才能访问系统显示器;并且通过使用

窗口与其他应用程序共享系统显示器

Page 10: Windows 环境下的程序设计

1010

Windows应用程序设计模式

事件驱动 Windows 应用程序的执行顺序取决于事件发生的顺序,描

述事件发生的信息称为消息,而事件驱动程序设计则是围绕着消息的产生与处理而展开的

消息可以分为由硬件设备产生的输入消息和来自 Windows系统的窗口管理消息

发送消息—— send

指派消息—— post

Page 11: Windows 环境下的程序设计

1111

Windows应用程序设计模式

事件驱动

硬件输入 系统消息队列

应用程序队列 1

应用程序队列n

Windows

WinMain函数消息循环

窗口函数1

窗口函数m

应用程序1

WinMain函数消息循环

应用程序n

窗口函数1

窗口函数m

Page 12: Windows 环境下的程序设计

1212

Windows应用程序设计模式

Windows应用程序的开发流程 Windows 应用程序分为程序代码和用户界面资源两部分,

两部分通过资源编译器组合为一个完整的 EXE文件 将用户界面资源一类的静态数据与程序代码相分离有如下一

些优点 :– 减少内存要求;– 划清了程序员与用户界面设计人员的任务分工– 用户界面风格的变化可以不必修改程序代码或只需进行少量的修改

Page 13: Windows 环境下的程序设计

1313

Windows应用程序设计模式

Windows应用程序的开发流程

.C .H .RC

.DEF

.DLG

.EXE链接器.LIB

.

. .BMP .CUR.ICO .FON

.RES

.OBJ

资源编译器

C 编译器

字体编辑器图象编辑器对话框编辑器

工具

文本文件

二进制文件

Page 14: Windows 环境下的程序设计

1414

Windows应用程序的基本结构

Windows应用程序具有相对固定的基本结构,入口点函数WinMain和窗口函数构成了 Windows应用程序的基本框架

Page 15: Windows 环境下的程序设计

1515

Windows应用程序的基本结构

WinMain函数– 是程序的入口点,相当于标准 C 语言中的 main函数

WinMain函数主要由四部分组成:– 注册窗口类– 创建窗口– 显示窗口– 建立消息循环

Page 16: Windows 环境下的程序设计

1616

Windows应用程序的基本结构

WinMain函数消息循环 Windows并不直接把输入消息发送给应用程序,而是将其送

入应用程序的消息队列之中。此外, Windows和其他应用程序也可以将消息指派到应用程序队列中

应用程序必须读取应用程序队列,检索消息并将它们发送出去,以便适当的窗口函数能够处理它们,负责这一任务的便是消息循环

Page 17: Windows 环境下的程序设计

1717

Windows应用程序的基本结构

WinMain函数消息循环– while(GetMessage(&Msg, NULL, 0,0))

– {

– TranslateMessage(&Msg);

– DispatchMessage(&Msg);

– }

GetMessage函数检索到 WM_QUIT消息时返回非零值,检索到其他消息均返回

Page 18: Windows 环境下的程序设计

1818

Windows应用程序的基本结构

窗口函数 窗口函数也称为窗口过程,负责从 Windows接收消息,并根

据这些消息完成特定的操作 窗口函数是一个回调函数,由 Windows系统调用,应用程序

并不会直接调用它的窗口函数 窗口函数的主体是由一系列 case语句组成的消息处理程序

段 如果窗口函数不处理某些消息,则必须把它们传给DefWindowProc函数

Page 19: Windows 环境下的程序设计

case 1

case 2

case 3

Default

Windows 系统

应用程序WinMain( )

消息循环

WndProc( )

④DispatchMessage( )

DefWindowProc( )

检索到的消息③

GetMessage( )②

指派的消息

WM_KEYDOWNWM_KEYUPWM_MOUSEMOVEWM_LBUTTONDOWNWM_QUIT…...

发送的消息

WM_CREATEWM_DESTROYWM_SIZEWM_PAINT…...

应用程序的消息队列

回调

Windows应用程序的消息处理过程

Page 20: Windows 环境下的程序设计

2020

Windows应用程序的基本结构

当用户关闭窗口时, Windows系统将把 WM_DESTROY消息发送给该窗口的窗口函数,在这种情况下,窗口函数应该使用 PostQuitMessage函数将 WM_QUIT消息发送到应用程序队列中,这样可以使 GetMessage函数检索到 WM_QUIT消息,从而结束消息循环,退出应用程序

Page 21: Windows 环境下的程序设计

case 1

case 2

...

case WM_DESTROY

Default

Windows 系统

应用程序WinMain( )

消息循环

WndProc( )

PostQuitMessage (0)

WM_QUIT消息⑤

GetMessage ( )④

WM_QUIT消息

应用程序的消息队列

WM_DESTROY消息

退出消息循环结束应用程序

WM_DESTROY

消息的处理过程

Page 22: Windows 环境下的程序设计

2222

结构化异常处理

Windows在系统底层提供了一种称为结构化异常处理 SEH的系统机制。利用 SEH可以把程序主要的工作同错误处理分离开来,这样的分离,可以使程序员集中精力关注程序要完成的任务,而将可能发生的错误放在后面处理

异常是在应用程序的正常执行过程中发生的不正常事件。 CPU引发的异常称为硬件异常,操作系统和应用程序直接引发的异常,称为软件异常

Page 23: Windows 环境下的程序设计

2323

结构化异常处理

SHE是操作系统的一种系统机制,与特定的程序设计语言无关

应用程序要利用系统提供的 SHE机制,则必须借助于特定程序设计语言的相关语法

因此, SEH不但涉及操作系统,而且与编译器有密切的关系 结构化异常处理包括异常处理和终止处理两个方面

Page 24: Windows 环境下的程序设计

2424

结构化异常处理

异常处理– __try

– {

– ... //guarded section

– }

– __except(exception filter)

– {

– ... //exception handler

– }

Page 25: Windows 环境下的程序设计

2525

结构化异常处理

异常处理 异常过滤器返回如下三个异常标识符之一

– ECXEPTION_EXECUTE_HANDLER

– ECXEPTION_CONTINUE_EXECUTION

– ECXEPTION_CONTINUE_SEARCH

Page 26: Windows 环境下的程序设计

2626

结构化异常处理

终止处理 Windows应用程序在运行时通常要分配资源,使用这些资源,然后释放它们

由于异常改变了控制的流程,因此很容易导致无法释放在产生异常的代码块中分配的资源

使用终止处理程序可以保证进行这样的清除工作

Page 27: Windows 环境下的程序设计

2727

结构化异常处理

终止处理– __try

– {

– ...

– }

– __finally

– {

– ...

– }

Page 28: Windows 环境下的程序设计

2828

结构化异常处理

终止处理 有两种情况可能使受保护段不正常地结束

– 在 try块中执行了 return、 goto、 break或 continue等控制语句

– 在 try块中发生异常

Page 29: Windows 环境下的程序设计

2929

结构化异常处理

软件异常 当一个函数执行失败时,习惯上要返回一些特殊的值来,函

数的调用者可以检查这些特殊值并采取一种替代的动作 如果这个调用者是被另一个调用者调用的函数,那么它还需

要将它自己的失败代码返回给它的调用者 这种错误代码的逐层传递会使源程序变得非常难于编写和维护

采用软件异常则可以解决这些问题

Page 30: Windows 环境下的程序设计

3030

动态链接库

动态链接库 DLL是一个可执行程序模块,模块中包含了可以被其他应用程序或其他 DLL共享的程序代码和资源

Page 31: Windows 环境下的程序设计

3131

动态链接库

采用 DLL的优点:– 当多个进程同时使用同一个 DLL时,只要在内存中装入它的一

个副本即可,从而可以节省内存;– DLL与调用它的应用程序相分离,因此可以在不修改应用程序

的情况下对 DLL进行更新;– 只要在调用 DLL中的函数时遵循相同的调用规范,那么 DLL

中的函数就可以被各种编程语言编制的应用程序调用

Page 32: Windows 环境下的程序设计

3232

动态链接库

DLL到进程地址空间的映射– 装入时刻动态链接

经过编译的.obj文件 引入库,包含DLL函数的重定位信息

链接器

可执行程序

重定位信息

动态链接库

调用DLL中的函数内存

Page 33: Windows 环境下的程序设计

3333

动态链接库

DLL到进程地址空间的映射– 运行时刻动态链接– 在运行时刻,通过调用 LoadLibrary可以使 DLL加载到一个进程的地址空间中

– 为了在运行时刻从 DLL中调用一个函数,可以通过调用GetProcAddress获取函数的地址

Page 34: Windows 环境下的程序设计

3434

动态链接库

DLL到进程地址空间的映射

虚拟地址空间

0

2GB

0

2GB

进程1 进程2

DLL数据(共享)

DLL数据(私用进程1)

DLL数据(私用进程1)

DLL代码

物理内存

Page 35: Windows 环境下的程序设计

3535

动态链接库

DLL的入口点函数 DLL没有 WinMain函数,不含有消息循环,一般也不获取自己的消息,但是它有自己特殊的入口点函数,入口点函数的缺省名为 DllMain

当进程和线程被初始化或终止时, DllMain函数被Windows系统调用

DllMain要做的主要任务是执行进程级或线程级的初始化和清理工作

如果不要求 DLL初始化, DllMain可以只是一个虚设函数

Page 36: Windows 环境下的程序设计

3636

动态链接库

DLL的创建和使用 创建 DLL文件需要用到源文件( .C)和头文件

( .H)。 DLL源文件通常包括入口点函数和供应用程序调用的 DLL库函数。头文件中含有 DLL要导出的所有函数与变量的说明

在应用程序中调用 DLL中的函数或访问 DLL中的变量时,须告诉编译器要调用的函数或要访问的变量是在 DLL中:– __declspec(dllimport)

– int Sub(int nPara1, int Para2);

Page 37: Windows 环境下的程序设计

3737

习题

Win32子系统与 Win32 API的关系是什么? 什么是事件驱动? Windows应用程序为什么采用事件驱动的

程序设计方法,而不是象传统 DOS应用程序那样采用过程驱动的程序设计方法?

与静态链接相比,动态链接有哪些优点?有哪些缺点?

Page 38: Windows 环境下的程序设计

3838

Windows驱动程序模型

WDM以 Windows NT 4.0的内部结构为基础,同时引入了 Windows 9x的即插即用特性,为存在于 Windows 98和Windows 2000/XP/2003操作系统中的设备驱动程序提供了一个统一的参考框架

WDM驱动程序还可以在不修改源代码的情况下经过重新编译后在非 Intel平台上运行,因此 WDM是一个跨平台的驱动程序模型

Page 39: Windows 环境下的程序设计

3939

设备和驱动程序的分层

WDM是一个分层化的驱动程序模型,在这个模型中,驱动程序的层或堆栈一起工作处理 I/O请求

FiDO

FDO

FiDO

PDO

上层过滤器驱动程序

功能驱动程序

下层过滤器驱动程序

总线驱动程序

IRP

Page 40: Windows 环境下的程序设计

4040

设备和驱动程序的分层

总线驱动程序 总线驱动程序负责枚举连接在该总线上的所有设备并进行必

要处理 Microsoft为大多数总线如 PCI、 PnPISA、 SCSI以及USB等提供了驱动程序

机器中每种类型的总线都有相应的总线驱动程序 总线枚举时驱动程序识别其上的设备并为其创建一个物理设

备对象

Page 41: Windows 环境下的程序设计

4141

设备和驱动程序的分层

功能驱动程序 功能驱动程序是一个设备的主要驱动程序,它知道如何控制

设备的主要功能 功能驱动程序为它的设备提供操作接口,处理对设备的读 /

写,并管理设备的电源策略 功能驱动程序创建一个功能设备对象 FDO放在设备栈中

Page 42: Windows 环境下的程序设计

4242

设备和驱动程序的分层

过滤器驱动程序 过滤器驱动程序过滤对每个设备、每一类设备或一条总线的I/O请求

过滤器驱动程序是可选择的

Page 43: Windows 环境下的程序设计

4343

IRP的处理

IRP是驱动程序操作的中心。 I/O管理器接收一个 I/O请求之后,在把它传递到合适的驱动程序堆栈中的最高层驱动程序之前,分配并初始化一个 IRP

当一个 IRP由多个驱动程序处理时,使用多个 I/O堆栈单元。每个驱动程序从当前 I/O堆栈单元得到它的 IRP参数。如果把一个 IRP沿当前设备的驱动程序堆栈向下传递,必须使用正确的常数设置下一个堆栈单元

Page 44: Windows 环境下的程序设计

4444

IRP的处理

驱动程序1

驱动程序2

驱动程序3

驱动程序4

I/O堆栈单元 1

I/O堆栈单元 2

I/O堆栈单元 3

I/O堆栈单元 4

IRP

最低

最高

Page 45: Windows 环境下的程序设计

4545

用户程序对设备的访问过程

Windows中对设备的访问分为用户态和核心态两种方式:– 用户态通过调用 Win32 API函数如ReadFile、 WriteFile等访问设备,它不能直接控制硬件

– 核心态通过发送 I/O请求包 IRP来运行驱动程序实现对设备的控制

Page 46: Windows 环境下的程序设计

4646

用户程序对设备的访问过程

应用程序

Win32子系统 用户态

核心态I/O系统服务

I/O管

理器

IRP 高层驱动程序

中层驱动程序

低层驱动程序

HAL

Page 47: Windows 环境下的程序设计

4747

WDM驱动程序的结构

分发例程I/O控制例程

StartIo

AdapterControl

OnInterrupt

DpcForIsr

DriverEntry

AddDevice

基本驱动程序例程

必须的驱动程序例程处理请求队列需要包含StarIo如果设备产生中断需要包含中断和DPC例程DMA 操作需要包含AdapterControl例程可选的IRP分发例程

DispatchPnp

DispatchPower

DispatchWmi

DispatchRead

DispatchWrite

Page 48: Windows 环境下的程序设计

4848

WDM驱动程序的结构

初始化例程,当 I/O管理器把驱动程序加载到操作系统中时,它执行驱动程序的初始化例程

添加设备例程,用于支持 PnP管理器的操作 一系列分发 ( 调度 ) 例程,调度例程是设备驱动程序提供的

主要函数 启动 I/O例程,驱动程序可以使用启动 I/O例程来初始化与

设备之间的数据传输

Page 49: Windows 环境下的程序设计

4949

WDM驱动程序的结构

中断服务例程( ISR),当一个设备中断时,内核的中断调度程序把控制转交给这个例程。 ISR运行在高级的设备中断请求级( IRQL)上,越简单越好,以避免对低优先级中断产生不希望的阻塞

中断服务 DPC例程, DPC例程执行在 ISR执行以后的大部分设备中断处理工作。 DPC例程在低于 ISR的 IRQ的时候执行,从而避免对其他中断产生不希望的阻塞。 DPC例程初始化I/O完成并启动关于设备的下一个队列的 I/O操作

Page 50: Windows 环境下的程序设计

5050

WDM驱动程序编程实例

WdmDriver是一个 WDM驱动程序,它实现了一个 4 字节的核心态内存缓冲区, Win32 应用程序可以对该缓冲区进行读写操作

由于采用 WDM模型, WdmDriver 可以运行在 Windows 98 和 Windows 2000/XP/2003两个平台上

Page 51: Windows 环境下的程序设计

5151

DriverEntry例程

驱动程序向 I/O管理器显露一个名为 DriverEntry的函数,在启动驱动程序的时候, I/O管理器将调用这个入口函数。 DriverEntry相当于作为应用程序入口的 main函数或WinMain函数

驱动程序可以被多个类似的硬件使用,但驱动程序的某些全局初始化操作只能在第一次被装入时执行一次, DriverEntry例程就是用于这个目的

DriverEntry例程的主要工作是把各种函数指针填入驱动程序对象,这些指针为操作系统指明了驱动程序容器中各种子例程的位置

Page 52: Windows 环境下的程序设计

5252

DriverEntry例程extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,

IN PUNICODE_STRING RegistryPath)

{

DriverObject->DriverUnload = DriverUnload;

DriverObject->DriverExtension->AddDevice = AddDevice;

DriverObject->DriverStartIo = StartIo;

DriverObject->MajorFunction[IRP_MJ_PNP]=DispatchPnp;

DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;

DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = DispatchWmi;

...

servkey.Buffer = (PWSTR) ExAllocatePool(PagedPool,

RegistryPath->Length + sizeof(WCHAR));

if (!servkey.Buffer)

return STATUS_INSUFFICIENT_RESOURCES;

servkey.MaximumLength = RegistryPath->Length + sizeof(WCHAR);

RtlCopyUnicodeString(&servkey, RegistryPath);

return STATUS_SUCCESS;

}

Page 53: Windows 环境下的程序设计

5353

AddDevice例程

AddDevice函数的基本职责是创建一个设备对象并把它连接到以 pdo为栈底的设备堆栈中,主要步骤如下:– 调用 IoCreateDevice创建设备对象,并建立一个私有的设

备扩展对象 – 注册一个或多个设备接口,以便应用程序能知道设备的存在。另外,还可以给出设备名并创建符号连接

– 调用 IoAttachDeviceToDeviceStack函数,把新设备对象放到堆栈上

– 初始化设备对象的 Flag成员

Page 54: Windows 环境下的程序设计

5454

AddDevice例程

1 .创建设备对象与设备扩展对象 :PDEVICE_OBJECT fdo;

NTSTATUS status = IoCreateDevice(DriverObject,

sizeof(DEVICE_EXTENSION),

NULL,

FILE_DEVICE_UNKNOWN,

FILE_DEVICE_SECURE_OPEN,

FALSE,

&fdo);

if (!NT_SUCCESS(status))

return status;

PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

pdx->DeviceObject = fdo;

pdx->Pdo = pdo;

Page 55: Windows 环境下的程序设计

5555

AddDevice例程

2 .注册设备接口...

status = IoRegisterDeviceInterface(pdo,

&GUID_SIMPLE,

NULL,

&pdx->ifname);

...

if(!NT_SUCCESS(status))

{

IoDeleteDevice(fdo);

return status;

}

Page 56: Windows 环境下的程序设计

5656

AddDevice例程

3 .建立设备堆栈

...

pdx->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);

...

if(!pdx->LowerDeviceObject)

{

IoDeleteDevice(fdo);

return STATUS_DEVICE_REMOVED;

}

Page 57: Windows 环境下的程序设计

5757

AddDevice例程

4 .设置设备标志

fdo ->Flags |= DO_BUFFERED_IO; fdo ->Flags &= ~DO_DEVICE_INITIALIZING;

return STATUS_SUCCESS;

Page 58: Windows 环境下的程序设计

5858

其他必须的例程

DispatchPnp例程 DispatchPower例程 DispatchWmi例程

Page 59: Windows 环境下的程序设计

5959

DispatchPnp例程NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp)

{

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

ULONG fcn = stack->MinorFunction;

NTSTATUS status = StaTUS_SUCCESS;

Switch(fcn)

{

case IRP_MN_START_DEVICE:

status = PnpStartDeviceHandler(fdo, irp);

break;

case IRP_MN_REMOVE_DEVICE:

status = PnpRemoveDeviceHandler(fdo, irp);

break;

...

default:

PnpDefaultHandler(fdo, irp);

};

return status;

}

Page 60: Windows 环境下的程序设计

6060

DispatchPower例程

NTSTATUS DispatchPower (IN PDEVICE_OBJECT fdo,

IN PIRP Irp)

{

PWDM_DEVICE_EXTENSION dx =

(PWDM_DEVICE_EXTENSION)fdo->DeviceExtension;

PoStartNextPowerIrp( Irp);

IoSkipCurrentIrpStackLocation(Irp);

return PoCallDriver( dx->NextDevice, Irp);

}

Page 61: Windows 环境下的程序设计

6161

DispatchWmi例程

驱动程序对 WMI的支持主要是基于对主代码为IRP_MJ_SYSTEM_CONTROL的 IRP的支持。为了能接收到这种IRP,必须先注册这种需求:– IoWMIRegistrationControl(fdo, WMI_ACTION_REGISTER);

调用 IoWMIRegistrationControl函数的恰当位置是在AddDevice例程中,注册完成后,一旦系统认为可以安全地向驱动程序发送系统控制 IRP时,它就向驱动程序发出一个IRP_MJ_SYSTEM_CONTROL请求,以获得设备的详细寄存信息

对于 WDM驱动程序而言,系统控制 IRP的分发例程DispatchWmi是必须提供的,一般的做法是委托 WMILIB来处理系统控制 IRP, WMILIB实际上是一个内核模式 DLL,它导出的服务可以被其他驱动程序调用

Page 62: Windows 环境下的程序设计

6262

其他可选的例程

Windows应用程序与设备驱动程序打交道主要是通过CreateFile、 ReadFile、 WriteFile 和DeviceIoControl等 Win32 API来进行的,这些 API对应着驱动程序的一些分发例程

Page 63: Windows 环境下的程序设计

6363

DispatchWrite例程NTSTATUS DispatchWrite( IN PDEVICE_OBJECT fdo,

IN PIRP Irp)

{

PWDM_DEVICE_EXTENSION dx =

(PWDM_DEVICE_EXTENSION)fdo->DeviceExtension;

PIO_STACK_LOCATION pIrpStack =

IoGetCurrentIrpStackLocation(Irp);

NTSTATUS status = STATUS_SUCCESS;

ULONG BytesTxd = 0;

ULONG WriteLen = pIrpStack->Parameters.Write.Length;

if( WriteLen>SHARED_MEMORY_SIZE)

status = STATUS_INVALID_PARAMETER;

else if( WriteLen>0)

{

RtlMoveMemory( SharedMemory,

Irp->AssociatedIrp.SystemBuffer, WriteLen);

BytesTxd = WriteLen;

}

Irp->IoStatus.Status = status;

Irp->IoStatus.Information = BytesTxd;

IoCompleteRequest(Irp,IO_NO_INCREMENT);

return status;

}

Page 64: Windows 环境下的程序设计

6464

WDM驱动程序编程实例

驱动程序中除了 DriverEntry例程必须以 DriverEntry命名以外,其他例程都可以使用程序员自定义的名字,并且都要由 DriverEntry例程向系统注册

Page 65: Windows 环境下的程序设计

6565

开发 WDM驱动程序的一般方法

对照相关设备的资料仔细分析驱动程序应实现哪些功能 根据 WDM设备驱动程序的组成,采用渐进的方法对驱动程序进行模块化设计

Page 66: Windows 环境下的程序设计

6666

开发 WDM驱动程序的一般方法

一个 WDM设备驱动程序通常完成以下工作:– 初始化– 创建、删除设备– 即插即用处理– 访问硬件– 处理电源管理– 使用 WMI

– 处理 Win32I/O及控制请求 将这些功能划分为不同模块

Page 67: Windows 环境下的程序设计

设备驱动程序的创建与调试过程

观察与体验观察与体验

Page 68: Windows 环境下的程序设计

6868

构造 WDM驱动程序开发环境

1 )安装 Microsoft Visual Studio .NET

2 )安装 Microsoft Windows DDK

3 )安装 Debugging Tools for Windows

Page 69: Windows 环境下的程序设计

6969

构造 WDM驱动程序开发环境

安装成功 Visual Studio .NET后,运行界面如下图所示

Page 70: Windows 环境下的程序设计

7070

构造 WDM驱动程序开发环境

安装成功 Windows DDK后,菜单栏如下图所示

Page 71: Windows 环境下的程序设计

7171

构造 WDM驱动程序开发环境

安装成功 Debugging Tools后,菜单栏如下图所示

Page 72: Windows 环境下的程序设计

7272

编辑、编译和链接

1 )编写驱动程序源文件,包括:– WdmDriver.h

– guid.h

– init.cpp

– Pnp.cpp

– Wmi.cpp

– Dispatch.cpp

– Wdm.mof

Page 73: Windows 环境下的程序设计

7373

编辑、编译和链接

2 )编译链接驱动程序,生成驱动程序可执行文件 成功编译一个驱动程序需要在要被编译的源文件目录下面提

供三个文本文件(三个文件都没有扩展名):– MAKEFILE

– SOURCES

– DIRS

驱动程序生成工具 BUILD从这三个文件读取输入,并且创建BUILD.LOG、 BUILD.ERR等文件作为输出,如果一切正常,执行 BUILD的最后结果是创建驱动程序的可执行版本,其文件类型是 .SYS

Page 74: Windows 环境下的程序设计

7474

编辑、编译和链接

2 )编译链接驱动程序,生成驱动程序可执行文件 驱动程序的编译 单击开始所有程序 Development Kits Windows DDK Build Enviroments Win XP Checked Build Enviroment,将出现一个控制台窗口

使用 cd命令进入待编译驱动程序所在的目录,键入 build命令即可编译

运行 build命令只编译需要重新编译的文件 , 而 build -c 命令则强迫编译器重新编译所有的文件

Page 75: Windows 环境下的程序设计

7575

编辑、编译和链接

Page 76: Windows 环境下的程序设计

7676

安装驱动程序

设备驱动程序的自动安装由一个以 inf为扩展名的文本文件控制。正确的保存在 Windows 系统上的一个 inf文件,允许自动安装驱动程序文件,或者在对话框支持下安装驱动程序文件

Page 77: Windows 环境下的程序设计

7777

安装驱动程序

驱动程序的安装过程: 首先进入控制面板,选择“添加新硬件”, “下一步”后系

统会扫描硬件,选择“是,硬件已经连接好”,然后在对话框的底部选择“添加新的硬件设备”,接着选择“安装我手动从列表选择的硬件”,确定后再选“从磁盘安装”,“浏览”找到 WdmDriver.inf文件所在的文件夹,单击“确定”。从接下来的对话框中指定 WdmDriver.sys所在的位置,系统将把驱动程序 WdmDriver.sys复制到 Windows系统的 system32\drivers文件夹中

Page 78: Windows 环境下的程序设计

7878

安装驱动程序

安装之后, WdmDriver应该出现在设备管理器的“其它设备”类别中,选中该设备,单击“属性”,可以查看驱动程序的信息 :

Page 79: Windows 环境下的程序设计

7979

驱动程序测试

测试程序 TestWdm.cpp执行以下操作:– 打开 wdmdriver设备– 读存储在共享内存缓冲区中的第一个 DWORD。– 把 0xabcdef01写到缓冲区– 从缓冲区中读取 4 个字节– 往缓冲区写 5 个字节,因为设置的缓冲区大小只有 4 个字节,

所以会失败,并报错– 关闭设备

Page 80: Windows 环境下的程序设计

8080

驱动程序测试

如果驱动程序工作正常,屏幕显示为:

Page 81: Windows 环境下的程序设计

8181

驱动程序测试

如果驱动程序工作不正常,则需要进行调试 支持驱动程序调试的工具为 Microsoft的 Debugging Tools for Windows

WinDbg 是一个功能齐全的调试器,支持 C 语言源代码级调试,可以使用驱动程序的源代码设置各种断点

WinDbg的使用需要双机环境,目标机运行驱动程序和测试应用程序,宿主机运行调试器,使用起来不是特别方便

Page 82: Windows 环境下的程序设计

8282

驱动程序测试

WinDbg

主机和目标计算机通过无 Modem串行电缆通过串行口通讯

Page 83: Windows 环境下的程序设计

8383

驱动程序调试

WinDbg目标机配置: 目标机器的 boot.ini增加一行启动选项: /debug /debugport=com1 /baudrate=115200

Page 84: Windows 环境下的程序设计

8484

驱动程序调试

WinDbg宿主机配置: 启动 WinDBD

在 File菜单中选择 Symbol File Path设置符号文件搜索路径

在 File菜单中选择 Source File Path设置源文件搜索路径

在 File菜单中选择 Image File Path设置可执行文件搜索路径

Page 85: Windows 环境下的程序设计

8585

驱动程序调试

WinDbg宿主机配置: 启动 WinDBD,在 File菜单中选择 Kernel Debug,在出

现的对话框中设置串行端口和波特率

Page 86: Windows 环境下的程序设计

8686

驱动程序调试

设置好串行端口和波特率后单击确定,出现如下画面,宿主机等待与目标机的连接:

Page 87: Windows 环境下的程序设计

8787

驱动程序调试

在目标机中选择“启用调试程序”选项引导机器,则在宿主机上显示与目标机的连接信息:

Page 88: Windows 环境下的程序设计

8888

驱动程序调试

如果目标机器正在运行,在 WinDbg命令窗口输入 Ctrl+Breakc,则暂停目标机器的运行

从 File菜单选择 open source file打开驱动程序源文件 把光标移到有分号的源代码行上 单击断点按钮,可以在驱动程序源文件中设置断点,设置断点源代码变

为红色 单击 F5键,可恢复目标机器运行 :

Page 89: Windows 环境下的程序设计

8989

驱动程序调试

Page 90: Windows 环境下的程序设计

9090

驱动程序调试

在目标机上运行测试程序,则系统将在驱动程序的断点处中断

Page 91: Windows 环境下的程序设计

9191

驱动程序调试

断点

Page 92: Windows 环境下的程序设计

Thoughts Change Life意念改变生活