45、Windows驱动程序模型笔记(三)

4DriverUnload例程

    WDM驱动程序中,DriverUnload例程的作用就是释放DriverEntry例程在全局初始化过程中申请的任何资源,但它几乎没什么可做。如果你在DriverEntry中备份了RegistryPath串,应该在这里释放备份所占用的内存。

VOID DriverUnload(PDRIVER_OBJECT DriverObject)

{

RtlFreeUnicodeString(&servkey);

}

    如果DriverEntry例程返回一个失败状态代码,系统将不再调用DriverUnload例程。所以,不能让DriverEntry例程出错后产生任何副作用,必须在它返回错误代码前消除副作用。

5、驱动程序再初始化例程

    I/O管理器提供了一个服务函数:IoRegisterDriverReinitialization。它可以为非WDM驱动程序解决一个奇特的问题。这里我想解释一下这个问题,从中你可以知道为什么WDM驱动程序不用担心问题。非WDM驱动程序需要在DriverEntry例程中枚举它的硬件,并在其硬件的所有可能实例被识别前装入内存并初始化。例如,鼠标和键盘设备就是这样。假定DriverEntry枚举了所有鼠标或键盘硬件并为它们创建了设备对象,但如果DriverEntry例程运行的太快,那么这些驱动程序将不能正常工作。因此,它们必须使用 IoRegisterDriverReinitialization函数寄存一个例程,之后I/O管理器在某个驱动程序检测到新硬件存在时再回调这个寄存例程。最后再初始化例程运行,同时也把自身寄存为下一次回调的函数。

    WDM驱动程序不需要寄存再初始化例程,因为它们不需要用自己的代码去检测硬件。PnP管理器自动把新硬件匹配到正确的WDM驱动程序上,并调用该驱动程序的AddDevice例程,再由AddDevice例程做所有必要的初始化工作。

6AddDevice例程

    一个驱动程序可以被多个设备利用。WDM驱动程序有一个特殊的AddDevice函数,PnP管理器为每个设备实例调用该函数

NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo)

{

}

    DriverObject指向一个驱动程序对象(在DriverEntry例程中初始化的那个驱动程序对象)。pdo参数指向设备堆栈底部的物理设备对象。

对于功能驱动程序,其AddDevice函数的基本职责是创建一个设备对象并把它连接到以pdo为底的设备堆栈中。相关步骤如下:

1.调用IoCreateDevice创建设备对象,并建立一个私有的设备扩展对象。

2.寄存一个或多个设备接口,以便应用程序能知道设备的存在。另外,还可以给出设备名并创建符号连接。

3.初始化设备扩展和设备对象的Flag成员。

4.调用IoAttachDeviceToDeviceStack函数把新设备对象放到堆栈上。

IoCreateDevice的第6个参数:

    排斥属性仅关系到打开请求的目标是命名设备对象。如果你遵守Microsoft推荐的WDM驱动程序设计方针,没有为设备对象命名,那么打开请求将直接指向PDOPDO通常不能被标记为排斥,因为总线驱动程序没有办法知道设备是否需要排斥特征。把PDO标为排斥的唯一的机会在注册表中,即设备硬件键或类键的Properties子键含有Exclusive超越值。为了完全避免依赖排斥属性,你应该利用IRP_MJ_CREAT例程弹出任何有违规行为的打开请求。

7、为设备命名

    David Solomon在《Inside Windows NT, Second Edition (Microsoft Press, 1998)》的第三章“System Mechanisms”中给出了关于Windows NT对象管理器和命名空间的一个比较完整的阐述。

    通常设备对象都把自己的名字放到\Device目录中。设备的名称有两个用途;第一个用途,设备命名后,其它内核模式部件可以通过调用IoGetDeviceObjectPointer函数找到该设备,找到设备对象后,就可以向该设备的驱动程序发送IRP。另一个用途,允许应用程序打开命名设备的句柄,这样它们就可以向驱动程序发送IRP。应用程序可以使用标准的CreateFile API打开命名设备句柄,然后用ReadFileWriteFile,和DeviceIoControl向驱动程序发出请求。应用程序打开设备句柄时使用\\.\路径前缀而不是标准的UNC(统一命名约定)名称,如C:\MYFILE.CPP\\FRED\C-Drive\HISFILE.CPP。在内部,I/O管理器在执行名称搜索前自动把\\.\转换成\??\。为了把\??目录中的名字与名字在其它目录(例如,在\Device目录)中的对象相连接,对象管理器实现了一种称为符号连接(symbolic link)的对象。

    符号连接有点象桌面上的快捷方式,符号连接在Windows NT中的主要用途是把处于列表前面的DOS形式的名称连接到设备上。用CreateFile打开名称为“C:\MYFILE.CPP”的对象,对象管理器将以下面过程打开该文件:

1.内核模式代码最开始看到的名称是\??\C:\MYFILE.CPP。对象管理器在根目录中查找“??”

2.找到\??目录后,对象管理器在其中查找“C:”。它发现找到的对象是一个符号连接,所以它就用这个符号连接组成一个新的内核模式路径名:\Device\HarddiskVolume1\MYFILE.CPP,然后析取它。

3.使用新路径名后,对象管理器重新在根目录中查找“Device”

4.找到\Device目录后,对象管理器在其中查找“HarddiskVolume1”,最后它找到一个以该名字命名的设备。

如果命名了设备对象,那么任何内核模式程序都可以打开该设备的句柄。另外,任何内核模式或用户模式程序都能创建连接到该设备的符号连接,并可以使用这个符号连接打开设备的句柄。

因此,由于超越的影响,你不应该命名你的设备对象。应用程序仍可以使用注册的接口(interface)访问你的设备。

在调用IoCreateDevice时指定设备特征参数为FILE_DEVICE_SECURE_OPEN。该标志将使Windows 在额外名称部件存在的情况下仍检查调用者是否有权限打开设备句柄。

如果决定命名设备对象,通常应该把对象名放在名称空间的\Device分支中。

UNICODE_STRING devname;

RtlInitUnicodeString(&devname, L"\\Device\\Simple0");

IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &devname, ...);

\??目录以前叫做\DosDevices\DosDevice仍可以使用,但它本身是\??目录的符号连接。由于设备对象不能复制到控制台事务的外边,而符号连接可以,因此你应该在\Device目录中保存设备命名,而在\DosDevices目录中放一个符号连接。

8GUID

GUID用于标识软件接口,它与COM(部件对象模型)中用于标识COM接口的标识符相同,它还用于OSF(开放软件基金)DCE(分布式计算环境) 中,标识RPC(远程过程调用)目标。参考Kraig Brockschmidt的《Inside OLE, Second Edition (Microsoft Pres 1995)》第66页,介绍了更多相关的知识,原始算法规范由OSF制定,相关部分见http://www.opengroup.org/onlinepubs/9629399/apdxa.htm

GUIDGEN生成GUID,用有意义的名字换掉<<name>>,如GUID_SIMPLE,并把这个定义包含到驱动程序或应用程序中。

调用IoRegisterDeviceInterface函数,注册设备接口。注册过程实际就是先创建一个符号连接名,然后再把它存入注册表。之后,当响应PnP请求IRP_MN_START_DEVICE时,驱动程序将调用IoSetDeviceInterfaceState函数使能该接口。为接口名最终指向PDO,所以PDO的安全描述符将最终控制设备的访问权限。

9、其它全局性的设备初始化操作

初始化设备扩展

当调用IoDeleteDevice删除这个设备对象时,需要使用一个自旋锁来解决同步安全问题。初始化默认的DPC对象

许多设备使用中断来报告操作完成。中断处理对中断服务例程(ISR)能做什么做了严格的限定。特别是ISR不能调用用于报告IRP完成的例程 (IoCompleteRequest)。利用DPC(推迟过程调用)可以绕过这个限制。你的设备对象中应包含一个辅助DPC对象,它可以调度你的DPC 例程,该对象应该在设备对象创建后不久被初始化。

设置缓冲区对齐掩码[1]

初始化设备标志

建立设备堆

每个过滤器驱动程序和功能驱动程序都有责任把设备对象放到设备堆栈上,从PDO开始一直向上。可以调用IoAttachDeviceToDeviceStack完成:

NTSTATUS AddDevice(..., PDEVICE_OBJECT pdo)

{

PDEVICE_OBJECT fdo;

IoCreateDevice(..., &fdo);

pdx->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);
}
清除DO_DEVICE_INITIALIZING标志(在WDM驱动中)。

[1] Windows驱动程序模型设计

[2] http://www.oneysoft.com/

[3] 驱动程序开发书籍

•Art Baker,《The Windows NT Device Driver Book: A Guide for Programmers》,(Prentice Hall, 1997)

•Chris Cant,《Writing Windows WDM Device Drivers》,(R&D Press, 1999)

•Edward N. DekkerJoseph M. Newcomer,《Developing Windows NT Device Drivers: A Programmer's Handbook》,(Addison-Wesley, 1999)

•Rajeev Nagar,《Windows NT File System Internals: A Developer's Guide》,(O'Reilly & Associates, 1997)

•Peter G. ViscarolaW. Anthony Mason,《Windows NT Device Driver Development》,(Macmillan, 1998)

其它参考书籍

•David A. Solomon,《Inside Windows NT, Second Edition》,(Microsoft Press, 1998)

posted @ 2010-12-29 23:29  浪里飞  阅读(2094)  评论(0编辑  收藏  举报