可等待定时器这种内核对象,它们会在某个指定的时间触发,或每隔一段时间触发一次。它们通常用来在某个时间执行一些操作。
0x01 创建一个可等待定时器 CreateWaitableTimer
(在创建的时候,可等待的计时器对象总是处于未触发状态)
HANDLE WINAPI CreateWaitableTimer(
__in_opt LPSECURITY_ATTRIBUTES lpTimerAttributes, //安全描述符,为NULL时使用默认的
__in BOOL bManualReset, //要创建一个手动重置定时器还是一个自动重置计时器
//当手动重置计时器被触发时,正在等待该计时器的所有线程都会变成可调度状态
//当自动重置计时器被触发时,只有一个正在等待该计时的线程会变成可调度状态
__in_opt LPCTSTR lpTimerName //该可等待计时器的名称
);
0x02 获取一个已经存在的可等待计时器的句柄 OpenWaitableTimer
HANDLE WINAPI OpenWaitableTimer(
__in DWORD dwDesiredAccess, //访问权限
__in BOOL bInheritHandle, //是否允许子进程继承该句柄
__in LPCTSTR lpTimerName //要打开的对象名称
);
0x03 触发计时器 SetWaitableTimer函数
BOOL WINAPI SetWaitableTimer(
__in HANDLE hTimer, //想要触发的计时器
__in const LARGE_INTEGER *pDueTime, //计时器第一次触发的时间
__in LONG lPeriod, //第一次触发后,计时器的触发频度,当给lPeriod参数传0时,我们设置的是一次性定时器,这种定时器只触发一次,之后再不触发。
__in_opt PTIMERAPCROUTINE pfnCompletionRoutine, //异步过程调用APC函数
__in_opt LPVOID lpArgToCompletionRoutine, //APC函数的参数
__in BOOL fResume //是否继续执行,一般传FALSE
);
0x04 将指定的计时器取消 CancelWaitableTimer函数
BOOL WINAPI CancelWaitableTimer(
__in HANDLE hTimer
);
这样计时器就永远不会触发了,除非以后再调用SetWaitableTimer来对它进行重置。如果想要改变触发器的触发时间,不必先调用CancelWaitableTimer,因为每次调用SetWaitableTimer都会在设置新的触发时间之前将原来的触发时间取消掉。
// 计时器.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <windows.h> #include <iostream> #include <ctime> using namespace std; DWORD WINAPI ThreadProcedure(LPVOID ParameterData); void GetSystemTime(); BOOL __IsLoop = TRUE; int main() { HANDLE ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProcedure, NULL, 0, NULL); printf("Input AnyKey To Exit\r\n"); getchar(); __IsLoop = FALSE; WaitForSingleObject(ThreadHandle, INFINITE); if (ThreadHandle!=NULL) { CloseHandle(ThreadHandle); ThreadHandle = NULL; } return 0; } DWORD WINAPI ThreadProcedure(LPVOID ParameterData) { //创建一个时钟 HANDLE TimeHandle = NULL; LARGE_INTEGER DueTime; DueTime.QuadPart = -10000000; TimeHandle = CreateWaitableTimer(NULL, FALSE, NULL); //同步事件(SynchronizationEvent) //当事件对象为激发时,如遇到KeWaitForXX等内核函数,事件对象则自动变回未激发态 //通知事件(NotificationEvent) //当事件对象为激发时,如遇到KeWaitForXX等内核函数,事件对象则不会变回未激发态 //If this parameter is TRUE, the timer is a manual-reset notification timer. Otherwise, the timer is a synchronization timer. while (__IsLoop) { if (!SetWaitableTimer(TimeHandle, &DueTime, 0, NULL, NULL, 0)) { printf("SetWaitableTimer failed (%d)\n", GetLastError()); return 0; } BOOL IsOk = WaitForSingleObject(TimeHandle, INFINITE); IsOk -= WAIT_OBJECT_0; if (IsOk==0) { system("cls"); GetSystemTime(); } else { break; } } CancelWaitableTimer(TimeHandle); CloseHandle(TimeHandle); TimeHandle = NULL; printf("ThreadProcedure() Exit\r\n"); return 0; } void GetSystemTime() { char TimeData[MAX_PATH] = { 0 }; auto TimeObject = time(NULL); tm v1; localtime_s(&v1, &TimeObject); //格式化时间字符串 strftime(TimeData, _countof(TimeData), "%Y-%m-%d %H:%M:%S", &v1); printf("%s\r\n", TimeData); }