zoukankan      html  css  js  c++  java
  • 向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 毫秒 ", 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 ", 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 "));
    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 ",ProcessName));
    25.  
      */
    26.  
      }

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

     

     

    jpg 改 rar 

     

     

  • 相关阅读:
    Windows Socket编程简介
    IIS7.0 Appcmd 命令详解
    VC显示网页验证码、模拟CSDN网页登录
    c++对象初始化中 ZeroMemory、memset、直接赋0的区别
    在MFC程序中显示 JPG/GIF图像
    开始学习WTL——(1)关于STL/ATL/WTL之间的区别
    可编辑子项的CListCtrl类
    VC添加自定义消息
    VC调用JavaScript函数--处理QQ网页登录密码加密(空间、农场、WEB QQ等)
    VC创建定时关闭的MessageBox
  • 原文地址:https://www.cnblogs.com/kuangke/p/9397830.html
Copyright © 2011-2022 走看看