是否可以捕获Translate / Dispatch Message循环中的窗口消息/事件

时间:2014-12-18 17:53:17

标签: c++ windows winapi

是否可以捕获messages/events内的窗口Translate/Dispatch Message loop

这是窗口的消息处理方法

LRESULT CALLBACK MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_KEYDOWN:
        PressedKey[wParam] = true;
        break;
    case WM_KEYUP:
        PressedKey[wParam] = false;
        break;
    case WM_SIZE:

        break;
    default:
        break;
    }

    return DefWindowProc(hwnd, msg, wParam, lParam);
}

这里是Translate/Dispatch Message loop

void MyScreen::RunScreenMainLoop()
{
    while (WM_QUIT != msg.message)
    {
        //I wanna handle the messages here as well!
        switch (msg.message)
        {
        case WM_SIZE:
            show("size event called");
            break;
        default:
            break;
        }
        if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            //do other stuff
        }
    }
}

但是它永远不会进入switch语句,是否有一个工作要做到这一点?

4 个答案:

答案 0 :(得分:3)

一个明显的问题似乎是您在初始化之前阅读msg.message。请注意,在致电msg.message之前,您正在阅读PeekMessage。当然,由于我们无法看到msg被宣布的位置,也许真正的代码不会遇到这个问题。

现在,主要问题是WM_SIZE不是排队的消息,并且不通过消息队列到达。异步排队消息(如输入消息,计时器消息,绘制消息和直接传递给窗口过程的同步消息)之间存在重要区别。并且WM_SIZE是非排队的,同步的。

您可以从documentation中了解到这一点:

  

窗口通过其WindowProc函数接收此消息。

你不会用GetMessagePeekMessage等来捕获它。拦截此消息的方法来自窗口proc中的代码。

要了解有关排队和非排队邮件的详情,您可以从MSDN开始使用此主题:About Messages and Message Queues

答案 1 :(得分:1)

这不是你的消息循环应该如何看。试试这个:

void MyScreen::RunScreenMainLoop()
{
    MSG msg;
    while (1)
    {
        if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                break;

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            //do other stuff
        }
    }
}

然后通过继承这些窗口拦截特定窗口的消息:

Subclassing Controls

LRESULT CALLBACK MySubWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (msg)
    {
        case WM_SIZE:
            show("size event called");
            break;

        case WM_NCDESTROY:
          RemoveWindowSubclass(hWnd, MySubWndProc, uIdSubclass);
          break;

        // other case statements as needed...
    }

    return DefSubclassProc(hWnd, msg, wParam, lParam); // will dispatch the message to MsgProc()
}

hWnd = CreateWindowEx(...);
SetWindowSubclass(hWnd, MySubWndProc, 0, 0);

答案 2 :(得分:0)

您编写了消息泵,因此您可以在rmessage循环中自由添加代码来处理消息。例如,如果您不希望WM_CHAR转换,请不要致电TranslateMessage()If you want normal windows to have dialog-style tab navigation, call IsDialogMessage(). You can literally go crazy here.

线程消息以相同的方式工作。主题消息没有窗口,因此DispatchMessage()对他们没有任何作用。你必须处理消息泵中的那些。

但是,请记住,如果您输入对话框或使用其自己的消息泵的其他内容,您的自定义将丢失。 Here's an explanation that uses thread messages.

MFC,ATL,Qt,WPF等也可能有自己的消息泵设置,你必须注意(或他们自己的消息泵,期间,在这种情况下,你必须看看API是否提供挂钩机制)。

答案 3 :(得分:0)

如果您只想循环处理邮件,只需访问MSG获取您的邮件信息,如下所示:

 void MyScreen::RunScreenMainLoop()
{
    while (WM_QUIT != msg.message)
    {
        // Handle here your messages
        if (msg.message == WM_LBUTTONDOWN) // Mouse Left Button Event
        {
            MessageBox(NULL, L"You Clicked!", L"Info", MB_OK);
        }
        //
        if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
//do other stuff
        }
    }

}