http://www.paper.edu.cn
IRP_MJ_CREATE 的 IRP,请求使用设备。当关闭设备时,我们就调用 CloseFile 函数,内
核则发送主功能名域(MajorFunction)为 IRP_MJ_CLOSE 的 IRP,减去对驱动的一个引用
(因为可能同时有几个应用程序在调用一个驱动)。
我们为了完成操作,在应用程序里调用 DeviceIoControl 函数。这个函数由操作系统提
供,它通过向相应的设备驱动发送一个控制代码,使这个设备驱动执行相应的操作。
BOOL DeviceIoControl(
HANDLE hDevice, //设备句柄,指向我们的设备
DWORD dwIoControlCode, //代表操作的控制代码,可由用户自己定义
LPVOID lpInBuffer, //指向输入缓冲,内含操作需要的数据
DWORD nInBufferSize, //输入缓冲区大小
LPVOID lpOutBuffer, //指定输出缓冲,操作完成后可以从这里返回数据
DWORD nOutBufferSize, //输出缓冲区大小
LPDWORD lpByteReturned, //指出输出缓冲区内返回的数据的长度
LPOVERLAPPED lpOverlapped //指向一个数据结构,一般我们设置为 NULL
);
我们向操作系统发送 DeviceIoControl 函数后,驱动程序就会收到主功能码为
IRP_MJ_DEVICE_CONTROL 的 IRP,而此 IRP 的副功能码(MinorFunction)则为函数中发
出的控制代码。所以,我们的驱动根据收到的这个控制代码,并接收 IRP 中相应域中获得输
入缓冲区的数据指针,进行相应的处理来满足应用程序的要求。
四,WDM 驱动程序初始化
驱动程序使用 DriverEntry 作为入口点,与我们在 Windows 应用程序中定义的 WinMain
相似。通常情况下,它是驱动的默认入口点。驱动程序实际上也是基于消息和中断驱动的,
这个消息就指的是 IRP。DriverEntry 的第一个参数是 DRIVER_OBJECT,这个数据结构内
一些域(如 MajorFunction)包含了消息函数的入口。我们在自己的驱动内对不同请求类型
的 IRP 编写相应的派遣函数,并在 DRIVER_OBJECT 结构中初始化。DriverEntry 的第二个
参数是注册表中本设备服务键的键名字符串,驱动可以把一些需要保存的信息保存在该键
中。 DriverEntry 入口函数如下:
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
// 下面设置设备的属性,标明各个消息函数的入口
DriverObject->MajorFunction[IRP_MJ_CREATE] = MsgCreateDevice;
//此函数在应用程序首先连接设备对象时由内核调用,用来判断驱动是否允许被访问
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MsgCloseDevice; //关闭设备消息
//此函数在应用程序要关闭设备对象连接时被调用。
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MsgIOCTL;
- 3 -