如何在 win32 中使用 sendmessage 发送具有定时器过程的 wm_timer

How do I use sendmessage for sending wm_timer that has timer proc in win32

我有一个计时器,ID 1,它有一个 timerproc 作为回调函数。

我正在 timerproc 中制作其他计时器(ID 2、3、...),它们使用 WM_TIMER 事件,而不是另一个 timerproc。

创建window时,我想立即生成定时器事件,ID 1。

所以我就这样使用了 SendMessage 函数

SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc);

但是没用。

如何在 window 的第一次正确激活 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);
    }

When creating window, I want to immediately generate Timer Event, ID 1. So I used SendMessage function like that

SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc);

but it didn't work.

仅当定时器向拥有线程的消息队列发送信号以生成 WM_TIMER 消息时,定时器才会调用回调,然后由 (Peek|Get)Message() 检索并传递给 DispatchMessage()通过线程的消息循环。如果分配了一个,它是 DispatchMessage() 调用定时器回调,否则它将 WM_TIMER 消息传递到 window 的 WndProc:

If the lpmsg parameter points to a WM_TIMER message and the lParam parameter of the WM_TIMER message is not NULLlParam points to a function that is called instead of the window procedure.

使用SendMessage()绕过window的消息队列,直接进入window的WndProc。这就是为什么您没有看到调用计时器回调的原因。

因此,至少,您必须使用 PostMessage() 而不是 SendMessage(),这样您的手动 WM_TIMER 消息才能通过 window 的消息队列并达到 DispatchMessage():

PostMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc);

否则,您将不得不用自己的假 MSG 直接调用 DispatchMessage()

MSG msg = {};
msg.hwnd = hWnd;
msg.message = WM_TIMER;
msg.wParam = 1;
msg.lParam = (LPARAM) &timerproc;
msg.time = GetTickCount();
GetCursorPos(&msg.pt);
DispatchMessage(&msg);

然而,这实际上不是必需的,因为...

How do I activate timerproc at right that the first time of window?

回调是一个函数,所以直接调用它,就像其他函数一样:

//SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&MakeRain);
MakeRain(hWnd, WM_TIMER, 1, GetTickCount());