Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS Tech Support » Any change in CExtCmdItem code in latest version? Collapse All
Subject Author Date
Suhai Gyorgy Mar 2, 2007 - 8:03 AM

Dear Support,

We are just about to release a new version of our product, but while testing the Release version, we encountered a crash while closing the application. The crash happens somewhere inside CFrameWnd::DestroyWindow(), but only in Release, never in Debug.

We have tried to narrow down the possible causes of the crash. Our application is multilanguage, and we use the following code to set the correct text for the command with ID nCmdId:

void RcStrings::set_command_strings(UINT nCmdId, HWND hWnd)
{
	CExtCmdItem * pCmdItem =
			g_CmdManager->CmdGetPtr(
				g_CmdManager->ProfileNameFromWnd(hWnd),
				nCmdId
				);
	ASSERT (pCmdItem != NULL );

	TCHAR *pctCmdString = SysMem::alloc_string(get_rc_string(nCmdId));
	TCHAR *pctBegin = pctCmdString;
	TCHAR *pctEnd = SysChar::strchr(pctBegin, ’\n’); if (pctEnd) *pctEnd = EOS;
	TCHAR *pctTab = SysChar::strchr(pctBegin, ’\t’); if (pctTab) *pctTab = EOS;
	pCmdItem->m_sMenuText = pctBegin;
	if (pctTab) pCmdItem->m_sAccelText = pctTab + 1; 
	if (pctEnd) {
		pctBegin = pctEnd + 1;
		pctEnd = SysChar::strchr(pctBegin, ’\n’); if (pctEnd) *pctEnd = EOS;
		//pCmdItem->m_sTipStatus = pctBegin; 
		if (pctEnd) {
			pctBegin = pctEnd + 1;
			pctEnd = SysChar::strchr(pctBegin, ’\n’); if (pctEnd) *pctEnd = EOS;
			pCmdItem->m_sTipTool = pctBegin;
		}
	}
	SysMem::mem_free(pctCmdString, __FILE__, __LINE__);
}
get_rc_string(nCmdId) takes care of getting the appropiate command texts in "MenuText\tAccelText\nStatusTip\nToolTip" format (\tAcceltext part is optional).

Crash always happens while closing the window, but only if I clicked on a command while running the application, or sometimes even enough if I just pop up one of the submenus.
In our CMainFrame::OnCreate, we go through all the commands (they are listed in an array) to change their texts with RcStrings::set_command_strings. If I just command this loop, the crash dissappears. I tried to modify one of your samples to reproduce the problem, but didn’t succeed for now. I was hoping you could point me to a direction, what things I should check, what kind of changes were made around CExtCmdItem’s texts since your last version. The very same code runs smoothly when compiling with your v2.63. Our version release is stuck at the moment because of this.

Thank you,
Chris

Suhai Gyorgy Mar 2, 2007 - 9:05 AM

Sorry, I forgot to add exception message: Access violation reading location 0x00000000.

Sergiy Lavrynenko Mar 2, 2007 - 11:06 AM

Dear Chris,

This exception is not related to the CExtCmdItem class. Please let me know more details about the string initialization APIs listed in the root message of this thread. Where the text lines are really stored in? I mean the get_rc_string() API. Does this API access any cross-thread/cross-process COM-based interfaces?

Suhai Gyorgy Mar 5, 2007 - 1:59 AM

To clarify it isn’t the string initialization to blame, I changed the mentioned method and removed call of get_rc_string():

void RcStrings::set_command_strings(UINT nCmdId, HWND hWnd)
{
	CExtCmdItem * pCmdItem =
			g_CmdManager->CmdGetPtr(
				g_CmdManager->ProfileNameFromWnd(hWnd),
				nCmdId
				);
	ASSERT (pCmdItem != NULL );

	//TCHAR *pctCmdString = SysMem::alloc_string(get_rc_string(nCmdId));
	TCHAR pctCmdString[] = _T("Test\tTest\nTest\nTest");
	TCHAR *pctBegin = pctCmdString;
	TCHAR *pctEnd = SysChar::strchr(pctBegin, ’\n’); if (pctEnd) *pctEnd = EOS;
	TCHAR *pctTab = SysChar::strchr(pctBegin, ’\t’); if (pctTab) *pctTab = EOS;
	pCmdItem->m_sMenuText = pctBegin;
	if (pctTab) pCmdItem->m_sAccelText = pctTab + 1; // van Accel a Command-hoz
	if (pctEnd) {
		pctBegin = pctEnd + 1;
		pctEnd = SysChar::strchr(pctBegin, ’\n’); if (pctEnd) *pctEnd = EOS;
		pCmdItem->m_sTipStatus = pctBegin;
		if (pctEnd) {
			pctBegin = pctEnd + 1;
			pctEnd = SysChar::strchr(pctBegin, ’\n’); if (pctEnd) *pctEnd = EOS;
			pCmdItem->m_sTipTool = pctBegin;
		}
	}
	//SysMem::mem_free(pctCmdString, __FILE__, __LINE__);
}
Crash still happens with this changed code, but if I comment out loop with calling of RcStrings::set_command_strings in CMainFrame::OnCreate, crash disappears. And as I wrote earlier, the very same code runs fine with previous version of Prof-UIS.

Technical Support Mar 5, 2007 - 11:57 AM

Seems your project requires more detailed testing. In a simple case, the ASSERT( AfxCheckMemory() ); code should be inserted at all reasonable places in all the memory management code provided by the SysMem namespace. But this requires the memory allocations based on the debug versions of the new/delete operators provided by MFC (i.e. the DEBUG_NEW should be defined at the beginning of the source files). The better memory crashing testes can be done with the Rational’s Purify software even trial version.

Suhai Gyorgy Mar 2, 2007 - 9:04 AM

I tested further(I turned on debugging in Release version). When debugging at the time of crash, Call stack shows:
    myApp.exe!CExtHookSink::HookChains_t::HookChainsWindowProc() + 0x167    C++
    myApp.exe!CExtHookSink::HookChains_t::g_HookWndProc() + 0x7b    C++
    user32.dll!77d48734()     
    user32.dll!77d48816()     
    user32.dll!77d4b4c0()     
    user32.dll!77d4b50c()     
    ntdll.dll!7c90eae3()     
    user32.dll!77d4daf6()     
    myApp.exe!CWnd::DestroyWindow() Line 989    C++
    myApp.exe!CMainFrame::DestroyWindow() Line 527    C++

So as I suspected, crash happens somewhere inside your piece of code. Please, check this issue!

Sergiy Lavrynenko Mar 2, 2007 - 11:00 AM

Dear Chris,

I have tried to re-produce the crash by debugging the SDI sample application. I have stepped through the sub-tree of functions invoked from the CExtHookSink::HookChains_t::HookChainsWindowProc() method and tried to setup all the local variables to NULL values but I failed to re-produce exactly the same Call Stack window content like in your message.

Please let me know the following details:

1) Whether the customizable toolbars and menus are used in the crashed application (I guess - yes).

2) Whether any kind if APIs which can track their own message loops are invoked at shutdown (any kind of cross-thread/cross-process COM interface invocations).

I guess there is something exist in your application what makes the de-initialization sequence of window hooks not exactly corresponding to the their installation sequence (in the inversed order) and some of CExtHookSink-based objects become destroyed/deleted earlier than expected. If my guess is correct, then putting the following code into the beginning of CMainFrame::DestroyWindow() method will fix the problem:

// this line is needed if the CMainFrame class is derived from the CExtCustomizeSite class
CExtCustomizeSite::RemoveAllWndHooks();
// this line will preliminary remove menu bar’s hooks
m_wndMenuBar.RemoveAllWndHooks();



Suhai Gyorgy Mar 5, 2007 - 2:13 AM

1) No, we are not using your customization subsystem.
2) In CMainFrame::DestroyWindow, we call CExtControlBar::ProfileBarStateSave; g_CmdManager->ProfileWndRemove; save two values in registry with the usual ::RegCreateKeyEx, ::RegSetValueEx, etc. APIs; kill a timer with CWnd::KillTimer and clear the clipboard with the following code:

 	COleDataObject oDataObject;
	if (oDataObject.AttachClipboard() && oDataObject.IsDataAvailable(ourClipboardFmt))
		::OleSetClipboard(NULL);
Thats all.

But m_wndMenuBar.RemoveAllWndHooks(); seems to solve our problem, no crash when that call is included right before calling CFrameWnd::DestroyWindow() at the end of CMainFrame::DestroyWindow. Even though, I still don’t know what CExtHookSink-based object could have caused the crash.

Technical Support Mar 5, 2007 - 11:58 AM

The Win32 APIs can pass hook calls during their invocations. But unfortunately we cannot find out which hook sink object is destroyed in the incorrect moment because its run-time type information in invalid and unavailable. Hook sinks are used by menu bar, MDI tabs, tab page containers, window non-client area skinning subsystem, some common controls, customize site and dynamic bar site. Even of two items of these list are used in your project, it is hardly possible to detect which of them is destroyed incorrectly. The only solution we see is to switch to using thread hooks in Prof-UIS.

Suhai Gyorgy Mar 7, 2007 - 2:30 AM

We are only using the menu bar and some common controls from the above list. How could we switch to using thread hooks in Prof-UIS?

Technical Support Mar 7, 2007 - 6:15 AM

You should not do anything special to switch to using thread hooks. We will implement this in Prof-UIS in one of the next releases. We recommend you use the current solution when you remove the menu bar’s hook explicitly