Как использовать sendmessage для отправки wm_timer с таймером в win32 - PullRequest
0 голосов
/ 11 октября 2018

У меня есть таймер, ID 1, для которого в качестве функции обратного вызова используется timerproc.

Я делаю другие таймеры (ID 2, 3, ...) в timerproc, и они используют WM_TIMER событие, а не другой timerproc.

При создании окна я хочу немедленно создать событие таймера с идентификатором 1.

Поэтому я использовал такую ​​функцию 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);
    }

1 Ответ

0 голосов
/ 11 октября 2018

При создании окна я хочу немедленно сгенерировать событие таймера, идентификатор 1. Поэтому я использовал такую ​​функцию SendMessage

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

, но она не сработала.

Обратный вызов вызывается таймером, только когда таймер сигнализирует очередь сообщений потока-владельца, чтобы сгенерировать сообщение WM_TIMER, которое затем извлекается (Peek|Get)Message() и передается в DispatchMessage() циклом сообщений потока.DispatchMessage() вызывает обратный вызов таймера, если он назначен, иначе он доставляет сообщение WM_TIMER в WndProc окна:

Если параметр lpmsg указывает на сообщение WM_TIMERи параметр lParam сообщения WM_TIMER не NULL, lParam указывает на функцию, которая вызывается вместо оконной процедуры.

Использование SendMessage() позволяет обойти окноочередь сообщений и отправляется непосредственно в WndProc окна.Вот почему вы не видите, как вызывается обратный вызов таймера.

Так что, по крайней мере, вам придется использовать PostMessage() вместо SendMessage(), чтобы ваше ручное сообщение WM_TIMER могло пройтиочередь сообщений окна достигает и DispatchMessage():

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());
...