Posting messages from threads

Hi

I have a thread which performs tasks according to the event set by the main program. One task is
to update the value for a Progress bar.


UINT DTThread (LPVOID lpArg)
{
       // get the params
      // including events

      HANDLE ah[3];
      ah[0] = pKillEvent->m_hObject;
      ah[1] = pAquireEvent->m_hObject;
      ah[2] = pTransEvent->m_hObject;

      BOOL bStopped = FALSE;

     while(!bStopped) {

            switch(::WaitForMultipleObjects(sizeof(ah)/sizeof(HANDLE), ah, FALSE, INFINITE))
            {
            case WAIT_OBJECT_0:                  // Kill Event has become signalled
                  {
                        
                        #ifdef _DEBUG

                              CString msg;
                              msg.Format("DataTransmissionThread() Stopping DT Thread\n");
                              TRACE0(msg);

                        #endif
                        
                        bStopped = TRUE;
                        
                        break;
                  }

            case WAIT_OBJECT_0+1:            // AquireEvent has become signalled
                  {
                        #ifdef _DEBUG

                              CString msg;
                              msg.Format("DataTransmissionThread() Aquiring data...\n");
                              TRACE0(msg);

                        #endif

                        //for(int i = 0; i < uAccumTime; i++)
                        //{
                              ::PostMessage(hWndDest, WM_UPDATE_ACCUM_BAR, MAKEWPARAM(0, 35/*fIncr*/), 0);
                              //::Sleep(1000);
                        //}

                        #ifdef _DEBUG

                              msg.Format("DataTransmissionThread() Finished Aquiring data...\n");
                              TRACE0(msg);

                        #endif

                        //AfxMessageBox("Finished Aquiring");

                        //::PostMessage(hWndDest, WM_STOP_DATA_TRANS, 0, 0);

                        break;
                  }

            case WAIT_OBJECT_0+2:            // Transmit event has become signalled
                  {
                        #ifdef _DEBUG

                              CString msg;
                              msg.Format("DataTransmissionThread() Transmitting data to DTE\n");
                              TRACE0(msg);

                        #endif

                        break;
                  }

            default:
                  {
                        #ifdef _DEBUG

                              CString msg;
                              msg.Format("DataTransmissionThread() ERROR : Unknown event occured!\n");
                              TRACE0(msg);

                        #endif

                        break;
                  }
            }
      }
 

           return 0;
}


I also have a Message handle for WM_UPDATE_ACCUM_BAR - which if I post a message to just from the init function
of the dialog works OK, however when called from the thread I never get the trace output or any chages to the progress bar!


LRESULT CSCUDialog::OnUpdateAccumulatorBar (WPARAM wParam, LPARAM /*lParam*/)
{
      int nIndex = LOWORD(wParam);
      float fIncr = HIWORD(wParam);

#ifdef _DEBUG

      CString msg;
      msg.Format("OnUpdateAccumulatorBar() Index = %d, FIncrement = %2.2f\n", nIndex, fIncr);
      TRACE0(msg);

#endif

      if(!(fIncr < 100)) {                              // then we must be finished accumulating
            m_pbAccumD1.SetValue(100);
            //m_eTransEvent.PulseEvent();
            //m_eKillEvent.SetEvent();
      }
      else
      {
            m_pbAccumD1.SetValue(m_pbAccumD1.GetValue() + fIncr);
      }

#ifdef _DEBUG

      msg.Format("OnUpdateAccumulatorBar() New Value = %2.2f\n", m_pbAccumD1.GetValue());
      TRACE0(msg);

#endif

      return 0;
}

I have also tried to send the message from the thread to update the accumulator bar but never seem to fire up the function!

From Debug Window I get

DataTransmissionThread() Setup process....
DataTransmissionThread() Aquiring data...
DataTransmissionThread() Finished Aquiring data...


The output from OnUpdateAccumulatorBar() should be inbetween  lines 2 and 3 above!

Why is it not working?

Can anyone see what I am doing wrong.

Any help much appreciated

LittlePerson
LittlePersonAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

SteHCommented:
Have you tried looking a the window with Spy++ to see where the message arrives if at all anywhere? What is the definition of WM_UPDATE_ACCUM_BAR? Are you sending it to the ProgressBar or to your dialog?
0
LittlePersonAuthor Commented:
I send the message to the dialog and the message handler updates the progress bar.

I've never used Spy++, but  I'll give it a go!

Thanks
0
SteHCommented:
The routing seems to be OK for me. Can it be that the message is somehow filtered? Spy++ will show you this.
0
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

itsmeandnobodyelseCommented:
Where did you get hWndDest from? That should be the window handle of your dialog.

Normally a thread get's a pointer of the dialog/view/document  as argument. Then, the thread function casts that pointer to correct class and is able to use member functions like GetSafeHwnd to get the window handle of the dialog. This handle must be used for PostMessage. Or you just take the dialog pointer:

         CMyDlg* pDlg = (CMyDlg*)lpArg;
         pDlg->PostMessage(...);

However, this is not thread-safe and could make your porgram make kaboom.

Tell me, if you need infos on a thread-safe solution of this.

Regards, Alex

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
LittlePersonAuthor Commented:
itsmeandnobodyelse

Well spotted - I had left out the hWnd for the dialog Window from the parameters before calling the thread.
Very remiss (spelling!)

Thanks for the help both of you

Regards
LittlePerson
0
LittlePersonAuthor Commented:
Tell me, if you need infos on a thread-safe solution of this.

I'd certainly appreciate one

Thanks
0
itsmeandnobodyelseCommented:
To post a message from a thread adds some messages to the message loop of your dialog. As the dialog runs in the main thread, it might happen that inserting messages from thread will spoil the loop management. So, messages could become corrupted or skipped or are not processed in the right order.
Therefore you have to avoid to write directly to the message queue that runs in another thread. The solution is now to write the messages from the thread to a container and let the main thread read post the messages in a OnTimer handler. To avoid having similar problems when adding messages to the container, i. e. the thread writes messages and same time OnTimer reads and delete messages, that might spoil the container, we need a CRITICAL_SECTION object that let us do some parts exclusively, i. e. the other thread must wait till some container management is done.

You need a CRITICAL_SECTION object that is defined globally or - if you have more threads - as member of yor thread-controlling class, in your case the dialog class; then you should start a timer for your dialog that looks for messages from the thread.

struct MyMessage
{
      UINT        m_msg;
      WPARAM  m_wp;
      LPARAM    m_lp;
};

class CMyDlg : public CDialog
{
     ....
public:
    CRITICAL_SECTION m_cs;              // to lock actions
    CPtrArray                m_msgs;         // to hold private messages from thread
    int                          m_nMsg;         // to count messages
    ....
};

Then, before you invoke the thread you have to initialize the critical section object

 InitializeCriticalSection(&pDlg->m_cs);
 pDlg->m_toRead = 0;
 pDlg->m_toWrite = 0;

 pDlg->SetTimer(99, 200);   // OnTimer() is invoked all 200 ms
 // invoke the thread

UINT CMyDialog::OnTimer(UINT id)
{
     if (id == 99)
     {
           MyMessage* pMsg = NULL;
           EnterCriticalSection(&m_cs);
           for (int i = 0; i < m_nMsg; i++)
           {
                 pMsg = (MyMessage*)m_msgs[i];
                 PostMessage(pMsg->m_msg, pMsg->m_wp, pMsg->m_lp);
                 delete pMsg;
           }
           m_msgs.RemoveAll();
           m_nMsg = 0;
           LeaveCriticalSection(&m_cs);
     }
}

void CMyDialog::PostMessagesFromThread(MyMessage* pMsg)
{
        EnterCriticalSection(&m_cs);
        m_msgs.Append(pMsg);
        m_nMsg++;
        LeaveCriticalSection(&m_cs);
}

Then in your thread you may post messages like this:

       // PostMessage(hWndDest, WM_UPDATE_ACCUM_BAR, MAKEWPARAM(0, 35/*fIncr*/), 0);
        CMyDlg* pDlg = (CMyDlg*)lpArg;
        MyMessage* pMsg = new MyMessage;
        pMsg->m_msg = WM_UPDATE_ACCUM_BAR;
        pMsg->m_wp   = MAKEWPARAM(0, 35/*fIncr*/);
        pMsg->lp         = 0;
        pDlg->PostMessageFromThread(pMsg);

Hope that helps.

Alex

Note, you have to init m_nMsg to 0 in your dialog constructor.

 
       




0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.