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 ...
", 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
"));

    //检验是运行在任意线程上下文
    PEPROCESS pEProcess = IoGetCurrentProcess();

    PTSTR ProcessName = (PTSTR)((LONGLONG)pEProcess + 0x174);

    DbgPrint("多余参数 %d , %d , %d", pDpc->Number, SysArg1, SysArg2);
    DbgPrint("%s
", ProcessName);
}

NTSTATUS DemoDeviceControlDispatch(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
    NTSTATUS ntstatus = STATUS_SUCCESS;
    DbgPrint("enter DemoDeviceControlDispatch ...
");
    
    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!
"));

        //从用户模式传进来的超时
        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!
"));

        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;
}
原文地址:https://www.cnblogs.com/a-s-m/p/12356432.html