• 29、定时器


    一般两种方法使用/设置定时器,一种是使用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!\n"));
    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!\n",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\n",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\n"));
    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\n"));
    117 pDevExt->lTimerCount = TIMER_OUT;
    118 IoStartTimer(pDevObj);
    119 break;
    120 }
    121 case IOCTL_STOP:
    122 {
    123 KdPrint(("IOCTL_STOP\n"));
    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\n"));
    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_Driver\Ioctls.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\n",
    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\n"));
    28
    29 //检验是运行在任意线程上下文
    30 PEPROCESS pEProcess = IoGetCurrentProcess();
    31
    32 PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);
    33
    34 KdPrint(("%s\n",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\n"));
    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!\n"));
    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!\n"));
    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\n"));
    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_Driver\Ioctls.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\n",
    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、等待

    1KeWaitForSingleObject

    2KeDelayExecutionThread KeWaitForSingleObject类似,都是强制当前线程进入睡眠状态。

    3KeStallExecutionProcessor 其让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!\n"));
    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!\n"));
    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!\n"));
    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!\n"));
    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\n"));
    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\n"));
    102 WaitMicroSecond1(ulMircoSecond);
    103 break;
    104 }
    105 case IOCTL_WAIT_METHOD2:
    106 {
    107 KdPrint(("IOCTL_WAIT_METHOD2\n"));
    108 WaitMicroSecond2(ulMircoSecond);
    109 break;
    110 }
    111 case IOCTL_WAIT_METHOD3:
    112 {
    113 KdPrint(("IOCTL_WAIT_METHOD3\n"));
    114 WaitMicroSecond3(ulMircoSecond);
    115 break;
    116 }
    117 case IOCTL_WAIT_METHOD4:
    118 {
    119 KdPrint(("IOCTL_WAIT_METHOD4\n"));
    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\n"));
    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_Driver\Ioctls.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\n",
    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\n"));
    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\n"));
    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\n",current_time_info.Year));
    49 KdPrint(("Current month:%d\n",current_time_info.Month));
    50 KdPrint(("Current day:%d\n",current_time_info.Day));
    51 KdPrint(("Current Hour:%d\n",current_time_info.Hour));
    52 KdPrint(("Current Minute:%d\n",current_time_info.Minute));
    53 KdPrint(("Current Second:%d\n",current_time_info.Second));
    54 KdPrint(("Current Milliseconds:%d\n",current_time_info.Milliseconds));
    55 KdPrint(("Current Weekday:%d\n",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\n"));
    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\n"));
    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\n"));
    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

    4IRP超时处理

    规定时间内对某一设备的操作没有反应,则可以取消该操作。应用程序中使用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!\n"));
    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\n"));
    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\n"));
    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 }
    示例代码 P290

  • 相关阅读:
    Linux下使用select延时
    update不能直接使用select的返回结果
    C++类模板声明与定义为何不能分开
    MySQL开启日志记录执行过的SQL语句
    如何使用FastCGI处理自定义HTTP头
    MongoDB添加认证
    Ubuntu16.04安装MongoDB
    nginx: [emerg] getpwnam(“www”) failed
    C++ 智能指针(一)
    协同过滤
  • 原文地址:https://www.cnblogs.com/mydomain/p/1877125.html
Copyright © 2020-2023  润新知