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
CODE PROJECT For Those Who Code
  • Home
  • Articles
  • FAQ
Community
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. sending messages from a worker thread to cdocument

sending messages from a worker thread to cdocument

Scheduled Pinned Locked Moved C / C++ / MFC
question
13 Posts 5 Posters 2 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.
  • M markkuk

    PostMessage sends the message to a window, and a worker thread doesn't have a window associated with it. Get a handle to your application's main window and use it, e.g.

    HWND hMain = AfxGetMainWnd()->m_hWnd;
    ::PostMessage(hMain, MYMESSAGE, 0, 0);

    D Offline
    D Offline
    derhackler
    wrote on last edited by
    #3

    thx for your reply. i tried it with the following statement but it does not work. CWnd* m_pWnd = (CWnd*)AfxGetMainWnd(); CString* s = new CString(cstrName); PostMessage((HWND)m_pWnd,UWM_PROGRESSDELETE,0,(LPARAM)s); the afx_msg function is never called. any ideas?

    B 1 Reply Last reply
    0
    • D derhackler

      thx for your reply. i tried it with the following statement but it does not work. CWnd* m_pWnd = (CWnd*)AfxGetMainWnd(); CString* s = new CString(cstrName); PostMessage((HWND)m_pWnd,UWM_PROGRESSDELETE,0,(LPARAM)s); the afx_msg function is never called. any ideas?

      B Offline
      B Offline
      BenDev
      wrote on last edited by
      #4

      The AfxGetMainWnd() will return the main window of the thread that made the call and it's not likely to be to one you want it receive the message. Furthermore, you should avoid using MFC objects in your thread if they have been created in another thread. MFC doesn't handle that very well... My prefered solution is to pass the HWND you need to your thread as a parameter : CWinThread* pThread = AfxBeginThread(MyThread, (HWND)m_hWnd); // or any HWND you want UINT MyThread(LPVOID pParam) { HWND hWnd = (HWND)pParam; ::PostMessage(hWnd, ... } You can pass a CWnd* as well but remember you want be able to access all its methods. In your case, if you only want to do a pWnd->PostMessage(...), it will work. ------------------------- Benoit Devigne http://www.bdevigne.com contact@bdevigne.com

      A D 2 Replies Last reply
      0
      • D derhackler

        bonjour! i've got a little worker thread in my CDocument derived class. i've also defined a message and a message handler in my CDocument. i tried to post my message with PostMessage(NULL,MYMESSAGE,...) but it didn't work. i think the decleration of MYMESSAGE is ok (#define UWM_MYMESSAGE (WM_APP + 7) what's the right way to post messages to a cdocument? thx benedikt

        L Offline
        L Offline
        Lost User
        wrote on last edited by
        #5

        hey der, Is the message handler working properly if you call it from the main thread? If it is, then I would run the Spy tool to make sure that the message is being sent and then you can look at the parameters in the message to see that they are correct. Nothing but fun fun fun!;)

        D 1 Reply Last reply
        0
        • B BenDev

          The AfxGetMainWnd() will return the main window of the thread that made the call and it's not likely to be to one you want it receive the message. Furthermore, you should avoid using MFC objects in your thread if they have been created in another thread. MFC doesn't handle that very well... My prefered solution is to pass the HWND you need to your thread as a parameter : CWinThread* pThread = AfxBeginThread(MyThread, (HWND)m_hWnd); // or any HWND you want UINT MyThread(LPVOID pParam) { HWND hWnd = (HWND)pParam; ::PostMessage(hWnd, ... } You can pass a CWnd* as well but remember you want be able to access all its methods. In your case, if you only want to do a pWnd->PostMessage(...), it will work. ------------------------- Benoit Devigne http://www.bdevigne.com contact@bdevigne.com

          A Offline
          A Offline
          Ajit Jadhav
          wrote on last edited by
          #6

          Hi all: Let two things sink in. (It took time for me to, anyways!) (i) He just wants to access just the CDocument-derived object--not a window. CDocument is not derived from CWinThread. There can be command rounting via MFC, but NO message pump. (ii) This is not a GUI thread, but a worker thread. So, why bother with window handles and PostMessage API at all? The solution is as simple as just passing the CMyDocument object as is!

          CWinThread* pThread = ::AfxBeginThread( MyWorkerThreadProc, this );

          In the worker thread proc

          UINT MyWorkerThreadProc( void* pParam )
          {
          //
          // ... other worker code
          //

          // EVERYTIME using Doc in this thread proc,
          // ensure doc object is still around. (Think MDI app)
          // Some Synch-primitive \*necessary\* but not shown here.
          if( doc is no longer around )
          {
              // doc ptr is not valid. 
              // Worker thread should terminate immediately.
              return -1;   // returning will destroy this thread automatically
          }
          else
          {
              // Feel free to call any member function of the doc.
              CMyDocument\* pDoc = (CMyDocument\*) pParam;
              pDoc->CallAnyMemberFunction();
          }
          //
          // ... other worker code
          //
          
          // Worker task through successfully
          return 1;
          

          }

          Pl. correct me if I got something wrong. Thanks. -- Ajit Your project today is your great-grandchildrens' "ancestor clock."

          1 Reply Last reply
          0
          • B BenDev

            The AfxGetMainWnd() will return the main window of the thread that made the call and it's not likely to be to one you want it receive the message. Furthermore, you should avoid using MFC objects in your thread if they have been created in another thread. MFC doesn't handle that very well... My prefered solution is to pass the HWND you need to your thread as a parameter : CWinThread* pThread = AfxBeginThread(MyThread, (HWND)m_hWnd); // or any HWND you want UINT MyThread(LPVOID pParam) { HWND hWnd = (HWND)pParam; ::PostMessage(hWnd, ... } You can pass a CWnd* as well but remember you want be able to access all its methods. In your case, if you only want to do a pWnd->PostMessage(...), it will work. ------------------------- Benoit Devigne http://www.bdevigne.com contact@bdevigne.com

            D Offline
            D Offline
            derhackler
            wrote on last edited by
            #7

            thx for your answer. but it doesnt really work. CDocument don't have a HWND. here are all the relevant functions of my thread. maybe something other is wrong. //the function which starts the thread CUserManagerDoc::fnDeleteUser(CStringList &lstToDelete) { //is thread running? if(bDeleteRunning) { MessageBox(NULL,"Es wird gerade gelöscht!","Achtung",MB_OK|MB_ICONEXCLAMATION); return 1; } ..... some code .... bDeleteRunning = true; pThread = AfxBeginThread(fnThreadDeleteUser,this); return 1; } UINT CUserManagerDoc::fnThreadDeleteUser(LPVOID p) { //start the function CUserManagerDoc* me = (CUserManagerDoc*)p; me->fnThreadDeleteUser(); return 0; } //the thread function void CUserManagerDoc::fnThreadDeleteUser() { ..... some code .... CString* s = new CString("Test"); CWnd* m_pWnd = (CWnd*)AfxGetMainWnd(); PostMessage((HWND)m_pWnd,UWM_PROGRESSDELETE,0,(LPARAM)s); } //message handler for the user defined message LRESULT CUserManagerDoc::OnProgressDelete(WPARAM wParam, LPARAM lParam) { //get the text CString *s = (CString *)lParam; ........ some code ...... return NULL; }

            A 1 Reply Last reply
            0
            • L Lost User

              hey der, Is the message handler working properly if you call it from the main thread? If it is, then I would run the Spy tool to make sure that the message is being sent and then you can look at the parameters in the message to see that they are correct. Nothing but fun fun fun!;)

              D Offline
              D Offline
              derhackler
              wrote on last edited by
              #8

              thx for your reply. the message handler works but the spy tool doesn't receive my message. (i think)

              1 Reply Last reply
              0
              • D derhackler

                thx for your answer. but it doesnt really work. CDocument don't have a HWND. here are all the relevant functions of my thread. maybe something other is wrong. //the function which starts the thread CUserManagerDoc::fnDeleteUser(CStringList &lstToDelete) { //is thread running? if(bDeleteRunning) { MessageBox(NULL,"Es wird gerade gelöscht!","Achtung",MB_OK|MB_ICONEXCLAMATION); return 1; } ..... some code .... bDeleteRunning = true; pThread = AfxBeginThread(fnThreadDeleteUser,this); return 1; } UINT CUserManagerDoc::fnThreadDeleteUser(LPVOID p) { //start the function CUserManagerDoc* me = (CUserManagerDoc*)p; me->fnThreadDeleteUser(); return 0; } //the thread function void CUserManagerDoc::fnThreadDeleteUser() { ..... some code .... CString* s = new CString("Test"); CWnd* m_pWnd = (CWnd*)AfxGetMainWnd(); PostMessage((HWND)m_pWnd,UWM_PROGRESSDELETE,0,(LPARAM)s); } //message handler for the user defined message LRESULT CUserManagerDoc::OnProgressDelete(WPARAM wParam, LPARAM lParam) { //get the text CString *s = (CString *)lParam; ........ some code ...... return NULL; }

                A Offline
                A Offline
                Ajit Jadhav
                wrote on last edited by
                #9

                OK. Got the picture almost fully. Just one more part. Guess you have to look at how the message map entries for the UWM_PROGRESSDELETE look like in the project (not just in the Doc). Since CDocument is not a CWnd (and also not a CWinThread), MFC will NOT find a way to directly route UWM_PROGRESSDELETE to CUserManagerDoc. Therefore, you might have to add ON_THREAD_MESSAGE entries in CMyView or CMyFrameWnd where MFC will route these messages. Then, you could arrange for MFC to forward those to CDocument.... I would probably go for a more lengthy but a very straightforward and clean solution as following. Derive a CMyWorkerThread from CWinThread class, and add ON_THREAD_MESSAGE entries for PROGRESSDELETE in CMyWorkerThread class, *not* in the CUserManagerDoc class. Have a CMyWorkerThread* as m_pThread in Doc. Instantiate CMyWorkerThread on the heap in a doc function, and then call m_pThread->Create() to get the worker thread going. You can also cache the doc ptr as a member variable into the CMyWorkerThread class. If so, ensure you say

                m_pThread->m_pCreatingDoc = this; // this means doc

                before calling m_pThread->Create(). To use: In CUserManagerDoc, call

                m_pThread->PostThreadMessage( UWM_PROGRESSDELETE, 0, (LPARAM) pData );

                To access Doc from CMyWorkerThread handler for ProgressDelete(), just use the cached ptr. (Some multi-threading synch object might be necessary to ensure m_pDoc in CMyWorkerThread is valid.) This will always work. See if it is suitable for your needs. -- Ajit Your project today is your great-grandchildrens' "ancestor clock."

                D 1 Reply Last reply
                0
                • A Ajit Jadhav

                  OK. Got the picture almost fully. Just one more part. Guess you have to look at how the message map entries for the UWM_PROGRESSDELETE look like in the project (not just in the Doc). Since CDocument is not a CWnd (and also not a CWinThread), MFC will NOT find a way to directly route UWM_PROGRESSDELETE to CUserManagerDoc. Therefore, you might have to add ON_THREAD_MESSAGE entries in CMyView or CMyFrameWnd where MFC will route these messages. Then, you could arrange for MFC to forward those to CDocument.... I would probably go for a more lengthy but a very straightforward and clean solution as following. Derive a CMyWorkerThread from CWinThread class, and add ON_THREAD_MESSAGE entries for PROGRESSDELETE in CMyWorkerThread class, *not* in the CUserManagerDoc class. Have a CMyWorkerThread* as m_pThread in Doc. Instantiate CMyWorkerThread on the heap in a doc function, and then call m_pThread->Create() to get the worker thread going. You can also cache the doc ptr as a member variable into the CMyWorkerThread class. If so, ensure you say

                  m_pThread->m_pCreatingDoc = this; // this means doc

                  before calling m_pThread->Create(). To use: In CUserManagerDoc, call

                  m_pThread->PostThreadMessage( UWM_PROGRESSDELETE, 0, (LPARAM) pData );

                  To access Doc from CMyWorkerThread handler for ProgressDelete(), just use the cached ptr. (Some multi-threading synch object might be necessary to ensure m_pDoc in CMyWorkerThread is valid.) This will always work. See if it is suitable for your needs. -- Ajit Your project today is your great-grandchildrens' "ancestor clock."

                  D Offline
                  D Offline
                  derhackler
                  wrote on last edited by
                  #10

                  thanks for your detailed answer. i tried it with the first way you mentioned. I added the necessary message functions in my CMainFrame class. The message map handels the messages via ON_THREAD_MESSAGE(UWM_PROGRESSDELETE, OnProgressDelete) and ON_THREAD_MESSAGE(UWM_PROGRESSCREATE, OnProgressCreate). The CDocument function which stores the thread retrieves a window handle via m_pWnd = (HWND)AfxGetApp()->m_pMainWnd. My thread function calls the function: CString* s = new CString(cstrName); PostMessage(m_pWnd,UWM_PROGRESSDELETE,0,(LPARAM)s); but my message handlers are never called. i think i don't really understand your second solution. creating the CMyWorkerThread is clear. caching the doc ptr too. but i'd like to send a message to something where i can savely make some changes on my user interface. i think you mentioned how to send messages into the running thread and not vice versa. or do i really understand nothing...:((

                  A 2 Replies Last reply
                  0
                  • D derhackler

                    thanks for your detailed answer. i tried it with the first way you mentioned. I added the necessary message functions in my CMainFrame class. The message map handels the messages via ON_THREAD_MESSAGE(UWM_PROGRESSDELETE, OnProgressDelete) and ON_THREAD_MESSAGE(UWM_PROGRESSCREATE, OnProgressCreate). The CDocument function which stores the thread retrieves a window handle via m_pWnd = (HWND)AfxGetApp()->m_pMainWnd. My thread function calls the function: CString* s = new CString(cstrName); PostMessage(m_pWnd,UWM_PROGRESSDELETE,0,(LPARAM)s); but my message handlers are never called. i think i don't really understand your second solution. creating the CMyWorkerThread is clear. caching the doc ptr too. but i'd like to send a message to something where i can savely make some changes on my user interface. i think you mentioned how to send messages into the running thread and not vice versa. or do i really understand nothing...:((

                    A Offline
                    A Offline
                    Ajit Jadhav
                    wrote on last edited by
                    #11

                    About the second solution I proposed (CWinThread derived class). Gee, you got it perfectly right--it will post messages to worker but not in reverse. Sorry. So now I get the problem. (i)The worker thread should (ii) post (iii) user-defined messages to (iv) one of the main app windows. (v) But, even CMainFrame doesn't trap user messages (vi) via ON_THREAD_MESSAGE. :suss: This is getting interesting by itself because the mistake is going to be obviously small and simple... Lemme give it a try on a real program rather than just think about it and get back to you later if something strikes. -- Ajit Your project today is your great-grandchildrens' "ancestor clock."

                    1 Reply Last reply
                    0
                    • D derhackler

                      thanks for your detailed answer. i tried it with the first way you mentioned. I added the necessary message functions in my CMainFrame class. The message map handels the messages via ON_THREAD_MESSAGE(UWM_PROGRESSDELETE, OnProgressDelete) and ON_THREAD_MESSAGE(UWM_PROGRESSCREATE, OnProgressCreate). The CDocument function which stores the thread retrieves a window handle via m_pWnd = (HWND)AfxGetApp()->m_pMainWnd. My thread function calls the function: CString* s = new CString(cstrName); PostMessage(m_pWnd,UWM_PROGRESSDELETE,0,(LPARAM)s); but my message handlers are never called. i think i don't really understand your second solution. creating the CMyWorkerThread is clear. caching the doc ptr too. but i'd like to send a message to something where i can savely make some changes on my user interface. i think you mentioned how to send messages into the running thread and not vice versa. or do i really understand nothing...:((

                      A Offline
                      A Offline
                      Ajit Jadhav
                      wrote on last edited by
                      #12

                      Hi, The first solution does work. Graft the following code on the AppWizard-generated MDI app (accept all defaults). Notes: 1. ON_THREAD_MESSAGE must appear exactly once for each User-Message in the whole project. 2. Synch support (not shown) is necessary. The simpler check on window handle, ::IsWindow( hWndAcceptingPost ), does not work. It leads to mem leaks. In App.h

                      // global #define user message
                      #define MYMESSAGE (WM_USER+7)

                      In Doc.cpp

                      // Prototype
                      static UINT MyThreadProc( void* pParam );

                      // Function implementation
                      UINT MyThreadProc( void* pParam )
                      {
                      HWND hWnd = (HWND) pParam;
                      int nIters = 10;
                      for( int i = 0; i < nIters; i++ )
                      {
                      // Simulate worker doing a part of real work
                      ::Sleep( 500 );

                      	CString\* pS = new CString; // Handler will delete
                      	pS->Format( "Done %d of %d", i, nIters );
                      
                      	// Make sure we can post
                      	**// Unfortuantely, the C-commented portion, (checking window
                      	// handle without event support, leads to memory leaks 
                      	// due to undeleted pS.
                      	/\* 
                      	if( ! ::IsWindow( hWnd ) )
                      	{
                      		delete pS;
                      		pS = 0;
                      		return -2;
                      	}
                      	\*/**
                      	::PostMessage( pH->m\_hWnd, MYMESSAGE, (WPARAM)i, (LPARAM) pS );
                      }
                      return 0;
                      

                      }

                      // This is the menu handler I added in Doc
                      // for actually starting the ball roll...
                      void CMyDoc::OnLaunchWorkerThread()
                      {
                      CWnd* pWnd = ::AfxGetMainWnd();
                      HWND hWnd = pWnd->GetSafeHwnd();
                      ::AfxBeginThread( MyThreadProc, (void*) hWnd );
                      }

                      In MainFrame.h

                      // Generated message map functions
                      protected:
                      //{{AFX_MSG(CMainFrame)
                      afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
                      afx_msg void OnMyMessage(WPARAM wParam, LPARAM lParam); // Typed manually
                      //}}AFX_MSG
                      DECLARE_MESSAGE_MAP()

                      In MainFrame.cpp

                      BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
                      //{{AFX_MSG_MAP(CMainFrame)
                      ON_WM_CREATE()
                      ON_THREAD_MESSAGE(MYMESSAGE, OnMyMessage) // Typed manually.
                      //}}AFX_MSG_MAP
                      END_MESSAGE_MAP()

                      void CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam)
                      {
                      CString* pS = (CString*) lParam;
                      TRACE( "Got (%d) %s\n", (int)wParam, *pS );
                      delete pS;
                      pS = 0;
                      }

                      Your project today is your great-grandchildrens' "ancestor clock."

                      D 1 Reply Last reply
                      0
                      • A Ajit Jadhav

                        Hi, The first solution does work. Graft the following code on the AppWizard-generated MDI app (accept all defaults). Notes: 1. ON_THREAD_MESSAGE must appear exactly once for each User-Message in the whole project. 2. Synch support (not shown) is necessary. The simpler check on window handle, ::IsWindow( hWndAcceptingPost ), does not work. It leads to mem leaks. In App.h

                        // global #define user message
                        #define MYMESSAGE (WM_USER+7)

                        In Doc.cpp

                        // Prototype
                        static UINT MyThreadProc( void* pParam );

                        // Function implementation
                        UINT MyThreadProc( void* pParam )
                        {
                        HWND hWnd = (HWND) pParam;
                        int nIters = 10;
                        for( int i = 0; i < nIters; i++ )
                        {
                        // Simulate worker doing a part of real work
                        ::Sleep( 500 );

                        	CString\* pS = new CString; // Handler will delete
                        	pS->Format( "Done %d of %d", i, nIters );
                        
                        	// Make sure we can post
                        	**// Unfortuantely, the C-commented portion, (checking window
                        	// handle without event support, leads to memory leaks 
                        	// due to undeleted pS.
                        	/\* 
                        	if( ! ::IsWindow( hWnd ) )
                        	{
                        		delete pS;
                        		pS = 0;
                        		return -2;
                        	}
                        	\*/**
                        	::PostMessage( pH->m\_hWnd, MYMESSAGE, (WPARAM)i, (LPARAM) pS );
                        }
                        return 0;
                        

                        }

                        // This is the menu handler I added in Doc
                        // for actually starting the ball roll...
                        void CMyDoc::OnLaunchWorkerThread()
                        {
                        CWnd* pWnd = ::AfxGetMainWnd();
                        HWND hWnd = pWnd->GetSafeHwnd();
                        ::AfxBeginThread( MyThreadProc, (void*) hWnd );
                        }

                        In MainFrame.h

                        // Generated message map functions
                        protected:
                        //{{AFX_MSG(CMainFrame)
                        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
                        afx_msg void OnMyMessage(WPARAM wParam, LPARAM lParam); // Typed manually
                        //}}AFX_MSG
                        DECLARE_MESSAGE_MAP()

                        In MainFrame.cpp

                        BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
                        //{{AFX_MSG_MAP(CMainFrame)
                        ON_WM_CREATE()
                        ON_THREAD_MESSAGE(MYMESSAGE, OnMyMessage) // Typed manually.
                        //}}AFX_MSG_MAP
                        END_MESSAGE_MAP()

                        void CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam)
                        {
                        CString* pS = (CString*) lParam;
                        TRACE( "Got (%d) %s\n", (int)wParam, *pS );
                        delete pS;
                        pS = 0;
                        }

                        Your project today is your great-grandchildrens' "ancestor clock."

                        D Offline
                        D Offline
                        derhackler
                        wrote on last edited by
                        #13

                        bonjour! thanks for your answer. now it works. i think there was a little problem with my PostMessage function. i used PostMessage(...) instead of ::PostMessage(...). PostMessage didn't work. I wanted to access my CDocument. Now i've moved the code for my thread in a new class. This class gets a pointer to my CDocument. The thread now launches a dialog which shows a litte progress bar. this dialog is initialized with my CDocument pointer and receives the messages of my thread. I hope the Dialog can now savely access my Cdocument data. bb benedikt

                        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