zoukankan      html  css  js  c++  java
  • 内核模式 定时器学习


    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	
    

    #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;
    }













































  • 相关阅读:
    Vue实现的mini计算器
    动态 WebApi 引擎使用教程(3行代码完成动态 WebApi 构建)
    [备忘] 解决 rzc discover exited with code -2147450730 问题
    一个由于侵入框架引起的故障
    计算机基础--01
    csharp: read xml
    Hystrix 原理深入分析-spring cloud 入门教程
    Hystrix 简介-spring cloud 入门教程
    linux下使用 du查看某个文件或目录占用磁盘空间的大小
    最火的Spring Cloud Gateway 为经过身份验证的用户启用速率限制实践-spring cloud 入门教程
  • 原文地址:https://www.cnblogs.com/zcc1414/p/3982454.html
Copyright © 2011-2022 走看看