自定义WM_APP消息未发布在消息队列中

时间:2019-10-31 00:41:14

标签: c windows winapi

我正在尝试将WM_SIZE发送到窗口过程时发送自定义消息(WM_APP +1)。我希望能够使用PeekMessage从其他函数中捕获它并执行某些操作。但是,当我测试它时,消息似乎没有发送到队列。添加一些printf语句向我展示了它进入了窗口过程。奇怪的是,当我逐步调试程序中的代码时,它可以正常工作,但是当我正常运行时,它又回到了无法正常工作的状态。

存在问题的示例程序,调整窗口大小以进行测试:

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

#pragma comment(lib, "user32.lib")

#define OBG_EVENT_QUIT 0
#define OBG_EVENT_RESIZE 1
#define OBG_EVENT_NO -1
#define OBG_EVENT_UNKNOWN -2

//user defined event
#define OBG_WM_RESIZE (WM_APP + 1)

typedef union
{
    int type;

    struct
    {
        int type;
        int width;
        int height;

    } resizeEvent;

} obg_event;

LRESULT CALLBACK obgpf_DefaultWindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
    LRESULT result = 0;

    switch(message)
    {
        case WM_CLOSE:
        {
            PostMessageA(window, WM_QUIT, 0, 0);
        } break;

        //this should be handled by OBGGetEvent
        case OBG_WM_RESIZE:
        {
            printf("MESSAGE WENT THROUGH. DON'T WANT THIS\n");
        } break;

        case WM_SIZE:
        {
            PostMessageA(window, OBG_WM_RESIZE, wParam, lParam);
        } break;

        default:
        {
            result = DefWindowProc(window, message, wParam, lParam);
        } break;
    }

    return result;
}

int OBGGetEvent(obg_event *event)
{
    int moreMessages = 0;
    MSG message;

    if(PeekMessage(&message, 0, 0, 0, PM_REMOVE))
    {
        moreMessages = 1;
        switch(message.message)
        {
            case WM_QUIT:
            {
                event->type = OBG_EVENT_QUIT;
            } break;


            case OBG_WM_RESIZE:
            {
                event->type = OBG_EVENT_RESIZE;
                event->resizeEvent.type = OBG_EVENT_RESIZE;
                event->resizeEvent.width = LOWORD(message.lParam);
                event->resizeEvent.height = HIWORD(message.lParam);
            } break;

            default:
            {
                event->type = OBG_EVENT_UNKNOWN;
                TranslateMessage(&message);
                DispatchMessage(&message);
            } break;
        }
    }
    else
    {
        event->type = OBG_EVENT_NO;
    }

    return moreMessages;
}

int main()
{
    HINSTANCE instance = GetModuleHandleA(0);

    WNDCLASSEX windowClass = {0};
    windowClass.cbSize = sizeof(windowClass);
    windowClass.style = CS_HREDRAW | CS_VREDRAW;
    windowClass.lpfnWndProc = obgpf_DefaultWindowCallback;
    windowClass.hInstance = instance;
    windowClass.lpszClassName = "testClass";
    windowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
    windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    windowClass.hIconSm = LoadIcon(0, IDI_APPLICATION);
    windowClass.hCursor = LoadCursorA(0, IDC_ARROW);

    HWND window;

    if(RegisterClassEx(&windowClass))
    {
        window = CreateWindowEx(0,
                                windowClass.lpszClassName,
                                "test window",
                                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                                CW_USEDEFAULT,
                                CW_USEDEFAULT,
                                500,
                                300,
                                0,
                                0,
                                instance,
                                0);

        if(window)
        {
            int appIsRunning = 1;
            obg_event event = {0};
            event.type = -1;
            while(appIsRunning)
            {
                while(OBGGetEvent(&event))
                {
                    if(event.type == OBG_EVENT_QUIT)
                    {
                        printf("event quit\n");
                        appIsRunning = 0;
                        break;
                    }
                    else if(event.type == OBG_EVENT_RESIZE)
                    {
                        printf("window resized: width %d height %d\n", event.resizeEvent.width, event.resizeEvent.height);
                    }
                }

                Sleep(33);
            }
        }
        else
        {
            printf("window error\n");
        }
    }
    else
    {
        printf("windowClass error\n");
    }

    return 0;
}

我尝试使用SendMessage而不是PeekMessage进行此操作,但是发生了同样的事情。不知道我缺少什么或误会了,但是我们会提供任何帮助!

编辑:添加了一个完整的工作程序来重现该问题

1 个答案:

答案 0 :(得分:2)

谢谢您的示例代码。

您看到的行为是因为使用鼠标调整窗口大小时,操作系统会进入模式消息循环以处理鼠标输入。在此循环中,您的消息循环不会运行-这意味着您的PeekMessage()和特殊消息处理也不会运行。相反,消息只是按常规方式发送到您的窗口过程中。

马上想到两种解决方案,但是如何处理这实际上取决于程序的设计以及为什么要以这种方式处理大小事件。

我的第一个想法是跟踪您是否处于模态大小调整循环中,并将通知消息推迟发布,直到循环结束为止。下面是使用您提供的窗口过程进行操作的示例。

第二种解决方案是只要获得WM_SIZE就直接直接调用调整大小事件处理程序(或者,如果必须通过事件系统,则将其处理程序放入窗口过程中,而不要使用{{1 }}。

第一个建议的示例代码:

PostMessage

(对不起,这是C ++代码,我刚刚注意到您已将其标记为C,但是原理是相同的。)