Solved

Posting messages from threads

Posted on 2003-12-05
7
382 Views
Last Modified: 2013-11-20
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
0
Comment
Question by:LittlePerson
  • 3
  • 2
  • 2
7 Comments
 
LVL 13

Expert Comment

by:SteH
ID: 9881702
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
 

Author Comment

by:LittlePerson
ID: 9881719
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
 
LVL 13

Assisted Solution

by:SteH
SteH earned 80 total points
ID: 9881764
The routing seems to be OK for me. Can it be that the message is somehow filtered? Spy++ will show you this.
0
Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 120 total points
ID: 9881834
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
 

Author Comment

by:LittlePerson
ID: 9881913
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
 

Author Comment

by:LittlePerson
ID: 9881916
Tell me, if you need infos on a thread-safe solution of this.

I'd certainly appreciate one

Thanks
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 9882306
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

Featured Post

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Turn a spreadsheet into a vba executable. 2 85
Whole sheet autoscrub still needed 19 50
mapBully challenge 6 127
Problem to App source 6 32
Here is how to use MFC's automatic Radio Button handling in your dialog boxes and forms.  Beginner programmers usually start with a OnClick handler for each radio button and that's just not the right way to go.  MFC has a very cool system for handli…
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.

815 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now