views:

524

answers:

2

Hello,

After switching from VS2005 to VS2008 SP1, I found an issue that I can't explain.
A program works fine under VS2005 in both release and debug mode. Under VS2008, when entering the debugger an assert is raised.
If I let the program run (in debug or release mode), no assertion at all.

I spent almost two days on this and I don't understand what I do wrong.

Description of the program: I have a MFC dialog based program that creates a user thread (CWinThread) that creates the main dialog of the application.
A worker thread loops infinitely and posts each second a message to the dialog. The message is processed in the gui thread.

Some parts of my code:

The InitInstance of the gui thread:

BOOL CGraphicalThread::InitInstance()
{
    CGUIThreadDlg* pDlg = new CGUIThreadDlg();
    pDlg->Create(CGUIThreadDlg::IDD);
    m_pMainWnd = pDlg;
    AfxGetApp()->m_pMainWnd = pDlg;
    return TRUE;
}

The worker thread:

UINT ThreadProc(LPVOID pVoid)
{
    do
    {
        AfxGetApp()->m_pMainWnd->PostMessage(WM_APP+1, (WPARAM)new CString("Hello"), NULL);
        Sleep(1000);
    }
    while(!bStopThread);

    return 0;
}

The dialog message handler is like this:

LRESULT CGUIThreadDlg::OnMsg(WPARAM wp, LPARAM lp)
{
    CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST1);
    CString* ps = (CString*)wp;
    pList->InsertString(-1, *ps);
    delete ps;
    return 1L;
}

This works perfectly fine with VS2005. But with VS2008, but as soon as a put a breakpoint and enter the debugging mode, I have an assertion raised ???
wincore.cpp line 906

CObject* p=NULL;
if(pMap)
{
      ASSERT( (p = pMap->LookupPermanent(m_hWnd)) != NULL ||
              (p = pMap->LookupTemporary(m_hWnd)) != NULL);
}
ASSERT((CWnd*)p == this);   // must be us
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another.  The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.

If I remove the GUI thread and create the dialog into the CWinApp thread, the problem doesn't occur anymore.

Does anybody have any idea?
Am I doing something wrong?

Thank you

+3  A: 
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another.  The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
daanish.rumani
Yes I know. I'm not manipulating the windows in another thread, just posting message to it.I've tried to used the raw HWND but the issue is still there.Anyway, it doesn't explain why it works fine with VS2005 and not with VS2008.
wincore.cpp is different for VC++ version 8 and 9. Version 8 is VS 2005 and version 9 is VS 2008
daanish.rumani
I'd recommend to pass the HWND from the main dialog as the thread parameter, and then in the thread call CWnd::FromHandle(hWnd)->PostMessage(...);
Ismael
A: 

@Ismael: I had already tried that the assert is still fired. The only way I found to remove the assert is to create the dialog into the CWinApp thread. But this doesn't explain what happens since there's still the worker thread that post to the dialog every second. Anyway , thanks.

@daanish.rumani: I've checked the wincore.cpp and the CWnd::AssertValid() is exactly the same (but there's of lot of differences in the rest of the files).

I would accept that a piece of code works with VS2005 and not VS2008, but

  1. I can't see what I do wrong. If I do something wrong, what is the correct way to proceed?
  2. Why the assert is only fired when a breakpoint is hit and I step over the Sleep call? I can run the program fine, even when its compiled in debug mode, as long as I don't enter the debugger. Could it be a bug in the debugger?
Ideally, you should edit your original question to add theses precisions. Answers are for others :)
Romain Verdier
Yes. Unless you really found an _answer_ yourself, don't post an answer. Just edit your question and/or comment below other people's answers or comments.
Daniel Daranas
Sorry for that, I'll take care