Solved

Posting messages from threads

Posted on 2003-12-05
7
378 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
Comment Utility
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
Comment Utility
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
Comment Utility
The routing seems to be OK for me. Can it be that the message is somehow filtered? Spy++ will show you this.
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 120 total points
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
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 gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

762 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