Hi ...

I have been trying to implement some message handling in MFC dlls for a couple days. I have read some good info on CodeGuru site. Many times there is the lack a full conclusion. My message issues were also in a thread, which complicated things a bit. I have decided that I would post the solution to problem below on the site. I hope it will help the next developer with similar issues.

The problem.

I have an MFC application (SDI) and two MFC dlls. One dll (MxTcpComm.dll) is listening on a socket then sending a message when it gets a connection/data. The other dll will handle the message (MxProcess.dll). Both dlls are threaded. Originally I was sending the message back to the application (Test.exe) and handling it in the MainFrame Class with ON_MESSAGE(WM_THREADED_SERVER_PROCESS, OnMessageThreadedServer).

The biggest problem was moving the message handling from Test.exe to MxProcess.dll. I attempted to create a hidden window in the Constructor of the CMxProcessControlManage Class. The message handling code using ::GetMessage() was inside of a thread started from CMxProcessControlManage Class. This did not work as the thread will have its own message loop. To make this work I needed to move the code to create the hidden window into the thread where the messages are being handled.

Below are the code snippets for each component.
Code:
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
Test.exe
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

BOOL CTestApp::InitInstance()
{
    // If we have enabled the peer-peer process control then we will 
    // start the threads.  
    if (IsEnablePeerToPeer())
    { 

        //AfxMessageBox("Note:  A new Process Control Manager is in place and not yet operational."); 

        CMxProcessControlManage *pMxProcessControlManage; 
        pMxProcessControlManage = new CMxProcessControlManage(); 

        // Set the values 
        pMxProcessControlManage->SetLog(GetLog()); 
        pMxProcessControlManage->SetOwner(GetOwner());

        pMxProcessControlManage->SetAppIp(GetProcessControlAppIp()); 
        pMxProcessControlManage->SetAppPort(GetProcessControlAppPort()); 
        pMxProcessControlManage->SetPeerIp(GetProcessControlPeerIp()); 
        pMxProcessControlManage->SetPeerPort(GetProcessControlPeerPort()); 

        // Start the process
        pMxProcessControlManage->Start(); 

    }

}



\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
MxProcess.dll
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

CMxProcessControlManage::CMxProcessControlManage()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    LoadRegistrySettings();

    m_pOwner = 0x00;
    SetThreadCount(0);
    SetThreadInit(false);
    SetThreadAlive(false);

    // *** This will not handle messages in the thread.  We needed to 
    // *** move this inside the thread
    m_pWnd = new CWnd;
    m_pWnd->Create(NULL,                        // Class name
                   "hidden window",             // Window name
                   WS_OVERLAPPEDWINDOW,         // Style
                   CRect(0,0,10,10),            // Size and position
                   CWnd::GetDesktopWindow(),    // Parent window
                   0);                          // ID of child window

}


int CMxProcessControlManage::Start(void) 
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    
    if (!(m_ThreadPrimary = AfxBeginThread(ThreadProcessControlManager, this)))
    {
        nReturn = -1; 
    }
    
    return nReturn; 
}


UINT CMxProcessControlManage::ThreadProcessControlManager(LPVOID pParam)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    int nThreadCount = 0;
    int nIndex = 0;
    int nRowCount = 0;

    MSG     *pMsg = NULL; 

    bool        bMessageLoop = true; 
    unsigned int  nTimerId1 = 0; 

    CMxProcessControlManage* pProcessControlManage = (CMxProcessControlManage*)pParam;

    // Create the hidden window that will be used to handle messages in this 
    // thread

    CWnd *pWnd = new CWnd;
    pWnd->Create(NULL,                        // Class name
                 "hidden window",             // Window name
                 WS_OVERLAPPEDWINDOW,         // Style
                 CRect(0,0,10,10),            // Size and position
                 CWnd::GetDesktopWindow(),    // Parent window
                 0);                          // ID of child window


    pProcessControlManage->SetOwner(pWnd); 


    // Start the process control listening thread. 
    if (!(pProcessControlManage->m_ThreadListener = AfxBeginThread(ThreadProcessControlListener, pProcessControlManage)))
    {
        csLogMessage.Format("Process control listener thread failing to start!"); 
        pProcessControlManage->m_pLog->Write(MXLOG_SEVERITY_ERROR, csLogMessage, csMethodName);
    }




    // Begin listening for messages from listing socket.


    pMsg = new MSG; 

    // Start the program control timer.  This timer will signal that 
    // a message should be sent to the server
    nTimerId1 = ::SetTimer(NULL, NULL, 92500, NULL); 


    while (bMessageLoop)
    {
        // Get messages from the hidden window message loop
        ::GetMessage(pMsg, pProcessControlManage->GetOwner()->m_hWnd, 0, 0); 

        switch (pMsg->message)
        {
            case WM_TIMER:

                if (pMsg->wParam == nTimerId1)
                { 
                    csLogMessage.Format("Message loop timeout exceeded."); 
                    pProcessControlManage->m_pLog->Write(MXLOG_SEVERITY_INFO, csLogMessage, csMethodName);
                    bMessageLoop = false;
                    DispatchMessage(pMsg);
                }
                break; 

            case WM_THREADED_SERVER_PROCESS:
                csLogMessage.Format("Message: WM_THREADED_SERVER_PROCESS."); 
                pProcessControlManage->m_pLog->Write(MXLOG_SEVERITY_INFO, csLogMessage, csMethodName);
                DispatchMessage(pMsg);
                break; 

            default:
                DispatchMessage(pMsg);
                break; 
        }
    }


    // delete the message object
    delete pMsg; 

    // delete the hidden window    
    delete pWnd; 

    return 0;
}



UINT CMxProcessControlManage::ThreadProcessControlListener(LPVOID pParam)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());


    if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0)
    {
        csLogMessage.Format("WSAStartup() returned error code: %d.  Thread:%d", 
                            nCode, 
                            nThreadCount); 
        pProcessControlManage->m_pLog->Write(MXLOG_SEVERITY_ERROR, csLogMessage, csMethodName);
    }
    else
    { 

        csLogMessage.Format("Winsock started.  Thread:%d", nThreadCount); 
        pProcessControlManage->m_pLog->Write(MXLOG_SEVERITY_INFO, csLogMessage, csMethodName);

        csLogMessage.Format("Create the pThreaderServer object.  Thread:%d", nThreadCount); 
        pProcessControlManage->m_pLog->Write(MXLOG_SEVERITY_INFO, csLogMessage, csMethodName);

        // Create the pMxThreaderServer object
        CMxThreadedServer *pMxThreaderServer; 
        pMxThreaderServer = new CMxThreadedServer(); 

        pMxThreaderServer->SetOwner(pProcessControlManage->GetOwner()); 

        // This should block here forever !! 
        csLogMessage.Format("Starting pThreaderServer object.  Thread:%d", nThreadCount); 
        pProcessControlManage->m_pLog->Write(MXLOG_SEVERITY_INFO, csLogMessage, csMethodName);
        pMxThreaderServer->Start(pProcessControlManage->GetAppIp(), 
                                 pProcessControlManage->GetAppPort());

        // Shut Winsock back down and take off.
        WSACleanup();
    }

    // Ending message 
    csLogMessage.Format("Ending listening thread.  Thread:%d", nThreadCount); 
    pProcessControlManage->m_pLog->Write(MXLOG_SEVERITY_INFO, csLogMessage, csMethodName);

    return 0;
}


\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
MxTcpComm.dll
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

int CMxThreadedServer::Start(const char* pcAddress, int nPort)
{

    SetUpListener(pcAddress, htons(nPort));

    if (m_sListen == INVALID_SOCKET) 
    {
        return 3;
    }

    // Waiting for connections
    while (1) 
    {
        AcceptConnection();
    }

    return 0;
}


void CMxThreadedServer::AcceptConnection(void)
{    
    sockaddr_in sinRemote;
    int nAddrSize = sizeof(sinRemote);

    while (1)
    {
        m_sAccept = accept(m_sListen, 
                           (sockaddr*)&sinRemote,
                           &nAddrSize);

        if (m_sAccept != INVALID_SOCKET)
        {
            if (!(m_ThreadReceiveHandler = AfxBeginThread(ThreadReceiveHandler, this)))
            {
                // ThreadReceiveHandler thread failed to start!
            }

        }
        else 
        {
            // handle WSA errors
            return;
        }
    }
}


UINT CMxThreadedServer::ThreadReceiveHandler(LPVOID pParam)
{

    int nRetval = 0;

    // Cast the void pointer passed to the thread back to caller
    CMxThreadedServer *pMxThreadedServer = (CMxThreadedServer*)pParam;


    if (!pMxThreadedServer->ReceiveIncomingPackets())
    {
        // handle WSA errors
        nRetval = 3;
    }

    // Shutting connection down.
    if (pMxThreadedServer->ShutdownConnection())
    {
        // connection down 
    }
    else
    {
        // handle WSA errors
        nRetval = 3;
    }

    return nRetval;
}


bool CMxThreadedServer::ReceiveIncomingPackets(void)
{
    // Read data from client
    char acReadBuffer[1024];
    int nReadBytes;

    do
    {
        // Get the data from the socket
        nReadBytes = recv(m_sAccept, acReadBuffer, 1024, 0);

        // Check the bytes received.
        if (nReadBytes > 0)
        {

            csTemp = (CString)acReadBuffer;
            csTemp = csTemp.Left(nReadBytes); 
            SetReceiveData(csTemp);

            if (GetOwner())
            {
                // Send a message that we are done
                ::PostMessage(GetOwner()->m_hWnd,
                            WM_THREADED_SERVER_PROCESS,
                            (WPARAM) MXTS_MESSAGE_DATA_RECEIVED,
                            (LPARAM) nReadBytes);
            }
        }
        else if (nReadBytes == SOCKET_ERROR)
        {
            return false;
        }
    } 
    while (nReadBytes != 0);

    cout << "Connection closed by peer." << endl;
    return true;
}


The End