views:

43

answers:

3

I tried to create a dialog in a UI thread(CWinThread). However, it crashes when the CDialog::Create() is called. I had verified with previous implementation, the dialog is successfully created in non-threading mode.

Does any guru here know the crash reason of creating a dialog in CWinThread?

Without Threading:

class CProduction : public CDialog{
...
}
class CScrollProductionView : public CScrollView{
CProduction *m_pProduction;
...
}

void CScrollProductionView::OnInitialUpdate(){
   m_pProduction = new CProduction(0, *m_pVisionAdapter);
   m_pProduction->Create(IDD_DLG_PROD, this);  //--> created dialog successfully
   m_pProduction->ShowWindow(SW_SHOW);
}

Implement UI Thread:

class CProduction : public CDialog{
...
}
class CScrollProductionView : public CScrollView{
  CProductionThread* m_pProdThread;
  ...
}

class CProductionThread : public CWinThread{
   CProduction *m_pProduction;
   ...
}

void CScrollProductionView::OnInitialUpdate(){
   m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_INIT, (LPARAM)m_pVisionAdapter);
   m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_CREATE_DLG, (LPARAM)this);

 }

void CProductionThread::InitMessageHandler(WPARAM wParam, LPARAM lParam)
{
   printf("Receiving InitMessageHandler msg %d\n", (UINT)wParam);
   switch(wParam)
   {
    case PROD_INIT:
    {
      CVisionAdapter* pAdapter = (CVisionAdapter*)lParam;
      m_pProduction = new CProduction(NULL, *pAdapter);
    }
     break;
    case PROD_CREATE_DLG:
     {
      CScrollProductionView* pView = (CScrollProductionView*)lParam;
      m_pProduction->Create(IDD_DLG_PROD, pView);  //--> Crash here
      m_pProduction->ShowWindow(SW_SHOW);
     }
       break;
     default:
       break;
   }
}

Error message:

Debug Assertion Failed! ..
File: .... wincore.cpp
Line: 9906

Thanks you for viewing this question.

A: 

The crash is caused by MFC referring invalid window handle (which passed in as parent) during creation.

As a general rule, a thread can access only MFC objects that it created. This is because temporary and permanent Windows handle maps are kept in thread local storage to help maintain protection from simultaneous access from multiple threads.

http://msdn.microsoft.com/en-us/library/h14y172e(VS.71).aspx

an easy fix stated in the MSDN involves changing the code into

...

m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_CREATE_DLG, (LPARAM)this->GetSafeHwnd());

...

CScrollProductionView* pView = (CScrollProductionView*)CScrollProductionView::FromHandle((HWND)lParam);
m_pProduction->Create(IDD_DLG_PROD, pView);
m_pProduction->ShowWindow(SW_SHOW);

Edit:
Fixed the link to msdn.

YeenFei
Does not work...
wengseng
"If you have a multithreaded application that creates a thread in a way other than using a CWinThread object, you cannot access other MFC objects from that thread..." from http://msdn.microsoft.com/en-us/library/h14y172e(v=VS.90).aspx
wengseng
@wengseng, how does it turn out on your side? i'm able to simulate the crashing on my side, which is fixed after the posted modifications.
YeenFei
A: 

I suspect that the problem is that your CProduction object has not been created when the PROD_CREATE_DLG message is being handled. This may be because of using PostThreadMessage. Using PostThreadMessage is fraught with problems. In particular, the messages may get lost, so the thread never sees the PROD_INIT message.

In the single-threaded code you create your CProduction object right before the Create call. Why don't you do the same in the multi-threaded code?

If you really want to use windows messages to communicate between your threads, I would create a "message only" window (See http://msdn.microsoft.com/en-us/library/ms632599.aspx#message_only) instead, as the window messages will not get lost in the same way that the thread messages do.

Alternatively, use a thread-safe queue to pass custom messages between threads, such as my example queue at http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

Anthony Williams
+3  A: 

Try not to create CWinThread, instead of creating a worker thread, if you have many communication between classes like passing object pointers, strings etc.
You will feel less headache if update the GUI through message handling.

mushroom