我有一个ID为1的计时器,其中有一个timerproc作为回调函数。
我在timerproc中创建其他计时器(ID 2、3,...),它们使用WM_TIMER
事件,而不是另一个timerproc。
创建窗口时,我想立即生成ID为1的Timer事件。
所以我就这样使用了SendMessage函数
SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc);
但是没有用。
如何在第一次出现窗口时立即激活timerproc?
void CALLBACK MakeRain(HWND hWnd, UINT iMessage, UINT_PTR wParam, DWORD lParam)
{ /* this is timerproc for ID 1 */
if (gRdx >= MAX_WORDS_COUNT) return;
gRain[gRdx].f = 1;
gRain[gRdx].x = rand() % (gRect.right - 30);
gRain[gRdx].y = 10;
int id = RdxToTID(gRdx);
int vel = rand() % 2000 + 1000;
SetTimer(hWnd, id, vel, NULL); /* In here I am making other timers */
gRdx++;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
int tid = wParam;
int rdx = TIDToRdx(tid);
switch (iMessage)
{
case WM_CREATE:
GetClientRect(hWnd, &gRect);
srand((unsigned int)time(NULL));
SetTimer(hWnd, 1, MAKE_RAIN_TERM, MakeRain);
/* my trying, It is not working */
//SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&MakeRain);
return 0;
case WM_TIMER:
gRain[rdx].y += 10;
if (gRain[rdx].y >= gRect.bottom) {
gRain[rdx].f = 0;
KillTimer(hWnd, tid);
}
InvalidateRect(hWnd, NULL, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
for (int i = 0; i < MAX_WORDS_COUNT; i++) {
if (gRain[i].f == 0) continue;
TextOut(hdc, gRain[i].x, gRain[i].y, words[i], lstrlen(words[i]));
}
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
KillTimer(hWnd, 1);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, iMessage, wParam, lParam);
}
答案 0 :(得分:2)
创建窗口时,我想立即生成ID为1的Timer Event。 所以我就这样使用了SendMessage函数
SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc);
但是没有用。
仅当计时器发信号通知拥有线程的消息队列以生成WM_TIMER
消息时,计时器才会调用该回调,然后由(Peek|Get)Message()
检索并由DispatchMessage()
传递给DispatchMessage()
线程的消息循环。如果分配了计时器,则WM_TIMER
会调用计时器回调,否则它将lpmsg
消息传递到窗口的WndProc:
如果
WM_TIMER
参数指向一条lParam
消息,而WM_TIMER
消息的NULL
参数不是lParam
,则SendMessage()
指向而不是调用窗口过程的函数。
使用PostMessage()
绕过窗口的消息队列,直接进入窗口的WndProc。这就是为什么您没有看到计时器回调被调用的原因。
因此,至少必须使用SendMessage()
而不是WM_TIMER
,以便您的手动DispatchMessage()
消息可以通过窗口的消息队列并到达{{1} }:
PostMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc);
否则,您将必须用自己的假DispatchMessage()
直接呼叫MSG
:
MSG msg = {};
msg.hwnd = hWnd;
msg.message = WM_TIMER;
msg.wParam = 1;
msg.lParam = (LPARAM) &timerproc;
msg.time = GetTickCount();
GetCursorPos(&msg.pt);
DispatchMessage(&msg);
但是,实际上并没有必要,因为...
如何在第一次出现窗口时立即激活timerproc?
回调是一个函数,因此就像其他任何函数一样,直接调用它即可
//SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&MakeRain);
MakeRain(hWnd, WM_TIMER, 1, GetTickCount());