2015-07-21 2 views
0

У меня есть очень специфическая проблема, связанная с немодальным диалоговым окном в моем приложении.Диалоговое окно зависает и перестает отвечать

Диалоговое окно замерзает и перестает отвечать на любые сообщения, отправленные ему другими функциями в моем приложении. Интересно, что моя отладка говорит мне, что он зависает, когда в процедуре диалога было получено около 5000 сообщений, которые DID NOT. Единственное объяснение, о котором я могу думать, это то, что очередь сообщений 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(); 
    } 
} 

Я действительно надеюсь, что один из вас есть идея о том, что это неправильно, потому что это действительно трудно трудно отлаживать!

Диалог процедура реализована следующим образом: (К сожалению, что вы должны увидеть мой фактический код)

Первый статический диалог процедура перенаправляет сообщения на пользовательский метод:

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

Можете ли вы показать окно proc для диалогового окна? –

+0

Также, как долго выполняется 'advanceFrame()'? Если вы измените свой цикл сообщений с 'if (PeekMessage (...' to 'while (PeekMessage (...' это имеет значение? –

+0

(для объяснения моего вышеизложенного комментария - скажем, advanceFrame() занимает 1/50-е секунды, это означает, что ваш цикл сообщений может обрабатывать не более 50 сообщений в секунду. Легко видеть, как это может увязнуть в этом) –

ответ

5

Ваша процедура диалога создает два объекта GDI, кисть и ручку, каждый раз, когда она вызывается. Он никогда не уничтожает эти объекты. По умолчанию для объектов GDI существует ограничение в 10 000 на процесс. Как только вы достигнете этого предела, вызовы для создания объектов не удастся. Затем ваш код попытается выполнить рисование с использованием недопустимых значений дескриптора, что означает, что ваше окно заморожено.

Решение должно создавать объекты только один раз при обработке сообщения WM_INITDIALOG. Также всегда проверяйте возвращаемое значение функций, которые вы вызываете для ошибок. Если вы проверили возвращаемые значения в CreateSolidBrush и CreatePen, вы могли бы подумать об этом раньше.

+0

Ничего себе! Это правда. Спасибо, также за советы по отладке! Я даже не подумал, что это может быть проблемой. Я очень благодарен. – Silverback