Messageprocessing in DLL's

I have created DLL used for DLC communication
(a low level network protocol). I want to be able
to load the DLL, start a service thread and post
it messages.

The VC+5.0 environment has a wizard that can create a
DLL template. The produced code gives me a CWinApp derived
object that should be able to receive messages.

However, if I try to start it's CWinThread::Run() method
it terminates since there is no Windows handle assigned
to the DLL (i think).

How do I post a message to a service routine running in a DLL?

Cincerly
Rune.Bundesen @ i-data.com
puffAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

MikeP090797Commented:
You use LoadLibrary from an EXE, and the ::Run is called automaticly. the ::Run is instead of DllMain function of a DLL.
0
puffAuthor Commented:
Thanks for the reply.
Unfortunately it's a little more complex then that I think.
Perhabs im missing something, but here is what I think is
the problem.

I want to load a dll from an exe file (using loadlibrary).
The exe file is a CWinApp itself and lives in the main
thread.

After the library is loaded, I want to call a function
from the dll (still inside the main thread), lets call it
Init().

Inits function is to start a new thread holding a message pump.
I have tried this.. (CDlcDriverThread is a derrivation of
CWinThread).

DWORD CALLBACK InitDlcDriver(HWND hWndReceiver)
{
 AFX_MANAGE_STATE(AfxGetStaticModuleState());
 BOOL bRes;

 pDlcDriverThread=new CDlcDriverThread(hWndReceiver);
 bRes=pDlcDriverThread->CreateThread();

 if (!bRes) AfxMessageBox("Cannot create DlcDriverThread");
 return pDlcDriverThread->m_nThreadID;
}

The 'new' operation seems to create a valid object,
but the thread being created shuts down almost immediately.
I have tried to remove the CWinApp object in the dll, since
i thought it could be associated with having two CWinApp's,
but this just causes CreateThread to give an assertion error
[AfxGetApp() returns Null].

I just cant figure out how on earth I can create a
userinterface thread from a function inside a dll!.
Probably a trivial problem once you know the answer,
and I need it to be a userinterface thread since I want
to post the new thread messages (do this, do that, etc.)

thanks for the go Mike ;-), I hope you can clarify things
further.
0
IgorGrebnevCommented:
Dear Puff,
You can create new user interface thread in DLL, just like you can do that inside of code of your main exe.
The problem that you mixed the CWinApp object created inside of the DLL with application wizard with creation of new thread. THe application object inside of DLL used for managing of DLL module ( handle of DLL, name of INI file ) but its Run() funciton is never called.

What you need is to create new CWinThread object and call its Run() function. It should be different class from the CWinApp object created in the DLL.
Creating of user interface threads in DLL is not different from creation of threads inside of exe.
For creation of user-interface thread your need to derive class from CWinThread object.
class CMyThread : public CWinThread

{ BOOL InitInstance() { return TRUE; }
}
YOu should override InitInstance(), because the base implementation return FALSE, thus the thread closed immidiately.
Then you write
CMyThread *pMyThread = new CMyThread;
pMyThread->CreateThread(...);
and the new thread runs and enter message loop. You can send messages to the thread with PostThreadMessage API. You should close the thread by posting WM_QUIT message to the thread, thus the MFC message loop is broken and thread exit. You do not need to call delete on thread object, because the default implementation of MFC do it after calling of ExitInstance() of the thread object.
I worked a lot with user-interface threads and created userful base class "CBaseThread" that used for posting of messages to the thread ( the thread do not have window) closing it and syncronisation. I just copy the source of the the BaseTHread.h and BaseTHread.cpp into the my answer and I can send it to you by mail if you provide the address. Here the source:


// BaseThread.h : header file. Base for all IP threads.
//
/////////////////////////////////////////////////////////////////////////////
// CBaseThread thread

class CBaseThread : public CWinThread
{
      DECLARE_DYNAMIC(CBaseThread)
  CEvent *m_pInitEvent;
  void WaitUntilInit();
//------------------------------
  BOOL m_IsInitSucceded;
//------------------- Should not be iverridden by derived classes
  virtual BOOL  InitInstance();
protected:
      CBaseThread(); // protected constructor used by derived classes
//--------------- Derived threads should use this function for initialization
  virtual BOOL InitThread() { return TRUE; }  
public:
//----------- Waits until InitInstance is finished
      BOOL CreateIPThread(UINT nStackSize = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
  BOOL PostIPMessage( WPARAM, LPARAM );
//---------------- Should NOT be called from the contents of this thread.
  void CloseThread();
  // Overrides
//------------------ Notification function from WM_IPTHREAD_NOTIFY
protected:
//----The value of lParam depends on wParam. In base class do nothing, like pure virtual
  virtual void OnIPThreadMsg( WPARAM, LPARAM ) {}  

      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CBaseThread)
protected:
      virtual int   ExitInstance();
      virtual BOOL  PreTranslateMessage(MSG* pMsg);
      //}}AFX_VIRTUAL

// Implementation
protected:
      virtual ~CBaseThread();

      // Generated message map functions
      //{{AFX_MSG(CBaseThread)
            // NOTE - the ClassWizard will add and remove member functions here.
      //}}AFX_MSG

      DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////


// BaseThread.cpp : implementation file
//

#include "stdafx.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CBaseThread

IMPLEMENT_DYNAMIC(CBaseThread, CWinThread)

CBaseThread::CBaseThread()

{ m_pInitEvent = new CEvent( FALSE, TRUE );
  m_pInitEvent->ResetEvent();
  m_IsInitSucceded = TRUE;
}

CBaseThread::~CBaseThread()
{
}

BOOL CBaseThread::InitInstance()          
{//----------Creates message Que for the threadv and unlock init event
  MSG msg;
  PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE );              
  m_IsInitSucceded = InitThread();
  m_pInitEvent->SetEvent();
  return TRUE;
}

int CBaseThread::ExitInstance()
{
      if ( m_pInitEvent != NULL )
  { delete m_pInitEvent;
  }
      return CWinThread::ExitInstance();
}

//----------- Waits until InitInstance is finished
void CBaseThread::WaitUntilInit()

{ if ( m_pInitEvent != NULL )
  { m_pInitEvent->Lock();
    if ( m_IsInitSucceded )
    { delete m_pInitEvent;
      m_pInitEvent = NULL;
    }
  }
  else
  { ASSERT( FALSE );
  }
}

BEGIN_MESSAGE_MAP(CBaseThread, CWinThread)
      //{{AFX_MSG_MAP(CBaseThread)
            // NOTE - the ClassWizard will add and remove mapping macros here.
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBaseThread message handlers

BOOL CBaseThread::PreTranslateMessage(MSG* pMsg)
{
      if ( pMsg->hwnd      == NULL &&  pMsg->message == WM_IPTHREAD_NOTIFY )
  { OnIPThreadMsg( pMsg->wParam, pMsg->lParam );
    return TRUE; // No further processing
  }      
      return CWinThread::PreTranslateMessage(pMsg);
}

BOOL CBaseThread::CreateIPThread( UINT nStackSize, LPSECURITY_ATTRIBUTES lpSecurityAttrs )

{//--------------- Do NOT create suspended thread!!!
  BOOL retVal = CWinThread::CreateThread( 0, nStackSize, lpSecurityAttrs );
  if ( retVal )
  { WaitUntilInit();
    return m_IsInitSucceded;
  }
  return retVal;
}

void CBaseThread::CloseThread()

{ if ( m_hThread != NULL )
  { HANDLE hThread = m_hThread;
    BOOL result = ::PostThreadMessage( m_nThreadID, WM_QUIT, 0, 0 );
    ASSERT( result );
    WaitForSingleObject( hThread, INFINITE );
  }
}

BOOL CBaseThread::PostIPMessage( WPARAM wParam, LPARAM lParam  )

{ BOOL retVal = ::PostThreadMessage( m_nThreadID, WM_IPTHREAD_NOTIFY, wParam, lParam );
  ASSERT( retVal );
  return retVal;
}



 
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
puffAuthor Commented:
Thanks for the reply Igor, you hit it right on the spot!
Your solution works fine, so Ill incorporate your class
into my code right away.

Sorry I missed my address, here it is.
Email work: Rune.Bundesen@i-data.com

Cincerly
-Rune Bundesen
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.