Reputation: 39
I have a very specific problem involving a modeless dialog box in my application.
The dialog box freezes and becomes unresponsive to any messages sent to it by other functions in my application. What is interesting is that my debugging tells me that it freezes when the dialog procedure has received just around 5000 messages that it DID NOT handle. The only explanation I can think of is that the Windows Message Queue may be full and it is more or less confirmed by the fact that the stream of messages going through the dialog box seem to tone down immensely.
Now - I've never used dialog boxes in conjunction with an ordinary main window before, and so I may be making illegal moves. By this I mean that I update the dialog box's controls (static texts and a list box) directly by sending the specific controls messages using SendMessage or SetWindowText functions.
What I think is weird is, that this technique works perfectly until 5000 messages have passed.
The main loop sends messages to the dialog box via the parent window handle and use of IsDialogMessage function.
Both the Main window and the dialog box still receives messages, but the dialog box freezes.
Is there a way for me to empty the message queue manually or check its current volume to check if that is actually the problem? I use PeekMessage function to retrieve my messages, which according to MSDN should remove a message from the bottom of the Message queue.
Here is how I've implemented My main loop ( I am pretty sure it's completely legal ):
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();
}
}
I really hope one of you have an idea about what is wrong, because this is REALLY hard hard to debug!
The Dialog procedure is implemented like so: ( Sorry that you have to see my actual code )
First the static dialog procedure redirects the messages to a custom method:
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;
}
Then the actual procedure looks like this:
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;
}
Upvotes: 0
Views: 1218
Reputation: 39631
Your dialog procedure is creating two GDI objects, a brush and pen, every time it's called. It never destroys these objects. By default there's a 10,000 per process limit on GDI objects. Once you reach that limit the calls to create the objects will fail. Your code will then try to draw using invalid handle values, making it appear that your window has frozen.
The solution is to only create the objects once when handling the WM_INITDIALOG message. Also always check the return value of the functions you call for errors. If you had checked the return values to CreateSolidBrush and CreatePen you potentially could have figured this out earlier.
Upvotes: 6