• 多态


    多态

    本文选自《竹林蹊径:深入浅出Windows驱动开发》一书

    如果纯粹是为了尝鲜,在驱动中加入一个类,内部却只是一团硬板,那就完全多此一举了。所以本节笔者将带领大家在内核中实现类的多态。以CY001 USB设备驱动为例进行讲解,代码请参考本书工程UsbBaseClass和CY001UsbClass,前者以基类实现设备驱动,后者以子类实现设备驱动。

    6.3.1 基类、子类

    笔者对基类的要求是能够实现USB设备的最基本要素,使得设备能够在系统中显现,能够正常运行和移除。所以设备栈一定要成功建立,基本的Pnp/Power接口也必须要提供,但用户层接口可以暂不考虑。最终的结果是PnpAdd函数实现得非常完整,因为必须要将设备栈建立起来;EvtDevicePrepareHardware和EvtDeviceReleaseHardware函数也得以完整实现,这样设备能够正确运行和移除,但细节方面的设置如休眠等则以接口留出。

    子类必须实现更完善的功能,如休眠、唤醒设置。下面的例子分别对应着基类和子类的实现。

    // 配置设备驱动的电源管理功能

    NTSTATUS DrvClass::InitPowerManagement()

    {

    return STATUS_SUCCESS;

    }

    这是基类的实现,空空如也,子类则要复杂许多倍。

    // 配置设备驱动的电源管理功能

    NTSTATUS CY001Drv::InitPowerManagement()

    {

    NTSTATUS status = STATUS_SUCCESS;

    WDF_USB_DEVICE_INFORMATION usbInfo;

    KDBG(DPFLTR_INFO_LEVEL, "[InitPowerManagement]");

    // 获取设备信息

    WDF_USB_DEVICE_INFORMATION_INIT(&usbInfo);

    WdfUsbTargetDeviceRetrieveInformation(m_hUsbDevice, &usbInfo);

    // 设置设备的休眠和远程唤醒功能

    // …… 详见代码

    return status;

    }

    6.3.2 实现多态

    怎么能够实现多态呢?当前,动态对象是在入口函数中创建的,而按照现有逻辑,入口函数是不允许修改的。笔者要提供一个机会,让库使用者可以创建动态对象。为此笔者特地有一个规定,所有库使用者必须定义一个宏,以注册自己的驱动类。

    REGISTER_DRV_CLASS(DriverName)

    如果不使用子类,则需要定义下面的宏而直接使用基类。

    REGISTER_DRV_CLASS_NULL()

    那么这两个宏到底有什么作用呢?要看宏定义了:

    // 注册子类

    #define REGISTER_DRV_CLASS(DriverName) \

    DrvClass* GetDrvClass(){\

    return (DrvClass*)new(NonPagedPool, '10YC') DriverName();\

    }

    // 注册基类

    #define REGISTER_DRV_CLASS_NULL()\

    DrvClass* GetDrvClass(){\

    return new(NonPagedPool, 'ESAB') UsbBaseClass();\

    }

    两个宏都是为了定义一个名称为GetDrvClass的函数。前者注册驱动类的子类,并在GetDrvClass的实现中动态创建子类对象,在返回时将子类对象的指针转换为基类对象指针;后者则声明直接使用基类,并在GetDrvClass的实现中动态创建一个基类对象,并返回其指针。

    调用者不必关心被创建的对象到底是来自基类还是子类,他只要使用在基类中定义的接口就可以了,而借助虚拟函数的运行时绑定策略,即可实现多态。

    需要注意的是宏REGISTER_DRV_CLASS(DrvClass),其作用和REGISTER_DRV_ CLASS_NULL()是一样的,都将定义一个GetDrvClass函数。

    好戏还要看DriverEntry()函数中的实现,重新修改后的函数代码如下:

    NTSTATUS Driver(DRIVER_OBJECT Driver,

    UNICODE_STRING Register)

    {

    DrvClass* pDriver = GetDrvClass();

    return pDriver->DriverEntry(Driver, Register);

    }

    真是无与伦比的简洁,它通过GetDrvClass函数实现了多态,并立刻将驱动的实现交付到了pDriver对象的手中,而pDriver可以是基类,也可以是任意一个从基类继承的子类。

    实现多态的核心是两个类注册宏,以及在入口函数中对GetDrvClass函数的调用。需要注意的是,如果用户同时定义了两个宏,那么系统就会因为发现两个完全一样的GetDrvClass函数而使编译失败;反之,如果上述两个宏一个都没有定义,那么在链接时,将因为无法找到函数定义而链接失败。

    驱动工程UsbBaseClass使用驱动基类直接驱动CY001 USB设备,从SOURCE文件中可以看到,它含有的编译文件为DrvClass.cpp和GetDrvClass.cpp两个文件,前者是基类的定义文件,后者只有一行代码,即REGISTER_DRV_CLASS_NULL()。这是最简单的驱动工程。

    驱动工程CY001USBClass使用驱动子类CY001DrvClass驱动CY001 USB设备,从SOURCE文件中可以看到,它依旧包含了DrvClass.cpp文件,此外还包含了若干个子类的实现文件。

    所以,读者只要在DrvClass甚至CY001DrvClass类的基础上实现子类化,并注册新的子类,就能够实现功能扩展。

    如图6-6所示是本节所讲的多态实现原理图。

    clip_image002

    图6-6 多态关系图

    6.3.3 测试

    编译UsbBaseClass工程的代码,用得到的CY001.sys文件替代system32\drivers目录下的同名文件,以驱动CY001 USB设备。尝试使用本书中的UsbKitApp程序,会发现能够正确枚举到USB设备,但软件的具体功能如获取描述符等,无法正常使用。

    以同样的方法测试编译CY001UsbClass工程后得到的CY001.sys文件,并运行UsbKitApp程序以测试,会发现和WDFCY001工程的测试结果完全一样。

    本文选自《竹林蹊径:深入浅出Windows驱动开发》一书

  • 相关阅读:
    全代码实现WordPress分类目录和标签添加新的自定义字段
    基于max-height实现不定高度元素的折叠/合并,展开/收缩的动画效果
    css实现不定宽高的图片img居中裁剪_类似微信朋友圈图片效果
    你知道我们平时在CSS中写的%都是相对于谁吗?
    纯css如何绘制三角形_利用border实现画三角形的原理方法
    wordpress建站不得不知的安全防护(二)
    wordpress建站不得不知的安全防护(一)
    Java连载55-接口的作用、接口举例
    Java连载54-两种单例模式、接口详解
    Python连载54-FTP编程
  • 原文地址:https://www.cnblogs.com/broadview/p/1957507.html
Copyright © 2020-2023  润新知