关于DeviceIoControl实现异步的笔记

做的都是同步实现的。当然很多情况这并不是很好的解决问题。现在手上的问题是:用户层通知底层驱动(Filter Driver)做某件事,然后返回该事件执行的结果。如果该事件是一件简单的事情,这里是指极短时间内可以完成的,那么在允许范围内,我们可以用同步来完成。但是如果该事件是一件耗时的工作,而应用程序不能一直在等着该事件的完成信号,况且好像DeviceIoControl有时间限制的(?)。这就需要用异步的方式来解决问题:例如:同事叫你去吃饭,你听到后,可以马上去,也可以等会再去,吃完后再回到Office就好了。关键是我以前没有实现过,现在就手上的数资料来分析下可以实现的流程。

一、我们先看看关键函数DeviceIoControl:

Cpp代码 复制代码  收藏代码
  1. BOOL WINAPI DeviceIoControl(   
  2.   __in         HANDLE hDevice,   
  3.   __in         DWORD dwIoControlCode,   
  4.   __in_opt     LPVOID lpInBuffer,   
  5.   __in         DWORD nInBufferSize,   
  6.   __out_opt    LPVOID lpOutBuffer,   
  7.   __in         DWORD nOutBufferSize,   
  8.   __out_opt    LPDWORD lpBytesReturned,   
  9.   __inout_opt  LPOVERLAPPED lpOverlapped   
  10. );  
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中指定:

Cpp代码 复制代码  收藏代码
  1. HANDLE WINAPI CreateFile(   
  2.   __in      LPCTSTR lpFileName,   
  3.   __in      DWORD dwDesiredAccess,   
  4.   __in      DWORD dwShareMode,   
  5.   __in_opt  LPSECURITY_ATTRIBUTES lpSecurityAttributes,   
  6.   __in      DWORD dwCreationDisposition,   
  7.   __in      DWORD dwFlagsAndAttributes,   
  8.   __in_opt  HANDLE hTemplateFile   
  9. );  
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 。这就表明底层驱动接受到了请求,然后应用程序应该有一种方式可以检测到该请求被底层正确执行完成的信号。

这里有个疑问:网上看到很多的例子,都是手动触发异步的完成,包括:驱动和应用层的异步通信

他们的做法没有等到最后的执行结果返回:所以在底层驱动手动设置了一些信息:

Cpp代码 复制代码  收藏代码
  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 (IoCode)   
  8.     {   
  9.     case IO_TEST_PENDING:   
  10.         status = PsCreateSystemThread(&hthread, (ACCESS_MASK)0L, NULL, (HANDLE)0, NULL, ThreadPending, NULL);   
  11.         if (!NT_SUCCESS(status))   
  12.         {   
  13.             return status;   
  14.         }   
  15.            
  16.         KdPrint(("Pending thread ok..."));   
  17.   
  18.     //直接设置为pending 返回给应用层。   
  19.         status = STATUS_PENDING;   
  20.         IoMarkIrpPending(pIrp);   
  21.         pIrp->IoStatus.Status = status;   
  22.         return status;   
  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会挂起调用线程直至内核对象变成有信号态。 

Cpp代码 复制代码  收藏代码
  1. DWORD WINAPI WaitForSingleObject(   
  2.   __in  HANDLE hHandle,   
  3.   __in  DWORD dwMilliseconds   
  4. );  
DWORD WINAPI WaitForSingleObject(
  __in  HANDLE hHandle,
  __in  DWORD dwMilliseconds
);

 

WaitForSingleObject 函数用来检测 hHandle 事件的信号状态,当函数的执行时间超过 dwMilliseconds 就返回,但如果参数 dwMilliseconds INFINITE 时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到 WaitForSingleObject 有返回直才执行后面的代码。

这里我们把它处理成一个Event,所以在调用DeviceIoControl之前,我们必须创建一个Event:

 

Cpp代码 复制代码  收藏代码
  1. HANDLE CreateEvent(      
  2.   LPSECURITY_ATTRIBUTES lpEventAttributes,   // 安全属性      
  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函数。

例如:

Cpp代码 复制代码  收藏代码
  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状态,然后应用线程接着执行余下的代码:

Cpp代码 复制代码  收藏代码
  1. switch (varEventResult)   
  2. {   
  3. case WAIT_OBJECT_0:   
  4. // It works   
  5. break;   
  6.   
  7. case WAIT_TIMEOUT:   
  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;
}

 

当然你也可是这样使用:

Cpp代码 复制代码  收藏代码
  1.  // This will return immediately...    
  2. ULONG rc = DeviceIoControl( handle_, IOCTL_TSII_BOARD_SIGNAL_AT_TIMECODE, &tcsp,    
  3. sizeof(tcsp), NULL, NULL, &nbytes, &overlapped); // How do I handle this???   
  4.  if (rc == 0){    
  5.      if (GetLastError() != ERROR_IO_PENDING) {    
  6.                throw Exception("overlapped i/o exception\n");   
  7.         
  8.       }   
  9.     }    
  10. DWORD  transf_byte;   
  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:

Cpp代码 复制代码  收藏代码
  1. BOOL  
  2. WINAPI   
  3. GetOverlappedResult(   
  4.     HANDLE hFile,   
  5.     LPOVERLAPPED lpOverlapped,   
  6.     LPDWORD lpNumberOfBytesTransferred,   
  7.     BOOL bWait   
  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.

这样应该就差不多可以了吧(我猜的~,细节除外)。

下面是参考资料:

  1. 驱动和应用层的异步通信 http://bbs.pediy.com/showthread.php?t=59015
  2. DeviceIoControl的异步问题http://bbs.driverdevelop.com/read.php?tid-67288.html
  3. WaitForSingleObject的用法http://hi.baidu.com/zouhaoo/blog/item/1e863851615e3b858d54306c.html
  4. 多线程中使用waitforsingleobject方法http://www.360doc.com/content/09/0428/12/27287_3299491.shtml
  5. DeviceIoControl return code using Overlapped I/O http://www.osronline.com/showthread.cfm?link=167510
  6. 应用层跟驱动异步通信的问题,irp该如何处理?http://bbs.driverdevelop.com/read.php?tid-113399.html
  7. DeviceIOControl and overlapped I/O problem http://forums.devshed.com/c-programming-42/deviceiocontrol-and-overlapped-i-o-problem-255708.html
  8. http://www.techtalkz.com/microsoft-device-drivers/295657-deviceiocontrol-overlapped.html
  9. DeviceIoControl and OVERLAPPED problem

前面我们谈到了关于异步I/O的实现:关于DeviceIoControl实 现异步的笔记【1】 。可是实现起来,你会发现你的程序在DevieIoControl已经被挂起,而且返回的结果是非0。这就与真正的异步调用返回结果有出入,理论上应该返回0,且GetLastError()值为ERROR_IO_PENDING。

C代码   收藏代码
  1. /** 
  2.    Send the packets defined by users 
  3. */  
  4. BOOL FilterWrapper::SendMyOwnPacket()  
  5. {  
  6.    BOOL result = FALSE;  
  7.    DWORD bytesWritten = 0;  
  8.    DWORD varEventResult;  
  9.    OVERLAPPED varOverLapped;  
  10.    HANDLE varObjectHandle = 0;  
  11.    LPVOID testBuffer = NULL;   
  12.   
  13.    PBYTE pBuf = NULL;  
  14.    DWORD testBufferLength = (DWORD)sizeof("Hi Mon, I finish your request!\n");    
  15.    testBuffer =  new BYTE[testBufferLength];    
  16.     if(testBuffer == NULL)    
  17.     {    
  18.     goto Exit;    
  19.     }   
  20.      
  21.    varObjectHandle = CreateEvent(NULL,TRUE, TRUE,"");  
  22.    if(varObjectHandle == NULL)  
  23.       goto Exit;  
  24.    memset(&varOverLapped,0,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.           printf("Overlapped I/O exception\n");  
  44.           goto Exit;  
  45.         }else{  
  46.           printf("Overlappedn pending....\n");  
  47.        }          
  48.     }  
  49.     printf("Son, I am calling you for dinner...\n");  
  50.     varEventResult = WaitForSingleObject(varObjectHandle,6000);  
  51.     switch(varEventResult)  
  52.     {  
  53.       case WAIT_OBJECT_0 :  
  54.            printf("overlapped i/0 workss\n");  
  55.            pBuf = (PBYTE)testBuffer;  
  56.            printf("Return buffer is %s\n",pBuf);  
  57.            result = TRUE;  
  58.            break;  
  59.       case WAIT_TIMEOUT:  
  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 result;  
  72. }     

 所以每次都不会打印Overlappedn pending....这一句,因为DeviceIoControl返回为非零。我原本愚蠢的以为,底层驱动是不需要更改就可以实现异步I/O。但是我错了,从一开始我就错了。那么亡羊补牢吧。我们进行底层驱动的处理:

由于你要求驱动做的工作不能即时完成,所以我们先返回一个PENDING状态:

C代码   收藏代码
  1. case IOCTL_FILTER_SEND_MYOWN_PACKET:  
  2.         InputBuffer = OutputBuffer = (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 Status;  
  13.     break;  

 这里返回的状态为STATUS_PENDING,所以导致GetLastError值为ERROR_IO_PENDING,而是用overlapped i/o的异步方式导致DeviceIoControl返回为0.

别以为要做好了,还有好多疑问:

 

  1. 如何叫底层驱动做我么要他做的事情呢(很明显这里不能用常规的函数,否则当前线程就会执行这个函数的功能)
  2. 刚才的IRP请求到底执行结束没?
  3. 最后以何种方式告诉User层应用程序,某个时间已经是signaled状态,然后读取最后执行结果?

带着这个三个问题,我们继续讲:

既然不能用常规的函数,我们想想有什么方法可以让这个函数独立运行,而不受当前线程控制,答案就是在创建一个线程,负责该项工作。所以在上面的代码中间添加:

C代码   收藏代码
  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.             DEBUGP(DL_TEST,("Fail to start a thread!\n"));  
  12.              return Status;  
  13.        }      

 注意这里传入当前IRP的指针。当该线程完成工作后,结束该IRP。

接下来看看线程调用printSomething这个函数:

Cpp代码   收藏代码
  1. VOID  
  2. printSomething(  
  3.    IN PIRP    pIrp  
  4.    ){  
  5.      PUCHAR    OutputBuffer = NULL;  
  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.      DEBUGP(DL_TEST,("Five seconds,I have finished done something,hahhaha\n"));  
  10.      pIrp->IoStatus.Status = NDIS_STATUS_SUCCESS;  
  11.      OutputBuffer = (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秒钟。

C代码   收藏代码
  1. VOID   
  2. mySleepTimer(  
  3.    IN ULONG time  
  4. ){  
  5.    LARGE_INTEGER my_interval;  
  6.    my_interval.QuadPart = RELATIVE(SECONDS(5));  
  7.    KeDelayExecutionThread(KernelMode,FALSE,&my_interval);  
  8. }  

 关键是在SECONDS()的宏定义,来自Osronline的牛人写的:

Cpp代码   收藏代码
  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 

-------------------参考资料-----------------

  1. DPC定时器何时返回的问题 http://bbs.pediy.com/showthread.php?t=110344
  2. 内核中线程的创建与销毁 http://hi.baidu.com/sysinternal/blog/item/f2b877084535c532e92488cc.html
  3. 关于DeviceIoControl异步调用的笔记【1】:http://yexin218.iteye.com/blog/638445

最后感谢两个人: 南部天天以及古越魂



用PsCreateSystemThread来在内核中创建线程。读书笔记而已,高手飘过好 了~~~~~

先用KmdManager加载驱动,然后在DebugView中查看。。。。

SysThread.c部分代码

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.                            FILE_DEVICE_UNKNOWN,         //  
  18.                            0,              // No standard device characteristics  
  19.                            FALSE,             // not exclusive device  
  20.                            &pDeviceObject  
  21.                            );  
  22. if( !NT_SUCCESS(ntStatus) ) {  
  23.          return ntStatus;  
  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 (!NT_SUCCESS(ntStatus)){  
  38.          IoDeleteDevice( pDriverObject->DeviceObject );  
  39. }  
  40.   
  41. return ntStatus;  
  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 STATUS_SUCCESS;  
  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 STATUS_SUCCESS;  
  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 dwControlCode;  
  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 IOCTL_SYSTHREAD_START:  
  112.           StartThread(pdx);          //线程开始  
  113.           break;  
  114.   
  115.          case IOCTL_SYSTHREAD_STOP:  
  116.           StopThread(pdx);          //线程结束  
  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 ntStatus;  
  128. }  
  129.   
  130. ///  
  131. ///  
  132. NTSTATUS StartThread(PSYSTHREAD_DEVICE_EXTENSION pdx)  
  133. {  
  134. NTSTATUS status;  
  135. HANDLE hthread;  
  136.            //初始化event对象  
  137. KeInitializeEvent(&pdx->evKill,  
  138.              SynchronizationEvent, // auto reset  
  139.              FALSE                   // 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.                KdPrint(("Fail Start ThreadProc()!\n"));  
  153.                return status;  
  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 STATUS_SUCCESS;  
  165.   
  166. }  
  167. ///  
  168. ///  
  169.   
  170. VOID StopThread(PSYSTHREAD_DEVICE_EXTENSION pdx)  
  171. {  
  172. KeSetEvent(&pdx->evKill, 0, FALSE); //通过KeSetEvent事件结束线程  
  173.            KeWaitForSingleObject(pdx->thread, Executive, KernelMode, FALSE, NULL);  
  174. ObDereferenceObject(pdx->thread);  
  175. }  
  176. ///  
  177. ///  
  178. VOID ThreadProc(PSYSTHREAD_DEVICE_EXTENSION pdx)  
  179. {  
  180. NTSTATUS status;  
  181. int cnt = 0;  
  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.           KdPrint(("^_^ ThreadProc()运行了%d秒!\n", cnt++));  
  191.          else  
  192.           break;  
  193. }  
  194.            KdPrint(("^_^ ThreadProc()停止!\n"));  
  195. PsTerminateSystemThread(STATUS_SUCCESS);  
  196. }  


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值