Download - Windows 环境下的程序设计

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意念改变生活


Top Related