对话框冻结并停止响应

时间:2015-07-21 22:24:23

标签: c++ winapi

我的应用程序中存在涉及无模式对话框的非常具体的问题。

对话框冻结,对我的应用程序中的其他功能发送给它的任何消息都没有响应。有趣的是,我的调试告诉我,当对话程序收到大约5000条 DID NOT 处理的消息时,它会冻结。我能想到的唯一解释是Windows消息队列可能已满,并且或多或少地证实了通过对话框的消息流似乎非常低调。

现在 - 我之前从未使用过与普通主窗口相关的对话框,因此我可能会进行非法移动。我的意思是我通过使用SendMessage或SetWindowText函数发送特定的控件消息来直接更新对话框的控件(静态文本和列表框)。

我认为奇怪的是,这种技术在5000条消息通过之前完美无缺。

主循环通过父窗口句柄和使用IsDialogMessage函数向对话框发送消息。

主窗口和对话框仍然会收到消息,但对话框会冻结。

有没有办法让我手动清空邮件队列或检查其当前卷以检查这是否真的是问题?我使用PeekMessage函数来检索我的消息,根据MSDN,它应该从消息队列的底部删除一条消息。

以下是我实现My main循环的方式(我很确定它完全合法):

while (true)    //while there is a message
{
    //if there was a windows message
    if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )  )
    {
        if ( msg.message == WM_QUIT  )  //if the message was WM_QUIT
                return 0;   //Exit the message loop

        if (  !IsDialogMessage( m_StatusHwnd, &msg ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }
    else
    {
        advanceFrame();
    }
}

我真的希望你们其中一个人对错误有所了解,因为这很难调试!

Dialog程序的实现方式如下:(很抱歉,你必须看到我的实际代码)

首先,静态对话框程序将消息重定向到自定义方法:

BOOL CALLBACK DXCore::statusDlgProc( HWND hwnd,
                                    UINT msg,
                                    WPARAM wParam,
                                    LPARAM lParam )
{

    if ( msg == WM_INITDIALOG )  SetWindowLongPtr( hwnd, DWLP_USER, lParam);
    DXCore * pCore = reinterpret_cast<DXCore*>( GetWindowLongPtr( hwnd, DWLP_USER ) ) ;
    if ( pCore ) return pCore->displayStatusDlgProc( hwnd, msg, wParam, lParam );

    //return the message for windows to handle it
    return FALSE;
}

然后实际程序如下:

BOOL                DXCore::displayStatusDlgProc( HWND hwnd,
                                        UINT msg,
                                        WPARAM wParam,
                                        LPARAM lParam )
{




HBRUSH brush = CreateSolidBrush( COLORREF( RGB( 255, 0, 0 ) ) ); //red
HPEN blackPen = CreatePen( PS_SOLID, 2, COLORREF( RGB(0,0,0 ) ) );
HDC hdc; PAINTSTRUCT ps;


RECT clientArea; 
GetClientRect( hwnd, &clientArea );
int gizmoRadius= 5;


m_GismoOrigon.x = clientArea.left + 150;
m_GismoOrigon.y = clientArea.top + 460;

//OutputDebugString( "Dillermand\n" );
dlgProcCounter += 1;




switch ( msg )
{


case WM_INITDIALOG:
    m_FPSCount = GetDlgItem( hwnd, IDC_STATIC_FPS );
    if ( !m_FPSCount ) MessageBox( NULL, "ghFPSCount", "DAMN", MB_OK );

    m_CamPosX = GetDlgItem( hwnd, IDC_CAMPOSX );
    if ( !m_CamPosX ) MessageBox( NULL, "ghCamPosX", "DAMN", MB_OK );

    m_CamPosY = GetDlgItem( hwnd, IDC_CAMPOSY );
    if ( !m_CamPosY ) MessageBox( NULL, "ghCamPosY", "DAMN", MB_OK );

    m_CamPosZ = GetDlgItem( hwnd, IDC_CAMPOSZ );
    if ( !m_CamPosZ ) MessageBox( NULL, "ghCamPosZ", "DAMN", MB_OK );

    m_hStatusMessages = GetDlgItem( hwnd, IDSTATUS_PROGMSG );
    if ( !m_hStatusMessages ) MessageBox( NULL, "ghStatusMessages", "DAMN", MB_OK );
    else
    {
        SetParent( m_hStatusMessages, hwnd );
    }


    m_RunButton = GetDlgItem( hwnd, IDCSTATUS_RUN_BTN );
    if ( !m_RunButton ) MessageBox( NULL, "ghRunButton ", "DAMN", MB_OK );

    m_PauseButton = GetDlgItem( hwnd, IDSTATUS_PAUSE_BTN );
    if ( !m_PauseButton ) MessageBox( NULL, "ghPauseButton", "DAMN", MB_OK );

    SetWindowText( m_CamPosX, "0" );
    SetWindowText( m_CamPosY, "0" );
    SetWindowText( m_CamPosZ, "0" );



    return TRUE;

case WM_PAINT:



    hdc = BeginPaint( hwnd, &ps );

        SelectObject( hdc, brush );
        SelectObject( hdc, blackPen );
        Ellipse( hdc, m_GismoOrigon.x - gizmoRadius, m_GismoOrigon.y - gizmoRadius, m_GismoOrigon.x + gizmoRadius, m_GismoOrigon.y + gizmoRadius ) ;

        EndPaint( hwnd, &ps );

    return TRUE;

case WM_COMMAND:

    return TRUE;

case WM_NOTIFY:

    return TRUE;

case WM_CTLCOLORSTATIC:
    return TRUE;


case WM_TIMER:
    return TRUE;



case WM_DESTROY:
    if ( MessageBox( hwnd, "Exit Program?", "Do Not Want!", MB_YESNO ) == IDYES )
    {
        PostQuitMessage( 0 );
    }
    else ShowWindow(m_StatusHwnd, true );
    return TRUE;




case WM_CLOSE:
    DestroyWindow( m_StatusHwnd );

    return TRUE;


default:

    string s = std::to_string( dlgProcCounter ) + " Unhandled Dlg message: " + std::to_string( msg ) + "\n";
    OutputDebugString( s.c_str( ) );
    return (INT_PTR)FALSE;
}



return FALSE;
}

1 个答案:

答案 0 :(得分:6)

每次调用时,对话框程序都会创建两个GDI对象,一个画笔和一个笔。它永远不会破坏这些物体。默认情况下,GDI对象的每个进程限制为10,000。达到该限制后,创建对象的调用将失败。然后,您的代码将尝试使用无效的句柄值进行绘制,使您的窗口显示已冻结。

解决方案是在处理WM_INITDIALOG消息时仅创建一次对象。还要始终检查您调用的函数的返回值是否有错误。如果您已经检查了CreateSolidBrush和CreatePen的返回值,那么您可能已经提前确定了这一点。