Winapi 如何使用sendmessage发送win32中具有timer proc的wm_计时器

Winapi 如何使用sendmessage发送win32中具有timer proc的wm_计时器,winapi,timer,sendmessage,Winapi,Timer,Sendmessage,我有一个计时器,ID为1,它有一个timerproc作为回调函数 我在timerproc中创建其他计时器(ID 2,3,…),它们使用WM_TIMER事件,而不是另一个timerproc 创建窗口时,我想立即生成计时器事件,ID为1 所以我使用了SendMessage这样的函数 SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc); SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc

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

我在timerproc中创建其他计时器(ID 2,3,…),它们使用
WM_TIMER
事件,而不是另一个timerproc

创建窗口时,我想立即生成计时器事件,ID为1

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

SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc);
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);
    }
void CALLBACK MakeRain(HWND-HWND、UINT-iMessage、UINT-PTR-wParam、DWORD-lParam)
{/*这是ID 1的timerproc*/
如果(gRdx>=最大字数)返回;
颗粒[gRdx].f=1;
颗粒[gRdx].x=rand()%(gRect.right-30);
晶粒[gRdx].y=10;
int id=RdxToTID(gRdx);
int vel=rand()%2000+1000;
SetTimer(hWnd,id,vel,NULL);/*在这里我制作其他计时器*/
gRdx++;
}
LRESULT回调WndProc(HWND HWND、UINT iMessage、WPARAM WPARAM、LPARAM LPARAM)
{
HDC-HDC;
PAINTSTRUCT-ps;
int tid=wParam;
int rdx=TIDToRdx(tid);
开关(iMessage)
{
案例WM_创建:
GetClientRect(hWnd和gRect);
srand((无符号整数)时间(NULL));
设置计时器(hWnd,1,MAKE_RAIN_TERM,MakeRain);
/*我的努力,它不起作用*/
//发送消息(hWnd、WM_定时器、1、(LPRAM)和MakeRain);
返回0;
案例WM_计时器:
晶粒[rdx].y+=10;
if(gRain[rdx].y>=gRect.bottom){
颗粒[rdx].f=0;
KillTimer(hWnd、tid);
}
无效(hWnd,NULL,TRUE);
返回0;
案例WM_油漆:
hdc=开始喷漆(hWnd和ps);
for(int i=0;i
创建窗口时,我想立即生成计时器事件,ID为1。 所以我使用了SendMessage这样的函数

SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc);
SendMessage(hWnd, WM_TIMER, 1, (LPARAM)&timerproc);
但它不起作用

只有当计时器向拥有线程的消息队列发出信号以生成
WM|u timer
消息时,才会调用回调,然后由
(Peek | Get)message()
检索,并通过线程的消息循环传递给
DispatchMessage()
。如果分配了计时器回调,则调用该回调的是
DispatchMessage()
,否则它会将
WM\u timer
消息传递到窗口的WndProc:

如果
lpmsg
参数指向
WM\u TIMER
消息,并且
WM\u TIMER
消息的
lParam
参数不是
NULL
,则
lParam
指向调用的函数,而不是窗口过程

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

因此,至少,您必须使用
PostMessage()
而不是
SendMessage()
,这样您的手动
WM\u计时器
消息就可以通过窗口的消息队列到达
DispatchMessage()

否则,您必须使用自己的伪
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);
然而,这实际上是没有必要的,因为

如何在窗口的第一时间激活右侧的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);
    }
回调函数是一个函数,因此只需直接调用它,就像任何其他函数一样:

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

据我所知,TimerProc函数的lParam表示TimerProc函数的地址。你到底想做什么?使用
SetTimer(hWnd,1,MAKE_RAIN_TERM,MakeRain)
是否调用了
MakeRain
?肯定是。除此之外,至少还有两个bug在等待发生:
1
计时器将以准确的时间间隔过期的假设是没有根据的。如果使用该假设编写动画代码,它将看起来参差不齐<代码>2
计时器ID为指针大小。使用该功能可防止ID冲突,例如,使用(全局)对象的地址作为计时器ID。如果您希望即时调用
MakeRain
,不要使用magic,只需调用它即可。感谢您提供了正确数量的代码来查找问题。值得注意的是
WM_timer
是在队列处理函数中生成的,计时器实际上从未使其排队。“消息由GetMessage或PeekMessage函数发布。”因此调用
PostMessage
不会复制实际触发的计时器(尽管它可能会到达同一个处理程序)。是的,我知道这一点。计时器在队列中设置一个标志,然后消息检索检查该标志,如果队列中没有更高优先级的消息,则生成一个假的
WM_timer
消息。然后,该假消息与任何其他消息一样到达
DispatchMessage()
,DM将调用计时器回调或将消息传递到窗口的WndProc。手动发布
WM_TIMER
消息不会“触发计时器”,但会导致发布的
WM_TIMER
消息从消息队列中出来并到达
DispatchMessage()
与生成的
WM\u计时器
消息的方式相同。Raymond Chen在博客中介绍了
WM\u计时器
消息是如何生成的:以及。