Windows驱动开发-DPC定时器
DCP是一种使用更加灵活的定时器,可以对任意间隔时间进行定时。DPC定时器的内部使用了一个定时器对象KTIMER,当你设定了定时器之后,从设定开始起经过这个时间之后操作系统会将一个DPC定时器的例程插入到DPC的队列,操作系统读取DPC队列的时候定时器例程就能够被执行。这里的DPC定时器例程就相当于一个定时器的回调函数。
在使用需要一些相关的初始化操作
1,初始化Timer
VOID KeInitializeTimer(PKTIMER Timer); //参数Timer是定时器的指针
2,初始化DPC对象
VOID KeInitializeDpc(PRKDPC Dpc,PKDEFERRED_ROUTINE DeferredRoutine,PVOID DeferredContext); //Dpc是输入参数DPC的对象指针 //DeferredRoutine是一个与DPC关联的定时器例程函数,当定时器被触发的时候这个例程函数就会被执行调用 //DeferredContext是一个传入定时器例程的参数
3,当初始化完成之后使用函数KeSetTimer函数开启定时器,
BOOLEAN KeSetTimer( PKTIMER Timer,LARGE_INTEGER DueTime,PKDPC Dpc); //Timer是定时器对象的指针. //DueTimer这个参数是设定的时间间隔. //Dpc表示传入定时器例程的参数. //返回值:BOOL类型的,表示成功或者失败.
4,取消定时器使用内核函数KeCancelTimer,
BOOLEAN KeCancelTimer(PKTIMER Timer);
在调用KeSetTimer函数之后,经过DueTime的时间,操作系统会调用一次定时器的例程,其中如果DueTime是一个正整数,则会代表绝对时间,也就是相对于1601年1月1日到触发DPC定时器的那个时刻,如果DueTime是负数,那它表示的是间隔多长时间,DueTime的单位是100ns。
示例代码:
用户层
#define IO_CONTROL_TRANSMIT_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN,0x8080,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IO_CONTROL_START_TIMER CTL_CODE(FILE_DEVICE_UNKNOWN,0x8081,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IO_CONTROL_STOP_TIMER CTL_CODE(FILE_DEVICE_UNKNOWN,0x8082,METHOD_IN_DIRECT,FILE_ANY_ACCESS) int main() { HANDLE hDevice = CreateFile(L"\\\\.\\MyDeviceSymbolLinkName01", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDevice == INVALID_HANDLE_VALUE) { printf("failed to obtain file handle to device with win32 error code %d ...\n", GetLastError()); return 1; } DWORD dwOutput; DWORD dwMircoSeconds = 1000 * 1000 * 2;//100ns一个单位 //发送启动定时器命令 DeviceIoControl(hDevice, IO_CONTROL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL); Sleep(20000); //发送终止定时器命令 DeviceIoControl(hDevice, IO_CONTROL_STOP_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL); CloseHandle(hDevice); return 0; }
驱动层:
//FirstDriver.h #pragma once #define IO_CONTROL_TRANSMIT_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN,0x8080,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IO_CONTROL_START_TIMER CTL_CODE(FILE_DEVICE_UNKNOWN,0x8081,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IO_CONTROL_STOP_TIMER CTL_CODE(FILE_DEVICE_UNKNOWN,0x8082,METHOD_IN_DIRECT,FILE_ANY_ACCESS) typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT pDevObj; UNICODE_STRING ustrDeviceName; UNICODE_STRING ustrSymbolLinkName; KDPC pollingDPC; KTIMER pollingTimer; LARGE_INTEGER pollingInterVal; }DEVICE_EXTENSION, * PDEVICE_EXTENSION; NTSTATUS unload(PDRIVER_OBJECT driver); NTSTATUS DemoDeviceControlDispatch(PDEVICE_OBJECT pDeviceObject, PIRP pIrp); NTSTATUS DeviceCreate(PDEVICE_OBJECT pDeviceObject, PIRP pIrp); NTSTATUS DeviceClose(PDEVICE_OBJECT pDeviceObject, PIRP pIrp); NTSTATUS DemoCreateDevice(PDRIVER_OBJECT pDriver, PCWSTR devName, PCWSTR devSymName);
//FirstDriver.c #include <ntddk.h> #include "FirstDriver.h" NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) { NTSTATUS ntstatus = STATUS_SUCCESS; driver->DriverUnload = unload; driver->MajorFunction[IRP_MJ_CREATE] = DeviceCreate;//创建 driver->MajorFunction[IRP_MJ_CLOSE] = DeviceClose;//关闭 driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DemoDeviceControlDispatch; ntstatus = DemoCreateDevice(driver, L"\\Device\\MyDevice01", L"\\??\\MyDeviceSymbolLinkName01"); if (!NT_SUCCESS(ntstatus)) { DbgPrint("IoCreateDevice Failed"); return ntstatus; } DbgPrint("%ws", reg_path->Buffer); DbgPrint("driver load success..."); return STATUS_SUCCESS; } VOID PollingTimerDPC(PKDPC pDpc, PVOID pContext, PVOID SysArg1, 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")); //检验是运行在任意线程上下文 PEPROCESS pEProcess = IoGetCurrentProcess(); PTSTR ProcessName = (PTSTR)((LONGLONG)pEProcess + 0x174); DbgPrint("多余参数 %d , %d , %d", pDpc->Number, SysArg1, SysArg2); DbgPrint("%s\n", ProcessName); } NTSTATUS DemoDeviceControlDispatch(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { NTSTATUS ntstatus = STATUS_SUCCESS; DbgPrint("enter DemoDeviceControlDispatch ...\n"); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); //ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength; //ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength; ULONG ctlCode = stack->Parameters.DeviceIoControl.IoControlCode; PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension; ULONG info = 0; switch (ctlCode) { case IO_CONTROL_START_TIMER: { KdPrint(("IOCTL_START_TIMER!\n")); //从用户模式传进来的超时 ULONG ulMircoSeconds = *(PULONG)pIrp->AssociatedIrp.SystemBuffer; pDevExt->pollingInterVal = RtlConvertLongToLargeInteger(ulMircoSeconds * -10); KeSetTimer(&pDevExt->pollingTimer, pDevExt->pollingInterVal, &pDevExt->pollingDPC); break; } case IO_CONTROL_STOP_TIMER: { KdPrint(("IOCTL_STOP_TIMER!\n")); KeCancelTimer(&pDevExt->pollingTimer); break; } default: ntstatus = STATUS_INVALID_VARIANT; break; } pIrp->IoStatus.Status = ntstatus; pIrp->IoStatus.Information = info; IoCompleteRequest(pIrp, IO_NO_INCREMENT); DbgPrint("leave the demo device control dispatch ..."); DbgPrint("device io control test success...%d", pDeviceObject->ActiveThreadCount); return ntstatus; } NTSTATUS DeviceCreate(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { //业务代码区 //设置返回状态 pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); DbgPrint("create device success...%d", pDeviceObject->ActiveThreadCount); return STATUS_SUCCESS; } NTSTATUS DeviceClose(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { //业务代码区 //设置返回状态 pIrp->IoStatus.Status = STATUS_SUCCESS;//getLastError()得到的值 pIrp->IoStatus.Information = 0; //返回给3环多少数据,没有填0 IoCompleteRequest(pIrp, IO_NO_INCREMENT); DbgPrint("close device success...%d", pDeviceObject->ActiveThreadCount); return STATUS_SUCCESS; } NTSTATUS DemoCreateDevice(PDRIVER_OBJECT pDriver, PCWSTR devName, PCWSTR devSymName) { PDEVICE_OBJECT pDevice; PDEVICE_EXTENSION pDevExt; UNICODE_STRING DeviceName; UNICODE_STRING SymbolLinkName; RtlInitUnicodeString(&DeviceName, devName); RtlInitUnicodeString(&SymbolLinkName, devSymName); NTSTATUS ntstatus = STATUS_SUCCESS; ntstatus = IoCreateDevice(pDriver, sizeof(DEVICE_EXTENSION), &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevice); if (!NT_SUCCESS(ntstatus)) { DbgPrint("IoCreateDevice Failed"); return ntstatus; } ntstatus = IoCreateSymbolicLink(&SymbolLinkName, &DeviceName); if (!NT_SUCCESS(ntstatus)) { DbgPrint("IoCreateSymbolicLink Failed"); IoDeleteDevice(pDevice); return ntstatus; } pDevice->Flags |= DO_BUFFERED_IO; pDevExt = (PDEVICE_EXTENSION)pDevice->DeviceExtension; pDevExt->pDevObj = pDevice; pDevExt->ustrDeviceName = DeviceName; pDevExt->ustrSymbolLinkName = SymbolLinkName; KeInitializeTimer(&pDevExt->pollingTimer); KeInitializeDpc(&pDevExt->pollingDPC, PollingTimerDPC, (PVOID)pDevice); return ntstatus; } NTSTATUS unload(PDRIVER_OBJECT driver) { PDEVICE_OBJECT pDev; DbgPrint("driver :%ws unload", driver->DriverName.Buffer); pDev = driver->DeviceObject; while (pDev != NULL) { PDEVICE_EXTENSION pDevExt = { 0 }; pDevExt = (PDEVICE_EXTENSION)pDev->DeviceExtension; //删除符号链接 UNICODE_STRING pLinkName = pDevExt->ustrSymbolLinkName; DbgPrint("this is the divice name : %ws", pLinkName.Buffer); IoDeleteSymbolicLink(&pLinkName); pDev = pDev->NextDevice; IoDeleteDevice(pDevExt->pDevObj); } DbgPrint("driver unload success..."); return STATUS_SUCCESS; }