WM_TIMER在特定条件下丢失

Eur*_*low -1 c winapi

#include <windows.h>
#include <stdio.h>

class tWnd {
private:
    static LRESULT CALLBACK Disp_test_WndProc(
        HWND hwnd,        // handle to window
        UINT uMsg,        // message identifier
        WPARAM wParam,    // first message parameter
        LPARAM lParam)    // second message parameter
    {
        switch (uMsg) 
        {
            case WM_TIMER:{
                printf("timer\n");

                return 0;
            }

            case WM_PAINT: 
                // Paint the window's client area. 
                return 0; 

            case WM_DESTROY: 
                return 0; 

            case WM_HOTKEY:{

            } return 0;
            // 
            // Process other messages. 
            // 
            default: 
                return DefWindowProc(hwnd, uMsg, wParam, lParam); 
        } 
        return 0; 
    }

public:     
    tWnd() {

            WNDCLASSA wc;
            wc.style = CS_HREDRAW | CS_VREDRAW; 
            wc.lpfnWndProc = (WNDPROC) Disp_test_WndProc; 
            wc.cbClsExtra = 0; 
            wc.cbWndExtra = 0; 
            wc.hInstance = GetModuleHandle(NULL); 
            wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
            wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
            wc.hbrBackground = (HBRUSH) NULL; 
            wc.lpszMenuName =  ""; 
            wc.lpszClassName = "Test"; 

            if (!RegisterClass(&wc)) 
               return; //cannot register window class



        HWND testingWindow = CreateWindowEx(WS_EX_TOPMOST,"Test","topmost",WS_VISIBLE,0,0,200,200,0,0,0,0);

        SetTimer(testingWindow,101,500,(TIMERPROC)NULL);

        MSG recent;
        BOOL result;
        while((result=GetMessage(&recent,testingWindow,0,0))&&result!=-1) { //bool can be -1 in MS world
            if(recent.message==WM_USER+1) break;
            TranslateMessage(&recent);
            DispatchMessage(&recent);
        }
    }
};

int main(int argc, char **argv)
{
    tWnd();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

此代码永远不会获得WM_TIMER消息.

#include <windows.h>
#include <stdio.h>

class tWnd {
private:
    static LRESULT CALLBACK Disp_test_WndProc(
        HWND hwnd,        // handle to window
        UINT uMsg,        // message identifier
        WPARAM wParam,    // first message parameter
        LPARAM lParam)    // second message parameter
    {
        switch (uMsg) 
        {
            case WM_TIMER:{
                printf("timer\n");

                return 0;
            }

            case WM_DESTROY: 
                return 0; 

            case WM_HOTKEY:{

            } return 0;
            // 
            // Process other messages. 
            // 
            default: 
                return DefWindowProc(hwnd, uMsg, wParam, lParam); 
        } 
        return 0; 
    }

public:     
    tWnd() {

            WNDCLASSA wc;
            wc.style = CS_HREDRAW | CS_VREDRAW; 
            wc.lpfnWndProc = (WNDPROC) Disp_test_WndProc; 
            wc.cbClsExtra = 0; 
            wc.cbWndExtra = 0; 
            wc.hInstance = GetModuleHandle(NULL); 
            wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
            wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
            wc.hbrBackground = (HBRUSH) NULL; 
            wc.lpszMenuName =  ""; 
            wc.lpszClassName = "Test"; 

            if (!RegisterClass(&wc)) 
               return; //cannot register window class



        HWND testingWindow = CreateWindowEx(WS_EX_TOPMOST,"Test","topmost",WS_VISIBLE,0,0,200,200,0,0,0,0);

        SetTimer(testingWindow,101,500,(TIMERPROC)NULL);

        MSG recent;
        BOOL result;
        while((result=GetMessage(&recent,testingWindow,0,0))&&result!=-1) { //bool can be -1 in MS world
            if(recent.message==WM_USER+1) break;
            TranslateMessage(&recent);
            DispatchMessage(&recent);
        }
    }
};

int main(int argc, char **argv)
{
    tWnd();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这段代码很好地获取了WM_TIMER消息.

两者之间的唯一区别是WM_PAINT消息在第二个变体中是默认处理的.为什么要处理WM_PAINT会阻止程序接收WM_TIMER消息?我该如何解决这个问题?

如果重要的话,我正在使用MingW w64(GCC 5.3.0).

IIn*_*ble 5

窗口WM_PAINT在其无效区域非空时接收消息.这在文档中称为ValidateRect():

系统继续生成WM_PAINT消息,直到验证当前更新区域.

标准WM_PAINT处理程序验证无效区域(例如通过调用BeginPaint()),默认实现执行此操作.简单地返回0将不会验证窗口,并继续接收WM_PAINT消息.

WM_TIMER消息的优先级低于WM_PAINT消息.您的窗口过程永远不会看到计时器消息,因为它一直忙于忽略绘制消息.这在文档中称为WM_TIMER:

WM_TIMER消息是低优先级消息.仅当线程的消息队列中没有其他更高优先级的消息时,GetMessagePeekMessage函数才会发布此消息.

  • @EuriPinhollow:它需要验证无效区域.它通常通过调用`BeginPaint`,然后绘制无效部分来实现.如果你没有任何绘画,你也可以调用`ValidateRect`. (2认同)