Windows驱动程序的基本结构

以下均为个人见解,如果有误,敬请指正,谢谢

Windows驱动程序的两个重要的数据结构,驱动设备对象DRIVER_OBJECT、设备对象结构DEVICE_OBJECT,这里简略了两个结构体中的成员,具体的网上都是,自己去搜吧

1、typedef struct _DRIVER_OBJECT{

PDEVICE_OBJECT DeviceObject;/*该设备对象是由程序员自己生成,非OS生成,该设备对象为驱动对象指向的第一个设备对象,设备对象的结构体中有NextDevice,所以可以通过NextDevice指针遍历设备链,卸载的时候也是通过NextDevice指针删除设备对象的,最后一个设备对象为空。*/

UNICODE_STRING DRIVER_NAME;/*驱动名称*/

PDRIVER_UNLOAD DriverUnLoad;/*驱动卸载时的回调函数*/

PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];/*函数指针数组,每个指针对用相对应的IRP处理函数*/

}DRIVER_OBJECT;

2、typedef struct _DEVICE_OBJECT{

struct _DRIVER_OBJECT *DriverObject;/*驱动对象*/

struct _DEVICE_OBJECT *NextDevice;/*指向同一层驱动的下一个设备对象*/

struct _DEVICE_OBJECT *AttachedDevice;/*指向高一层驱动的下一个设备对象*/

struct _DEVOBJ_EXTENSION *DeviceObjectExtension;/*设备扩展对象*/

ULONG Flags, DeviceType;/*DeviceType为设备类型,Flags为设备的标志位,每个标志位都有特定含义,Flags=DO_BUFFERED_IO:读写操作采用缓冲方式(系统赋值缓冲区)访问用户模式数据,Flags=DO_EXCLUSIVE:一次只允许一个线程打开设备句柄,Flags=DO_DIRECT_IO:读写操作使用直接方式(内存描述符表)访问用户模式数据,Flags=DO_DEVICE_INITIALIZING:设备对象正在初始化,Flags=DO_POWER_PAGEABLE:必须在PASSIVE_LEVEL级上处理IRP_MJ_PNP请求,Flags=DO_POWER_INRUSH:设备上电期间需要大电流*/

}DEVICE_OBJECT;

将驱动对象和设备对象联合起来,在参照代码看更好理解(以下为我个人在写NT驱动的设备扩展的结构):

typedef struct _DEVICE_EXTENSION
{
	PDEVICE_OBJECT pDevice;//设备对象
	UNICODE_STRING ustrDeviceName;//设备名称
	UNICODE_STRING ustrSymLinkName;//符号链接名
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;

NT驱动简单些,主要DRIVER_ENTRY, DRIVER_UNLOAD和IRP的处理函数,主线很明了。

#pragma INITCODE
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, 
								IN PUNICODE_STRING pRegistryPath)
{
	NTSTATUS status;
	KdPrint(("Entry DriverEntry\n"));

	//注册其他驱动调用入口函数
	pDriverObject->DriverUnload = HelloDDKUnload;
	pDriverObject->MajorFunction[IRP_MJ_CREATE] = 
	pDriverObject->MajorFunction[IRP_MJ_CLOSE] = 
	pDriverObject->MajorFunction[IRP_MJ_WRITE] = 
	pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine;

	//创建驱动设备对象
	status = CreateDevice(pDriverObject);
	status = CreateDevice2(pDriverObject);

	Dump(pDriverObject);

	KdPrint(("DriverEntry end\n"));
	return status;
}


上面为驱动的入口函数,其中INITCODE为DDK提供的宏,表明为加载的时候,加载完毕就不存在内存中。第二个形参为设备服务键的键名字符串指针,需要保存起来。这里主要讲解一下创建驱动设备对象,别的没有什么说的了,Dump函数是用来查看调试信息的,有无不影响代码的运行,这里讲代码贴出:

#pragma INITCODE
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject)
{
	NTSTATUS status;
	PDEVICE_OBJECT pDevObj;
	PDEVICE_EXTENSION pDevExt;
	
	//创建设备名称
	UNICODE_STRING devName;
	RtlInitUnicodeString(&devName, L"\\Device\\MyDDKDevice");

	//创建设备
	status = IoCreateDevice(pDriverObject, 
							sizeof(DEVICE_EXTENSION),
							&(UNICODE_STRING)devName,
							FILE_DEVICE_UNKNOWN,
							0,
							TRUE,
							&pDevObj
							);

	if(!NT_SUCCESS(status))
		return status;

	pDevObj->Flags |= DO_BUFFERED_IO;
	pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
	pDevExt->pDevice = pDevObj;
	pDevExt->ustrDeviceName = devName;
	
	//创建符号链接
	UNICODE_STRING symLinkName;
	RtlInitUnicodeString(&symLinkName, L"\\??\\HelloDDK");
	pDevExt->ustrSymLinkName = symLinkName;

	status = IoCreateSymbolicLink(&symLinkName, &devName);
	if(!NT_SUCCESS(status))
	{
		IoDeleteDevice(pDevObj);
		return status;
	}

	return STATUS_SUCCESS;
}

由IoCreateDevice函数返回设备对象指针(地址),设置了设备对象的Flags和扩展设备对象的成员,在内核模式下的符号链接是以"\??\"开头,区别于用户模式下的"\\.\"。

然后再看看卸载历程,代码如下:

#pragma PAGECODE
void HelloDDKUnload(IN PDRIVER_OBJECT pDriverObject)
{
	PDEVICE_OBJECT pNextObj;
	KdPrint(("Enter DriverUnload\n"));
	pNextObj = pDriverObject->DeviceObject;
	while(pNextObj != NULL)
	{
		PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextObj->DeviceExtension;

		//删除符号链接
		UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
		IoDeleteSymbolicLink(&pLinkName);
		pNextObj = pNextObj->NextDevice;
		IoDeleteDevice(pDevExt->pDevice);
	}
}
注意宏PAGECODE为分页内存,在这里值讨论了同一层驱动的设备链,代码体现出卸载删除了符号链接和设备对象。

到这里就算结束了,因为关于IRP的处理放到以后再说吧,说IRP那估计要写好几篇的,个人不擅长语言表达,有什么不懂的,在问吧,希望对大家有点帮助。



你可能感兴趣的:(Windows驱动程序的基本结构)