我有一个非常具体的问题,涉及我的应用程序中的无模式对话框.
该对话框冻结,并且对我的应用程序中的其他功能发送给它的任何消息都没有响应.有趣的是,我的调试告诉我,当对话程序收到大约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();
}
}
Run Code Online (Sandbox Code Playgroud)
我真的希望你们中的一个人知道出了什么问题,因为这真的很难调试!
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;
}
Run Code Online (Sandbox Code Playgroud)
那么实际的过程如下所示:
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;
}
Run Code Online (Sandbox Code Playgroud)
您的对话程序每次调用时都会创建两个GDI对象,一个画笔和一个笔.它永远不会破坏这些物体.默认情况下,GDI对象的每个进程限制为10,000.达到该限制后,创建对象的调用将失败.然后,您的代码将尝试使用无效的句柄值进行绘制,使您的窗口显示已冻结.
解决方案是仅在处理WM_INITDIALOG消息时创建一次对象.还要始终检查您调用的函数的返回值是否有错误.如果您已经将返回值检查到CreateSolidBrush和CreatePen,那么您可能已经提前确定了这一点.