当我使用MsgWaitForMultipleObjects时为什么不能退出MFC程序?

时间:2018-08-08 12:15:13

标签: mfc

HANDLE g_event = CreateEvent(NULL, TRUE, FALSE, L"tasdfasdfsadfasdfasdfas");
BOOL bIsok = TRUE;
while(bIsok)
{
    DWORD dwTime = MsgWaitForMultipleObjects(1, &g_event, FALSE, 5000, QS_ALLINPUT);
    MSG msg;
    switch(dwTime)
    {
    case WAIT_OBJECT_0:
    break;

    case WAIT_OBJECT_0 + 1:
    {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            switch(msg.message)
            {
            case WM_DESTROY:
            case WM_CLOSE:
            case WM_QUIT:
                break;
            default:
                break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    break;
    case WAIT_TIMEOUT:
    break;
    }
}

运行此代码,然后单击关闭按钮。该窗口将隐藏,但程序不会退出。

为什么以及如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

该过程永远不会终止,因为while(bIsok)循环的谓词永远不会求值为false。要解决此问题,代码需要在关闭时更新bIsok。最简单的解决方法是在WM_QUIT消息处理程序中这样做:

    if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        switch(msg.message)
        {
        case WM_DESTROY:
        case WM_CLOSE:
            break;
        case WM_QUIT:
            bIsok = false;
            break;
        default:
            break;
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

尽管解决了紧迫的问题,但仍有更多应解决的代码问题,尤其是当消息到达时,无法完全耗尽消息队列。 MsgWaitForMultipleObjects的文档包含以下说明:

  

WAIT_OBJECT_0 + nCount :在线程的输入队列中可以使用dwWakeMask参数中指定类型的新输入。 PeekMessageGetMessageWaitMessage等功能将队列中的消息标记为旧消息。因此,在调用这些函数之一之后,对MsgWaitForMultipleObjects的后续调用将不会返回,直到指定类型的新输入到达为止。。

每当收到一条消息时,代码仅处理第一条消息,然后继续等待消息。相反,代码应在继续之前处理所有消息。

并非严格要求,但我还将应用以下更改:

  • MsgWaitForMultipleObjects中删除超时。不需要它,只是使线程反复唤醒,即使什么也没发生。
  • 将消息处理移至顶层窗口的窗口过程。 Closing the window提供有关标准过程的信息:响应DestroyWindow调用WM_CLOSE,响应PostQuitMessage调用WM_DESTROY

这是顶级窗口的window procedure

LRESULT CALLBACK MyWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    switch( uMsg )
    {
    case WM_CLOSE:
        ::DestroyWindow( hwnd );
        return 0;
    case WM_DESTROY:
        ::PostQuitMessage( 0 );
        return 0;
    default:
        return ::DefWindowProc( hwnd, uMsg, wParam, lParam );
    }
}

更新后的主循环:

HANDLE g_event = CreateEvent(NULL, TRUE, FALSE, L"tasdfasdfsadfasdfasdfas");
BOOL bIsok = TRUE;
while(bIsok)
{
    DWORD dwTime = MsgWaitForMultipleObjects(1, &g_event, FALSE, INFINITE, QS_ALLINPUT);
    switch(dwTime)
    {
    case WAIT_OBJECT_0:
    break;

    case WAIT_OBJECT_0 + 1:
    {
        MSG msg;
        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if(msg.message == WM_QUIT)
            {
                bIsok = false;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    break;
    case WAIT_TIMEOUT:
    break;
    }
}