【问题标题】:Dialog box freezes and stops responding对话框冻结并停止响应
【发布时间】:2015-07-21 22:24:23
【问题描述】:

我有一个非常具体的问题,涉及我的应用程序中的无模式对话框。

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

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

我认为奇怪的是,这种技术在 5000 条消息传递之前完美运行。

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

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

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

这是我实现主循环的方式(我很确定它是完全合法的):

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;
}

【问题讨论】:

  • 你能显示你的对话框的窗口过程吗?
  • 另外,advanceFrame() 需要多长时间才能完成?如果您将消息循环从 if (PeekMessage(... 更改为 while (PeekMessage(... 会有所不同吗?
  • (解释我上面的评论 - 说 advanceFrame() 需要 1/50 秒,这意味着您的消息循环每秒最多可以处理 50 条消息。很容易看出它是如何陷入困境的这样做)
  • 感谢您的意见:AdvanceFrame() 现在不需要时间 - 因为它几乎什么都不做(我们说的是 200 - 1000 纳秒)。我不知道如何实现一段时间( peekMessage ... ),但仍然确保 AdvanceFrame 已运行。危险在于,如果只有一次没有消息,循环就会结束。
  • 实际上,您只需将if 更改为while 并取出else

标签: c++ winapi


【解决方案1】:

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

解决方案是在处理 WM_INITDIALOG 消息时只创建一次对象。还要始终检查您调用的函数的返回值是否存在错误。如果您检查过 CreateSolidBrush 和 CreatePen 的返回值,您可能会更早发现这一点。

【讨论】:

  • 哇!这是真的。谢谢 - 也为调试建议!我什至没有考虑到这可能是问题所在。我非常感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-15
  • 1970-01-01
相关资源
最近更新 更多