完整的程序在下载: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. 创建线程,用于监测内核事件的到来 // HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, Thread1, &hEvent, 0, NULL); //先将用户层的等待Event传入内核 DeviceIoControl(hDevice, IOCTL_SET_EVENT, &hEvent, sizeof(hEvent), NULL, 0, &dwOutput, NULL);
UINT WINAPI Thread1(LPVOID para) { HANDLE *phEvent = (HANDLE *)para; while(1) { //获得初始值 QueryPerformanceCounter(&litmp); qt1=litmp.QuadPart; //等待 WaitForSingleObject(*phEvent, INFINITE); //获得终止值 QueryPerformanceCounter(&litmp); qt2=litmp.QuadPart; //获得对应的时间值,转到毫秒单位上 dfm=(double)(qt2-qt1); dft=dfm/dff; printf("本次等待用时: %.3f 毫秒\n", dft*1000.0); } }
DWORD dwMircoSeconds = 1000 * 50; //单位微秒 DeviceIoControl(hDevice, IOCTL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
case IOCTL_SET_EVENT: { //把传递进来的用户层等待事件取出来 HANDLE hUserEvent = *(HANDLE *)pIrp->AssociatedIrp.SystemBuffer; //将用户层事件转化为内核等待对象 status = ObReferenceObjectByHandle(hUserEvent, EVENT_MODIFY_STATE, *ExEventObjectType, KernelMode, (PVOID*)&pDevExt->pEvent, NULL); KdPrint(("status = %d\n", status));//status应该为0才对 ObDereferenceObject(pDevExt->pEvent); break; }
#pragma LOCKEDCODE VOID PollingTimerDpc( IN PKDPC pDpc, IN PVOID pContext, IN PVOID SysArg1, IN PVOID SysArg2 ) { PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; KeSetTimer( &pdx->pollingTimer, pdx->pollingInterval, &pdx->pollingDPC ); KdPrint(("PollingTimerDpc\n")); //定时器到来,通知用户层 if(pdx->pEvent) KeSetEvent(pdx->pEvent, IO_NO_INCREMENT, FALSE); /* //检验是运行在任意线程上下文 PEPROCESS pEProcess = IoGetCurrentProcess(); PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174); KdPrint(("%s\n",ProcessName)); */ }