Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. UI-thread with both message pump and an infinite loop

UI-thread with both message pump and an infinite loop

Scheduled Pinned Locked Moved C / C++ / MFC
designtutorial
14 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G GameProfessor

    hi, I need to create an UI-thread. The main task of this thread is to perform an infinite loop that do the sending/receiving data. This thread must be able to receive message from Main thread to change behaviour. I try to put the loop in CMyThread::Run() and put the PeekMessage also in the loop but it doesn't work. I don't know how to do it. int CMyThread::Run() { for (;;) { DoMyWork(); if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE )!=0) // my UI thread has no window { TranslateMessage(&msg); DispatchMessage(&msg); } } return CWinThread::Run(); }

    S Offline
    S Offline
    Stephen Hewitt
    wrote on last edited by
    #3

    GameProfessor wrote:

    if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE )!=0) // my UI thread has no window { TranslateMessage(&msg); DispatchMessage(&msg); }

    This code should look like this:

    while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }

    Your code continually dispatches the same message forever since you're using the PM_NOREMOVE flag. I also use while instead of if: do some work, process all outstanding messages then repeat.

    Steve

    G 1 Reply Last reply
    0
    • S Stephen Hewitt

      GameProfessor wrote:

      if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE )!=0) // my UI thread has no window { TranslateMessage(&msg); DispatchMessage(&msg); }

      This code should look like this:

      while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
      {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
      }

      Your code continually dispatches the same message forever since you're using the PM_NOREMOVE flag. I also use while instead of if: do some work, process all outstanding messages then repeat.

      Steve

      G Offline
      G Offline
      GameProfessor
      wrote on last edited by
      #4

      It doesn't work. I defined my message handler using ON_THREAD_MESSAG macro. And it seems that I must left the CMyThread::Run intact then these message handler can work. How can I have my thread keep on running my send/recv loop while still be able to handle message from the main thread ?

      K S 2 Replies Last reply
      0
      • G GameProfessor

        It doesn't work. I defined my message handler using ON_THREAD_MESSAG macro. And it seems that I must left the CMyThread::Run intact then these message handler can work. How can I have my thread keep on running my send/recv loop while still be able to handle message from the main thread ?

        K Offline
        K Offline
        kasturi_haribabu
        wrote on last edited by
        #5

        I think that you also introduce atleast a Sleep(0) after the DispatchMessage statement.

        G S 2 Replies Last reply
        0
        • G GameProfessor

          It doesn't work. I defined my message handler using ON_THREAD_MESSAG macro. And it seems that I must left the CMyThread::Run intact then these message handler can work. How can I have my thread keep on running my send/recv loop while still be able to handle message from the main thread ?

          S Offline
          S Offline
          Stephen Hewitt
          wrote on last edited by
          #6

          That's because by implementing your own message pump instead of using CWinThread’s you’re bypassing MFC’s message routing architecture. There are always such dangers when mixing low-level code (Win32 calls) and high-level code (MFC’s CWinThread) without understanding how they relate to each other. To do what you’re trying to do within the MFC architecture proceed as follows: 1. Override your CMyThread's OnIdle member function. It should look like this:

          BOOL CMyThread::OnIdle(LONG lCount)
          {
          DoMyWork();
          CWinThread::OnIdle(lCount);
          return TRUE;
          }

          2. Remove your CMyThread::Run override.

          Steve

          G 1 Reply Last reply
          0
          • K kasturi_haribabu

            I think that you also introduce atleast a Sleep(0) after the DispatchMessage statement.

            S Offline
            S Offline
            Stephen Hewitt
            wrote on last edited by
            #7

            What for? It will not help.

            Steve

            1 Reply Last reply
            0
            • K kasturi_haribabu

              I think that you also introduce atleast a Sleep(0) after the DispatchMessage statement.

              G Offline
              G Offline
              GameProfessor
              wrote on last edited by
              #8

              It still doesn't work. Actually, can DispatchMessage() work with a message handler defined using macro ON_THREAD_MESSAGE ?

              S 1 Reply Last reply
              0
              • G GameProfessor

                It still doesn't work. Actually, can DispatchMessage() work with a message handler defined using macro ON_THREAD_MESSAGE ?

                S Offline
                S Offline
                Stephen Hewitt
                wrote on last edited by
                #9

                I don't think so.

                Steve

                1 Reply Last reply
                0
                • S Stephen Hewitt

                  That's because by implementing your own message pump instead of using CWinThread’s you’re bypassing MFC’s message routing architecture. There are always such dangers when mixing low-level code (Win32 calls) and high-level code (MFC’s CWinThread) without understanding how they relate to each other. To do what you’re trying to do within the MFC architecture proceed as follows: 1. Override your CMyThread's OnIdle member function. It should look like this:

                  BOOL CMyThread::OnIdle(LONG lCount)
                  {
                  DoMyWork();
                  CWinThread::OnIdle(lCount);
                  return TRUE;
                  }

                  2. Remove your CMyThread::Run override.

                  Steve

                  G Offline
                  G Offline
                  GameProfessor
                  wrote on last edited by
                  #10

                  this doesn't work because things in OnIdle() can not be a loop and the framework doesn't loop that function by itself. I need an infinite loop. I have try these two methods: Method 1: --> my thread can not handle any message from main thread BOOL CMyThread::OnIdle(LONG lCount) { for(;;) { DoMyWork(); } CWinThread::OnIdle(lCount); return TRUE; } Method 2: --> DoMyWork() only run one time after we send message from Main thread to My thread. BOOL CMyThread::OnIdle(LONG lCount) { DoMyWork(); CWinThread::OnIdle(lCount); return TRUE; } I expect DoMyWork() to be loop to run forever !!! There must be a way, isn't it?

                  S 1 Reply Last reply
                  0
                  • G GameProfessor

                    this doesn't work because things in OnIdle() can not be a loop and the framework doesn't loop that function by itself. I need an infinite loop. I have try these two methods: Method 1: --> my thread can not handle any message from main thread BOOL CMyThread::OnIdle(LONG lCount) { for(;;) { DoMyWork(); } CWinThread::OnIdle(lCount); return TRUE; } Method 2: --> DoMyWork() only run one time after we send message from Main thread to My thread. BOOL CMyThread::OnIdle(LONG lCount) { DoMyWork(); CWinThread::OnIdle(lCount); return TRUE; } I expect DoMyWork() to be loop to run forever !!! There must be a way, isn't it?

                    S Offline
                    S Offline
                    Stephen Hewitt
                    wrote on last edited by
                    #11

                    GameProfessor wrote:

                    this doesn't work because things in OnIdle() can not be a loop

                    It will work: the loop is within MFC's CWinThread::Run function. There should be ***NO*** loop inside OnIdle! Try it and see. Remember to remove your Run override.

                    Steve

                    G 1 Reply Last reply
                    0
                    • S Stephen Hewitt

                      GameProfessor wrote:

                      this doesn't work because things in OnIdle() can not be a loop

                      It will work: the loop is within MFC's CWinThread::Run function. There should be ***NO*** loop inside OnIdle! Try it and see. Remember to remove your Run override.

                      Steve

                      G Offline
                      G Offline
                      GameProfessor
                      wrote on last edited by
                      #12

                      i'm sure it wont run because it's the first thing I've tried. !!! Here's the code: LRESULT CMyThread::OnMyMsg(WPARAM wParam, LPARAM lParam) { MessageBox(NULL,"super man","MyMSG message",MB_OK); // this never show up!!! return 0; } int CMyThread::Run() { for (;;) { i++; if (i>=10000) { i = 0; } } return CWinThread::Run(); } BOOL CMyThread::OnIdle(LONG lCount) { // TODO: Add your specialized code here and/or call the base class return CWinThread::OnIdle(lCount); }

                      S 2 Replies Last reply
                      0
                      • G GameProfessor

                        i'm sure it wont run because it's the first thing I've tried. !!! Here's the code: LRESULT CMyThread::OnMyMsg(WPARAM wParam, LPARAM lParam) { MessageBox(NULL,"super man","MyMSG message",MB_OK); // this never show up!!! return 0; } int CMyThread::Run() { for (;;) { i++; if (i>=10000) { i = 0; } } return CWinThread::Run(); } BOOL CMyThread::OnIdle(LONG lCount) { // TODO: Add your specialized code here and/or call the base class return CWinThread::OnIdle(lCount); }

                        S Offline
                        S Offline
                        Stephen Hewitt
                        wrote on last edited by
                        #13

                        I know it will; I've just build a test app from scratch and it does. So just try it ok! Here's code snippits: --------------------- // From CMyThead's implementation: BEGIN_MESSAGE_MAP(CMyThread, CWinThread) //{{AFX_MSG_MAP(CMyThread) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP ON_THREAD_MESSAGE(WM_USER, OnFromUI) // *******IMPORTANT******* END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMyThread message handlers BOOL CMyThread::OnIdle(LONG lCount) { DoMyWork(); // *******IMPORTANT******* CWinThread::OnIdle(lCount); // *******IMPORTANT******* return TRUE; // *******IMPORTANT******* } void CMyThread::DoMyWork() { } afx_msg LRESULT CMyThread::OnFromUI(WPARAM, LPARAM) { return 0; } // Creating the thead and a dialog: BOOL CWillWorkApp::InitInstance() { // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif CWinThread *pThread = AfxBeginThread(RUNTIME_CLASS(CMyThread)); CWillWorkDlg dlg(pThread); m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump. return FALSE; } // In the dialog: CWillWorkDlg::CWillWorkDlg(CWinThread *pThread, CWnd* pParent /*=NULL*/) : CDialog(CWillWorkDlg::IDD, pParent) , m_pThread(pThread) // *******IMPORTANT******* { //{{AFX_DATA_INIT(CWillWorkDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CWillWorkDlg::OnButton1() { m_pThread->PostThreadMessage(WM_USER, 0, 0); // *******IMPORTANT******* } =========================== CMyThread::DoMyWork() is called continuously and CMyThread::OnFromUI is called when I press a button from a dia

                        1 Reply Last reply
                        0
                        • G GameProfessor

                          i'm sure it wont run because it's the first thing I've tried. !!! Here's the code: LRESULT CMyThread::OnMyMsg(WPARAM wParam, LPARAM lParam) { MessageBox(NULL,"super man","MyMSG message",MB_OK); // this never show up!!! return 0; } int CMyThread::Run() { for (;;) { i++; if (i>=10000) { i = 0; } } return CWinThread::Run(); } BOOL CMyThread::OnIdle(LONG lCount) { // TODO: Add your specialized code here and/or call the base class return CWinThread::OnIdle(lCount); }

                          S Offline
                          S Offline
                          Stephen Hewitt
                          wrote on last edited by
                          #14

                          The reason your code doesn't work is that you haven't removed your Run override as I instructed. MFC's message pump is in CWinThread::Run but your override (CMyThread::Run) never calls it because it enters an endless loop and the call to MFC's is after it. Remove your Run function entirely.

                          Steve

                          1 Reply Last reply
                          0
                          Reply
                          • Reply as topic
                          Log in to reply
                          • Oldest to Newest
                          • Newest to Oldest
                          • Most Votes


                          • Login

                          • Don't have an account? Register

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • World
                          • Users
                          • Groups