向Windows内核驱动传递用户层定义的事件Event,并响应内核层的通知

完整的程序在下载:http://download.csdn.net/detail/dijkstar/7913249

 

用户层创建的事件Event是一个Handle句柄,和内核中的创建的内核模式下的KEVENT是一个东西。因此,在应用层创建的事件,可以在内核层获得并使用。这一部分的原理,见张帆编著的《Windows驱动技术详解》章节8.5.4,P237页;

程序是来自于《Windows驱动技术详解》章节8.5.4(驱动程序和应用程序交互事件对象)和章节10.2.1(DPC定时器)。

 

首先,在应用层创建一个等待事件Event,创建监控这个等待事件的线程,并把等待事件Event传递给内核:

 

  1.   //
  2.   // 1. 创建用户层的等待事件,传入内核
  3.   // 2. 创建线程,用于监测内核事件的到来
  4.   //
  5.   HANDLE hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
  6.   HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, Thread1, &hEvent, 0, NULL);
  7.    
  8.   //先将用户层的等待Event传入内核
  9.   DeviceIoControl(hDevice, IOCTL_SET_EVENT, &hEvent, sizeof(hEvent), NULL, 0, &dwOutput, NULL);

监控线程的内容:(里面用了查询指令周期数,可以测试每次等待WaitFor××的时间)

 

 

  1.   UINT WINAPI Thread1(LPVOID para)
  2.   {
  3.   HANDLE *phEvent = (HANDLE *)para;
  4.   while( 1)
  5.   {
  6.   //获得初始值
  7.   QueryPerformanceCounter(&litmp);
  8.   qt1=litmp.QuadPart;
  9.    
  10.   //等待
  11.   WaitForSingleObject(*phEvent, INFINITE);
  12.    
  13.    
  14.   //获得终止值
  15.   QueryPerformanceCounter(&litmp);
  16.   qt2=litmp.QuadPart;
  17.   //获得对应的时间值,转到毫秒单位上
  18.   dfm=( double)(qt2-qt1);
  19.   dft=dfm/dff;
  20.    
  21.    
  22.   printf( “本次等待用时: %.3f 毫秒\n”, dft* 1000.0);
  23.   }
  24.   }

用户层还通知驱动内核启动一个DPC定时器,用于每次来触发应用层的等待事件Event:

 

 

  1.   DWORD dwMircoSeconds = 1000 * 50; //单位微秒
  2.   DeviceIoControl(hDevice, IOCTL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL);

在驱动程序中,首先取出来应用层传递进来的事件,并把它转化为内核对象:

 

 

  1.   case IOCTL_SET_EVENT:
  2.   {
  3.   //把传递进来的用户层等待事件取出来
  4.   HANDLE hUserEvent = *(HANDLE *)pIrp->AssociatedIrp.SystemBuffer;
  5.    
  6.   //将用户层事件转化为内核等待对象
  7.   status = ObReferenceObjectByHandle(hUserEvent, EVENT_MODIFY_STATE,
  8.   *ExEventObjectType, KernelMode, (PVOID*)&pDevExt->pEvent, NULL);
  9.    
  10.   KdPrint(( “status = %d\n”, status)); //status应该为0才对
  11.    
  12.   ObDereferenceObject(pDevExt->pEvent);
  13.   break;
  14.   }

在内核的每次定时器到来时,激活等待事件,等于触发激活应用层的WaitFor××函数向下继续执行:

 

 

  1.   #pragma LOCKEDCODE
  2.   VOID PollingTimerDpc( IN PKDPC pDpc,
  3.   IN PVOID pContext,
  4.   IN PVOID SysArg1,
  5.   IN PVOID SysArg2 )
  6.   {
  7.   PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
  8.   PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
  9.   KeSetTimer(
  10.   &pdx->pollingTimer,
  11.   pdx->pollingInterval,
  12.   &pdx->pollingDPC );
  13.   KdPrint(( “PollingTimerDpc\n”));
  14.    
  15.   //定时器到来,通知用户层
  16.   if(pdx->pEvent)
  17.   KeSetEvent(pdx->pEvent, IO_NO_INCREMENT, FALSE);
  18.    
  19.    
  20.   /*
  21.   //检验是运行在任意线程上下文
  22.   PEPROCESS pEProcess = IoGetCurrentProcess();
  23.   PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);
  24.   KdPrint((“%s\n”,ProcessName));
  25.   */
  26.   }

程序中其他部分见源码解释,这个程序还有两个问题,一是应用层必须正常退出,否则驱动内核层因不能正常关闭DPC定时器,而继续执行已经找不到的等待事件,引起蓝屏崩溃;二是虽然在内核里,DPC定时器的触发精度为1个100ns级别,但当触发周期设置为20ms以下时,在应用层监控WaitFor,都是十几个毫秒的分辨精度,再向下设置已经没有意义。

 

 

 

jpg 改 rar