• Timer和DPC


    一般两种方法使用/设置定时器,一种是使用I/O定时器例程,一种是使用DPC例程。
    1、定时器的实现
    1)使用I/O定时器例程
    NTSTATUS
    IoInitializeTimer(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIO_TIMER_ROUTINE TimerRoutine,
    IN PVOID Context
    );
    IoStartTimer
    IoStopTimer
    开启定时器后,每隔1s系统调用一次定时器例程。TimerRoutine运行在DISPATCH_LEVEL级别,因此不能有分页内存。另外I/O定时器是运行在任意线程的,不能直接使用应用程序的内存地址。

      1 // .h
      2  //设定3秒间隔时间
      3  #define TIMER_OUT    3
      4
      5 typedef struct _DEVICE_EXTENSION {
      6     PDEVICE_OBJECT pDevice;
      7     UNICODE_STRING ustrDeviceName;    //设备名称
      8      UNICODE_STRING ustrSymLinkName;    //符号链接名
      9  
     10     LONG lTimerCount;
     11 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
     12  //.cpp
     13  #pragma LOCKEDCODE
     14 VOID OnTimer(
     15     IN PDEVICE_OBJECT DeviceObject,
     16     IN PVOID Context)
     17 {
     18     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
     19         DeviceObject->DeviceExtension;
     20     KdPrint(("Enter OnTimer! "));
     21
     22     //将计数器自锁减一
     23     InterlockedDecrement(&pDevExt->lTimerCount);
     24    
     25     //如果计数器减到0,重新编程TIMER_OUT,整个过程是互锁运算
     26     LONG previousCount = InterlockedCompareExchange(&pDevExt->lTimerCount,TIMER_OUT,0);
     27
     28     //每隔三秒,计数器一个循环,输出以下log
     29     if (previousCount==0)
     30     {
     31         KdPrint(("%d seconds time out! ",TIMER_OUT));
     32     }
     33
     34     //证明该线程运行在任意线程上下文的
     35     PEPROCESS pEProcess = IoGetCurrentProcess();
     36   
     37     PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);//即可得到用户进程
     38
     39     KdPrint(("The current process is %s ",ProcessName));
     40 }
     41
     42
     43 /************************************************************************
     44 * 函数名称:CreateDevice
     45 * 功能描述:初始化设备对象
     46 * 参数列表:
     47       pDriverObject:从I/O管理器中传进来的驱动对象
     48 * 返回 值:返回初始化状态
     49 *************************************************************************/
     50 #pragma INITCODE
     51 NTSTATUS CreateDevice (
     52         IN PDRIVER_OBJECT    pDriverObject)
     53 {
     54     NTSTATUS status;
     55     PDEVICE_OBJECT pDevObj;
     56     PDEVICE_EXTENSION pDevExt;
     57    
     58     //创建设备名称
     59     UNICODE_STRING devName;
     60     RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice");
     61    
     62     //创建设备
     63     status = IoCreateDevice( pDriverObject,
     64                         sizeof(DEVICE_EXTENSION),
     65                         &(UNICODE_STRING)devName,
     66                         FILE_DEVICE_UNKNOWN,
     67                         0, TRUE,
     68                         &pDevObj );
     69     if (!NT_SUCCESS(status))
     70         return status;
     71
     72     pDevObj->Flags |= DO_DIRECT_IO;
     73     pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
     74     pDevExt->pDevice = pDevObj;
     75     pDevExt->ustrDeviceName = devName;
     76
     77     IoInitializeTimer(pDevObj,OnTimer,NULL);
     78
     79     //创建符号链接
     80     UNICODE_STRING symLinkName;
     81     RtlInitUnicodeString(&symLinkName,L"\??\HelloDDK");
     82     pDevExt->ustrSymLinkName = symLinkName;
     83     status = IoCreateSymbolicLink( &symLinkName,&devName );
     84     if (!NT_SUCCESS(status))
     85     {
     86         IoDeleteDevice( pDevObj );
     87         return status;
     88     }
     89     return STATUS_SUCCESS;
     90 }
     91 #pragma PAGEDCODE
     92 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
     93                                  IN PIRP pIrp)
     94 {
     95     NTSTATUS status = STATUS_SUCCESS;
     96     KdPrint(("Enter HelloDDKDeviceIOControl "));
     97
     98     //得到当前堆栈
     99     PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
    100     //得到输入缓冲区大小
    101     ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
    102     //得到输出缓冲区大小
    103     ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
    104     //得到IOCTL码
    105     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
    106
    107     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
    108         pDevObj->DeviceExtension;
    109
    110     ULONG info = 0;
    111
    112     switch (code)
    113     {                        // process request
    114         case IOCTL_START_TIMER:
    115         {
    116             KdPrint(("IOCTL_START_TIMER "));
    117             pDevExt->lTimerCount = TIMER_OUT;
    118             IoStartTimer(pDevObj);
    119             break;
    120         }
    121         case IOCTL_STOP:
    122         {
    123             KdPrint(("IOCTL_STOP "));
    124             IoStopTimer(pDevObj);
    125             break;
    126         }
    127         default:
    128             status = STATUS_INVALID_VARIANT;
    129     }
    130
    131     // 完成IRP
    132     pIrp->IoStatus.Status = status;
    133     pIrp->IoStatus.Information = info;    // bytes xfered
    134     IoCompleteRequest( pIrp, IO_NO_INCREMENT );
    135
    136     KdPrint(("Leave HelloDDKDeviceIOControl "));
    137
    138     return status;
    139 }

     
     

     1 #include <windows.h>
     2 #include <stdio.h>
     3 //使用CTL_CODE必须加入winioctl.h
     4 #include <winioctl.h>
     5 #include "..NT_DriverIoctls.h"
     6
     7 int main()
     8 {
     9     HANDLE hDevice =
    10         CreateFile("\\.\HelloDDK",
    11                     GENERIC_READ | GENERIC_WRITE,
    12                     0,        // share mode none
    13                     NULL,    // no security
    14                     OPEN_EXISTING,
    15                     FILE_ATTRIBUTE_NORMAL,
    16                     NULL );        // no template
    17
    18     if (hDevice == INVALID_HANDLE_VALUE)
    19     {
    20         printf("Failed to obtain file handle to device: "
    21             "%s with Win32 error code: %d ",
    22             "MyWDMDevice", GetLastError() );
    23         return 1;
    24     }
    25
    26     DWORD dwOutput;
    27
    28     DeviceIoControl(hDevice, IOCTL_START_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL);
    29
    30     Sleep(10000);
    31
    32      DeviceIoControl(hDevice, IOCTL_STOP, NULL, 0, NULL, 0, &dwOutput, NULL);
    33
    34     CloseHandle(hDevice);
    35
    36     return 0;
    37 }

     
    示例代码 P278

    2)使用DPC例程
    DPC定时器内部使用定时器对象KTIMER,当指定的时间间隔到达后,OS会将一个DPC例程插入DPC队列。
    KeInitializeTimer
    KeInitializeDpc
    BOOLEAN
    KeSetTimer(
    IN PKTIMER Timer,
    IN LARGE_INTEGER DueTime, //设定时间间隔
    IN PKDPC Dpc OPTIONAL
    );
    如果DueTime为正数,则该时间表示从1601/01/01到触发DPC例程的那个时刻,单位是100ns,如果为负数,意味着间隔多长时间,单位也是100ns。
    在调用KeSetTimer后,触发一次DPC例程,如果想周期触发,则需要在DPC触发后,再次调用KeSetTimer。
    KeInitializeDpc

      1 //.h
      2 //设定3秒间隔时间
      3 #define TIMER_OUT    3
      4
      5 typedef struct _DEVICE_EXTENSION {
      6     PDEVICE_OBJECT pDevice;
      7     UNICODE_STRING ustrDeviceName;    //设备名称
      8     UNICODE_STRING ustrSymLinkName;    //符号链接名
      9
     10     KDPC pollingDPC;    // 存储DPC对象
     11     KTIMER pollingTimer;// 存储计时器对象
     12     LARGE_INTEGER pollingInterval;    // 记录计时器间隔时间
     13 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
     14 //.cpp
     15 #pragma LOCKEDCODE
     16 VOID PollingTimerDpc( IN PKDPC pDpc,
     17                       IN PVOID pContext,
     18                       IN PVOID SysArg1,
     19                       IN PVOID SysArg2 )
     20 {
     21     PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
     22     PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
     23     KeSetTimer(
     24         &pdx->pollingTimer,
     25         pdx->pollingInterval,
     26         &pdx->pollingDPC );
     27     KdPrint(("PollingTimerDpc "));
     28
     29     //检验是运行在任意线程上下文
     30     PEPROCESS pEProcess = IoGetCurrentProcess();
     31   
     32     PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);
     33
     34     KdPrint(("%s ",ProcessName));
     35 }
     36 /************************************************************************
     37 * 函数名称:CreateDevice
     38 * 功能描述:初始化设备对象
     39 * 参数列表:
     40       pDriverObject:从I/O管理器中传进来的驱动对象
     41 * 返回 值:返回初始化状态
     42 *************************************************************************/
     43 #pragma INITCODE
     44 NTSTATUS CreateDevice (
     45         IN PDRIVER_OBJECT    pDriverObject)
     46 {
     47     NTSTATUS status;
     48     PDEVICE_OBJECT pDevObj;
     49     PDEVICE_EXTENSION pDevExt;
     50    
     51     //创建设备名称
     52     UNICODE_STRING devName;
     53     RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice");
     54    
     55     //创建设备
     56     status = IoCreateDevice( pDriverObject,
     57                         sizeof(DEVICE_EXTENSION),
     58                         &(UNICODE_STRING)devName,
     59                         FILE_DEVICE_UNKNOWN,
     60                         0, TRUE,
     61                         &pDevObj );
     62     if (!NT_SUCCESS(status))
     63         return status;
     64
     65     pDevObj->Flags |= DO_DIRECT_IO;
     66     pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
     67     pDevExt->pDevice = pDevObj;
     68     pDevExt->ustrDeviceName = devName;
     69
     70     KeInitializeTimer( &pDevExt->pollingTimer );
     71
     72     KeInitializeDpc( &pDevExt->pollingDPC,
     73                         PollingTimerDpc,
     74                         (PVOID) pDevObj );
     75
     76     //创建符号链接
     77     UNICODE_STRING symLinkName;
     78     RtlInitUnicodeString(&symLinkName,L"\??\HelloDDK");
     79     pDevExt->ustrSymLinkName = symLinkName;
     80     status = IoCreateSymbolicLink( &symLinkName,&devName );
     81     if (!NT_SUCCESS(status))
     82     {
     83         IoDeleteDevice( pDevObj );
     84         return status;
     85     }
     86     return STATUS_SUCCESS;
     87 }
     88 #pragma PAGEDCODE
     89 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
     90                                  IN PIRP pIrp)
     91 {
     92     NTSTATUS status = STATUS_SUCCESS;
     93     KdPrint(("Enter HelloDDKDeviceIOControl "));
     94
     95     //得到当前堆栈
     96     PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
     97     //得到输入缓冲区大小
     98     ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
     99     //得到输出缓冲区大小
    100     ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
    101     //得到IOCTL码
    102     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
    103
    104     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
    105         pDevObj->DeviceExtension;
    106
    107     ULONG info = 0;
    108
    109     switch (code)
    110     {                        // process request
    111         case IOCTL_START_TIMER:
    112         {
    113             KdPrint(("IOCTL_START_TIMER! "));
    114
    115             //从用户模式传进来的超时
    116             ULONG ulMircoSeconds = *(PULONG)pIrp->AssociatedIrp.SystemBuffer;
    117
    118             pDevExt->pollingInterval = RtlConvertLongToLargeInteger( ulMircoSeconds * -10 );
    119
    120             KeSetTimer(
    121                 &pDevExt->pollingTimer,
    122                 pDevExt->pollingInterval,
    123                 &pDevExt->pollingDPC );
    124             break;
    125         }
    126         case IOCTL_STOP_TIMER:
    127         {
    128             KdPrint(("IOCTL_STOP_TIMER! "));
    129
    130             KeCancelTimer(&pDevExt->pollingTimer);
    131
    132             break;
    133         }
    134         default:
    135             status = STATUS_INVALID_VARIANT;
    136     }
    137
    138     // 完成IRP
    139     pIrp->IoStatus.Status = status;
    140     pIrp->IoStatus.Information = info;    // bytes xfered
    141     IoCompleteRequest( pIrp, IO_NO_INCREMENT );
    142
    143     KdPrint(("Leave HelloDDKDeviceIOControl "));
    144
    145     return status;
    146 }
    147 //main
    148 #include <windows.h>
    149 #include <stdio.h>
    150 //使用CTL_CODE必须加入winioctl.h
    151 #include <winioctl.h>
    152 #include "..NT_DriverIoctls.h"
    153
    154 int main()
    155 {
    156     HANDLE hDevice =
    157         CreateFile("\\.\HelloDDK",
    158                     GENERIC_READ | GENERIC_WRITE,
    159                     0,        // share mode none
    160                     NULL,    // no security
    161                     OPEN_EXISTING,
    162                     FILE_ATTRIBUTE_NORMAL,
    163                     NULL );        // no template
    164
    165     if (hDevice == INVALID_HANDLE_VALUE)
    166     {
    167         printf("Failed to obtain file handle to device: "
    168             "%s with Win32 error code: %d ",
    169             "MyWDMDevice", GetLastError() );
    170         return 1;
    171     }
    172
    173     DWORD dwOutput;
    174     DWORD dwMircoSeconds = 1000*1000*2;
    175
    176     DeviceIoControl(hDevice, IOCTL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
    177
    178     Sleep(10000);
    179
    180      DeviceIoControl(hDevice, IOCTL_STOP_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL);
    181
    182     CloseHandle(hDevice);
    183
    184     return 0;
    185 }

     
    示例代码 P282

    DPC例程运行在DISPATCH_LEVEL级别。
    2、等待
    1)KeWaitForSingleObject
    2)KeDelayExecutionThread 与KeWaitForSingleObject类似,都是强制当前线程进入睡眠状态。
    3)KeStallExecutionProcessor 其让CPU处于忙等待,而不是睡眠,类似于自旋锁。浪费CPU时间,不宜超过50us。
    4)使用定时器
    定时器对象同其它内核对象一样,也有两个状态:激发与未激发态。初始化时未激发态,使用KeSetTimer后,经过指定时间后,变成激发态,可以用KeWaitForSingleObject来进行等待。

      1 #pragma PAGEDCODE
      2 VOID WaitMicroSecond1(ULONG ulMircoSecond)
      3 {
      4     KEVENT kEvent;
      5
      6     KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));
      7
      8     //初始化一个未激发的内核事件
      9     KeInitializeEvent(&kEvent,SynchronizationEvent,FALSE);
     10
     11     //等待时间的单位是100纳秒,将微秒转换成这个单位
     12     //负数代表是从此刻到未来的某个时刻
     13     LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond);
     14
     15     //在经过timeout后,线程继续运行
     16     KeWaitForSingleObject(&kEvent,
     17         Executive,
     18         KernelMode,
     19         FALSE,
     20         &timeout);
     21
     22     KdPrint(("Thread is running again! "));
     23 }
     24
     25 #pragma PAGEDCODE
     26 VOID WaitMicroSecond2(ULONG ulMircoSecond)
     27 {
     28     KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));
     29
     30     //等待时间的单位是100纳秒,将微秒转换成这个单位
     31     //负数代表是从此刻到未来的某个时刻
     32     LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond);
     33
     34     //此种方法类似于KeWaitForSingleObject
     35     //将当前线程进入睡眠状态,间隔时间到转入运行状态
     36     KeDelayExecutionThread(KernelMode,FALSE,&timeout);
     37
     38     KdPrint(("Thread is running again! "));
     39 }
     40
     41 #pragma PAGEDCODE
     42 VOID WaitMicroSecond3(ULONG ulMircoSecond)
     43 {
     44     KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));
     45
     46     //忙等待,此种方法属于忙等待,比较浪费CPU时间
     47     //因此使用该方法不宜超过50微秒
     48     KeStallExecutionProcessor(ulMircoSecond);
     49
     50     KdPrint(("Thread is running again! "));
     51 }
     52
     53 #pragma PAGEDCODE
     54 VOID WaitMicroSecond4(ULONG ulMircoSecond)
     55 {
     56     //使用计时器
     57
     58     KTIMER kTimer;//内核计时器
     59
     60     //初始化计时器
     61     KeInitializeTimer(&kTimer);
     62
     63     LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( ulMircoSecond * -10 );
     64
     65     //注意这个计时器没有和DPC对象关联
     66     KeSetTimer(&kTimer,timeout,    NULL);
     67     KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond));
     68
     69     KeWaitForSingleObject(&kTimer,Executive,KernelMode,FALSE,NULL);
     70
     71     KdPrint(("Thread is running again! "));
     72 }
     73 #pragma PAGEDCODE
     74 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
     75                                  IN PIRP pIrp)
     76 {
     77     NTSTATUS status = STATUS_SUCCESS;
     78     KdPrint(("Enter HelloDDKDeviceIOControl "));
     79
     80     //得到当前堆栈
     81     PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
     82     //得到输入缓冲区大小
     83     ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
     84     //得到输出缓冲区大小
     85     ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
     86     //得到IOCTL码
     87     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
     88
     89     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
     90         pDevObj->DeviceExtension;
     91
     92     ULONG info = 0;
     93
     94     //得到用户程序传进来的微秒数
     95     ULONG ulMircoSecond = *(PULONG)pIrp->AssociatedIrp.SystemBuffer;
     96
     97     switch (code)
     98     {                        // process request
     99         case IOCTL_WAIT_METHOD1:
    100         {
    101             KdPrint(("IOCTL_WAIT_METHOD1 "));
    102             WaitMicroSecond1(ulMircoSecond);
    103             break;
    104         }
    105         case IOCTL_WAIT_METHOD2:
    106         {
    107             KdPrint(("IOCTL_WAIT_METHOD2 "));
    108             WaitMicroSecond2(ulMircoSecond);
    109             break;
    110         }
    111         case IOCTL_WAIT_METHOD3:
    112         {
    113             KdPrint(("IOCTL_WAIT_METHOD3 "));
    114             WaitMicroSecond3(ulMircoSecond);
    115             break;
    116         }
    117         case IOCTL_WAIT_METHOD4:
    118         {
    119             KdPrint(("IOCTL_WAIT_METHOD4 "));
    120             WaitMicroSecond4(ulMircoSecond);
    121             break;
    122         }
    123         default:
    124             status = STATUS_INVALID_VARIANT;
    125     }
    126
    127     // 完成IRP
    128     pIrp->IoStatus.Status = status;
    129     pIrp->IoStatus.Information = info;    // bytes xfered
    130     IoCompleteRequest( pIrp, IO_NO_INCREMENT );
    131
    132     KdPrint(("Leave HelloDDKDeviceIOControl "));
    133
    134     return status;
    135 }
    136 //.cpp
    137 #include <windows.h>
    138 #include <stdio.h>
    139 //使用CTL_CODE必须加入winioctl.h
    140 #include <winioctl.h>
    141 #include "..NT_DriverIoctls.h"
    142
    143 int main()
    144 {
    145     HANDLE hDevice =
    146         CreateFile("\\.\HelloDDK",
    147                     GENERIC_READ | GENERIC_WRITE,
    148                     0,        // share mode none
    149                     NULL,    // no security
    150                     OPEN_EXISTING,
    151                     FILE_ATTRIBUTE_NORMAL,
    152                     NULL );        // no template
    153
    154     if (hDevice == INVALID_HANDLE_VALUE)
    155     {
    156         printf("Failed to obtain file handle to device: "
    157             "%s with Win32 error code: %d ",
    158             "MyDDKDevice", GetLastError() );
    159         return 1;
    160     }
    161
    162     DWORD dwOutput;
    163
    164     DWORD dwMicroSecond = 1000;
    165     DeviceIoControl(hDevice, IOCTL_WAIT_METHOD1, &dwMicroSecond, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
    166     DeviceIoControl(hDevice, IOCTL_WAIT_METHOD2, &dwMicroSecond, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
    167     DeviceIoControl(hDevice, IOCTL_WAIT_METHOD3, &dwMicroSecond, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
    168     DeviceIoControl(hDevice, IOCTL_WAIT_METHOD4, &dwMicroSecond, sizeof(DWORD), NULL, 0, &dwOutput, NULL);
    169
    170     CloseHandle(hDevice);
    171
    172     return 0;
    173 }

     
    示例代码 P286

    3、其它相关函数
    获取当前系统时间:KeQuerySystemTime
    This value is computed for the GMT time zone. To adjust this value for the local time zone use ExSystemTimeToLocalTime.(在控制面板中设置)
    RtlTimeFieldsToTime converts TIME_FIELDS information to a system time value
    RtlTimeToTimeFields

      1 /************************************************************************
      2 * 函数名称:DriverEntry
      3 * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
      4 * 参数列表:
      5       pDriverObject:从I/O管理器中传进来的驱动对象
      6       pRegistryPath:驱动程序在注册表的中的路径
      7 * 返回 值:返回初始化驱动状态
      8 *************************************************************************/
      9 #pragma INITCODE
     10 extern "C" NTSTATUS DriverEntry (
     11             IN PDRIVER_OBJECT pDriverObject,
     12             IN PUNICODE_STRING pRegistryPath    )
     13 {
     14     NTSTATUS status;
     15     KdPrint(("Enter DriverEntry "));
     16
     17     //设置卸载函数
     18     pDriverObject->DriverUnload = HelloDDKUnload;
     19
     20     //设置派遣函数
     21     for (int i = 0; i < arraysize(pDriverObject->MajorFunction); ++i)
     22         pDriverObject->MajorFunction[i] = HelloDDKDispatchRoutin;
     23
     24     pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDeviceIOControl;
     25    
     26     //创建驱动设备对象
     27     status = CreateDevice(pDriverObject);
     28
     29     KdPrint(("Leave DriverEntry "));
     30     return status;
     31 }
     32 #pragma PAGEDCODE
     33 VOID Time_Test()
     34 {
     35     LARGE_INTEGER current_system_time;
     36     //得到当前系统时间
     37     KeQuerySystemTime(&current_system_time);
     38
     39     LARGE_INTEGER current_local_time;
     40     //从系统时间转换成当地时区时间
     41     ExSystemTimeToLocalTime(&current_system_time,&current_local_time);
     42
     43     TIME_FIELDS current_time_info;
     44     //由当地时区时间得到月日年信息
     45     RtlTimeToTimeFields(&current_local_time,&current_time_info);
     46
     47     //显示年月日等信息
     48     KdPrint(("Current year:%d ",current_time_info.Year));
     49     KdPrint(("Current month:%d ",current_time_info.Month));
     50     KdPrint(("Current day:%d ",current_time_info.Day));
     51     KdPrint(("Current Hour:%d ",current_time_info.Hour));
     52     KdPrint(("Current Minute:%d ",current_time_info.Minute));
     53     KdPrint(("Current Second:%d ",current_time_info.Second));
     54     KdPrint(("Current Milliseconds:%d ",current_time_info.Milliseconds));
     55     KdPrint(("Current Weekday:%d ",current_time_info.Weekday));
     56 }
     57
     58 #pragma PAGEDCODE
     59 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
     60                                  IN PIRP pIrp)
     61 {
     62     NTSTATUS status = STATUS_SUCCESS;
     63     KdPrint(("Enter HelloDDKDeviceIOControl "));
     64
     65     //得到当前堆栈
     66     PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
     67     //得到输入缓冲区大小
     68     ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
     69     //得到输出缓冲区大小
     70     ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
     71     //得到IOCTL码
     72     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
     73
     74     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
     75         pDevObj->DeviceExtension;
     76
     77     ULONG info = 0;
     78
     79     switch (code)
     80     {                        // process request
     81         case IOCTL_TIME_TEST:
     82         {
     83             KdPrint(("IOCTL_TIME_TEST "));
     84             Time_Test();
     85             break;
     86         }
     87         default:
     88             status = STATUS_INVALID_VARIANT;
     89     }
     90
     91     // 完成IRP
     92     pIrp->IoStatus.Status = status;
     93     pIrp->IoStatus.Information = info;    // bytes xfered
     94     IoCompleteRequest( pIrp, IO_NO_INCREMENT );
     95
     96     KdPrint(("Leave HelloDDKDeviceIOControl "));
     97
     98     return status;
     99 }
    100
    101 DWORD dwOutput;
    102 DeviceIoControl(hDevice, IOCTL_TIME_TEST, NULL, 0, NULL, 0, &dwOutput, NULL);
    103 CloseHandle(hDevice);

     
    示例代码 P288

    4、IRP超时处理
    规定时间内对某一设备的操作没有反应,则可以取消该操作。应用程序中使用CancelIo,驱动中用IoCancelIrp,来取消操作。也可以通过设置IRP超时,来取消IRO,这时进入IRP取消例程。
    1)初始个定时器和DPC例程,进行关联。
    2)操作IRP前,开户定时器,超时进入DPC例程。
    3)如果超时前结束该IRP操作,则应取消定时器。

      1 typedef struct _DEVICE_EXTENSION {
      2     PDEVICE_OBJECT pDevice;
      3     UNICODE_STRING ustrDeviceName;    //设备名称
      4     UNICODE_STRING ustrSymLinkName;    //符号链接名
      5
      6     KDPC pollingDPC;    // 存储DPC对象
      7     KTIMER pollingTimer;// 存储计时器对象
      8     PIRP currentPendingIRP;//记录当前挂起的IRP
      9 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
     10
     11 pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKRead;
     12
     13 #pragma LOCKEDCODE
     14 VOID OnTimerDpc( IN PKDPC pDpc,
     15                       IN PVOID pContext,
     16                       IN PVOID SysArg1,
     17                       IN PVOID SysArg2 )
     18 {
     19     PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;
     20     PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
     21
     22     PIRP currentPendingIRP = pdx->currentPendingIRP;
     23
     24     KdPrint(("Cancel the current pending irp! "));
     25
     26     //设置完成状态为STATUS_CANCELLED
     27      currentPendingIRP->IoStatus.Status = STATUS_CANCELLED;
     28      currentPendingIRP->IoStatus.Information = 0;    // bytes xfered
     29      IoCompleteRequest( currentPendingIRP, IO_NO_INCREMENT );
     30 }
     31
     32 /************************************************************************
     33 * 函数名称:CreateDevice
     34 * 功能描述:初始化设备对象
     35 * 参数列表:
     36       pDriverObject:从I/O管理器中传进来的驱动对象
     37 * 返回 值:返回初始化状态
     38 *************************************************************************/
     39 #pragma INITCODE
     40 NTSTATUS CreateDevice (
     41         IN PDRIVER_OBJECT    pDriverObject)
     42 {
     43     NTSTATUS status;
     44     PDEVICE_OBJECT pDevObj;
     45     PDEVICE_EXTENSION pDevExt;
     46    
     47     //创建设备名称
     48     UNICODE_STRING devName;
     49     RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice");
     50    
     51     //创建设备
     52     status = IoCreateDevice( pDriverObject,
     53                         sizeof(DEVICE_EXTENSION),
     54                         &(UNICODE_STRING)devName,
     55                         FILE_DEVICE_UNKNOWN,
     56                         0, TRUE,
     57                         &pDevObj );
     58     if (!NT_SUCCESS(status))
     59         return status;
     60
     61     pDevObj->Flags |= DO_BUFFERED_IO;
     62     pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
     63     pDevExt->pDevice = pDevObj;
     64     pDevExt->ustrDeviceName = devName;
     65
     66     KeInitializeTimer( &pDevExt->pollingTimer );
     67
     68     KeInitializeDpc( &pDevExt->pollingDPC,
     69                         OnTimerDpc,
     70                         (PVOID) pDevObj );
     71
     72     //创建符号链接
     73     UNICODE_STRING symLinkName;
     74     RtlInitUnicodeString(&symLinkName,L"\??\HelloDDK");
     75     pDevExt->ustrSymLinkName = symLinkName;
     76     status = IoCreateSymbolicLink( &symLinkName,&devName );
     77     if (!NT_SUCCESS(status))
     78     {
     79         IoDeleteDevice( pDevObj );
     80         return status;
     81     }
     82     return STATUS_SUCCESS;
     83 }
     84
     85 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
     86                                  IN PIRP pIrp)
     87 {
     88     KdPrint(("Enter HelloDDKRead "));
     89
     90     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
     91             pDevObj->DeviceExtension;
     92
     93     //将IRP设置为挂起
     94     IoMarkIrpPending(pIrp);
     95
     96     //将挂起的IRP记录下来
     97     pDevExt->currentPendingIRP = pIrp;
     98
     99     //定义3秒的超时
    100     ULONG ulMicroSecond = 3000000;
    101
    102     //将32位整数转化成64位整数
    103     LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMicroSecond);
    104    
    105     KeSetTimer(
    106         &pDevExt->pollingTimer,
    107         timeout,
    108         &pDevExt->pollingDPC );
    109
    110     KdPrint(("Leave HelloDDKRead "));
    111
    112     //返回pending状态
    113     return STATUS_PENDING;
    114 }
    115
    116 //main
    117 #include <windows.h>
    118 #include <stdio.h>
    119 #include <process.h>
    120
    121 int main()
    122 {
    123     HANDLE hDevice =
    124         CreateFile("\\.\HelloDDK",
    125                     GENERIC_READ | GENERIC_WRITE,
    126                     FILE_SHARE_READ,
    127                     NULL,
    128                     OPEN_EXISTING,
    129                     FILE_ATTRIBUTE_NORMAL,
    130                     NULL );
    131
    132     if (hDevice == INVALID_HANDLE_VALUE)
    133     {
    134         printf("Open Device failed!");
    135         return 1;
    136     }
    137
    138     DWORD dwRead;
    139
    140     //如果读IRP没有被完成,ReadFile一直都不会退出!
    141     ReadFile(hDevice,NULL,0,&dwRead,NULL);
    142    
    143     ReadFile(hDevice,NULL,0,&dwRead,NULL);
    144
    145     CloseHandle(hDevice);
    146
    147     return 0;
    148 }

  • 相关阅读:
    3.约束及修改数据表
    RSA总结
    消息队列面试官爱问的问题(一)
    Maven模块化开发
    系统初始化脚本和检查初始化结果脚本(centos7)
    kubectl 命令自动补全
    Kubernetes1.13.1部署Kuberneted-dashboard v1.10.1
    python实现连接MySQL、Redis并获取数据
    shell 脚本实现退点输出
    理论经典:TCP协议的3次握手与4次挥手过程详解
  • 原文地址:https://www.cnblogs.com/ansen312/p/5864661.html
Copyright © 2020-2023  润新知