[zz]DriverEntry

[zz]DriverEntry

DriverEntry的第一个参数是一个指针,指向一个刚被初始化的驱动程序对象,该对象就代表你的驱动程序。WDM驱动程序的DriverEntry例程应完成对这个对象的初始化并返回。非WDM驱动程序需要做大量额外的工作,它们必须探测自己的硬件,为硬件创建设备对象(用于代表硬件),配置并初始化硬件使其正常工作。而对于WDM驱动程序,颇麻烦的硬件探测和配置工作由PnP管理器自动完成,我将在第六章讨论PnP。如果你想知道非WDM驱动程序是如何初始化自身的,参见Art Baker的《The Windows NT Device Driver Book (Prentice Hall, 1997)》、Viscarola和Mason的《Windows NT Device Driver Development (Macmillan, 1998)》。

DriverEntry的第二个参数是设备服务键的键名。这个串不是长期存在的(函数返回后可能消失),如果以后想使用该串就必须先把它复制到安全的地方。

对于WDM驱动程序的DriverEntry例程,其主要工作是把各种函数指针填入驱动程序对象。这些指针为操作系统指明了驱动程序容器中各种子例程的位置。它们包括下面这些指针成员(驱动程序对象中):

  • DriverUnload 指向驱动程序的清除例程。I/O管理器会在卸载驱动程序前调用该例程。通常,WDM驱动程序的DriverEntry例程一般不分配任何资源,所以DriverUnload例程也没有什么清除工作要做。
  • DriverExtension->AddDevice 指向驱动程序的AddDevice函数。PnP管理器将为每个硬件实例调用一次AddDevice例程。由于AddDevice例程对WDM驱动程序特别重要,所以我将在本章下一节单独讲述它。
  • DriverStartIo 如果驱动程序使用标准的IRP排队方式,应该设置该成员,使其指向驱动程序的StartIo例程。如果你不理解什么是“标准”排队方式,不要着急,到第五章你就会完全明白,许多驱动程序都使用这种方法。
  • MajorFunction 是一个指针数组,I/O管理器把每个数组元素都初始化成指向一个哑派遣函数,这个哑派遣函数仅返回失败。驱动程序可能仅需要处理几种类型的IRP,所以至少应该设置与那几种IRP类型相对应的指针元素,使它们指向相应的派遣函数。我将在第五章详细讨论IRP和派遣函数。现在,你仅需要知道至少有三种IRP必须处理。

下面是一个近乎完整的DriverEntry例程:

extern "C"
            NTSTATUS
            DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
            {
            DriverObject->DriverUnload = DriverUnload;							<--1
            DriverObject->DriverExtension->AddDevice = AddDevice;
            DriverObject->DriverStartIo = StartIo;
            DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;					<--2
            DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
            DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = DispatchWmi;
            ...												<--3
            servkey.Buffer = (PWSTR) ExAllocatePool(PagedPool, RegistryPath->Length + sizeof(WCHAR));	<--4
            if (!servkey.Buffer)
            return STATUS_INSUFFICIENT_RESOURCES;
            servkey.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
            RtlCopyUnicodeString(&servkey, RegistryPath);
            return STATUS_SUCCESS;									<--5
            }
  1. 前三条语句为驱动程序的其它入口点设置了函数指针。在这里,我用了能表达其功能的名字命名了这些函数:DriverUnload、AddDevice、StartIo。
  2. 每个WDM驱动程序必须能处理PNP、POWER、SYSTEM_CONTROL这三种请求;应该在这里为这些请求指定派遣函数。在早期的Windows 2000 DDK中,IRP_MJ_SYSTEM_CONTROL曾被称作IRP_MJ_WMI,所以我把系统控制派遣函数命名为DispatchWmi
  3. 在省略号处,你可以插入设置其它MajorFunction指针的代码。
  4. 如果驱动程序需要访问设备的服务键,可以在这里备份RegistryPath串。例如,如果驱动程序要作为WMI生产者(见第十章),则需要备份这个串。这里我假设已经在某处声明了一个类型为UNICODE_STRING的全局变量servkey
  5. 返回STATUS_SUCCESS指出函数成功。如果函数失败,应该返回NTSTATUS.H中的一个错误代码,或者返回用户定义的错误代码。STATUS_SUCCESS的值为0。

DriverUnload例程

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

VOID DriverUnload(PDRIVER_OBJECT DriverObject)
            {
            RtlFreeUnicodeString(&servkey);
            }

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

你可能感兴趣的:([zz]DriverEntry)