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 » GetErrorMessage Collapse All
Subject Author Date
Suhai Gyorgy Nov 16, 2006 - 5:10 AM

Dear Support,

I’m using CExtPropertyCtrl that I integrated into your FormEditor sample. One of my property stores have a property value that uses CExtGridCellFileImage cell. When I press the "..." button in the cell to open an icon file, and after that I return from the OpenFileDialog pressing OK, I get an assertion.

Call stack (using ProfUIS v2.55):

>    FormEditor.exe!CSimpleException::GetErrorMessage(wchar_t * lpszError=0x01827ba8, unsigned int nMaxError=0, unsigned int * pnHelpContext=0x0012e874) Line 196 + 0x2a    C++
    FormEditor.exe!CExtGridCellFile::OnButtonPressed(CExtGridWnd & wndGrid={...}, int nButtonType=0, const tagRECT & rcCellExtra={...}, const tagRECT & rcCell={...}, long nVisibleColNo=1, long nVisibleRowNo=2, long nColNo=1, long nRowNo=2, int nColType=0, int nRowType=0) Line 30528 + 0x43    C++

Your OnButtonPressed method (partial):

	if( dlgFileDialog.DoModal() == IDOK )
	{
		TextSet( LPCTSTR(dlgFileDialog.GetPathName()) ); // <--- from here into GetErrorMessage
		...
	}

When I was debugging and stopped in your code just before the assertion, I saw that I get into this GetErrorMessage method right after returning from LPCTSTR() but before getting into TextSet.

My main question: What could be the reason here to get into this GetErrorMessage method?
Since my code grew to be quite big, I tried to put as little as neccesary into your original FormEditor sample to reproduce the bug, but (developer’s worst nightmare) that version worked flowlessly. I might try to strip down my code, but it’d be a big job, and you might know the solution to my problem without me having to go through that hassle (espacially that I’m afraid I end up with a working version again).

Thank you,
Chris

Technical Support Nov 16, 2006 - 11:53 AM

We failed to reproduce the problem by adding the following code at the end of the CStarButton::GetPropertyStore() method in the PropertyGrid sample:

CExtPropertyValue * pValFileImage = new CExtPropertyValue( _T("FileImage") );
    pValFileImage->NameSet( _T("FileImage.") );
    pValFileImage->DescriptionSet( _T("FileImage.") );
CExtGridCellFileImage * pCellFileImage =
        STATIC_DOWNCAST(
            CExtGridCellFileImage,
            pValFileImage->ValueDefaultGetByRTC(
                RUNTIME_CLASS( CExtGridCellFileImage )
                )
            );
pCellFileImage;
    pValFileImage->ValueActiveFromDefault();
    pCategoryMisc->ItemInsert(
        pValFileImage
        );
If the problem occurs on one computer only, please try finding out what’s special with this computer. If the problem persists on more than one computer, would you send a test project to us?

Suhai Gyorgy Nov 17, 2006 - 2:26 AM

The problem persists on another computer as well. Making a test-project that has the same problem might take me a while, though. In the meanwhile I would like to ask something different that may not to do anything with the above problem, but could solve another of my problems:
As I mentioned above, I heavily modified your FormEditor sample for my own needs. But a struct named DOC_ITEM_DATA is still used, and I even added a CExtPropertyStore *m_pPS tag to it, as you suggested in your PropertyGrid-Walkthrough. Since my Document-based class has a CArray < DOC_ITEM_DATA, DOC_ITEM_DATA & > member and CArray needs an operator = for the DOC_ITEM_DATA, you wrote this operator = method already. Now I need to add the copying of this new m_pPS member to this method, as well. What’s the proper way to do this copying?

//.h
	struct AFX_NOVTABLE DOC_ITEM_DATA
	{
		DWORD m_dwItemID;
		CRect m_rcItem;
		CExtPropertyStore *m_pPS;
 
		DOC_ITEM_DATA();
		...
		~DOC_ITEM_DATA();
		DOC_ITEM_DATA & operator=( const DOC_ITEM_DATA & other );
		...
	}
 
// .cpp
CFormEditorDoc::DOC_ITEM_DATA::DOC_ITEM_DATA()
	: m_dwItemID( ID_CONTROL_POINTER )
	, m_rcItem( 0, 0, 0, 0 )
	, m_pPS(NULL)
{
}
 
CFormEditorDoc::DOC_ITEM_DATA::~DOC_ITEM_DATA()
{
	if( m_pPS != NULL ) {
		// Is this the right code here?
		CMainFrame *pFrame = reinterpret_cast<CMainFrame *>(AfxGetMainWnd());
		ASSERT_VALID(pFrame);
		if (pFrame->m_wndPropertyGrid.PropertyStoreGet() == m_pPS)
			pFrame->m_wndPropertyGrid.PropertyStoreSet(NULL);
		m_pPS->Delete();
	}
}
 
CFormEditorDoc::DOC_ITEM_DATA & CFormEditorDoc::DOC_ITEM_DATA::operator = (
	const CFormEditorDoc::DOC_ITEM_DATA & other
	)
{
	m_dwItemID = other.m_dwItemID;
	m_rcItem = other.m_rcItem;
	m_rcItem.NormalizeRect();
	if (m_pPS != NULL) {
		// What shall I put here?
	}
	return *this;
}

Technical Support Nov 17, 2006 - 12:46 PM

We think the CFormEditorDoc::DOC_ITEM_DATA::operator=() method should look like:

CFormEditorDoc::DOC_ITEM_DATA & CFormEditorDoc::DOC_ITEM_DATA::operator = (
    const CFormEditorDoc::DOC_ITEM_DATA & other
    )
{
    m_dwItemID = other.m_dwItemID;
    m_rcItem = other.m_rcItem;
    m_rcItem.NormalizeRect();
    bool bSetupOwnPropertyStore = false;
    CMainFrame * pFrame = (CMainFrame*)( ::AfxGetMainWnd() );
    ASSERT_VALID( pFrame );
    if( m_pPS != NULL )
    {
        if( pFrame->m_wndPropertyGrid.PropertyStoreGet() == m_pPS )
        {
            pFrame->m_wndPropertyGrid.PropertyStoreSet( NULL );
            bSetupOwnPropertyStore = true;
        }
        m_pPS->Delete();
        m_pPS = NULL;
    }
    if( other.m_pPS != NULL )
    {
        m_pPS = new CExtPropertyStore;
        CMemFile _file;
        { BLOCK BEGIN: saving
            CArchive ar( &_file, CArchive::store );
            other.m_pPS->Serialize( ar );
            ar.Flush();
            ar.Close();
        } BLOCK END: saving
        _file.Seek( 0, CFile::begin );
        { BLOCK BEGIN: loading
            CArchive ar( &_file, CArchive::load );
            m_pPS->Serialize( ar );
        } BLOCK END: loading
        if( bSetupOwnPropertyStore )
            pFrame->m_wndPropertyGrid.PropertyStoreSet( m_pPS );
    }
    return *this;
}
The better and faster solution should be not based on copied CExtPropertyStore objects. You can keep all the CExtPropertyStore objects somewhere outside DOC_ITEM_DATA objects. This would allow you to assign pointers only and not to reset the property store in the property grid control.

Suhai Gyorgy Nov 20, 2006 - 4:36 AM

I don’t exactly understand what you mean by keeping all the CExtPropertyStore objects somewhere outside DOC_ITEM_DATA objects. The problem with assigning pointers only is this: (as walkthrough suggests) in the CExtPropertyValues of the CExtPropertyStore I keep a pointer to the DOC_ITEM_DATA object to which this propertyvalue is assigned to. If in the operator = method I only assign the pointer of the propertystore to the new DOC_ITEM_DATA object, the pointers inside the propertyValues won’t point to the right DOC_ITEM_DATA. Actually this is also problem with the operator = method you showed above.

Technical Support Nov 20, 2006 - 1:05 PM

You have N controls on the form. You should use an array of N pointers to the CExtPropertyStore objects in the view class or in the document class. This will allow you to keep the pointers inside the document item classes in a simpler way and assign only pointer values without re-creating/cloning property stores and without refreshing the property grid control on assignment.

Suhai Gyorgy Nov 22, 2006 - 4:38 AM

I could successfully strip down my code to present the original problem I mentioned in the first message of this thread (the one with the GetErrorMessage). I’m sending it to you by e-mail.