6.2.4 WDM驱动实现
如果使用WDM方式进行类封装,对于非PNP类驱动,可以在入口函数中创建控制设备对象,并把类对象保存在设备对象的设备扩展中;对于PNP类驱动,应当在AddDevice函数中建立设备栈时创建类对象,并将其保存在功能设备对象的设备扩展中。笔者会以前者为例,简单讲一下实现。WDMClass示例工程,读者参照代码,在它的基础上很容易扩展出功能更为完善的驱动程序。
这里列出具体的封装过程。首先是类定义,定义一个通用的分发函数如下:
- class WDMDrvClass{
- public:
- static NTSTATUS DispatchFunc_sta(
- DEVICE_OBJECT Device,
- PIRP Irp);
-
- virtual NTSTATUS DispatchFunc(
- DEVICE_OBJECT Device,
- PIRP Irp);
-
- // 其他……
- };
同理,定义一个静态函数和一个类成员函数,静态函数将通过对象指针调用成员函数。入口函数中要这样定义:
- typedef struct{
- WDMDrvClass pThis;
- //……
- }DEVICE_EXTENSION;
-
- NTSTATUS DriverEntry( PDRIVER_OBJECT Driver,
- PUNICODE_STRING Register)
- {
- // 创建动态对象
- WDMDrvClass* pDrv = new(NonPagedPool, 'SAMP') WDMDrvClass();
-
- // 设置分发函数,全部指向DispatchFunc_sta
- for(int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
- Driver->DispatchFunction[i] = pDrv->DispatchFunc_sta;
- }
-
- // 创建控制设备对象,并同时创建设备扩展区
- IoCreateDeviceObject(..., sizeof(DEVICE_EXTENSION));
-
- // 把对象指针保存到设备扩展中
- DEVICE_EXTENSION* pContext = (DEVICE_EXTENSION*)
DeviceObject->DeviceExtension; - pContext->pThis = pDrv;
- return STATUS_SUCCESS;
- }
这一切就绪之后,我们还是来看看DispatchFunc_sta该如何实现吧。诚如我们所知,所有的驱动分发函数的第一个参数总是设备对象,正是我们所创建的那个。通过它,我们总是能够在静态函数中得到对象指针。下面是DispatchFunc_sta函数的实现。
- NTSTATUS WDMDrvClass::DispatchFunc_sta(
- DEVICE_OBJECT Device, PIRP Irp)
- {
- PDEVICE_EXTENSION pContext = Device->DeviceExtension;
- WDMDrv pThis = pContext->pThis;
- return pThis-> DispatchFunc(Device, Irp);
- }
与上述KMDF的实现类似,其他更详细的实现内容,请参阅工程代码。