完整的程序在下载: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传递给内核:
-
-
-
-
-
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, Thread1, &hEvent, 0, NULL);
-
-
-
DeviceIoControl(hDevice, IOCTL_SET_EVENT, &hEvent, sizeof(hEvent), NULL, 0, &dwOutput, NULL);
监控线程的内容:(里面用了查询指令周期数,可以测试每次等待WaitFor××的时间)
-
UINT WINAPI Thread1(LPVOID para)
-
-
HANDLE *phEvent = (HANDLE *)para;
-
-
-
-
QueryPerformanceCounter(&litmp);
-
-
-
-
WaitForSingleObject(*phEvent, INFINITE);
-
-
-
-
QueryPerformanceCounter(&litmp);
-
-
-
-
-
-
-
printf("本次等待用时: %.3f 毫秒\n", dft*1000.0);
-
-
用户层还通知驱动内核启动一个DPC定时器,用于每次来触发应用层的等待事件Event:
-
DWORD dwMircoSeconds = 1000 * 50;
-
DeviceIoControl(hDevice, IOCTL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
在驱动程序中,首先取出来应用层传递进来的事件,并把它转化为内核对象:
-
-
-
-
HANDLE hUserEvent = *(HANDLE *)pIrp->AssociatedIrp.SystemBuffer;
-
-
-
status = ObReferenceObjectByHandle(hUserEvent, EVENT_MODIFY_STATE,
-
*ExEventObjectType, KernelMode, (PVOID*)&pDevExt->pEvent, NULL);
-
-
KdPrint(("status = %d\n", status));
-
-
ObDereferenceObject(pDevExt->pEvent);
-
-
在内核的每次定时器到来时,激活等待事件,等于触发激活应用层的WaitFor××函数向下继续执行:
-
-
VOID PollingTimerDpc( IN PKDPC pDpc,
-
-
-
-
-
PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
-
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
-
-
-
-
-
KdPrint(("PollingTimerDpc\n"));
-
-
-
-
KeSetEvent(pdx->pEvent, IO_NO_INCREMENT, FALSE);
-
-
-
-
-
-
-
-
-
程序中其他部分见源码解释,这个程序还有两个问题,一是应用层必须正常退出,否则驱动内核层因不能正常关闭DPC定时器,而继续执行已经找不到的等待事件,引起蓝屏崩溃;二是虽然在内核里,DPC定时器的触发精度为1个100ns级别,但当触发周期设置为20ms以下时,在应用层监控WaitFor,都是十几个毫秒的分辨精度,再向下设置已经没有意义。
jpg 改 rar