Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 395
  • Last Modified:

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
0
LittlePerson
Asked:
LittlePerson
  • 3
  • 2
  • 2
2 Solutions
 
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
Independent Software Vendors: 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!

 
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
 
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

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 3
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now