We have added auto complete to an edit box we have on our status bar. Now we find that we can crash when calling SetIndicators. What is happening is that RemoveAll is looping over m_arrPanes and setting the m_pSutatusBar to null in the loop and then calling InternalRelease.
When InternalRelease is called, my CEdit control gets the expected DestroyWindow call. When the OS processes the window destruction call, the IAutoComplete object I have connected to the edit control is being decoupled and deep in the OS, the code dispatches WM_PAINT messages.
The status bar gets a WM_PAINT message and, to make a long story short this happens:
ToolkitPro1930vc160x64UD.dll!CXTPStatusBar::GetPaintManager() Line 1125 C++ ToolkitPro1930vc160x64UD.dll!CXTPStatusBar::GetStatusBarPaintManager() Line 1133 C++ ToolkitPro1930vc160x64UD.dll!CXTPStatusBarPane::OnDraw(CDC * pDC=0x0000000000ded240, CRect rcItem={...}) Line 271 C++ ToolkitPro1930vc160x64UD.dll!CXTPStatusBar::DrawPaneEntry(CDC * pDC=0x0000000000ded240, int nIndex=4, CRect rcItem={...}) Line 1144 C++ ToolkitPro1930vc160x64UD.dll!CXTPStatusBar::OnDraw(CDC * pDC=0x0000000000ded240) Line 1218 C++ ToolkitPro1930vc160x64UD.dll!CXTPStatusBar::OnPaint() Line 1151 C++
In OnDraw, the code loops thru the same array of CXTPStatusBarPane objects that are currently being released. The edit control pane is encountered and the OnDraw method is called and the code doesn't check to see that m_pStatusBar is now set to null by the RemoveAll code that is still executing.
We are seeing this with CJ 19.3 and Windows 10 1809 but it doesn't occur on all machines so may be somewhat OS dependent.
I added code in the edit control DestroyWindow call to PeekMessage and remove WM_PAINT (the OS dispatches the paint messages). That forces the paint to occur right away and I crash independent of the OS.
CWnd* pParent = GetParent(); if( pParent ) { MSG Msg; if( PeekMessage( &Msg, pParent->GetSafeHwnd(), WM_PAINT, WM_PAINT, PM_NOREMOVE|PM_NOYIELD ) ) { TRACE("Found paint message for status bar"); while (::PeekMessage(&Msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE)) { } } }
It looks like I will be modifying CJ code to either test the status bar backpointer so it doesn't crash or to remove the item from the array before destroying it.
|