Solved

Messageprocessing in DLL's

Posted on 1997-11-05
4
392 Views
Last Modified: 2013-11-20
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
0
Comment
Question by:puff
  • 2
4 Comments
 
LVL 8

Expert Comment

by:MikeP090797
ID: 1309395
You use LoadLibrary from an EXE, and the ::Run is called automaticly. the ::Run is instead of DllMain function of a DLL.
0
 

Author Comment

by:puff
ID: 1309396
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
 
LVL 1

Accepted Solution

by:
IgorGrebnev earned 300 total points
ID: 1309397
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
 

Author Comment

by:puff
ID: 1309398
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

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now