做的都是同步实现的。当然很多情况这并不是很好的解决问题。现在手上的问题是:用户层通知底层驱动(Filter Driver)做某件事,然后返回该事件执行的结果。如果该事件是一件简单的事情,这里是指极短时间内可以完成的,那么在允许范围内,我们可以用同步来完成。但是如果该事件是一件耗时的工作,而应用程序不能一直在等着该事件的完成信号,况且好像DeviceIoControl有时间限制的(?)。这就需要用异步的方式来解决问题:例如:同事叫你去吃饭,你听到后,可以马上去,也可以等会再去,吃完后再回到Office就好了。关键是我以前没有实现过,现在就手上的数资料来分析下可以实现的流程。
一、我们先看看关键函数DeviceIoControl:
- BOOL
- HANDLE
- DWORD
- LPVOID
- DWORD
- LPVOID
- DWORD
- LPDWORD
- __inout_opt LPOVERLAPPED lpOverlapped
- );
BOOL WINAPI DeviceIoControl(
__in HANDLE hDevice,
__in DWORD dwIoControlCode,
__in_opt LPVOID lpInBuffer,
__in DWORD nInBufferSize,
__out_opt LPVOID lpOutBuffer,
__in DWORD nOutBufferSize,
__out_opt LPDWORD lpBytesReturned,
__inout_opt LPOVERLAPPED lpOverlapped
);
+ ===== lpOverlapped =====
+ 一个指向OVERLAPPED结构体的指针 。
+ 如果hDevice用FILE_FLAG_OVERLAPPED 形式打开,lpOverlapped 必须指向一个合法的OVERLAPPED结构体。在这种情况下,进行异步操作 。
+ 如果hDevice用FILE_FLAG_OVERLAPPED 形式打开,而lpOverlapped为NULL,函数会返回不可预知的错误。
+ 如果hDevice打开时没有指定FILE_FLAG_OVERLAPPED 标志,lpOverlapped参数将被忽略,进行同步操作,函数直到操作完成或出现错误时才返回。
所以这里我们必须首先以FILE_FLAG_OVERLAPPED打开设备驱动。这里我们需要在CreateFile中指定:
- HANDLE
- LPCTSTR
- DWORD
- DWORD
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- DWORD
- DWORD
- HANDLE
- );
HANDLE WINAPI CreateFile(
__in LPCTSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile
);
如果dwFlagsAndAttributes指定值为:FILE_FLAG_OVERLAPPED,那么
写道
The file or device is being opened or created for asynchronous I/O.
When subsequent I/O operations are completed on this handle, the event specified in the OVERLAPPED structure will be set to the signaled state.
If this flag is specified, the file can be used for simultaneous read and write operations.
If this flag is not specified, then I/O operations are serialized, even if the calls to the read and write functions specify an OVERLAPPED structure.
For information about considerations when using a file handle created with this flag, see the Synchronous and Asynchronous I/O Handles section of this topic.
现在的问题来了,我们Overlapped的方式打开设备驱动,然后以异步的方式调用了DeviceIoControl,所以该函数会立马返回,返回值正确的应该为:ERROR_IO_PENDING 。这就表明底层驱动接受到了请求,然后应用程序应该有一种方式可以检测到该请求被底层正确执行完成的信号。
这里有个疑问:网上看到很多的例子,都是手动触发异步的完成,包括:驱动和应用层的异步通信
他们的做法没有等到最后的执行结果返回:所以在底层驱动手动设置了一些信息:
1. //获取irp状态
2. pIrp->IoStatus.Information = 0;
3. pIrp->IoStatus.Status = STATUS_SUCCESS;
4.
5. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
6. IoCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
7. switch
8. {
9. case
10. HANDLE)0, NULL, ThreadPending, NULL);
11. if
12. {
13. return
14. }
15.
16. "Pending thread ok..."));
17.
18. //直接设置为pending 返回给应用层。
19. status = STATUS_PENDING;
20. IoMarkIrpPending(pIrp);
21. pIrp->IoStatus.Status = status;
22. return
23. break;
24. }
//获取irp状态
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
IoCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
switch (IoCode)
{
case IO_TEST_PENDING:
status = PsCreateSystemThread(&hthread, (ACCESS_MASK)0L, NULL, (HANDLE)0, NULL, ThreadPending, NULL);
if (!NT_SUCCESS(status))
{
return status;
}
KdPrint(("Pending thread ok..."));
//直接设置为pending 返回给应用层。
status = STATUS_PENDING;
IoMarkIrpPending(pIrp);
pIrp->IoStatus.Status = status;
return status;
break;
}
可能他们仅仅是为了测试,没有叫底层驱动做一些复杂的事情。接着讲...
二、等待执行完成信号
这里调用WaitForSingleObject并传递设备内核对象的句柄。
WaitForSingleObject会挂起调用线程直至内核对象变成有信号态。
1. DWORD
2. HANDLE
3. DWORD
4. );
DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle,
__in DWORD dwMilliseconds
);
WaitForSingleObject 函数用来检测 hHandle事件的信号状态,当函数的执行时间超过 dwMilliseconds就返回,但如果参数 dwMilliseconds为 INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到 WaitForSingleObject 有返回直才执行后面的代码。
这里我们把它处理成一个Event,所以在调用DeviceIoControl之前,我们必须创建一个Event:
1. HANDLE
2. // 安全属性
3. BOOL bManualReset, // 复位方式
4. BOOL bInitialState, // 初始状态
5. LPCTSTR lpName // 对象名称
6. );
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全属性
BOOL bManualReset, // 复位方式
BOOL bInitialState, // 初始状态
LPCTSTR lpName // 对象名称
);
示例: // 创建一个有名的,不能被继承的,手动复原,初始状态是无信号状态的事件对象
Handle h = CreateEvent(NULL,TRUE,FALSE,“MyEvent”);
然后作为OVERLAPPED数据成员传入DeviceIoControl函数。
例如:
1. OVERLAPPED varHIDOverlapped;
2. ..
3. varEventObjectHandle = CreateEvent(NULL, TRUE, TRUE, "");
4.
5. if(varEventObjectHandle == INVALID_HANDLE_VALUE || varEventObjectHandle
6. == NULL){
7.
8. ..}
9.
10. varHIDOverlapped.hEvent = varEventObjectHandle;
11. varHIDOverlapped.Offset = 0;
12. varHIDOverlapped.OffsetHigh = 0;
13.
14. varCommand[0] = 0x05;
15. varCommand[1] = 0;
16. varCommand[2] = 0;
17. DeviceIoControl (varUSBHandle, IOCTL_USBPRINT_VENDOR_GET_COMMAND,
18. varCommand, 3, varStatus, 31, (LPDWORD)&varNumberOfBytes, (LPOVERLAPPED)
19. &varHIDOverlapped);
20.
21. varEventResult = WaitForSingleObject(varEventObjectHandle, 2000);
OVERLAPPED varHIDOverlapped;
..
varEventObjectHandle = CreateEvent(NULL, TRUE, TRUE, "");
if(varEventObjectHandle == INVALID_HANDLE_VALUE || varEventObjectHandle
== NULL){
..}
varHIDOverlapped.hEvent = varEventObjectHandle;
varHIDOverlapped.Offset = 0;
varHIDOverlapped.OffsetHigh = 0;
varCommand[0] = 0x05;
varCommand[1] = 0;
varCommand[2] = 0;
DeviceIoControl (varUSBHandle, IOCTL_USBPRINT_VENDOR_GET_COMMAND,
varCommand, 3, varStatus, 31, (LPDWORD)&varNumberOfBytes, (LPOVERLAPPED)
&varHIDOverlapped);
varEventResult = WaitForSingleObject(varEventObjectHandle, 2000);
当varEventResult返回的结果是:WAIT_OBJECT_0。表明句柄是一个signaled状态,然后应用线程接着执行余下的代码:
1. switch
2. {
3. case
4. // It works
5. break;
6.
7. case
8. // Timeout
9. varEventResult = CancelIo(varUSBHandle);
10. break;
11.
12. default:
13. break;
14. }
switch (varEventResult)
{
case WAIT_OBJECT_0:
// It works
break;
case WAIT_TIMEOUT:
// Timeout
varEventResult = CancelIo(varUSBHandle);
break;
default:
break;
}
当然你也可是这样使用:
1. // This will return immediately...
2. ULONG
3. sizeof(tcsp), NULL, NULL, &nbytes, &overlapped); // How do I handle this???
4. if
5. if
6. throw Exception("overlapped i/o exception\n");
7.
8. }
9. }
10. DWORD
11. if(GetOverlappedResult(handle_,&overlapped,&transf_byte,TRUE) == 0)
12. { //ERROR
13.
14. }
// This will return immediately...
ULONG rc = DeviceIoControl( handle_, IOCTL_TSII_BOARD_SIGNAL_AT_TIMECODE, &tcsp,
sizeof(tcsp), NULL, NULL, &nbytes, &overlapped); // How do I handle this???
if (rc == 0){
if (GetLastError() != ERROR_IO_PENDING) {
throw Exception("overlapped i/o exception\n");
}
}
DWORD transf_byte;
if(GetOverlappedResult(handle_,&overlapped,&transf_byte,TRUE) == 0)
{ //ERROR
}
关于GetOverlappedResult:
1. BOOL
2. WINAPI
3. GetOverlappedResult(
4. HANDLE
5. LPOVERLAPPED lpOverlapped,
6. LPDWORD
7. BOOL
8. )
BOOL
WINAPI
GetOverlappedResult(
HANDLE hFile,
LPOVERLAPPED lpOverlapped,
LPDWORD lpNumberOfBytesTransferred,
BOOL bWait
)
The GetOverlappedResult function returns the result of the last
operation that used lpOverlapped and returned ERROR_IO_PENDING.
这样应该就差不多可以了吧(我猜的~,细节除外)。
下面是参考资料:
- 驱动和应用层的异步通信 http://bbs.pediy.com/showthread.php?t=59015
- DeviceIoControl的异步问题http://bbs.driverdevelop.com/read.php?tid-67288.html
- WaitForSingleObject的用法http://hi.baidu.com/zouhaoo/blog/item/1e863851615e3b858d54306c.html
- 多线程中使用waitforsingleobject方法http://www.360doc.com/content/09/0428/12/27287_3299491.shtml
- DeviceIoControl return code using Overlapped I/O http://www.osronline.com/showthread.cfm?link=167510
- 应用层跟驱动异步通信的问题,irp该如何处理?http://bbs.driverdevelop.com/read.php?tid-113399.html
- DeviceIOControl and overlapped I/O problem http://forums.devshed.com/c-programming-42/deviceiocontrol-and-overlapped-i-o-problem-255708.html
- http://www.techtalkz.com/microsoft-device-drivers/295657-deviceiocontrol-overlapped.html
- DeviceIoControl and OVERLAPPED problem
前面我们谈到了关于异步I/O的实现:关于DeviceIoControl实 现异步的笔记【1】 。可是实现起来,你会发现你的程序在DevieIoControl已经被挂起,而且返回的结果是非0。这就与真正的异步调用返回结果有出入,理论上应该返回0,且GetLastError()值为ERROR_IO_PENDING。
1. /**
2. Send the packets defined by users
3. */
4. BOOL
5. {
6. BOOL
7. DWORD
8. DWORD
9. OVERLAPPED varOverLapped;
10. HANDLE
11. LPVOID
12.
13. PBYTE
14. DWORD testBufferLength = (DWORD)sizeof("Hi Mon, I finish your request!\n");
15. new BYTE[testBufferLength];
16. if(testBuffer == NULL)
17. {
18. goto
19. }
20.
21. "");
22. if(varObjectHandle == NULL)
23. goto
24. sizeof(OVERLAPPED));
25. varOverLapped.hEvent = varObjectHandle;
26. varOverLapped.Offset = 0;
27. varOverLapped.OffsetHigh = 0;
28.
29. // pass a new io control to underlying driver to send packets
30. if(!DeviceIoControl(
31. m_hFilter,
32. IOCTL_FILTER_SEND_MYOWN_PACKET,
33. "Request from user mode to Send A Packet.\n",
34. sizeof("Request from user mode to Send A Packet.\n"),
35. testBuffer,
36. testBufferLength,
37. &bytesWritten,
38. (LPOVERLAPPED)&varOverLapped))
39. {
40. //printf("Can't Send Packet\n");
41. if(GetLastError() != ERROR_IO_PENDING)
42. {
43. "Overlapped I/O exception\n");
44. goto
45. else{
46. "Overlappedn pending....\n");
47. }
48. }
49. "Son, I am calling you for dinner...\n");
50. varEventResult = WaitForSingleObject(varObjectHandle,6000);
51. switch(varEventResult)
52. {
53. case
54. "overlapped i/0 workss\n");
55. PBYTE)testBuffer;
56. "Return buffer is %s\n",pBuf);
57. result = TRUE;
58. break;
59. case
60. varEventResult = CancelIo(m_hFilter);
61. result = FALSE;
62. break;
63. default:
64. break;
65. }
66. // printf("Successfully Send A packet!^_^\n");
67. ResetEvent(varObjectHandle);
68. CloseHandle(varObjectHandle);
69. Exit:
70. delete[] testBuffer;
71. return
72. }
所以每次都不会打印Overlappedn pending....这一句,因为DeviceIoControl返回为非零。我原本愚蠢的以为,底层驱动是不需要更改就可以实现异步I/O。但是我错了,从一开始我就错了。那么亡羊补牢吧。我们进行底层驱动的处理:
由于你要求驱动做的工作不能即时完成,所以我们先返回一个PENDING状态:
1. case
2. PUCHAR)Irp->AssociatedIrp.SystemBuffer;
3. InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
4. OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
5. //这里等下讲如何叫底层驱动做该做的事情
6. //一个疑问在这里:如果像常规的函数在这里调用,那么跟同步I/O有何差异?
7. //如果不这样,有其他方法吗?
8. DEBUGP(DL_TEST,("I am waiting this io dispath\n"));
9. Status = STATUS_PENDING;
10. IoMarkIrpPending(Irp);
11. Irp->IoStatus.Status = Status;
12. return
13. break;
这里返回的状态为STATUS_PENDING,所以导致GetLastError值为ERROR_IO_PENDING,而是用overlapped i/o的异步方式导致DeviceIoControl返回为0.
别以为要做好了,还有好多疑问:
- 如何叫底层驱动做我么要他做的事情呢(很明显这里不能用常规的函数,否则当前线程就会执行这个函数的功能)
- 刚才的IRP请求到底执行结束没?
- 最后以何种方式告诉User层应用程序,某个时间已经是signaled状态,然后读取最后执行结果?
带着这个三个问题,我们继续讲:
既然不能用常规的函数,我们想想有什么方法可以让这个函数独立运行,而不受当前线程控制,答案就是在创建一个线程,负责该项工作。所以在上面的代码中间添加:
1. Status = PsCreateSystemThread(&threadHandle,
2. THREAD_ALL_ACCESS,
3. NULL,
4. NULL,
5. NULL,
6. (PKSTART_ROUTINE) printSomething,
7. Irp
8. );
9. if( !NT_SUCCESS(Status))
10. {
11. "Fail to start a thread!\n"));
12. return
13. }
注意这里传入当前IRP的指针。当该线程完成工作后,结束该IRP。
接下来看看线程调用printSomething这个函数:
1. VOID
2. printSomething(
3. IN PIRP pIrp
4. ){
5. PUCHAR
6. PUCHAR pTestBuf = "Hi Mon, I finish your request!\n";
7. ULONG bufSize = sizeof("Hi Mon, I finish your request!\n");
8. mySleepTimer(5);
9. "Five seconds,I have finished done something,hahhaha\n"));
10. pIrp->IoStatus.Status = NDIS_STATUS_SUCCESS;
11. PUCHAR)pIrp->AssociatedIrp.SystemBuffer;
12. NdisMoveMemory(OutputBuffer,pTestBuf,bufSize);
13. pIrp->IoStatus.Information = bufSize;
14. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
15. PsTerminateSystemThread(STATUS_SUCCESS);
16. }
这里,我们等待5秒钟,然后返回。返回前设置输出缓冲区的数据,返回给user,其次设置返回的状态Success等。最后调用IoCompleteRequest()函数通知User中的Event事件,把Event设置成Signaled状态,使得WaitForSignalObject函数可以继续执行。
这样才完成异步I/O的调用,其实自己细看,使用同步时,DeviceIoControl被挂起,现在使用异步,DeviceIoControl立刻返回,但是在WaitForSignalObject中挂起等待Event的状态改变。所以要真正实现异步,估计还需要在User层使用线程,用线程负责该DeviceIoControl的调用。才能真正意义上实现异步。
----------------------------------------附上MySleepTimer()------------------------------
这个函数实现的功能是延迟5秒钟。
1. VOID
2. mySleepTimer(
3. ULONG
4. ){
5. LARGE_INTEGER my_interval;
6. my_interval.QuadPart = RELATIVE(SECONDS(5));
7. KeDelayExecutionThread(KernelMode,FALSE,&my_interval);
8. }
关键是在SECONDS()的宏定义,来自Osronline的牛人写的:
1. //Define some times
2. #define ABSOLUTE(wait) (wait)
3.
4. #define RELATIVE(wait) (-(wait))
5.
6. #define NANOSECONDS(nanos) \
7. (((signed __int64)(nanos)) / 100L)
8.
9. #define MICROSECONDS(micros) \
10. (((signed __int64)(micros)) * NANOSECONDS(1000L))
11.
12. #define MILLISECONDS(milli) \
13. (((signed __int64)(milli)) * MICROSECONDS(1000L))
14.
15. #define SECONDS(seconds) \
16. (((signed __int64)(seconds)) * MILLISECONDS(1000L))
所以等相对的5秒钟就是 RELATIVE(SECONDS(5)),很强大~
------------------------------------附上图片---------------------------------
执行过程中,WaitForsignalObject被挂起:
最后执行完成:
下面是Debugview信息:
0005056 261.43447876 NDISLWF:
00005057 261.43450928 The input length is 42, and inputdata is Request from user mode to Send A Packet.
00005058 261.43450928
00005059 261.43460083 NDISLWF:
00005060 261.43460083 I am waiting this io dispath
.......
00005229 266.43710327 NDISLWF:
00005230 266.43713379 Five seconds,I have finished done something,hahhaha
-------------------参考资料-----------------
- DPC定时器何时返回的问题 http://bbs.pediy.com/showthread.php?t=110344
- 内核中线程的创建与销毁 http://hi.baidu.com/sysinternal/blog/item/f2b877084535c532e92488cc.html
- 关于DeviceIoControl异步调用的笔记【1】:http://yexin218.iteye.com/blog/638445
最后感谢两个人: 南部天天以及古越魂
用PsCreateSystemThread来在内核中创建线程。读书笔记而已,高手飘过好 了~~~~~
先用KmdManager加载驱动,然后在DebugView中查看。。。。
SysThread.c部分代码
1. NTSTATUS
2. DriverEntry(
3. IN PDRIVER_OBJECT pDriverObject,
4. IN PUNICODE_STRING regPath
5. )
6. {
7. PDEVICE_OBJECT pDeviceObject = NULL;
8. NTSTATUS ntStatus;
9. UNICODE_STRING uniNtNameString, uniWin32NameString;
10.
11.
12. RtlInitUnicodeString( &uniNtNameString, NT_DEVICE_NAME );
13. ntStatus = IoCreateDevice (
14. pDriverObject,
15. sizeof(SYSTHREAD_DEVICE_EXTENSION), // DeviceExtensionSize
16. &uniNtNameString,
17. //
18. // No standard device characteristics
19. // not exclusive device
20. &pDeviceObject
21. );
22. if( !NT_SUCCESS(ntStatus) ) {
23. return
24. }
25.
26. // 派遣函数
27. pDriverObject->MajorFunction[IRP_MJ_CREATE] = SysThreadOpen;
28. pDriverObject->MajorFunction[IRP_MJ_CLOSE] = SysThreadClose;
29. pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SysThreadDeviceIoControl;
30. pDriverObject->DriverUnload = SysThreadUnload;
31.
32. pDeviceObject->Flags |= DO_BUFFERED_IO;
33.
34.
35. RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME );
36. ntStatus = IoCreateSymbolicLink( &uniWin32NameString, &uniNtNameString );
37. if
38. IoDeleteDevice( pDriverObject->DeviceObject );
39. }
40.
41. return
42. }
43. ///
44. ///
45.
46. void
47. SysThreadUnload(
48. IN PDRIVER_OBJECT pDriverObject
49. )
50. {
51. PDEVICE_OBJECT pDeviceObject;
52. UNICODE_STRING uniWin32NameString;
53.
54. pDeviceObject = pDriverObject->DeviceObject;
55.
56. RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME );
57. IoDeleteSymbolicLink( &uniWin32NameString );
58. IoDeleteDevice( pDriverObject->DeviceObject );
59. }
60. ///
61. ///
62.
63. NTSTATUS
64. SysThreadOpen(
65. IN PDEVICE_OBJECT pDeviceObject,
66. IN PIRP pIrp
67. )
68. {
69. KdPrint((" SysThreadOpen() was Called.... \n"));
70. pIrp->IoStatus.Status = STATUS_SUCCESS;
71. pIrp->IoStatus.Information = 0;
72. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
73. return
74. }
75.
76. ///
77. ///
78.
79. NTSTATUS
80. SysThreadClose(
81. IN PDEVICE_OBJECT pDeviceObject,
82. IN PIRP pIrp
83. )
84. {
85. KdPrint((" SysThreadClose() was Called.... \n"));
86. pIrp->IoStatus.Status = STATUS_SUCCESS;
87. pIrp->IoStatus.Information = 0;
88. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
89. return
90. }
91. ///
92. ///
93.
94. NTSTATUS
95. SysThreadDeviceIoControl(
96. IN PDEVICE_OBJECT pDeviceObject,
97. IN PIRP pIrp
98. )
99. {
100. NTSTATUS ntStatus = STATUS_SUCCESS;
101. PIO_STACK_LOCATION pIrpStack;
102. PSYSTHREAD_DEVICE_EXTENSION pdx;
103. ULONG
104.
105. pdx = (PSYSTHREAD_DEVICE_EXTENSION) pDeviceObject->DeviceExtension;
106. pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
107. dwControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
108.
109. switch(dwControlCode)
110. {
111. case
112. //线程开始
113. break;
114.
115. case
116. //线程结束
117. break;
118.
119. default:
120. break;
121. }
122.
123. pIrp->IoStatus.Status = STATUS_SUCCESS;
124. pIrp->IoStatus.Information = 0;
125. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
126.
127. return
128. }
129.
130. ///
131. ///
132. NTSTATUS StartThread(PSYSTHREAD_DEVICE_EXTENSION pdx)
133. {
134. NTSTATUS status;
135. HANDLE
136. //初始化event对象
137. KeInitializeEvent(&pdx->evKill,
138. // auto reset
139. // initial state : FALSE ==> non-signaled
140. );
141. //创建ThreadProc
142. status = PsCreateSystemThread(&hthread,
143. THREAD_ALL_ACCESS,
144. NULL,
145. NULL,
146. NULL,
147. (PKSTART_ROUTINE) ThreadProc,
148. pdx
149. );
150. if( !NT_SUCCESS(status))
151. {
152. "Fail Start ThreadProc()!\n"));
153. return
154. }
155. ObReferenceObjectByHandle( hthread,
156. THREAD_ALL_ACCESS,
157. NULL,
158. KernelMode,
159. PVOID *) &pdx->thread,
160. NULL
161. );
162.
163. ZwClose(hthread);
164. return
165.
166. }
167. ///
168. ///
169.
170. VOID
171. {
172. KeSetEvent(&pdx->evKill, 0, FALSE); //通过KeSetEvent事件结束线程
173. thread, Executive, KernelMode, FALSE, NULL);
174. ObDereferenceObject(pdx->thread);
175. }
176. ///
177. ///
178. VOID
179. {
180. NTSTATUS status;
181. int
182.
183. LARGE_INTEGER timeout;
184. timeout.QuadPart = -1 * 10000000; // 1 second
185. //通过设置超时,每隔一秒打印一句话
186. while(1)
187. {
188. status = KeWaitForSingleObject(&pdx->evKill, Executive, KernelMode, FALSE, &timeout);
189. if( status == STATUS_TIMEOUT )
190. "^_^ ThreadProc()运行了%d秒!\n", cnt++));
191. else
192. break;
193. }
194. "^_^ ThreadProc()停止!\n"));
195. PsTerminateSystemThread(STATUS_SUCCESS);
196. }