Solved

Posting messages from threads

Posted on 2003-12-05
7
385 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Tab names are off by one 5 54
windows 10 how make picture as desktop background 2 72
VBA "SendKeys" Syntax for Multiple Keystrokes 7 133
lucky13 challenge 11 165
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
In this post we will learn different types of Android Layout and some basics of an Android App.
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.
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

734 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