29、定时器

一般两种方法使用/设置定时器,一种是使用I/O定时器例程,一种是使用DPC例程。

1、定时器的实现

1)使用I/O定时器例程

NTSTATUS

IoInitializeTimer(

IN PDEVICE_OBJECT DeviceObject,

IN PIO_TIMER_ROUTINE TimerRoutine,

IN PVOID Context

);

IoStartTimer

IoStopTimer

开启定时器后,每隔1s系统调用一次定时器例程。TimerRoutine运行在DISPATCH_LEVEL级别,因此不能有分页内存。另外I/O定时器是运行在任意线程的,不能直接使用应用程序的内存地址。

29、定时器 代码
   
     
1 // .h
2   // 设定3秒间隔时间
3   #define TIMER_OUT 3
4
5 typedef struct _DEVICE_EXTENSION {
6 PDEVICE_OBJECT pDevice;
7 UNICODE_STRING ustrDeviceName; // 设备名称
8   UNICODE_STRING ustrSymLinkName; // 符号链接名
9  
10 LONG lTimerCount;
11 } DEVICE_EXTENSION, * PDEVICE_EXTENSION;
12   // .cpp
13   #pragma LOCKEDCODE
14 VOID OnTimer(
15 IN PDEVICE_OBJECT DeviceObject,
16 IN PVOID Context)
17 {
18 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
19 DeviceObject -> DeviceExtension;
20 KdPrint(( " Enter OnTimer!\n " ));
21
22 // 将计数器自锁减一
23 InterlockedDecrement( & pDevExt -> lTimerCount);
24
25 // 如果计数器减到0,重新编程TIMER_OUT,整个过程是互锁运算
26 LONG previousCount = InterlockedCompareExchange( & pDevExt -> lTimerCount,TIMER_OUT, 0 );
27
28 // 每隔三秒,计数器一个循环,输出以下log
29 if (previousCount == 0 )
30 {
31 KdPrint(( " %d seconds time out!\n " ,TIMER_OUT));
32 }
33
34 // 证明该线程运行在任意线程上下文的
35 PEPROCESS pEProcess = IoGetCurrentProcess();
36
37 PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174 ); // 即可得到用户进程
38
39 KdPrint(( " The current process is %s\n " ,ProcessName));
40 }
41
42
43 /* ***********************************************************************
44 * 函数名称:CreateDevice
45 * 功能描述:初始化设备对象
46 * 参数列表:
47 pDriverObject:从I/O管理器中传进来的驱动对象
48 * 返回 值:返回初始化状态
49 ************************************************************************ */
50 #pragma INITCODE
51 NTSTATUS CreateDevice (
52 IN PDRIVER_OBJECT pDriverObject)
53 {
54 NTSTATUS status;
55 PDEVICE_OBJECT pDevObj;
56 PDEVICE_EXTENSION pDevExt;
57
58 // 创建设备名称
59 UNICODE_STRING devName;
60 RtlInitUnicodeString( & devName,L " \\Device\\MyDDKDevice " );
61
62 // 创建设备
63 status = IoCreateDevice( pDriverObject,
64 sizeof (DEVICE_EXTENSION),
65 & (UNICODE_STRING)devName,
66 FILE_DEVICE_UNKNOWN,
67 0 , TRUE,
68 & pDevObj );
69 if ( ! NT_SUCCESS(status))
70 return status;
71
72 pDevObj -> Flags |= DO_DIRECT_IO;
73 pDevExt = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
74 pDevExt -> pDevice = pDevObj;
75 pDevExt -> ustrDeviceName = devName;
76
77 IoInitializeTimer(pDevObj,OnTimer,NULL);
78
79 // 创建符号链接
80 UNICODE_STRING symLinkName;
81 RtlInitUnicodeString( & symLinkName,L " \\??\\HelloDDK " );
82 pDevExt -> ustrSymLinkName = symLinkName;
83 status = IoCreateSymbolicLink( & symLinkName, & devName );
84 if ( ! NT_SUCCESS(status))
85 {
86 IoDeleteDevice( pDevObj );
87 return status;
88 }
89 return STATUS_SUCCESS;
90 }
91 #pragma PAGEDCODE
92 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
93 IN PIRP pIrp)
94 {
95 NTSTATUS status = STATUS_SUCCESS;
96 KdPrint(( " Enter HelloDDKDeviceIOControl\n " ));
97
98 // 得到当前堆栈
99 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
100 // 得到输入缓冲区大小
101 ULONG cbin = stack -> Parameters.DeviceIoControl.InputBufferLength;
102 // 得到输出缓冲区大小
103 ULONG cbout = stack -> Parameters.DeviceIoControl.OutputBufferLength;
104 // 得到IOCTL码
105 ULONG code = stack -> Parameters.DeviceIoControl.IoControlCode;
106
107 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
108 pDevObj -> DeviceExtension;
109
110 ULONG info = 0 ;
111
112 switch (code)
113 { // process request
114 case IOCTL_START_TIMER:
115 {
116 KdPrint(( " IOCTL_START_TIMER\n " ));
117 pDevExt -> lTimerCount = TIMER_OUT;
118 IoStartTimer(pDevObj);
119 break ;
120 }
121 case IOCTL_STOP:
122 {
123 KdPrint(( " IOCTL_STOP\n " ));
124 IoStopTimer(pDevObj);
125 break ;
126 }
127 default :
128 status = STATUS_INVALID_VARIANT;
129 }
130
131 // 完成IRP
132 pIrp -> IoStatus.Status = status;
133 pIrp -> IoStatus.Information = info; // bytes xfered
134 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
135
136 KdPrint(( " Leave HelloDDKDeviceIOControl\n " ));
137
138 return status;
139 }

 

29、定时器 代码
   
     
1 #include < windows.h >
2 #include < stdio.h >
3 // 使用CTL_CODE必须加入winioctl.h
4 #include < winioctl.h >
5 #include " ..\NT_Driver\Ioctls.h "
6
7 int main()
8 {
9 HANDLE hDevice =
10 CreateFile( " \\\\.\\HelloDDK " ,
11 GENERIC_READ | GENERIC_WRITE,
12 0 , // share mode none
13 NULL, // no security
14 OPEN_EXISTING,
15 FILE_ATTRIBUTE_NORMAL,
16 NULL ); // no template
17
18 if (hDevice == INVALID_HANDLE_VALUE)
19 {
20 printf( " Failed to obtain file handle to device: "
21 " %s with Win32 error code: %d\n " ,
22 " MyWDMDevice " , GetLastError() );
23 return 1 ;
24 }
25
26 DWORD dwOutput;
27
28 DeviceIoControl(hDevice, IOCTL_START_TIMER, NULL, 0 , NULL, 0 , & dwOutput, NULL);
29
30 Sleep( 10000 );
31
32 DeviceIoControl(hDevice, IOCTL_STOP, NULL, 0 , NULL, 0 , & dwOutput, NULL);
33
34 CloseHandle(hDevice);
35
36 return 0 ;
37 }

 

示例代码 P278

2)使用DPC例程

DPC定时器内部使用定时器对象KTIMER,当指定的时间间隔到达后,OS会将一个DPC例程插入DPC队列。

KeInitializeTimer

KeInitializeDpc

BOOLEAN

KeSetTimer(

IN PKTIMER Timer,

IN LARGE_INTEGER DueTime, //设定时间间隔

IN PKDPC Dpc OPTIONAL

);

如果DueTime为正数,则该时间表示从1601/01/01到触发DPC例程的那个时刻,单位是100ns,如果为负数,意味着间隔多长时间,单位也是100ns

在调用KeSetTimer后,触发一次DPC例程,如果想周期触发,则需要在DPC触发后,再次调用KeSetTimer

KeInitializeDpc

29、定时器 代码
   
     
1 // .h
2 // 设定3秒间隔时间
3 #define TIMER_OUT 3
4
5 typedef struct _DEVICE_EXTENSION {
6 PDEVICE_OBJECT pDevice;
7 UNICODE_STRING ustrDeviceName; // 设备名称
8 UNICODE_STRING ustrSymLinkName; // 符号链接名
9
10 KDPC pollingDPC; // 存储DPC对象
11 KTIMER pollingTimer; // 存储计时器对象
12 LARGE_INTEGER pollingInterval; // 记录计时器间隔时间
13 } DEVICE_EXTENSION, * PDEVICE_EXTENSION;
14 // .cpp
15 #pragma LOCKEDCODE
16 VOID PollingTimerDpc( IN PKDPC pDpc,
17 IN PVOID pContext,
18 IN PVOID SysArg1,
19 IN PVOID SysArg2 )
20 {
21 PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
22 PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
23 KeSetTimer(
24 & pdx -> pollingTimer,
25 pdx -> pollingInterval,
26 & pdx -> pollingDPC );
27 KdPrint(( " PollingTimerDpc\n " ));
28
29 // 检验是运行在任意线程上下文
30 PEPROCESS pEProcess = IoGetCurrentProcess();
31
32 PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174 );
33
34 KdPrint(( " %s\n " ,ProcessName));
35 }
36 /* ***********************************************************************
37 * 函数名称:CreateDevice
38 * 功能描述:初始化设备对象
39 * 参数列表:
40 pDriverObject:从I/O管理器中传进来的驱动对象
41 * 返回 值:返回初始化状态
42 ************************************************************************ */
43 #pragma INITCODE
44 NTSTATUS CreateDevice (
45 IN PDRIVER_OBJECT pDriverObject)
46 {
47 NTSTATUS status;
48 PDEVICE_OBJECT pDevObj;
49 PDEVICE_EXTENSION pDevExt;
50
51 // 创建设备名称
52 UNICODE_STRING devName;
53 RtlInitUnicodeString( & devName,L " \\Device\\MyDDKDevice " );
54
55 // 创建设备
56 status = IoCreateDevice( pDriverObject,
57 sizeof (DEVICE_EXTENSION),
58 & (UNICODE_STRING)devName,
59 FILE_DEVICE_UNKNOWN,
60 0 , TRUE,
61 & pDevObj );
62 if ( ! NT_SUCCESS(status))
63 return status;
64
65 pDevObj -> Flags |= DO_DIRECT_IO;
66 pDevExt = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
67 pDevExt -> pDevice = pDevObj;
68 pDevExt -> ustrDeviceName = devName;
69
70 KeInitializeTimer( & pDevExt -> pollingTimer );
71
72 KeInitializeDpc( & pDevExt -> pollingDPC,
73 PollingTimerDpc,
74 (PVOID) pDevObj );
75
76 // 创建符号链接
77 UNICODE_STRING symLinkName;
78 RtlInitUnicodeString( & symLinkName,L " \\??\\HelloDDK " );
79 pDevExt -> ustrSymLinkName = symLinkName;
80 status = IoCreateSymbolicLink( & symLinkName, & devName );
81 if ( ! NT_SUCCESS(status))
82 {
83 IoDeleteDevice( pDevObj );
84 return status;
85 }
86 return STATUS_SUCCESS;
87 }
88 #pragma PAGEDCODE
89 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
90 IN PIRP pIrp)
91 {
92 NTSTATUS status = STATUS_SUCCESS;
93 KdPrint(( " Enter HelloDDKDeviceIOControl\n " ));
94
95 // 得到当前堆栈
96 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
97 // 得到输入缓冲区大小
98 ULONG cbin = stack -> Parameters.DeviceIoControl.InputBufferLength;
99 // 得到输出缓冲区大小
100 ULONG cbout = stack -> Parameters.DeviceIoControl.OutputBufferLength;
101 // 得到IOCTL码
102 ULONG code = stack -> Parameters.DeviceIoControl.IoControlCode;
103
104 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
105 pDevObj -> DeviceExtension;
106
107 ULONG info = 0 ;
108
109 switch (code)
110 { // process request
111 case IOCTL_START_TIMER:
112 {
113 KdPrint(( " IOCTL_START_TIMER!\n " ));
114
115 // 从用户模式传进来的超时
116 ULONG ulMircoSeconds = * (PULONG)pIrp -> AssociatedIrp.SystemBuffer;
117
118 pDevExt -> pollingInterval = RtlConvertLongToLargeInteger( ulMircoSeconds * - 10 );
119
120 KeSetTimer(
121 & pDevExt -> pollingTimer,
122 pDevExt -> pollingInterval,
123 & pDevExt -> pollingDPC );
124 break ;
125 }
126 case IOCTL_STOP_TIMER:
127 {
128 KdPrint(( " IOCTL_STOP_TIMER!\n " ));
129
130 KeCancelTimer( & pDevExt -> pollingTimer);
131
132 break ;
133 }
134 default :
135 status = STATUS_INVALID_VARIANT;
136 }
137
138 // 完成IRP
139 pIrp -> IoStatus.Status = status;
140 pIrp -> IoStatus.Information = info; // bytes xfered
141 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
142
143 KdPrint(( " Leave HelloDDKDeviceIOControl\n " ));
144
145 return status;
146 }
147 // main
148 #include < windows.h >
149 #include < stdio.h >
150 // 使用CTL_CODE必须加入winioctl.h
151 #include < winioctl.h >
152 #include " ..\NT_Driver\Ioctls.h "
153
154 int main()
155 {
156 HANDLE hDevice =
157 CreateFile( " \\\\.\\HelloDDK " ,
158 GENERIC_READ | GENERIC_WRITE,
159 0 , // share mode none
160 NULL, // no security
161 OPEN_EXISTING,
162 FILE_ATTRIBUTE_NORMAL,
163 NULL ); // no template
164
165 if (hDevice == INVALID_HANDLE_VALUE)
166 {
167 printf( " Failed to obtain file handle to device: "
168 " %s with Win32 error code: %d\n " ,
169 " MyWDMDevice " , GetLastError() );
170 return 1 ;
171 }
172
173 DWORD dwOutput;
174 DWORD dwMircoSeconds = 1000 * 1000 * 2 ;
175
176 DeviceIoControl(hDevice, IOCTL_START_TIMER, & dwMircoSeconds, sizeof (DWORD), NULL, 0 , & dwOutput, NULL);
177
178 Sleep( 10000 );
179
180 DeviceIoControl(hDevice, IOCTL_STOP_TIMER, NULL, 0 , NULL, 0 , & dwOutput, NULL);
181
182 CloseHandle(hDevice);
183
184 return 0 ;
185 }

 

示例代码 P282

DPC例程运行在DISPATCH_LEVEL级别。

2、等待

1KeWaitForSingleObject

2KeDelayExecutionThread KeWaitForSingleObject类似,都是强制当前线程进入睡眠状态。

3KeStallExecutionProcessor 其让CPU处于忙等待,而不是睡眠,类似于自旋锁。浪费CPU时间,不宜超过50us

4)使用定时器

定时器对象同其它内核对象一样,也有两个状态:激发与未激发态。初始化时未激发态,使用KeSetTimer后,经过指定时间后,变成激发态,可以用KeWaitForSingleObject来进行等待。

29、定时器 代码
   
     
1 #pragma PAGEDCODE
2 VOID WaitMicroSecond1(ULONG ulMircoSecond)
3 {
4 KEVENT kEvent;
5
6 KdPrint(( " Thread suspends %d MircoSeconds... " ,ulMircoSecond));
7
8 // 初始化一个未激发的内核事件
9 KeInitializeEvent( & kEvent,SynchronizationEvent,FALSE);
10
11 // 等待时间的单位是100纳秒,将微秒转换成这个单位
12 // 负数代表是从此刻到未来的某个时刻
13 LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( - 10 * ulMircoSecond);
14
15 // 在经过timeout后,线程继续运行
16 KeWaitForSingleObject( & kEvent,
17 Executive,
18 KernelMode,
19 FALSE,
20 & timeout);
21
22 KdPrint(( " Thread is running again!\n " ));
23 }
24
25 #pragma PAGEDCODE
26 VOID WaitMicroSecond2(ULONG ulMircoSecond)
27 {
28 KdPrint(( " Thread suspends %d MircoSeconds... " ,ulMircoSecond));
29
30 // 等待时间的单位是100纳秒,将微秒转换成这个单位
31 // 负数代表是从此刻到未来的某个时刻
32 LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( - 10 * ulMircoSecond);
33
34 // 此种方法类似于KeWaitForSingleObject
35 // 将当前线程进入睡眠状态,间隔时间到转入运行状态
36 KeDelayExecutionThread(KernelMode,FALSE, & timeout);
37
38 KdPrint(( " Thread is running again!\n " ));
39 }
40
41 #pragma PAGEDCODE
42 VOID WaitMicroSecond3(ULONG ulMircoSecond)
43 {
44 KdPrint(( " Thread suspends %d MircoSeconds... " ,ulMircoSecond));
45
46 // 忙等待,此种方法属于忙等待,比较浪费CPU时间
47 // 因此使用该方法不宜超过50微秒
48 KeStallExecutionProcessor(ulMircoSecond);
49
50 KdPrint(( " Thread is running again!\n " ));
51 }
52
53 #pragma PAGEDCODE
54 VOID WaitMicroSecond4(ULONG ulMircoSecond)
55 {
56 // 使用计时器
57
58 KTIMER kTimer; // 内核计时器
59
60 // 初始化计时器
61 KeInitializeTimer( & kTimer);
62
63 LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( ulMircoSecond * - 10 );
64
65 // 注意这个计时器没有和DPC对象关联
66 KeSetTimer( & kTimer,timeout, NULL);
67 KdPrint(( " Thread suspends %d MircoSeconds... " ,ulMircoSecond));
68
69 KeWaitForSingleObject( & kTimer,Executive,KernelMode,FALSE,NULL);
70
71 KdPrint(( " Thread is running again!\n " ));
72 }
73 #pragma PAGEDCODE
74 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
75 IN PIRP pIrp)
76 {
77 NTSTATUS status = STATUS_SUCCESS;
78 KdPrint(( " Enter HelloDDKDeviceIOControl\n " ));
79
80 // 得到当前堆栈
81 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
82 // 得到输入缓冲区大小
83 ULONG cbin = stack -> Parameters.DeviceIoControl.InputBufferLength;
84 // 得到输出缓冲区大小
85 ULONG cbout = stack -> Parameters.DeviceIoControl.OutputBufferLength;
86 // 得到IOCTL码
87 ULONG code = stack -> Parameters.DeviceIoControl.IoControlCode;
88
89 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
90 pDevObj -> DeviceExtension;
91
92 ULONG info = 0 ;
93
94 // 得到用户程序传进来的微秒数
95 ULONG ulMircoSecond = * (PULONG)pIrp -> AssociatedIrp.SystemBuffer;
96
97 switch (code)
98 { // process request
99 case IOCTL_WAIT_METHOD1:
100 {
101 KdPrint(( " IOCTL_WAIT_METHOD1\n " ));
102 WaitMicroSecond1(ulMircoSecond);
103 break ;
104 }
105 case IOCTL_WAIT_METHOD2:
106 {
107 KdPrint(( " IOCTL_WAIT_METHOD2\n " ));
108 WaitMicroSecond2(ulMircoSecond);
109 break ;
110 }
111 case IOCTL_WAIT_METHOD3:
112 {
113 KdPrint(( " IOCTL_WAIT_METHOD3\n " ));
114 WaitMicroSecond3(ulMircoSecond);
115 break ;
116 }
117 case IOCTL_WAIT_METHOD4:
118 {
119 KdPrint(( " IOCTL_WAIT_METHOD4\n " ));
120 WaitMicroSecond4(ulMircoSecond);
121 break ;
122 }
123 default :
124 status = STATUS_INVALID_VARIANT;
125 }
126
127 // 完成IRP
128 pIrp -> IoStatus.Status = status;
129 pIrp -> IoStatus.Information = info; // bytes xfered
130 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
131
132 KdPrint(( " Leave HelloDDKDeviceIOControl\n " ));
133
134 return status;
135 }
136 // .cpp
137 #include < windows.h >
138 #include < stdio.h >
139 // 使用CTL_CODE必须加入winioctl.h
140 #include < winioctl.h >
141 #include " ..\NT_Driver\Ioctls.h "
142
143 int main()
144 {
145 HANDLE hDevice =
146 CreateFile( " \\\\.\\HelloDDK " ,
147 GENERIC_READ | GENERIC_WRITE,
148 0 , // share mode none
149 NULL, // no security
150 OPEN_EXISTING,
151 FILE_ATTRIBUTE_NORMAL,
152 NULL ); // no template
153
154 if (hDevice == INVALID_HANDLE_VALUE)
155 {
156 printf( " Failed to obtain file handle to device: "
157 " %s with Win32 error code: %d\n " ,
158 " MyDDKDevice " , GetLastError() );
159 return 1 ;
160 }
161
162 DWORD dwOutput;
163
164 DWORD dwMicroSecond = 1000 ;
165 DeviceIoControl(hDevice, IOCTL_WAIT_METHOD1, & dwMicroSecond, sizeof (DWORD), NULL, 0 , & dwOutput, NULL);
166 DeviceIoControl(hDevice, IOCTL_WAIT_METHOD2, & dwMicroSecond, sizeof (DWORD), NULL, 0 , & dwOutput, NULL);
167 DeviceIoControl(hDevice, IOCTL_WAIT_METHOD3, & dwMicroSecond, sizeof (DWORD), NULL, 0 , & dwOutput, NULL);
168 DeviceIoControl(hDevice, IOCTL_WAIT_METHOD4, & dwMicroSecond, sizeof (DWORD), NULL, 0 , & dwOutput, NULL);
169
170 CloseHandle(hDevice);
171
172 return 0 ;
173 }

 

示例代码 P286

3、其它相关函数

获取当前系统时间:KeQuerySystemTime

This value is computed for the GMT time zone. To adjust this value for the local time zone use ExSystemTimeToLocalTime.(在控制面板中设置)

RtlTimeFieldsToTime converts TIME_FIELDS information to a system time value

RtlTimeToTimeFields

29、定时器 代码
   
     
1 /* ***********************************************************************
2 * 函数名称:DriverEntry
3 * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
4 * 参数列表:
5 pDriverObject:从I/O管理器中传进来的驱动对象
6 pRegistryPath:驱动程序在注册表的中的路径
7 * 返回 值:返回初始化驱动状态
8 ************************************************************************ */
9 #pragma INITCODE
10 extern " C " NTSTATUS DriverEntry (
11 IN PDRIVER_OBJECT pDriverObject,
12 IN PUNICODE_STRING pRegistryPath )
13 {
14 NTSTATUS status;
15 KdPrint(( " Enter DriverEntry\n " ));
16
17 // 设置卸载函数
18 pDriverObject -> DriverUnload = HelloDDKUnload;
19
20 // 设置派遣函数
21 for ( int i = 0 ; i < arraysize(pDriverObject -> MajorFunction); ++ i)
22 pDriverObject -> MajorFunction[i] = HelloDDKDispatchRoutin;
23
24 pDriverObject -> MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDeviceIOControl;
25
26 // 创建驱动设备对象
27 status = CreateDevice(pDriverObject);
28
29 KdPrint(( " Leave DriverEntry\n " ));
30 return status;
31 }
32 #pragma PAGEDCODE
33 VOID Time_Test()
34 {
35 LARGE_INTEGER current_system_time;
36 // 得到当前系统时间
37 KeQuerySystemTime( & current_system_time);
38
39 LARGE_INTEGER current_local_time;
40 // 从系统时间转换成当地时区时间
41 ExSystemTimeToLocalTime( & current_system_time, & current_local_time);
42
43 TIME_FIELDS current_time_info;
44 // 由当地时区时间得到月日年信息
45 RtlTimeToTimeFields( & current_local_time, & current_time_info);
46
47 // 显示年月日等信息
48 KdPrint(( " Current year:%d\n " ,current_time_info.Year));
49 KdPrint(( " Current month:%d\n " ,current_time_info.Month));
50 KdPrint(( " Current day:%d\n " ,current_time_info.Day));
51 KdPrint(( " Current Hour:%d\n " ,current_time_info.Hour));
52 KdPrint(( " Current Minute:%d\n " ,current_time_info.Minute));
53 KdPrint(( " Current Second:%d\n " ,current_time_info.Second));
54 KdPrint(( " Current Milliseconds:%d\n " ,current_time_info.Milliseconds));
55 KdPrint(( " Current Weekday:%d\n " ,current_time_info.Weekday));
56 }
57
58 #pragma PAGEDCODE
59 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
60 IN PIRP pIrp)
61 {
62 NTSTATUS status = STATUS_SUCCESS;
63 KdPrint(( " Enter HelloDDKDeviceIOControl\n " ));
64
65 // 得到当前堆栈
66 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
67 // 得到输入缓冲区大小
68 ULONG cbin = stack -> Parameters.DeviceIoControl.InputBufferLength;
69 // 得到输出缓冲区大小
70 ULONG cbout = stack -> Parameters.DeviceIoControl.OutputBufferLength;
71 // 得到IOCTL码
72 ULONG code = stack -> Parameters.DeviceIoControl.IoControlCode;
73
74 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
75 pDevObj -> DeviceExtension;
76
77 ULONG info = 0 ;
78
79 switch (code)
80 { // process request
81 case IOCTL_TIME_TEST:
82 {
83 KdPrint(( " IOCTL_TIME_TEST\n " ));
84 Time_Test();
85 break ;
86 }
87 default :
88 status = STATUS_INVALID_VARIANT;
89 }
90
91 // 完成IRP
92 pIrp -> IoStatus.Status = status;
93 pIrp -> IoStatus.Information = info; // bytes xfered
94 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
95
96 KdPrint(( " Leave HelloDDKDeviceIOControl\n " ));
97
98 return status;
99 }
100
101 DWORD dwOutput;
102 DeviceIoControl(hDevice, IOCTL_TIME_TEST, NULL, 0 , NULL, 0 , & dwOutput, NULL);
103 CloseHandle(hDevice);

 

示例代码 P288

4IRP超时处理

规定时间内对某一设备的操作没有反应,则可以取消该操作。应用程序中使用CancelIo,驱动中用IoCancelIrp,来取消操作。也可以通过设置IRP超时,来取消IRO,这时进入IRP取消例程。

1)初始个定时器和DPC例程,进行关联。

2)操作IRP前,开户定时器,超时进入DPC例程。

3)如果超时前结束该IRP操作,则应取消定时器。

29、定时器 代码
   
     
1 typedef struct _DEVICE_EXTENSION {
2 PDEVICE_OBJECT pDevice;
3 UNICODE_STRING ustrDeviceName; // 设备名称
4 UNICODE_STRING ustrSymLinkName; // 符号链接名
5
6 KDPC pollingDPC; // 存储DPC对象
7 KTIMER pollingTimer; // 存储计时器对象
8 PIRP currentPendingIRP; // 记录当前挂起的IRP
9 } DEVICE_EXTENSION, * PDEVICE_EXTENSION;
10
11 pDriverObject -> MajorFunction[IRP_MJ_READ] = HelloDDKRead;
12
13 #pragma LOCKEDCODE
14 VOID OnTimerDpc( IN PKDPC pDpc,
15 IN PVOID pContext,
16 IN PVOID SysArg1,
17 IN PVOID SysArg2 )
18 {
19 PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
20 PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
21
22 PIRP currentPendingIRP = pdx -> currentPendingIRP;
23
24 KdPrint(( " Cancel the current pending irp!\n " ));
25
26 // 设置完成状态为STATUS_CANCELLED
27 currentPendingIRP -> IoStatus.Status = STATUS_CANCELLED;
28 currentPendingIRP -> IoStatus.Information = 0 ; // bytes xfered
29 IoCompleteRequest( currentPendingIRP, IO_NO_INCREMENT );
30 }
31
32 /* ***********************************************************************
33 * 函数名称:CreateDevice
34 * 功能描述:初始化设备对象
35 * 参数列表:
36 pDriverObject:从I/O管理器中传进来的驱动对象
37 * 返回 值:返回初始化状态
38 ************************************************************************ */
39 #pragma INITCODE
40 NTSTATUS CreateDevice (
41 IN PDRIVER_OBJECT pDriverObject)
42 {
43 NTSTATUS status;
44 PDEVICE_OBJECT pDevObj;
45 PDEVICE_EXTENSION pDevExt;
46
47 // 创建设备名称
48 UNICODE_STRING devName;
49 RtlInitUnicodeString( & devName,L " \\Device\\MyDDKDevice " );
50
51 // 创建设备
52 status = IoCreateDevice( pDriverObject,
53 sizeof (DEVICE_EXTENSION),
54 & (UNICODE_STRING)devName,
55 FILE_DEVICE_UNKNOWN,
56 0 , TRUE,
57 & pDevObj );
58 if ( ! NT_SUCCESS(status))
59 return status;
60
61 pDevObj -> Flags |= DO_BUFFERED_IO;
62 pDevExt = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
63 pDevExt -> pDevice = pDevObj;
64 pDevExt -> ustrDeviceName = devName;
65
66 KeInitializeTimer( & pDevExt -> pollingTimer );
67
68 KeInitializeDpc( & pDevExt -> pollingDPC,
69 OnTimerDpc,
70 (PVOID) pDevObj );
71
72 // 创建符号链接
73 UNICODE_STRING symLinkName;
74 RtlInitUnicodeString( & symLinkName,L " \\??\\HelloDDK " );
75 pDevExt -> ustrSymLinkName = symLinkName;
76 status = IoCreateSymbolicLink( & symLinkName, & devName );
77 if ( ! NT_SUCCESS(status))
78 {
79 IoDeleteDevice( pDevObj );
80 return status;
81 }
82 return STATUS_SUCCESS;
83 }
84
85 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
86 IN PIRP pIrp)
87 {
88 KdPrint(( " Enter HelloDDKRead\n " ));
89
90 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
91 pDevObj -> DeviceExtension;
92
93 // 将IRP设置为挂起
94 IoMarkIrpPending(pIrp);
95
96 // 将挂起的IRP记录下来
97 pDevExt -> currentPendingIRP = pIrp;
98
99 // 定义3秒的超时
100 ULONG ulMicroSecond = 3000000 ;
101
102 // 将32位整数转化成64位整数
103 LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( - 10 * ulMicroSecond);
104
105 KeSetTimer(
106 & pDevExt -> pollingTimer,
107 timeout,
108 & pDevExt -> pollingDPC );
109
110 KdPrint(( " Leave HelloDDKRead\n " ));
111
112 // 返回pending状态
113 return STATUS_PENDING;
114 }
115
116 // main
117 #include < windows.h >
118 #include < stdio.h >
119 #include < process.h >
120
121 int main()
122 {
123 HANDLE hDevice =
124 CreateFile( " \\\\.\\HelloDDK " ,
125 GENERIC_READ | GENERIC_WRITE,
126 FILE_SHARE_READ,
127 NULL,
128 OPEN_EXISTING,
129 FILE_ATTRIBUTE_NORMAL,
130 NULL );
131
132 if (hDevice == INVALID_HANDLE_VALUE)
133 {
134 printf( " Open Device failed! " );
135 return 1 ;
136 }
137
138 DWORD dwRead;
139
140 // 如果读IRP没有被完成,ReadFile一直都不会退出!
141 ReadFile(hDevice,NULL, 0 , & dwRead,NULL);
142
143 ReadFile(hDevice,NULL, 0 , & dwRead,NULL);
144
145 CloseHandle(hDevice);
146
147 return 0 ;
148 }

 

示例代码 P290

你可能感兴趣的:(定时器)