Kernel Mode Driver Framework >> C/C++ (PNP) >> Timer
DPC
參考資訊:
1. Source Code
由於I/O Timer的Timer間隔固定為一秒,如果使用者想要可以彈性設定的Timer間隔,則需要使用DPC Timer,使用的步驟:
1. KeInitializeTimer()
2. KeInitializeDpc()
3. KeSetTimer()
4. KeCancelTimer()
DPC Timer如果使用KeSetTimer()做設定時,其Timer為一次性,也就是Callback僅會被呼叫一次,如果要使用週期性Timer,則需要改用KeSetTimerEx(),KeSetTimerEx()宣告如下:
BOOLEAN KeSetTimerEx(PKTIMER Timer, LARGE_INTEGER DueTime, LONG Period, PKDPC Dpc);
DueTime是第一次Timer的間隔,之後的間隔則使用Period數值。
main.c
#include <ntddk.h> #include <wdf.h> #define DEV_NAME L"\\Device\\MyDriver" #define SYM_NAME L"\\DosDevices\\MyDriver" #define IOCTL_START CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_STOP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) KDPC dpc; KTIMER obj; ULONG cnt=0; PDEVICE_OBJECT pDevice; VOID OnTimer(struct _KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2) { cnt+= 1; DbgPrint("DpcTimer: %d\n", cnt); } void IrpFileCreate(WDFDEVICE Device, WDFREQUEST Request, WDFFILEOBJECT FileObject) { DbgPrint("IrpFieCreate"); WdfRequestComplete(Request, STATUS_SUCCESS); } void IrpFileClose(WDFFILEOBJECT FileObject) { DbgPrint("IrpFieClose"); } void IrpIOCTL(WDFQUEUE Queue, WDFREQUEST Request, size_t OutputBufferLength, size_t InputBufferLength, ULONG IoControlCode) { LARGE_INTEGER tt; switch(IoControlCode){ case IOCTL_START: DbgPrint("IOCTL_START"); cnt = 0; tt.HighPart|= -1; tt.LowPart = (ULONG)-10000000; KeSetTimerEx(&obj, tt, 1000, &dpc); break; case IOCTL_STOP: DbgPrint("IOCTL_STOP"); KeCancelTimer(&obj); break; } WdfRequestComplete(Request, STATUS_SUCCESS); } NTSTATUS AddDevice(WDFDRIVER Driver, PWDFDEVICE_INIT pDeviceInit) { WDFDEVICE device; UNICODE_STRING suDevName; UNICODE_STRING szSymName; WDF_FILEOBJECT_CONFIG file_cfg; WDF_IO_QUEUE_CONFIG ioqueue_cfg; RtlInitUnicodeString(&suDevName, DEV_NAME); RtlInitUnicodeString(&szSymName, SYM_NAME); WdfDeviceInitAssignName(pDeviceInit, &suDevName); WdfDeviceInitSetIoType(pDeviceInit, WdfDeviceIoBuffered); WDF_FILEOBJECT_CONFIG_INIT(&file_cfg, IrpFileCreate, IrpFileClose, NULL); WdfDeviceInitSetFileObjectConfig(pDeviceInit, &file_cfg, WDF_NO_OBJECT_ATTRIBUTES); WdfDeviceCreate(&pDeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &device); WdfDeviceCreateSymbolicLink(device, &szSymName); pDevice = WdfDeviceWdmGetDeviceObject(device); KeInitializeTimer(&obj); KeInitializeDpc(&dpc, OnTimer, pDevice); WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioqueue_cfg, WdfIoQueueDispatchSequential); ioqueue_cfg.EvtIoDeviceControl = IrpIOCTL; return WdfIoQueueCreate(device, &ioqueue_cfg, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE); } NTSTATUS DriverEntry(PDRIVER_OBJECT pOurDriver, PUNICODE_STRING pRegistry) { WDF_DRIVER_CONFIG config; WDF_DRIVER_CONFIG_INIT(&config, AddDevice); return WdfDriverCreate(pOurDriver, pRegistry, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE); }
AddDevice()初始化Timer以及DPC Object
IrpIOCTL()啟動或停止DPC Timer
OnTimer()僅列印訊息,其餘事情不做
app.c
#define INITGUID #include <windows.h> #include <winioctl.h> #include <strsafe.h> #include <setupapi.h> #include <stdio.h> #include <stdlib.h> #define IOCTL_START CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_STOP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) int __cdecl main(int argc, char* argv[]) { HANDLE hFile = NULL; DWORD dwRet = 0; hFile = CreateFile("\\\\.\\MyDriver", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("failed to open mydriver\n"); return -1; } DeviceIoControl(hFile, IOCTL_START, NULL, 0, NULL, 0, &dwRet, NULL); Sleep(3000); DeviceIoControl(hFile, IOCTL_STOP, NULL, 0, NULL, 0, &dwRet, NULL); CloseHandle(hFile); return 0; }
結果