Winapi 如何使用sendmessage发送win32中具有timer proc的wm_计时器
我有一个计时器,ID为1,它有一个timerproc作为回调函数 我在timerproc中创建其他计时器(ID 2,3,…),它们使用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
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计时器
消息是如何生成的:以及。