UI-thread with both message pump and an infinite loop
-
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 ?
I think that you also introduce atleast a Sleep(0) after the DispatchMessage statement.
-
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 ?
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’sCWinThread
) 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 yourCMyThread
'sOnIdle
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
-
I think that you also introduce atleast a Sleep(0) after the DispatchMessage statement.
It still doesn't work. Actually, can DispatchMessage() work with a message handler defined using macro ON_THREAD_MESSAGE ?
-
I think that you also introduce atleast a Sleep(0) after the DispatchMessage statement.
What for? It will not help.
Steve
-
It still doesn't work. Actually, can DispatchMessage() work with a message handler defined using macro ON_THREAD_MESSAGE ?
I don't think so.
Steve
-
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’sCWinThread
) 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 yourCMyThread
'sOnIdle
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
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?
-
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?
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 insideOnIdle
! Try it and see. Remember to remove yourRun
override.Steve
-
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 insideOnIdle
! Try it and see. Remember to remove yourRun
override.Steve
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); }
-
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); }
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
-
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); }
The reason your code doesn't work is that you haven't removed your
Run
override as I instructed. MFC's message pump is inCWinThread::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 yourRun
function entirely.Steve