【问题标题】:My Win32 application won't exit the main loop我的 Win32 应用程序不会退出主循环
【发布时间】:2012-05-29 19:15:15
【问题描述】:

这是我的主循环:

    while(TRUE)
    {

    PeekMessage(&msg,hWnd,0,0,PM_REMOVE);
        if (msg.message==WM_QUIT)
            break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);


    }

这是我的回调程序:

 LRESULT CALLBACK WinProc(HWND hWnd,UINT msg1,WPARAM wParam,LPARAM lParam)
 {
    switch(msg1)
    {
        case WM_DESTROY  :
        {
            PostQuitMessage(0);
            return 0;
        }
        break;
    }

    return DefWindowProc(hWnd,msg1,wParam,lParam);
}

我发现当我按下关闭按钮时,WM_NCLBUTTONDOWN 将在下一个循环中由 PeekMessage 函数返回,并且没有 WM_QUIT!

【问题讨论】:

标签: c windows winapi


【解决方案1】:

做消息循环的correct way

BOOL bRet;
MSG msg;
while ((bRet = GetMessage(&msg, hWnd, 0, 0)) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
}

如果你真的需要,你可以使用PeekMessage...但是你为什么忽略返回值?

另外,请注意这是特定于一个窗口。我相信PostQuitMessage 是一个线程...我不记得它是我的头,但你可能需要通过NULL 而不是hWnd

如果您有任何其他窗口,也可能会劫持它们的消息循环——我认为这通常不是问题,但它可能是一个问题;请记住这一点。

【讨论】:

  • 哇!谢谢! (Damet garm!:D)我将其更改为 Null 并且有效!
  • GetMessage 的 hWnd 参数在主消息循环中应该是 NULL
  • 您是否有关于从 GetMessage(或 PeekMessage)返回的 -1 表示错误的文档?我在 SDK 文档中找不到这个。它说只有非零 == 消息可用。
  • @PaulKeiste:你点击我的链接了吗?
  • 问题说他/她需要使用PeekMessage,它不会像GetMessage那样返回错误值,所以答案的主要要点是红鲱鱼。核心问题是原始代码指定了一个特定的窗口而不是 NULL,并且 WM_QUIT 消息没有针对特定的窗口。 (另一个可能的问题是 WM_CLOSE 可能不会导致 WM_DESTROY。我通常通过调用 DestroyWindow 显式处理 WM_CLOSE。)
【解决方案2】:

这是我找到的一些代码。它应该给你一些可以使用的东西。

    // Main message loop:
do
{
    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    // Run game code here.
    gTradeApp->ExecuteNextAction();
}
while (msg.message != WM_QUIT);

和 WndProc

LRESULT CALLBACK WndProc(HWND aHWnd, UINT aMessage, WPARAM aWParam, LPARAM aLParam)
{
    switch (aMessage)
    {
    case WM_COMMAND:
        return HandleCommand(aHWnd, aMessage, aWParam, aLParam);

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(aHWnd, aMessage, aWParam, aLParam);
    }

    return 0;
}

【讨论】:

    【解决方案3】:

    我建议坚持这一点,以确保 GetMessage 返回的错误 (-1) 可以得到正确处理:

    while(GetMessage(&Msg, NULL, 0, 0) > 0) {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    

    另外,另一个错误是没有正确处理 WM_CLOSE。试试这个,让你的程序真正听 WM_CLOSE(关闭按钮):

    LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        switch(Message) {
            case WM_CLOSE: {
                DestroyWindow(hwnd); // this
                break;
            }
            case WM_DESTROY: {
                PostQuitMessage(0);
                break;
            }
            default:
                return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
     }
    

    【讨论】:

    • 好吧,PeekMessage 不会阻塞。不建议通过乞求 v​​oor 消息来锁定 CPU 内核。为什么实际上需要这样做?
    • @Orwell:在某些情况下您肯定需要使用PeekMessage。如果您不这么认为,请首先考虑为什么该功能存在...
    • @Mehrdad:你的意思是游戏引擎循环吗?在循环中等待消息而不是尽快填充帧缓冲区并不是最方便的渲染方式。嗯,嗯,是的,在这种情况下需要 PeekMessage。
    猜你喜欢
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 2016-03-12
    • 1970-01-01
    • 2023-02-23
    • 2011-04-30
    • 1970-01-01
    • 2013-04-26
    相关资源
    最近更新 更多