核心要点
最重要的一点是:SetTimer 并不是C语言的标准库函数,它是 Windows API (应用程序编程接口) 中的一个函数,专门用于 图形用户界面 程序开发。
- 适用环境:仅适用于 Windows 操作系统。
- 所属库:
user32.dll(在C语言中通常通过windows.h头文件来使用)。 - 功能:在应用程序中创建一个定时器,定时器会周期性地向应用程序发送
WM_TIMER消息,或者在一个指定的时间间隔后执行一个回调函数。
SetTimer 函数详解
SetTimer 函数主要有两种使用方式,这取决于你传递的参数。
函数原型
UINT_PTR SetTimer( HWND hWnd, // 窗口句柄 UINT_PTR nIDEvent, // 定时器ID UINT uElapse, // 时间间隔,单位是毫秒 TIMERPROC lpTimerFunc // 回调函数指针 );
参数说明
-
hWnd(HWND):- 一个窗口的句柄,这个窗口将接收定时器发出的
WM_TIMER消息。 - 如果你想在窗口的消息循环中处理定时器事件,这个参数就是你的窗口句柄。
- 如果你想使用回调函数(第四个参数),这个参数可以是
NULL。 - 如果是
NULL并且第四个参数也是NULL,系统会为调用线程创建一个 "非窗口定时器" (non-window timer),线程的消息队列会收到WM_TIMER消息。
- 一个窗口的句柄,这个窗口将接收定时器发出的
-
nIDEvent(UINT_PTR):- 一个定时器的标识符(ID)。
- 如果这个值是唯一的,
SetTimer就会创建一个新的定时器。 - 如果这个值已经存在一个定时器,那么该函数会重置那个已有的定时器,使其重新计时。
- 如果传入
0,系统会自动为你生成一个唯一的ID。
-
uElapse(UINT):- 定时器的时间间隔,单位是毫秒。
1000表示1秒,500表示0.5秒。
-
lpTimerFunc(TIMERPROC):- 一个指向回调函数的指针。
- 回调函数:这是一个由你定义,但由系统(在定时器触发时)调用的函数。
- 如果这个参数是
NULL,定时器触发时,系统会向hWnd指定的窗口发送WM_TIMER消息。 - 如果这个参数是一个有效的函数指针,定时器触发时,系统会直接调用这个函数,不会发送
WM_TIMER消息。
返回值
- 如果成功,返回新创建的定时器的ID(一个
UINT_PTR类型的值)。 - 如果失败,返回
0。
两种主要使用方式
通过窗口消息处理(lpTimerFunc = NULL)
这是最传统的方式,通常用于基于对话框或窗口的应用程序。
工作流程:
- 调用
SetTimer,将lpTimerFunc设为NULL。 - 在你的窗口过程函数(
WndProc)中,添加对WM_TIMER消息的case分支。 - 当定时器时间到,系统会自动将
WM_TIMER消息放入指定窗口的消息队列中。 - 你的
WndProc函数会收到这个消息并执行相应的代码。
示例代码:
#include <windows.h>
// 窗口过程函数的声明
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
// 1. 注册窗口类
WNDCLASS wc = {0};
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = "MyTimerWindow";
RegisterClass(&wc);
// 2. 创建窗口
HWND hWnd = CreateWindow("MyTimerWindow", "SetTimer 示例", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
NULL, NULL, hInstance, NULL);
// 3. 显示窗口
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// 4. 创建定时器 (每1000毫秒触发一次,ID为1)
SetTimer(hWnd, 1, 1000, NULL); // 注意这里lpTimerFunc是NULL
// 5. 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// 窗口过程函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_TIMER:
// 当定时器ID为1的消息到达时执行
if (wParam == 1) {
static int counter = 0;
counter++;
char buffer[100];
sprintf_s(buffer, sizeof(buffer), "定时器触发次数: %d", counter);
SetWindowText(hWnd, buffer); // 在窗口标题上显示次数
}
break;
case WM_DESTROY:
// 6. 销毁定时器!非常重要!
KillTimer(hWnd, 1);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
通过回调函数(lpTimerFunc != NULL)
这种方式更灵活,不依赖于窗口消息循环,常用于控制台程序或需要更精细定时控制的场景。
工作流程:
- 定义一个符合
TIMERPROC签名的回调函数。 - 调用
SetTimer,并将你的回调函数名作为第四个参数传入,hWnd可以为NULL。 - 当定时器时间到,系统会直接调用你的回调函数。
回调函数原型:
VOID CALLBACK TimerProc( HWND hwnd, // 窗口句柄,即SetTimer中的hWnd UINT uMsg, // 消息,对于定时器总是WM_TIMER UINT_PTR idEvent, // 定时器ID DWORD dwTime // 系统启动以来的毫秒数 );
示例代码:
#include <windows.h>
#include <stdio.h>
// 1. 定义回调函数
VOID CALLBACK MyTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {
// 当定时器ID为100触发时执行
if (idEvent == 100) {
printf("回调函数被触发!系统运行了 %d 毫秒,\n", dwTime);
}
}
int main() {
printf("程序启动,创建一个2秒触发一次的回调定时器,\n");
// 2. 创建定时器
// hWnd设为NULL,lpTimerFunc设为我们的回调函数
UINT_PTR timerID = SetTimer(NULL, 100, 2000, MyTimerProc);
if (timerID == 0) {
printf("创建定时器失败!\n");
return 1;
}
printf("定时器创建成功,ID为 %u,\n", timerID);
printf("程序将运行10秒后退出...\n");
// 3. 保持程序运行,以便回调函数能被调用
// 在实际应用中,这里可能是主程序的业务逻辑
Sleep(10000); // 睡眠10秒
// 4. 销毁定时器!非常重要!
KillTimer(NULL, timerID);
printf("定时器已销毁,程序退出,\n");
return 0;
}
重要注意事项
- 线程关联:
SetTimer创建的定时器与调用它的线程关联,回调函数会在该线程的上下文中执行。 - 必须销毁定时器:当你不再需要定时器时,必须调用
KillTimer函数来销毁它,否则会造成资源泄漏。KillTimer的参数与SetTimer对应。KillTimer(hWnd, nIDEvent); // 销毁指定窗口的指定ID的定时器 KillTimer(NULL, nIDEvent); // 销毁非窗口定时器
- 精度限制:
SetTimer的精度受限于系统的定时器精度(通常在10-16毫秒左右),设置一个比系统精度更小的时间间隔(如1毫秒)并不能保证精确的1毫秒触发,只会尽可能接近。 - 非阻塞:
SetTimer是异步的,调用它后,程序会立即继续执行后续代码,而不会等待定时器触发。 - 跨平台性:这是最大的限制。
SetTimer是Windows独有的,如果你需要编写跨平台的C语言程序,应该使用其他库,- POSIX 标准:
<unistd.h>中的sleep()(秒级),usleep()(微秒级),以及<time.h>中的nanosleep()。 - 第三方库:如
Boost.Asio(C++),或者libuv,SDL等库提供的定时器功能。
- POSIX 标准:
| 特性 | 说明 |
|---|---|
| 函数归属 | Windows API,非C标准库 |
| 核心功能 | 创建周期性或一次性定时器 |
| 两种模式 | 消息模式:向窗口发送 WM_TIMER 消息。 2. 回调模式:直接调用用户定义的函数。 |
| 关键步骤 | SetTimer 创建 -> 业务逻辑处理 -> KillTimer 销毁 |
| 适用场景 | Windows GUI程序(如MFC, Win32 SDK) |
| 跨平台替代 | sleep(), usleep(), nanosleep() (POSIX) |
希望这个详细的解释能帮助你完全理解C语言(特指Windows环境下)的 SetTimer 函数!
