内核模式 定时器学习

摘要:
为了运行不同的进程和应用程序,Pagefile.sys为物理内存分配了一些空间。允许在这些空间中交换数据页。)示例:1)初始化计时器IoInitializeTimer;2) 向设备扩展添加一个计数变量,以记录间隔秒LONGlTimerCount;3) 定义两个IOCTL代码IOCTL_START_TIMER+IOCTL_STOP当应用程序启动这两个IOCCTL请求时,打开和关闭计时器000000000。00000000输入驱动程序条目00000000。0008241 LeaveDriverEntry 00000000。026.68917799输入HelloDDKDispatchRoutin000000036.68918133 IRP_ MJ_ CREATE00000046.68969822 LeaveHelloDDKDdispatchRoutin00000056.69020081EnterHelloDDKDeviceIOControl000000066.69020319IOCTL _ START_ TIMER000000076.69070101LeaveHello DDKDevice IOControl00000087.63543415 InterOnTimer!


1)i/0定时器例程  每间隔1S 调用一次I/O定时器例程  可以定义初始值 为N  每次进入定时器例程 计数--   就变化成 NS定时器

2)DPC例程       MS级别间隔,US级别间隔

I/O定时器 学习

NTSTATUS 
  IoInitializeTimer(
    IN PDEVICE_OBJECT  DeviceObject,    //I/O定时器关联 设备对象指针
    IN PIO_TIMER_ROUTINE  TimerRoutine, //I/O定时器关联 定期例程
    IN PVOID  Context                   //传入定时器例程餐宿
    );
开启定时器:

VOID 
  IoStartTimer(
    IN PDEVICE_OBJECT  DeviceObject
    );
停止I/O定时器:

VOID 
  IoStopTimer(
    IN PDEVICE_OBJECT  DeviceObject
    );

I/O定时器例程运行再  DISPATCH_LEVEL级别  不能使用分页内存

Windows NT使用了分页文件Pagefile.sys。为了运行不同的进程和应用程序,Pagefile.sys给物理内存分配了一些空间。在这些空间内允许交换数据页。

示例:

1)初始化 定时器

IoInitializeTimer(pDevObj,OnTimer,NULL);

2)设备扩展中加入 计数变量 负责记录间隔秒数

 LONG lTimerCount;

3)定义两个IOCTL码  IOCTL_START_TIMER  +  IOCTL_STOP

当应用程序发起这两个IOCTL请求后,开启+关闭定时器

00000000	0.00000000	Enter DriverEntry	
00000001	0.00008241	Leave DriverEntry	
00000002	6.68917799	Enter HelloDDKDispatchRoutin	
00000003	6.68918133	 IRP_MJ_CREATE	
00000004	6.68969822	Leave HelloDDKDispatchRoutin	
00000005	6.69020081	Enter HelloDDKDeviceIOControl	
00000006	6.69020319	IOCTL_START_TIMER	
00000007	6.69070101	Leave HelloDDKDeviceIOControl	
00000008	7.63543415	Enter OnTimer!	                    //////////////////////////////////
00000009	7.63543749	previousCount = 2 	            //初始化为3 不停-- 
00000010	7.63543987	TIMER_OUT = 3 	
00000011	7.63544321	The current process is Idle	
00000012	8.63506699	Enter OnTimer!	
00000013	8.63507080	previousCount = 1 	
00000014	8.63507271	TIMER_OUT = 3 	
00000015	8.63507652	The current process is Idle	
00000016	9.63517284	Enter OnTimer!	
00000017	9.63517666	previousCount = 0 	
00000018	9.63517857	TIMER_OUT = 3 	
00000019	9.63518238	3 seconds time out!	
00000020	9.63518429	The current process is Idle	
00000021	10.63625240	Enter OnTimer!	
00000022	10.63712025	previousCount = 2 	
00000023	10.63813972	TIMER_OUT = 3 	
00000024	10.63814354	The current process is vmtoolsd.exe	
00000025	11.63535500	Enter OnTimer!	
00000026	11.63535786	previousCount = 1 	
00000027	11.63536072	TIMER_OUT = 3 	
00000028	11.63536358	The current process is Idle	
00000029	12.63484955	Enter OnTimer!	
00000030	12.63485241	previousCount = 0 	
00000031	12.63485527	TIMER_OUT = 3 	
00000032	12.63485718	3 seconds time out!	
00000033	12.63486099	The current process is Idle	
00000034	13.63495541	Enter OnTimer!	
00000035	13.63495827	previousCount = 2 	
00000036	13.63496113	TIMER_OUT = 3 	
00000037	13.63496399	The current process is Idle	
00000038	14.63765812	Enter OnTimer!	
00000039	14.63766193	previousCount = 1 	
00000040	14.63766384	TIMER_OUT = 3 	
00000041	14.63766670	The current process is Idle	
00000042	15.63519192	Enter OnTimer!	
00000043	15.63519955	previousCount = 0 	
00000044	15.63520241	TIMER_OUT = 3 	
00000045	15.63520622	3 seconds time out!	
00000046	15.63520908	The current process is irptrace.exe	
00000047	16.63495064	Enter OnTimer!	
00000048	16.63495255	previousCount = 2 	
00000049	16.63495636	TIMER_OUT = 3 	
00000050	16.63495827	The current process is Idle	
00000051	16.69157982	Enter HelloDDKDeviceIOControl	
00000052	16.69165039	IOCTL_STOP	
00000053	16.69217110	Leave HelloDDKDeviceIOControl	
00000054	16.69274902	Enter HelloDDKDispatchRoutin	
00000055	16.69275093	 IRP_MJ_CLEANUP	
00000056	16.69323921	Leave HelloDDKDispatchRoutin	
00000057	16.69375610	Enter HelloDDKDispatchRoutin	
00000058	16.69375801	 IRP_MJ_CLOSE	
00000059	16.69423866	Leave HelloDDKDispatchRoutin	

驱动代码:

#include "Driver.h"

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

	//设置卸载函数
	pDriverObject->DriverUnload = HelloDDKUnload;

	//设置派遣函数
	for (int i = 0; i < arraysize(pDriverObject->MajorFunction); ++i)
		pDriverObject->MajorFunction[i] = HelloDDKDispatchRoutin;

	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDeviceIOControl;
	
	//创建驱动设备对象
	status = CreateDevice(pDriverObject);

	KdPrint(("Leave DriverEntry
"));
	return status;
}

#pragma LOCKEDCODE                         //不能使用分页内存    运行再DISPATCH_LEVEL的IRQL级别
VOID OnTimer(
    IN PDEVICE_OBJECT DeviceObject,
    IN PVOID Context)
{
	PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
		DeviceObject->DeviceExtension;
	KdPrint(("Enter OnTimer!
"));

	//将计数器自锁减一
	InterlockedDecrement(&pDevExt->lTimerCount);
	
	//如果计数器减到0,重新编程TIMER_OUT,整个过程是互锁运算
	LONG previousCount = InterlockedCompareExchange(&pDevExt->lTimerCount,TIMER_OUT,0);//3秒
                                                                                                                                                                       KdPrint(("previousCount = %d
",previousCount));                                                                                                               KdPrint(("TIMER_OUT = %d
",TIMER_OUT));                                                                                                                                                                                                                  
	//每隔三秒,计数器一个循环,输出以下log
	if (previousCount==0)
	{
		KdPrint(("%d seconds time out!
",TIMER_OUT));
	}

	//证明该线程运行在任意线程上下文的
    PEPROCESS pEProcess = IoGetCurrentProcess();
   
    PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);//即可得到用户进程

    KdPrint(("The current process is %s
",ProcessName));  //为了证明该线程能运行再任意线程上下文  输处线程名称
}


/************************************************************************
* 函数名称:CreateDevice
* 功能描述:初始化设备对象
* 参数列表:
      pDriverObject:从I/O管理器中传进来的驱动对象
* 返回 值:返回初始化状态
*************************************************************************/
#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_DIRECT_IO;
	pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
	pDevExt->pDevice = pDevObj;
	pDevExt->ustrDeviceName = devName;

	IoInitializeTimer(pDevObj,OnTimer,NULL);

	//创建符号链接
	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;
}

/************************************************************************
* 函数名称:HelloDDKUnload
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
      pDriverObject:驱动对象
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) 
{
	PDEVICE_OBJECT	pNextObj;
	KdPrint(("Enter DriverUnload
"));
	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 );
	}
}

/************************************************************************
* 函数名称:HelloDDKDispatchRoutin
* 功能描述:对读IRP进行处理
* 参数列表:
      pDevObj:功能设备对象
      pIrp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp) 
{
	KdPrint(("Enter HelloDDKDispatchRoutin
"));

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//建立一个字符串数组与IRP类型对应起来
	static char* irpname[] = 
	{
		"IRP_MJ_CREATE",
		"IRP_MJ_CREATE_NAMED_PIPE",
		"IRP_MJ_CLOSE",
		"IRP_MJ_READ",
		"IRP_MJ_WRITE",
		"IRP_MJ_QUERY_INFORMATION",
		"IRP_MJ_SET_INFORMATION",
		"IRP_MJ_QUERY_EA",
		"IRP_MJ_SET_EA",
		"IRP_MJ_FLUSH_BUFFERS",
		"IRP_MJ_QUERY_VOLUME_INFORMATION",
		"IRP_MJ_SET_VOLUME_INFORMATION",
		"IRP_MJ_DIRECTORY_CONTROL",
		"IRP_MJ_FILE_SYSTEM_CONTROL",
		"IRP_MJ_DEVICE_CONTROL",
		"IRP_MJ_INTERNAL_DEVICE_CONTROL",
		"IRP_MJ_SHUTDOWN",
		"IRP_MJ_LOCK_CONTROL",
		"IRP_MJ_CLEANUP",
		"IRP_MJ_CREATE_MAILSLOT",
		"IRP_MJ_QUERY_SECURITY",
		"IRP_MJ_SET_SECURITY",
		"IRP_MJ_POWER",
		"IRP_MJ_SYSTEM_CONTROL",
		"IRP_MJ_DEVICE_CHANGE",
		"IRP_MJ_QUERY_QUOTA",
		"IRP_MJ_SET_QUOTA",
		"IRP_MJ_PNP",
	};

	UCHAR type = stack->MajorFunction;
	if (type >= arraysize(irpname))
		KdPrint((" - Unknown IRP, major type %X
", type));
	else
		KdPrint(("	%s
", irpname[type]));

	NTSTATUS status = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint(("Leave HelloDDKDispatchRoutin
"));

	return status;
}

#pragma PAGEDCODE
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	KdPrint(("Enter HelloDDKDeviceIOControl
"));

	//得到当前堆栈
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//得到输入缓冲区大小
	ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
	//得到输出缓冲区大小
	ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
	//得到IOCTL码
	ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;

	PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
		pDevObj->DeviceExtension;

	ULONG info = 0;

	switch (code)
	{						// process request
		case IOCTL_START_TIMER:
		{
			KdPrint(("IOCTL_START_TIMER
"));
			pDevExt->lTimerCount = TIMER_OUT;
			IoStartTimer(pDevObj);
			break;
		}
		case IOCTL_STOP:
		{
			KdPrint(("IOCTL_STOP
"));
			IoStopTimer(pDevObj);
			break;
		}
		default:
			status = STATUS_INVALID_VARIANT;
	}

	// 完成IRP
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = info;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint(("Leave HelloDDKDeviceIOControl
"));

	return status;
}
应用程序代码:

#include <windows.h>
#include <stdio.h>
//使用CTL_CODE必须加入winioctl.h
#include <winioctl.h>
#include "..NT_DriverIoctls.h"

int main()
{
	HANDLE hDevice = 
		CreateFile("\\.\HelloDDK",
					GENERIC_READ | GENERIC_WRITE,
					0,		// share mode none
					NULL,	// no security
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL,
					NULL );		// no template

	if (hDevice == INVALID_HANDLE_VALUE)
	{
		printf("Failed to obtain file handle to device: "
			"%s with Win32 error code: %d
",
			"MyWDMDevice", GetLastError() );
		return 1;
	}

	DWORD dwOutput;

	DeviceIoControl(hDevice, IOCTL_START_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL);//IOCTL_START_TIMER 这个是自定义的


	Sleep(10000);

 	DeviceIoControl(hDevice, IOCTL_STOP, NULL, 0, NULL, 0, &dwOutput, NULL);

	CloseHandle(hDevice);

	return 0;
}
IDLE 和 系统进程一样  都是一种特殊进程,没有响应的EXE文件与之对应


DPC定时器学习

更加灵活 任意间断时间使用DPC定时器

使用KTIMER对象当对定时器设置一个时间间隔后,每隔这段时间 系统将一个DPC例程插入DPC队列,当系统读取DPC队列时,对应DPC例程会被执行

初始化 定时器 对象:

VOID 
  KeInitializeTimer(
    IN PKTIMER  Timer       //定时器指针
    );

初始化 DPC 对象:

VOID 
  KeInitializeDpc(
    IN PRKDPC  Dpc,                           //初始化的DPC对象指针
    IN PKDEFERRED_ROUTINE  DeferredRoutine,   //与DPC关联的DPC例程 每当定时器间隔到时,操作系统就会将一个DPC对象插入队列 触发该例程
    IN PVOID  DeferredContext                 //传入DPC例程的参数
    );
开启定时器:

BOOLEAN 
  KeSetTimer(                      //在调用KeSetTimer 后,只会触发一次DPC例程,如果想周期的触发DPC例程,需要在DPC例程被触发后  再次调用KeSetTimer
    IN PKTIMER  Timer,             //定时器对象指针
    IN LARGE_INTEGER  DueTime,     //时间间隔    如果它是正数,绝对时间,负数 则意味着 间隔多长时间,时间单位 100NS
    IN PKDPC  Dpc  OPTIONAL        //传入DPC例程参数
    );
取消定时器:

BOOLEAN 
  KeCancelTimer(
    IN PKTIMER  Timer
    );
示例:

1)定义两个 IOCTL  -》开启+关闭定时器

2)在传递IOCTL_START_TIMER时,将间隔的时间 从应用程序 传递到驱动程序,这样时间间隔是由应用程序控制的

      应用程序中调用DeviceIOControl 让驱动程序开启定时器 + 关闭定时器,并告诉定时器间隔时间

	DeviceIoControl(hDevice, IOCTL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL);

	Sleep(10000);

 	DeviceIoControl(hDevice, IOCTL_STOP_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL);

3)设备扩展中加入 DPC对象 + 定时器对象

	KDPC pollingDPC;	// 存储DPC对象
	KTIMER pollingTimer;// 存储计时器对象
	LARGE_INTEGER pollingInterval;	// 记录计时器间隔时间
4)初始化 DPC对象时,需要将设备对象作为参数传递给DPC例程。这样在DPC例程中可以通过设备对象 指针获得间隔时间,时间记录在设备扩展中

	KeInitializeTimer( &pDevExt->pollingTimer );
	
	KeInitializeDpc( &pDevExt->pollingDPC,
		PollingTimerDpc,      //例程函数
						(PVOID) pDevObj );
5)在IRP_MJ_DEVICE_CONTROL 的派遣函数 中,接受 IOCTL_START_TIMER后,可以将应用程序传递进来的间隔时间记录下来

      调用KeSetTimer函数开启  定时器    在接受 IOCTL_STOP_TIMER后,调用 KeCancelTimer函数停止定时器

#include "Driver.h"

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

	//设置卸载函数
	pDriverObject->DriverUnload = HelloDDKUnload;

	//设置派遣函数
	for (int i = 0; i < arraysize(pDriverObject->MajorFunction); ++i)
		pDriverObject->MajorFunction[i] = HelloDDKDispatchRoutin;

	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDeviceIOControl;
	
	//创建驱动设备对象
	status = CreateDevice(pDriverObject);

	KdPrint(("Leave DriverEntry
"));
	return status;
}
#pragma LOCKEDCODE
VOID PollingTimerDpc( IN PKDPC pDpc,                             ////////////////////////////////////////////
					  IN PVOID pContext,
					  IN PVOID SysArg1,
					  IN PVOID SysArg2 ) 
{
	PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
	KeSetTimer(                        //只会触发一次 DPC例程,需要重新开启
		&pdx->pollingTimer,
		pdx->pollingInterval,   //每隔 一段  时间久执行一次   直到 应用程序 传递  STOP IRP 过来
		&pdx->pollingDPC );
	KdPrint(("PollingTimerDpc
"));

	//检验是运行在任意线程上下文
    PEPROCESS pEProcess = IoGetCurrentProcess();
   
    PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);

    KdPrint(("%s
",ProcessName));
}

/************************************************************************
* 函数名称:CreateDevice
* 功能描述:初始化设备对象
* 参数列表:
      pDriverObject:从I/O管理器中传进来的驱动对象
* 返回 值:返回初始化状态
*************************************************************************/
#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_DIRECT_IO;
	pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
	pDevExt->pDevice = pDevObj;
	pDevExt->ustrDeviceName = devName;

	KeInitializeTimer( &pDevExt->pollingTimer );                 //////////////////////////////////
	
	KeInitializeDpc( &pDevExt->pollingDPC,
		PollingTimerDpc,
						(PVOID) pDevObj );   ///////////////////////////////////

	//创建符号链接
	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;
}

/************************************************************************
* 函数名称:HelloDDKUnload
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
      pDriverObject:驱动对象
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) 
{
	PDEVICE_OBJECT	pNextObj;
	KdPrint(("Enter DriverUnload
"));
	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 );
	}
}

/************************************************************************
* 函数名称:HelloDDKDispatchRoutin
* 功能描述:对读IRP进行处理
* 参数列表:
      pDevObj:功能设备对象
      pIrp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp) 
{
	KdPrint(("Enter HelloDDKDispatchRoutin
"));

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//建立一个字符串数组与IRP类型对应起来
	static char* irpname[] = 
	{
		"IRP_MJ_CREATE",
		"IRP_MJ_CREATE_NAMED_PIPE",
		"IRP_MJ_CLOSE",
		"IRP_MJ_READ",
		"IRP_MJ_WRITE",
		"IRP_MJ_QUERY_INFORMATION",
		"IRP_MJ_SET_INFORMATION",
		"IRP_MJ_QUERY_EA",
		"IRP_MJ_SET_EA",
		"IRP_MJ_FLUSH_BUFFERS",
		"IRP_MJ_QUERY_VOLUME_INFORMATION",
		"IRP_MJ_SET_VOLUME_INFORMATION",
		"IRP_MJ_DIRECTORY_CONTROL",
		"IRP_MJ_FILE_SYSTEM_CONTROL",
		"IRP_MJ_DEVICE_CONTROL",
		"IRP_MJ_INTERNAL_DEVICE_CONTROL",
		"IRP_MJ_SHUTDOWN",
		"IRP_MJ_LOCK_CONTROL",
		"IRP_MJ_CLEANUP",
		"IRP_MJ_CREATE_MAILSLOT",
		"IRP_MJ_QUERY_SECURITY",
		"IRP_MJ_SET_SECURITY",
		"IRP_MJ_POWER",
		"IRP_MJ_SYSTEM_CONTROL",
		"IRP_MJ_DEVICE_CHANGE",
		"IRP_MJ_QUERY_QUOTA",
		"IRP_MJ_SET_QUOTA",
		"IRP_MJ_PNP",
	};

	UCHAR type = stack->MajorFunction;
	if (type >= arraysize(irpname))
		KdPrint((" - Unknown IRP, major type %X
", type));
	else
		KdPrint(("	%s
", irpname[type]));

	NTSTATUS status = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint(("Leave HelloDDKDispatchRoutin
"));

	return status;
}

#pragma PAGEDCODE
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	KdPrint(("Enter HelloDDKDeviceIOControl
"));

	//得到当前堆栈
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//得到输入缓冲区大小
	ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
	//得到输出缓冲区大小
	ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
	//得到IOCTL码
	ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;

	PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
		pDevObj->DeviceExtension;

	ULONG info = 0;

	switch (code)
	{						// process request
		case IOCTL_START_TIMER:
		{ 
			KdPrint(("IOCTL_START_TIMER!
"));

			//从用户模式传进来的超时
			ULONG ulMircoSeconds = *(PULONG)pIrp->AssociatedIrp.SystemBuffer;  //记录应用程序传递过来的 间隔时间

			pDevExt->pollingInterval = RtlConvertLongToLargeInteger( ulMircoSeconds * -10 );//时间单位是 100纳秒

			KeSetTimer(
				&pDevExt->pollingTimer,
				pDevExt->pollingInterval,
				&pDevExt->pollingDPC );
			break;
		}
		case IOCTL_STOP_TIMER:
		{ 
			KdPrint(("IOCTL_STOP_TIMER!
"));

			KeCancelTimer(&pDevExt->pollingTimer);

			break;
		}
		default:
			status = STATUS_INVALID_VARIANT;
	}

	// 完成IRP
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = info;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint(("Leave HelloDDKDeviceIOControl
"));

	return status;
}
应用程序:

#include <windows.h>
#include <stdio.h>
//使用CTL_CODE必须加入winioctl.h
#include <winioctl.h>
#include "..NT_DriverIoctls.h"

int main()
{
	HANDLE hDevice = 
		CreateFile("\\.\HelloDDK",
					GENERIC_READ | GENERIC_WRITE,
					0,		// share mode none
					NULL,	// no security
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL,
					NULL );		// no template

	if (hDevice == INVALID_HANDLE_VALUE)
	{
		printf("Failed to obtain file handle to device: "
			"%s with Win32 error code: %d
",
			"MyWDMDevice", GetLastError() );
		return 1;
	}

	DWORD dwOutput;
	DWORD dwMircoSeconds = 1000*1000*1;

	DeviceIoControl(hDevice, IOCTL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL);

	Sleep(10000);

 	DeviceIoControl(hDevice, IOCTL_STOP_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL);

	CloseHandle(hDevice);

	return 0;
}

等待学习:

1)KeWaitForSingleObject

NTSTATUS 
  KeWaitForSingleObject(                   //等待内核同步对象
    IN PVOID  Object,
    IN KWAIT_REASON  WaitReason,
    IN KPROCESSOR_MODE  WaitMode,
    IN BOOLEAN  Alertable,
    IN PLARGE_INTEGER  Timeout  OPTIONAL
    );

#pragma PAGEDCODE
VOID WaitMicroSecond1(ULONG ulMircoSecond)
{
	KEVENT kEvent;

	KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));

	//初始化一个未激发的内核事件
	KeInitializeEvent(&kEvent,SynchronizationEvent,FALSE);

	//等待时间的单位是100纳秒,将微秒转换成这个单位
	//负数代表是从此刻到未来的某个时刻
	LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond);

	//在经过timeout后,线程继续运行
	KeWaitForSingleObject(&kEvent,
		Executive,
		KernelMode,
		FALSE,
		&timeout);

	KdPrint(("Thread is running again!
"));
}
2)使用 KeDelayExecutionThread

NTSTATUS 
  KeDelayExecutionThread(          //强制当前线程进入  睡眠状态  经过睡眠时间后,线程恢复运行
    IN KPROCESSOR_MODE  WaitMode,
    IN BOOLEAN  Alertable,
    IN PLARGE_INTEGER  Interval
    );
#pragma PAGEDCODE
VOID WaitMicroSecond2(ULONG ulMircoSecond)
{
	KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));

	//等待时间的单位是100纳秒,将微秒转换成这个单位
	//负数代表是从此刻到未来的某个时刻
	LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond);

	//此种方法类似于KeWaitForSingleObject
	//将当前线程进入睡眠状态,间隔时间到转入运行状态
	KeDelayExecutionThread(KernelMode,FALSE,&timeout);

	KdPrint(("Thread is running again!
"));
}
3)KeStallExecutionProcessor
VOID 
  KeStallExecutionProcessor(   //让CPU处于忙等待状态,而不是处于睡眠。经过指定时间后,继续让线程运行  不宜超过50US
    IN ULONG  MicroSeconds
    );
1 000 000 US  =  1S

#pragma PAGEDCODE
VOID WaitMicroSecond3(ULONG ulMircoSecond)
{
	KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));

	//忙等待,此种方法属于忙等待,比较浪费CPU时间
	//因此使用该方法不宜超过50微秒
	KeStallExecutionProcessor(ulMircoSecond);

	KdPrint(("Thread is running again!
"));
}
4)使用定时器

#pragma PAGEDCODE
VOID WaitMicroSecond4(ULONG ulMircoSecond)
{
	//使用计时器   这里没有使用DPC例程 + 对象

	KTIMER kTimer;//内核计时器

	//初始化计时器
	KeInitializeTimer(&kTimer);

	LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( ulMircoSecond * -10 );

	//注意这个计时器没有和DPC对象关联
	KeSetTimer(&kTimer,timeout,	NULL); //第三个参数  没有设置 DPC例程  就没有DPC例程
	KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));

	KeWaitForSingleObject(&kTimer,Executive,KernelMode,FALSE,NULL);

	KdPrint(("Thread is running again!
"));
}

#include "Driver.h"

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

	//设置卸载函数
	pDriverObject->DriverUnload = HelloDDKUnload;

	//设置派遣函数
	for (int i = 0; i < arraysize(pDriverObject->MajorFunction); ++i)
		pDriverObject->MajorFunction[i] = HelloDDKDispatchRoutin;

	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDeviceIOControl;
	
	//创建驱动设备对象
	status = CreateDevice(pDriverObject);

	KdPrint(("Leave DriverEntry
"));
	return status;
}

/************************************************************************
* 函数名称:CreateDevice
* 功能描述:初始化设备对象
* 参数列表:
      pDriverObject:从I/O管理器中传进来的驱动对象
* 返回 值:返回初始化状态
*************************************************************************/
#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_DIRECT_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;
}

/************************************************************************
* 函数名称:HelloDDKUnload
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
      pDriverObject:驱动对象
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) 
{
	PDEVICE_OBJECT	pNextObj;
	KdPrint(("Enter DriverUnload
"));
	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 );
	}
}

/************************************************************************
* 函数名称:HelloDDKDispatchRoutin
* 功能描述:对读IRP进行处理
* 参数列表:
      pDevObj:功能设备对象
      pIrp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp) 
{
	KdPrint(("Enter HelloDDKDispatchRoutin
"));

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//建立一个字符串数组与IRP类型对应起来
	static char* irpname[] = 
	{
		"IRP_MJ_CREATE",
		"IRP_MJ_CREATE_NAMED_PIPE",
		"IRP_MJ_CLOSE",
		"IRP_MJ_READ",
		"IRP_MJ_WRITE",
		"IRP_MJ_QUERY_INFORMATION",
		"IRP_MJ_SET_INFORMATION",
		"IRP_MJ_QUERY_EA",
		"IRP_MJ_SET_EA",
		"IRP_MJ_FLUSH_BUFFERS",
		"IRP_MJ_QUERY_VOLUME_INFORMATION",
		"IRP_MJ_SET_VOLUME_INFORMATION",
		"IRP_MJ_DIRECTORY_CONTROL",
		"IRP_MJ_FILE_SYSTEM_CONTROL",
		"IRP_MJ_DEVICE_CONTROL",
		"IRP_MJ_INTERNAL_DEVICE_CONTROL",
		"IRP_MJ_SHUTDOWN",
		"IRP_MJ_LOCK_CONTROL",
		"IRP_MJ_CLEANUP",
		"IRP_MJ_CREATE_MAILSLOT",
		"IRP_MJ_QUERY_SECURITY",
		"IRP_MJ_SET_SECURITY",
		"IRP_MJ_POWER",
		"IRP_MJ_SYSTEM_CONTROL",
		"IRP_MJ_DEVICE_CHANGE",
		"IRP_MJ_QUERY_QUOTA",
		"IRP_MJ_SET_QUOTA",
		"IRP_MJ_PNP",
	};

	UCHAR type = stack->MajorFunction;
	if (type >= arraysize(irpname))
		KdPrint((" - Unknown IRP, major type %X
", type));
	else
		KdPrint(("	%s
", irpname[type]));

	NTSTATUS status = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint(("Leave HelloDDKDispatchRoutin
"));

	return status;
}

#pragma PAGEDCODE
VOID WaitMicroSecond1(ULONG ulMircoSecond)
{
	KEVENT kEvent;

	KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));

	//初始化一个未激发的内核事件
	KeInitializeEvent(&kEvent,SynchronizationEvent,FALSE);

	//等待时间的单位是100纳秒,将微秒转换成这个单位
	//负数代表是从此刻到未来的某个时刻
	LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond);

	//在经过timeout后,线程继续运行
	KeWaitForSingleObject(&kEvent,
		Executive,
		KernelMode,
		FALSE,
		&timeout);

	KdPrint(("Thread is running again!
"));
}

#pragma PAGEDCODE
VOID WaitMicroSecond2(ULONG ulMircoSecond)
{
	KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));

	//等待时间的单位是100纳秒,将微秒转换成这个单位
	//负数代表是从此刻到未来的某个时刻
	LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond);

	//此种方法类似于KeWaitForSingleObject
	//将当前线程进入睡眠状态,间隔时间到转入运行状态
	KeDelayExecutionThread(KernelMode,FALSE,&timeout);

	KdPrint(("Thread is running again!
"));
}

#pragma PAGEDCODE
VOID WaitMicroSecond3(ULONG ulMircoSecond)
{
	KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));

	//忙等待,此种方法属于忙等待,比较浪费CPU时间
	//因此使用该方法不宜超过50微秒
	KeStallExecutionProcessor(ulMircoSecond);

	KdPrint(("Thread is running again!
"));
}

#pragma PAGEDCODE
VOID WaitMicroSecond4(ULONG ulMircoSecond)
{
	//使用计时器

	KTIMER kTimer;//内核计时器

	//初始化计时器
	KeInitializeTimer(&kTimer);

	LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( ulMircoSecond * -10 );

	//注意这个计时器没有和DPC对象关联
	KeSetTimer(&kTimer,timeout,	NULL);
	KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));

	KeWaitForSingleObject(&kTimer,Executive,KernelMode,FALSE,NULL);

	KdPrint(("Thread is running again!
"));
}

#pragma PAGEDCODE
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	KdPrint(("Enter HelloDDKDeviceIOControl
"));

	//得到当前堆栈
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//得到输入缓冲区大小
	ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
	//得到输出缓冲区大小
	ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
	//得到IOCTL码
	ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;

	PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
		pDevObj->DeviceExtension;

	ULONG info = 0;

	//得到用户程序传进来的微秒数
	ULONG ulMircoSecond = *(PULONG)pIrp->AssociatedIrp.SystemBuffer;

	switch (code)
	{						// process request
		case IOCTL_WAIT_METHOD1:
		{
			KdPrint(("IOCTL_WAIT_METHOD1
"));
			WaitMicroSecond1(ulMircoSecond);
			break;
		}
		case IOCTL_WAIT_METHOD2:
		{
			KdPrint(("IOCTL_WAIT_METHOD2
"));
			WaitMicroSecond2(ulMircoSecond);
			break;
		}
		case IOCTL_WAIT_METHOD3:
		{
			KdPrint(("IOCTL_WAIT_METHOD3
"));
			WaitMicroSecond3(ulMircoSecond);
			break;
		}
		case IOCTL_WAIT_METHOD4:
		{
			KdPrint(("IOCTL_WAIT_METHOD4
"));
			WaitMicroSecond4(ulMircoSecond);
			break;
		}
		default:
			status = STATUS_INVALID_VARIANT;
	}

	// 完成IRP
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = info;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint(("Leave HelloDDKDeviceIOControl
"));

	return status;
}


时间 相关的其他 内核函数:

VOID 
  KeQuerySystemTime(                  //单位时间为100NS
    OUT PLARGE_INTEGER  CurrentTime   //返回当前系统时间
    );
VOID 
  ExSystemTimeToLocalTime(            //将系统时间转换为当前时区对应的时间
    IN PLARGE_INTEGER  SystemTime,    //输入系统时间
    OUT PLARGE_INTEGER  LocalTime     //返回当前时区时间
    );
VOID 
  ExLocalTimeToSystemTime(
    IN PLARGE_INTEGER  LocalTime,     //输入当前时区时间
    OUT PLARGE_INTEGER  SystemTime    //返回系统时间
    );
BOOLEAN 
  RtlTimeFieldsToTime(                //由当前的年月日  得到系统时间
    IN PTIME_FIELDS  TimeFields,      //输入的年月日
    IN PLARGE_INTEGER  Time           //输出转换的系统时间
    );
typedef struct TIME_FIELDS {
    CSHORT Year;             //1601
    CSHORT Month;            //1-12
    CSHORT Day;
    CSHORT Hour;
    CSHORT Minute;
    CSHORT Second;
    CSHORT Milliseconds;
    CSHORT Weekday;
} TIME_FIELDS;
VOID 
  RtlTimeToTimeFields(            //将系统时间 -》 年月日等信息
    IN PLARGE_INTEGER  Time,
    IN PTIME_FIELDS  TimeFields
    );
示例:

#pragma PAGEDCODE
VOID Time_Test()
{
	LARGE_INTEGER current_system_time;
	//得到当前系统时间
	KeQuerySystemTime(¤t_system_time);

	LARGE_INTEGER current_local_time;
	//从系统时间转换成当地时区时间
	ExSystemTimeToLocalTime(¤t_system_time,¤t_local_time);

	TIME_FIELDS current_time_info;
	//由当地时区时间得到月日年信息
	RtlTimeToTimeFields(¤t_local_time,¤t_time_info);

	//显示年月日等信息
	KdPrint(("Current year:%d
",current_time_info.Year));
	KdPrint(("Current month:%d
",current_time_info.Month));
	KdPrint(("Current day:%d
",current_time_info.Day));
	KdPrint(("Current Hour:%d
",current_time_info.Hour));
	KdPrint(("Current Minute:%d
",current_time_info.Minute));
	KdPrint(("Current Second:%d
",current_time_info.Second));
	KdPrint(("Current Milliseconds:%d
",current_time_info.Milliseconds));
	KdPrint(("Current Weekday:%d
",current_time_info.Weekday));
}

#pragma PAGEDCODE
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	KdPrint(("Enter HelloDDKDeviceIOControl
"));

	//得到当前堆栈
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//得到输入缓冲区大小
	ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
	//得到输出缓冲区大小
	ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
	//得到IOCTL码
	ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;

	PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
		pDevObj->DeviceExtension;

	ULONG info = 0;

	switch (code)
	{						// process request
		case IOCTL_TIME_TEST:
		{
			KdPrint(("IOCTL_TIME_TEST
"));
			Time_Test();
			break;
		}
		default:
			status = STATUS_INVALID_VARIANT;
	}

	// 完成IRP
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = info;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint(("Leave HelloDDKDeviceIOControl
"));

	return status;
}
int main()
{
	HANDLE hDevice = 
		CreateFile("\\.\HelloDDK",
					GENERIC_READ | GENERIC_WRITE,
					0,		// share mode none
					NULL,	// no security
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL,
					NULL );		// no template

	if (hDevice == INVALID_HANDLE_VALUE)
	{
		printf("Failed to obtain file handle to device: "
			"%s with Win32 error code: %d
",
			"MyWDMDevice", GetLastError() );
		return 1;
	}

	DWORD dwOutput;

	DeviceIoControl(hDevice, IOCTL_TIME_TEST, NULL, 0, NULL, 0, &dwOutput, NULL);

	CloseHandle(hDevice);

	return 0;
}

IRP的 超时 处理:

由于硬件设备,IRP 传递到底层驱动程序后 不能及时处理,甚至可能永远不被处理,这时需要超时情况来处理
在应用程序中  CancelIO  Win32 API 函数  或者 在驱动程序中执行  IoCancelIRP 内核函数

也可以设置IRP超时, IRP超时后,操作系统会取消IRP,从而进入IRP的取消例程

示例:

1)初始化一个定时器对象 + DPC对象 ,将DPC例程 和 定时器对象进行关联

2)在每次对IRP操作前,开启定时器,设置好一定的超时

3)如果在指定时间内对IRP的处理没有结束,那么操作系统会进入DPC例程

4)这里演示IRP_MJ_READ 返回 PENDING   IRP不会结束

5)本例子  超时  3S  ,在处理超时的DPC例程中,IRP被强制结束

00000001	8.88969421	Enter DriverEntry	
00000002	8.88976192	Leave DriverEntry	
00000003	22.56484413	Enter HelloDDKDispatchRoutin	
00000004	22.56485367	 IRP_MJ_CREATE	
00000005	22.56535339	Leave HelloDDKDispatchRoutin	
00000006	22.56587219	Enter HelloDDKRead	
00000007	22.56587982	Leave HelloDDKRead	
00000008	25.56596184	Cancel the current pending irp!	
00000009	25.56675720	Enter HelloDDKRead	
00000010	25.56677437	Leave HelloDDKRead	
00000011	28.56680679	Cancel the current pending irp!	
00000012	28.61609268	Enter HelloDDKDispatchRoutin	
00000013	28.61609459	 IRP_MJ_CLEANUP	
00000014	28.61660194	Leave HelloDDKDispatchRoutin	
00000015	28.61712837	Enter HelloDDKDispatchRoutin	
00000016	28.61713028	 IRP_MJ_CLOSE	
00000017	28.61759949	Leave HelloDDKDispatchRoutin	
00000018	34.55936050	Enter DriverUnload	
内核模式 定时器学习第1张

#include "Driver.h"

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

	//设置卸载函数
	pDriverObject->DriverUnload = HelloDDKUnload;

	//设置派遣函数
	pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;
	pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;
	pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin;
	pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKRead;
	pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;
	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;
	pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin;
	pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;
	pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;

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

	KdPrint(("Leave DriverEntry
"));
	return status;
}

#pragma LOCKEDCODE
VOID OnTimerDpc( IN PKDPC pDpc,
					  IN PVOID pContext,
					  IN PVOID SysArg1,
					  IN PVOID SysArg2 ) 
{
	PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;

	PIRP currentPendingIRP = pdx->currentPendingIRP;

	KdPrint(("Cancel the current pending irp!
"));

	//设置完成状态为STATUS_CANCELLED
 	currentPendingIRP->IoStatus.Status = STATUS_CANCELLED;
 	currentPendingIRP->IoStatus.Information = 0;	// bytes xfered
 	IoCompleteRequest( currentPendingIRP, IO_NO_INCREMENT );
}

/************************************************************************
* 函数名称:CreateDevice
* 功能描述:初始化设备对象
* 参数列表:
      pDriverObject:从I/O管理器中传进来的驱动对象
* 返回 值:返回初始化状态
*************************************************************************/
#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;

	KeInitializeTimer( &pDevExt->pollingTimer );

	KeInitializeDpc( &pDevExt->pollingDPC,
						OnTimerDpc,
						(PVOID) pDevObj );

	//创建符号链接
	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;
}

/************************************************************************
* 函数名称:HelloDDKUnload
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
      pDriverObject:驱动对象
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) 
{
	PDEVICE_OBJECT	pNextObj;
	KdPrint(("Enter DriverUnload
"));
	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 );
	}
}

/************************************************************************
* 函数名称:HelloDDKDispatchRoutin
* 功能描述:对读IRP进行处理
* 参数列表:
      pDevObj:功能设备对象
      pIrp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp) 
{
	KdPrint(("Enter HelloDDKDispatchRoutin
"));

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//建立一个字符串数组与IRP类型对应起来
	static char* irpname[] = 
	{
		"IRP_MJ_CREATE",
		"IRP_MJ_CREATE_NAMED_PIPE",
		"IRP_MJ_CLOSE",
		"IRP_MJ_READ",
		"IRP_MJ_WRITE",
		"IRP_MJ_QUERY_INFORMATION",
		"IRP_MJ_SET_INFORMATION",
		"IRP_MJ_QUERY_EA",
		"IRP_MJ_SET_EA",
		"IRP_MJ_FLUSH_BUFFERS",
		"IRP_MJ_QUERY_VOLUME_INFORMATION",
		"IRP_MJ_SET_VOLUME_INFORMATION",
		"IRP_MJ_DIRECTORY_CONTROL",
		"IRP_MJ_FILE_SYSTEM_CONTROL",
		"IRP_MJ_DEVICE_CONTROL",
		"IRP_MJ_INTERNAL_DEVICE_CONTROL",
		"IRP_MJ_SHUTDOWN",
		"IRP_MJ_LOCK_CONTROL",
		"IRP_MJ_CLEANUP",
		"IRP_MJ_CREATE_MAILSLOT",
		"IRP_MJ_QUERY_SECURITY",
		"IRP_MJ_SET_SECURITY",
		"IRP_MJ_POWER",
		"IRP_MJ_SYSTEM_CONTROL",
		"IRP_MJ_DEVICE_CHANGE",
		"IRP_MJ_QUERY_QUOTA",
		"IRP_MJ_SET_QUOTA",
		"IRP_MJ_PNP",
	};

	UCHAR type = stack->MajorFunction;
	if (type >= arraysize(irpname))
		KdPrint((" - Unknown IRP, major type %X
", type));
	else
		KdPrint(("	%s
", irpname[type]));


	//对一般IRP的简单操作,后面会介绍对IRP更复杂的操作
	NTSTATUS status = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint(("Leave HelloDDKDispatchRoutin
"));

	return status;
}

NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp) 
{
	KdPrint(("Enter HelloDDKRead
"));

	PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
			pDevObj->DeviceExtension;

	//将IRP设置为挂起
	IoMarkIrpPending(pIrp);

	//将挂起的IRP记录下来
	pDevExt->currentPendingIRP = pIrp;

	//定义3秒的超时
	ULONG ulMicroSecond = 3000000;

	//将32位整数转化成64位整数
	LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMicroSecond);
	
	KeSetTimer(
		&pDevExt->pollingTimer,
		timeout,
		&pDevExt->pollingDPC );

	KdPrint(("Leave HelloDDKRead
"));

	//返回pending状态
	return STATUS_PENDING;
}













































免责声明:文章转载自《内核模式 定时器学习》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇新的nivida显卡安装时候出现unknown chipsetsicily 6272. n钱m鸡问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

bat函数调用 带返回值

bat 脚本之 使用函数 摘自:https://blog.csdn.net/peng_cao/article/details/73999076 综述 bat函数写法 bat函数调用 bat函数返回值 综述 Windows bat脚本是一种解释性的脚本语言,可以拿到做很多事情。对于稍简单的问题:比如通过注册表判断下档期机器的语言啊,国家啊,安装了那...

Linux学习之路--shell学习

shell基础知识 什么是Shell Shell是命令解释器(command interpreter),是Unix操作系统的用户接口,程序从用户接口得到输入信息,shell将用户程序及其输入翻译成操作系统内核(kernel)能够识别的指令,并且操作系统内核执行完将返回的输出通过shell再呈现给用户,下图所示用户、shell和操作系统的关系: Shell也...

Gerapy框架的安装

Gerapy 框架 安装其实很简单,但是网上有很多内容都都没有关键的一步,导致我们登录进去的时候没有内容,至此记录一下,有助于记忆。 gerapy安装: pip install gerapy 检查gerapy的安装是否成功: gerapy gerapy的初始化: gerapy init 初始化完毕以后,我们的目录中就会生成一个gerapy的文件 cd ge...

C++ 常见崩溃问题分析

一、前言 从事自动化测试平台开发的编程实践中,遭遇了几个程序崩溃问题,解决它们颇费了不少心思,解决过程中的曲折和彻夜的辗转反侧却历历在目,一直寻思写点东西,为这段难忘的经历留点纪念,总结惨痛的教训带来的经验,以期通过自己的经历为他人和自己带来福祉:写出更高质量的程序; 由于 C 和 C++ 这两种语言血缘非常近,文本亦对 C 编程语言有借鉴作用; 二、C+...

如来神掌第一式第十四招----HAPROXY详解

################################################################################ Name : Mahavairocana # Author : Mahavairocana # QQ : 10353512 # WeChat : shenlan-qianlan # Blog :...

软件开发阶段数据库升级维护策略

    软件开发阶段数据库升级维护策略 一 为什么要维护升级   1.1 现状和出现的问题 如果你开发一个的项目,没有用到数据库,那么你不用维护数据库。 如果你开发一个项目,用到数据库了,但是从不用修改,那么数据库的维护也相对的简单。 当你开发一个大的项目,数据库有很多表,视图,存储过程,数据库分成了几个,开发的团队很大,开发的周期很长,由于业务的需求数据...