题外话:
今天继续坚持写笔记,原来例程是某个系统对外提供的功能接口或服务的集合,呵呵。
NT驱动开发学习笔记二2011.05.05
NT驱动的入口函数DriverEntry:
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT pDriverObject, //驱动对象指针
IN PUNICODE_STRING pRegistryPath) //设备服务在注册表中键名的字符串(全路径)
本函数主要是要对驱动程序初始化工作,由系统进程调用,系统进程就是任务管理器看到的一个名为System的进程。
在驱动加载的时候,系统启动新线程,调用执行体组件中的对象管理器,创建一个驱动对象,另外调用执行体组件中的配置管理程序,查询驱动程序在组册表中的项。
驱动入口函数主要负责3个工作:设置卸载例程函数 和 设置IRP派遣函数,这两个设置是对驱动对象的设置,还要创建设备。
可以看出,DriverEntry 都是做一些初始化工作,最好放在INITSegment里。
创建设备例程CreateDevice:
一般会把 创建设备对象 、 创建符号链接 和 设置设备对象 三个过程封装在一个CreateDevice函数里(INIT Segment),传进驱动对象指针,然后在入口函数调用。
①创建设备对象:
在NT式驱动中,创建设备对象是由下面内核函数完成的:
ntStatus = IoCreateDevice(
pDriverObject, //IN 驱动对象指针
sizeof(DEVICE_EXTENSION), //IN 设备扩展的大小
&szDeviceName, //IN 驱动的设备名称
FILE_DEVICE_UNKNOWN, //IN 驱动类型
0, TRUE, //IN 设备对象特征通常为0,IN 设置设备对象是否为内核对象使用
&pDeviceObject); //OUT 生成的设备的指针的地址,这里要注意了
OUT PDEVICE_OBJECT *DeviceObject
函数会返回一个NTSTATUS的数据,其是一个ULONG类型,利用NT_SUCCESS宏可以检查状态是否为 STATUS_SUCESS,如下:
if(!NT_SUCCESS(ntStatus))
{//这是一个通用的过程,判断了不同的情况输出
if (ntStatus==STATUS_INSUFFICIENT_RESOURCES)
KdPrint(("STATUS_INSUFFICIENT_RESOURCES 资源不足"));
if (ntStatus==STATUS_OBJECT_NAME_EXISTS )
KdPrint(("STATUS_OBJECT_NAME_EXISTS 指定对象名存在"));
if (ntStatus==STATUS_OBJECT_NAME_COLLISION)
KdPrint(("STATUS_OBJECT_NAME_COLLISION 对象名有冲突"));
KdPrint(("IoCreateDevice Failed.../r/n"));
return ntStatus;}
②创建设备的符号链接:
在NT式驱动中,设备都有一个符号链接,供ring0层找到指定设备。
ntStatus = IoCreateSymbolicLink(
&szSymLinkName, //IN 设备符号链接名称
&szDeviceName); //IN 设备名称
if(!NT_SUCCESS(ntStatus))
{
KdPrint(("IoCreateSymbolicLink Failed..."));
//删除设备对象,注意:设备符号链接创建失败就吧驱动对象删除了吧,避免很多问题
IoDeleteDevice(pDeviceObject);
return ntStatus;
}
③设置设备对象:
在NT式驱动中,有两种常用的访问用户模式数据方式:DO_BUFFERED_IO和DO_DERECT_IO(参考IRP派遣),通过设备扩展传递“类似全局变量”(注意是双引号)
//设置使用缓冲方式访问用户模式数据
pDeviceObject->Flags |= DO_BUFFERED_IO;
注意:这里设置使得设备支持缓冲区模式的IOCTL
//获取设备扩展指针
pDeviceExtension = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;
注意:DeviceExtension本来的类型是PVOID,所以要强制转换
//设置设备扩展
pDeviceExtension->pDeviceObject = pDeviceObject;
pDeviceExtension->szDeviceName = szDeviceName;
pDeviceExtension->szSymLinkName = szSymLinkName;
注意:这里传递的参数方便驱动卸载例程使用