Link to home
Start Free TrialLog in
Avatar of andy06
andy06Flag for Germany

asked on

MFC First chance exception

hi experts,
I created a MFC dialog based application with VS2008.There is no error message when compiling but when debugging the debugger stops on the following "ALTASSERT()" inside the altsimpstr.h file at line 107:

void Release() throw()
{
ATLASSERT( nRefs != 0 ); // The debugger stops hier
if( _AtlInterlockedDecrement( &nRefs ) <= 0 )
{
   pStringMgr->Free( this );
}
}
the call stack dump at that point of crash is:
mfc90d.dll!ATL::CStringData::Release()  Line 107 + 0x3 bytes
mfc90d.dll!ATL::CSimpleStringT<wchar_t,1>::~CSimpleStringT<wchar_t,1>()  Line 279
mfc90d.dll!ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >()  Line 1011 + 0x8 bytes
Test.exe!CTestDlg::~CTestDlg()  + 0x5a bytes
Test.exe!CTestApp::InitInstance()  Line 73 + 0x1c bytes
mfc90d.dll!AfxWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, char * lpCmdLine=0x00151f17, int nCmdShow=0x00000001)  Line 37 + 0xd bytes
Test.exe!WinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, char * lpCmdLine=0x00151f17, int nCmdShow=0x00000001)  Line 30
Test.exe!__tmainCRTStartup()  Line 574 + 0x35 bytes
Test.exe!WinMainCRTStartup()  Line 399

The first chance exception is at 0x7861d8ec with an access violation at the reading location 0xfffffffc.
What does that mean?
Thank you
Andy
      
      
      
      
      
      

      
      

      
Avatar of Gurudenis
Gurudenis
Flag of Ukraine image

I'm afraid there's no simple answer. You need to debug thoroughly. Have you tried:
1) commenting parts of the code
2) stepping through the code
3) ensuring that CString members of CTestDlg are only destroyed once

Also, see these links (with a bit of luck, one of these may prove to be relevant):
1) http://www.codeproject.com/script/Forums/View.aspx?fid=1647&msg=2741873
2) http://social.microsoft.com/Forums/en-US/vcgeneral/thread/26100fab-e983-4da2-8afb-9f805567828c
3) http://www.codeguru.com/forum/archive/index.php/t-224686.html
>>>> The first chance exception is at 0x7861d8ec with an access violation at the reading location 0xfffffffc.
>>>> What does that mean?

Firstly, a first chance exception not necessarily is an error. It simply means that the workflow happened to jump into a catch block. So, when debugging you often will see first chance exceptions which simply means that the MFC makes some checks, e. g. on handles/pointers associated to a window, and in case of an exception it knows that the entry isn't valid any more.

Things were different if an assertion happens after first chance exception. That means the original error was catched by the first chance but could not be solved. Hence they made an assertion in order to break the program in debug mode.

>>>> The first chance exception is at 0x7861d8ec with an access violation at the reading location 0xfffffffc.

You best change your debug settings so that the debugger stops immediately for 'access violation'. Goto menu "Debug - Exceptions -  Win32 Exceptions - c0000005 Access violations" and specify to immediately break in the debugger when 'access violaton happens'. Then, the debugger would break immediately after access violation and you can examine the call stack to find out which function (of yours) passed or used the wrong/invalid CString (It is often tjhat you were using a CString though it already was deleted - or the class object where it was member of  was deleted or run out of scope).
 
Avatar of andy06

ASKER

thank you very much for the hints...
I'm running actually a multi-threaded apllication and in my Threadfunction I declared something like this:
UINT _cdecl  Threadfunction (LPVOID lpParam)
{
CTestDlg *pDlg =(CTestDlg *) lpParam;
CString csMessage, csformat;
TCHAR MyText[] = _T("Begin Test");
csFormat.Format(MyText);
pDlg-> m_Size.SetWindowText(csFormat);
//.....Code
...
}
where m_Size is the associated member variable  of an Edit Control where some results are beeing displayed.
The debugger breaks 2  lines after  the statement:
pDlg -> m_Size.SetWindowText(csFormat);
and by the value of csformat and csMessage one can read :<Bad Ptr>
I checked the whole code and  "csformat" has been used only once and at the time of crash csMessage hasn't been used ...
Thank you

Avatar of AndyAinscow
MFC is NOT thread safe.  
You need to pass window handles not MFC objects between threads and then construct MFC objects and attach them to the supplied handle (or pass the information back to the MFC object and let that update the edit control).
>> pass the information back to the MFC object and let that update the edit control

This is usually the best way around. Consider something like:

static const MY_CUSTOM_MESSAGE = WM_APP + 123;

UINT _cdecl  Threadfunction (LPVOID lpParam)
{
    HWND dlg =(HWND) lpParam;
    CString csMessage, csformat;
    TCHAR MyText[] = _T("Begin Test");
    csFormat.Format(MyText);

    // Instead of pDlg-> m_Size.SetWindowText(csFormat), use:
    ::SendMessage(dlg,MY_CUSTOM_MESSAGE,(WPARAM)&csFormat,0);
   
    //.....Code
    ...
}

// To the dialog's message map, add:

ON_MESSAGE(MY_CUSTOM_MESSAGE, &CTestDlg::OnMyCustomMessage)

// Finally, handle that message like this:
LRESULT CTestDlg::OnMyCustomMessage(WPARAM wParam, LPARAM)
{
    CString* pS = (CString*)wParam;
    m_Size.SetWindowText(*pS)
    return 0;
}

Avatar of andy06

ASKER

AndyAinscow:
For example I know that to get the handle of the dialog window could be :
HWND m_hWnd= pDlg->GetSafeHwnd();
But what about the construction of MFC Objets which should be attached to the handle?I read about "Attach" but how could I use it to let my result appear in the Edit Control ?
Avatar of andy06

ASKER

I sent my last message before reading the last comment...
Isn't it better to use PostMessage instead of Sendmessage ...?
PostMessage is better (SendMessage would force the thread to wait).
I used SendMessage to simplify memory management of the CString parameter. In the real code, PostMessage is of course preferable, although SendMessage will only really be undesirable in more complicated applications.
>>>> You need to pass window handles not MFC objects between threads
That is not so much a difference as long as the thread could not  life longer than the dialog ...  If you can't guarantee that you would need to overwrite CWnd::OnNCDestroyWindow (that is the last handler before your dialog window actually was destroyed) and force your thread to terminate there e. g.  

void CMyDialog::OnNCDestroyWindow()
{
      m_thread.setStopFlag();
      int count = 10;
      while (--count > 0 && m_thread.stopRecognized() == FALSE)
      {
             Sleep(100);   // 100 msec
      }
       if (count < 0) // not stopped
       {
             // force termination
             TerminateThread(m_thread.m_handle);
        }
}

The above requires a thread structure like

struct MyThread
{
     HANDLE        m_handle;       // thread handle
     CMyDialog*   m_ptrParent;  // parent dialog
     BOOL            m_isStopped;  // stop flag
     BOOL            m_stopRecognized;  // stop flag regognized
     
     MyThread(CMyDialog * ptrParent)
         : m_handle(NULL), m_ptrParent(ptrParent),
           m_isStopped(FALSE), m_stopRecognized(FALSE)
     {}
   
     BOOL   stopRecognized()  { return m_stopRecognized; }
     void     setStopFlag() { m_isStopped = TRUE; }
     void     setHandle(HANDLE hdl) { m_handle = hdl; }
};

where the instance was passed when the thread was created (instead of the this as it was now):

 CMyDialog::CMyDialog()
   : CDialog(CMyDialog::IDD),
     m_thread(this)
 {
     ....
 }

void CMyDialog::OnBtnClickedStartThread()
{
     ...
     HANDLE hdl = CreateThread(NULL, 0, CMyDialog::ThreadFunc, &m_thread, NULL, NULL);
     // the handle can be set afterwards
     m_thread.setHandle(hdl);
}

>>>> Isn't it better to use PostMessage instead of Sendmessage ...?
Yes, if you call asynchronously from a thread you *MAY NOT* call SendMessage cause it is a synchronous call. If you check the docs you'll see that SetWindowText is 'sending' and not 'posting' a message.

PostMessage is thread-safe cause it *adds* a new message to the end of the message queue. But the problem using PostMessage is that the buffer posted needs to keep valid for some time cause the call may be deferred.

So, if you want to update a text of a control from thread you could do:


    static const char* szMsg = "Begin Test";
    pDlg->m_size.PostMessage(WM_SETTEXT, 0, (LPARAM)szMsg);

here the text was not passed as a CString object which may run out of scope while the PostMessage wasn't processed yet but is a literal which additional was made static so that it would keep valid for any compiler (all compilers I know even wouldn't destroy a literal which wasn't statically defined).

>>>> ATLASSERT( nRefs != 0 ); // The debugger stops hier

Why not? Why should the nRefs not be 0 ?

I can't see in the moment how both these problems are related.
>>>> if( _AtlInterlockedDecrement( &nRefs ) <= 0 )

Can you show the code where you call _AtlInterlockedIncrement ?

Did you handle the case where two threads increment nearly same time?

Is the nRefs defined as volatile?
>>>That is not so much a difference as long as the thread could not  life longer than the dialog

Not so, some MFC objects are thread specific and will fail (maybe this question is an instance of that behaviour) miserably when one tries to access the functionality directly from another thread.
>>>> some MFC objects are thread specific and will fail
The PostMessage is a thread-safe mechanism to pass messages from a thread to the main thread which runs the message pump. If doing so it is only the lifetime of MFC objects (and their pointers) which could spoil the access.  It is common practice to pass the 'this' pointer of a class instance in the main thread to a dependent  thread. The fact that this doing can fail is not a principal issue but only a matter of carefulness.
>>>The PostMessage is a thread-safe mechanism to pass messages from a thread to the main thread which runs the message pump

Yes, but that is not passing an MFC object such as a CWnd pointer and working directly with that object as the questioner attempted to do.  (Which is what your previous comment seemed to imply when you responded to my comment about thread safety)
Avatar of andy06

ASKER

>>> Can you show the code where you call _AtlInterlockedIncrement ?

Here is how my code looks like:
class CTestDlg : public CDialog
{
// Construction
public:
      CTestDlg(CWnd* pParent = NULL);      // Standard-Konstruktor
      CWinThread* m_thread;
//{{AFX_DATA(CTestDlg)
enum { IDD = IDD_TEST_DIALOG };
      CEdit      m_Size;
      CDisplay      m_Display;
      CImage      m_Image;
      float      m_Erg;
      CString      m_csStatus;
//}}AFX_DATA
//... Code

protected:
Image    Img;
......
DECLARE_EVENTSINK_MAP()
      //}}AFX_MSG
DECLARE_MESSAGE_MAP()
......
public:
int CalculateValue (Image Img);
afx_msg LRESULT OnDisplayImage(WPARAM,LPARAM);
.....
}
BOOL CTestDlg::OnInitDialog()
{
  //...Code
 m_thread=NULL;
//...Code
}
void CTestDlg::OnBnClickedStop()
{
    if (m_thread)
        m_thread->SuspendThread();
}
void CTestDlg::OnBnClickedBStart()
{
     if (m_thread)
    {
       m_thread ->ResumeThread();
   }
    else
    {
        m_thread= AfxBeginThread(ThreadFunction, this,THREAD_PRIORITY_NORMAL,0,0,NULL);
    }
}
UINT  _cdecl ThreadFunction(LPVOID lpParam)
{
CTestDlg *pDlg=(CTestDlg *)lpParam;
CString csMessage,csMessage1;
int H0, Loop;
static const char* szMsg = "Begin Test";
static const char* szMsg 1= "Test done";
pDlg->m_Size.PostMessage(WM_SETTEXT, 0, (lpParam)szMsg);

//Through the function SetNewImage() the image will be
// changed
//CalculateValue perfoms some calculations with the displayed image
//m_Image ist the member variable of the displayed image
//Image display,  H0 calculation and  H0 display
// should be performed  many times

for(Loop=0;Loop<30;Loop++)
{
     //Change the image
      SetNewImage();
    //Display the image
      ::PostMessage(pDlg->GetSafeHwnd(),WM_DISPLAYIMAGE, 0, 0);
       Sleep(1000);
     //Calculate H0
     H0 = pDlg->CalculateValue(pDlg->m_Image.GetImage());
     
      /* Display H0 in the Edit Box*/
      csMessage.Format(_T("%d"), H0);
      ::SetDlgItemText(pDlg->GetSafeHwnd(),IDC_EDIT1,csMessage);
      pDlg->m_editTest.UpdateWindow();

  csMessage1.Format(_T("Loop %d complete"),Loop);
::SetDlgItemText(pDlg->GetSafeHwnd(),IDC_EDIT_SIZE,csMessage1);
pDlg->m_Size.UpdateWindow();
}
pDlg->m_Size.PostMessage(WM_SETTEXT, 0, (lpParam)szMsg1);
AfxEndThread(0);
return 0;
}
Everything is working  fine.Only by debugging occurs the exception...
The other problem I noticed  is that when the Threadfunction is complete ,I can't start the process from the beginning again by clicking on the Start Button. I always have to close the dialog  and compile again...
ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial