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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM