Click here to Skip to main content
15,892,737 members
Articles / Desktop Programming / MFC

Notifying the Document

Rate me:
Please Sign up or sign in to vote.
4.36/5 (11 votes)
12 Jul 2006CPOL6 min read 63.9K   1.2K   35  
An article on delivering objects to the document in a document/view architecture, using the WM_NOTIFY message.
// NotifierAppDoc.cpp : implementation of the CNotifierAppDoc class
//

#include "stdafx.h"
#include "NotifierApp.h"

#include "NotifyObject.h"
#include "NotifyObjects.h"

#include "NotifierAppDoc.h"

#include <deque>



#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define THREAD_INFORMATION_RETURN (UINT)(-101)
#define THREAD_ERROR_RETURN (UINT)(-102)


// CNotifierAppDoc

IMPLEMENT_DYNCREATE(CNotifierAppDoc, CDocument)

BEGIN_MESSAGE_MAP(CNotifierAppDoc, CDocument)
END_MESSAGE_MAP()


// CNotifierAppDoc construction/destruction

CNotifierAppDoc::CNotifierAppDoc()
{
	m_IsInitialized = FALSE ; 
}

CNotifierAppDoc::~CNotifierAppDoc()
{
	m_InformationDeque->Push( PTS_STOP ) ;
	WaitForSingleObject( m_InformationThread->m_hThread, INFINITE ) ;
	m_InformationThread->Delete() ;
	signal_fifo::Destroy( &m_InformationDeque ) ;

	m_ErrorDeque->Push( PTS_STOP ) ;
	WaitForSingleObject( m_ErrorThread->m_hThread, INFINITE ) ;
	m_ErrorThread->Delete() ;
	signal_fifo::Destroy( &m_ErrorDeque ) ;
}

BOOL CNotifierAppDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	if ( m_IsInitialized == FALSE )
	{
		signal_fifo::Create( &m_InformationDeque ) ;
		m_InformationThread = ::AfxBeginThread( InformationThread, (LPVOID)this, THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED, 0, NULL ) ;
		m_InformationThread->m_bAutoDelete = false ;

		signal_fifo::Create( &m_ErrorDeque ) ;
		m_ErrorThread = ::AfxBeginThread( ErrorThread, (LPVOID)this, THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED, 0, NULL ) ;
		m_ErrorThread->m_bAutoDelete = false ;

		m_IsInitialized = TRUE ; 
	}

	return TRUE;
}


UINT CNotifierAppDoc::InformationThread( void * p )
{
	CNotifierAppDoc * Doc = reinterpret_cast<CNotifierAppDoc*>(p) ;
	ASSERT( Doc ) ;
	int index = 1 ; 
	bool _Stop = false ;
	do
	{
		DWORD State = WaitForSingleObject( Doc->m_InformationDeque->Event(), 1000L ) ; 
		if ( State == WAIT_OBJECT_0 )
		{
			PTSIGNAL Signal = PTS_EMPTY ;
			do
			{
				Signal = Doc->m_InformationDeque->Pop() ;
				switch ( Signal ) 
				{
				case PTS_EMPTY:
					TRACE( _T("CNotifierAppDoc::InformationThread() : PTS_EMPTY\n") ) ;
					// It may be that another thread got this first
					break ;
				case PTS_SIGNAL:
					TRACE( _T("CNotifierAppDoc::InformationThread() : PTS_SIGNAL\n") ) ;
					Sleep(500); // wait for .5 sec before executing
					Doc->OnInformationThread( index++ ) ;
					break ;
				case PTS_STOP:
					TRACE( _T("CNotifierAppDoc::InformationThread() : PTS_STOP\n") ) ;
					Sleep(3000) ;
					_Stop = true ; 
					break ;
				}
			} while ( Signal == PTS_SIGNAL ) ;
		}
	} while ( _Stop == false ) ;
	return THREAD_INFORMATION_RETURN ;
}

UINT CNotifierAppDoc::ErrorThread( void * p ) 
{
	CNotifierAppDoc * Doc = reinterpret_cast<CNotifierAppDoc*>(p) ;
	ASSERT( Doc ) ;
	int index = 1 ; 
	bool _Stop = false ;
	do
	{
		DWORD State = WaitForSingleObject( Doc->m_ErrorDeque->Event(), 1000L ) ; 
		if ( State == WAIT_OBJECT_0 )
		{
			PTSIGNAL Signal = PTS_EMPTY ;
			do
			{
				Signal = Doc->m_ErrorDeque->Pop() ;
				switch ( Signal ) 
				{
				case PTS_EMPTY:
					TRACE( _T("CNotifierAppDoc::ErrorThread() : PTS_EMPTY\n") ) ;
					// It may be that another thread got this first
					break ;
				case PTS_SIGNAL:
					TRACE( _T("CNotifierAppDoc::ErrorThread() : PTS_SIGNAL\n") ) ;
					Sleep(2000); // wait for 2 sec before executing
					Doc->OnErrorThread( index++ ) ;
					break ;
				case PTS_STOP:
					TRACE( _T("CNotifierAppDoc::ErrorThread() : PTS_STOP\n") ) ;
					Sleep(5000) ;
					_Stop = true ; 
					break ;
				}
			} while ( Signal == PTS_SIGNAL ) ;
		}
	} while ( _Stop == false ) ;
	return THREAD_ERROR_RETURN ;
}

void CNotifierAppDoc::OnErrorThread( int index ) 
{
	TRACE( _T("CNotifierAppDoc::OnErrorThread()\n") ) ;
	HWND hMain = AfxGetApp()->m_pMainWnd->GetSafeHwnd() ;
	NMHDR hdr = { hMain, IDD_NotifyAppDoc, 0 } ;
	CString s ;
	s.Format( _T("Error Item %d"), index ) ; 
	CErrorObject * pObject = new CErrorObject( index, s, hdr ) ;
	::PostMessage( hMain, WM_NOTIFY, 0, (LPARAM)&(pObject->m_hdrObject) ) ;
}


void CNotifierAppDoc::OnInformationThread( int index ) 
{
	TRACE( _T("CNotifierAppDoc::OnInformationThread()\n") ) ;
	HWND hMain = AfxGetApp()->m_pMainWnd->GetSafeHwnd() ;
	NMHDR hdr = { hMain, IDD_NotifyAppDoc, 0 } ;
	CString s ;
	s.Format( _T("Information Item %d"), index ) ; 
	CInformationObject * pObject = new CInformationObject( index, s, hdr ) ;
	::PostMessage( hMain, WM_NOTIFY, 0, (LPARAM)&(pObject->m_hdrObject) ) ;
}


void CNotifierAppDoc::RequestInformation() 
{
	m_InformationDeque->Push( PTS_SIGNAL ) ;
}


void CNotifierAppDoc::RequestError()
{
//	m_ErrorThread.Signal() ;
	m_ErrorDeque->Push( PTS_SIGNAL ) ;
}


// CNotifierAppDoc serialization

void CNotifierAppDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}
}


// CNotifierAppDoc diagnostics

#ifdef _DEBUG
void CNotifierAppDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CNotifierAppDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG


BOOL CNotifierAppDoc::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
	if ( HIWORD(nCode) == WM_NOTIFY )
	{
		WORD wCode = LOWORD(nCode) ;
		AFX_NOTIFY * notify = reinterpret_cast<AFX_NOTIFY*>(pExtra) ;
		if ( notify->pNMHDR->idFrom == IDD_NotifyAppDoc )
		{
			LPNMHDROBJECT lpnmhdr = (LPNMHDROBJECT)(notify->pNMHDR) ;
			CNotifyObject * pObject = lpnmhdr->pObject ;
			UpdateAllViews( NULL, pObject->get_Message(), pObject ) ;
			delete pObject ; 
			*(notify->pResult) = 1 ;
			return TRUE ;
		}
		int x = 0 ;
	}
	return CDocument::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}


class critical_section_t
{
public:
	critical_section_t()
	{
		::InitializeCriticalSection( &m_CS ) ;
	}
	virtual ~critical_section_t()
	{
		::DeleteCriticalSection( &m_CS ) ;
	}
	operator LPCRITICAL_SECTION()
	{
		return &m_CS ; 
	}
protected:
	CRITICAL_SECTION m_CS ; 
};

class cs_lock_t
{
public:
	cs_lock_t( critical_section_t & cst )
	{
		m_pCS = (LPCRITICAL_SECTION)cst ;
		::EnterCriticalSection( m_pCS ) ;
	}
	cs_lock_t( LPCRITICAL_SECTION pcs )
	{
		m_pCS = pcs ;
		::EnterCriticalSection( m_pCS ) ;
	}
	virtual ~cs_lock_t()
	{
		::LeaveCriticalSection(m_pCS) ;
	}

protected:
	CRITICAL_SECTION * m_pCS ; 
};

class signal_fifo_impl : public signal_fifo
{
protected:
	typedef std::deque<PTSIGNAL> signals_t ; 
	typedef signals_t::iterator signals_ptr ; 
public:
	signal_fifo_impl()
	{
		m_Event = CreateEvent(NULL, FALSE, FALSE, NULL ) ;
	}
	~signal_fifo_impl()
	{
		CloseHandle( m_Event ) ;
	}
	virtual PTSIGNAL Pop()
	{
		PTSIGNAL pop = PTS_EMPTY ;
		if ( m_Signals.size() > 0 )
		{
			cs_lock_t lock(m_CS) ;
			pop = m_Signals[0] ;
			m_Signals.pop_front() ; 
		}
		return pop ;
	}
	virtual void Push( PTSIGNAL Signal )
	{
		{
			cs_lock_t lock(m_CS) ;
			m_Signals.push_back( Signal ) ;
		}
		::SetEvent( m_Event ) ;
	}
	virtual size_t Size()
	{
		size_t sReturn = 0 ;
		{
			cs_lock_t lock(m_CS) ;
			sReturn = m_Signals.size() ; 
		}
		return sReturn ; 
	}
	virtual HANDLE & Event()
	{
		return m_Event ;
	}
protected:
	HANDLE				m_Event ; 
	signals_t			m_Signals ; 
	critical_section_t	m_CS ; 
};

void signal_fifo::Create( signal_fifo ** signals )
{
	signal_fifo_impl * p = new signal_fifo_impl ;
	*signals = p ; 
}

void signal_fifo::Destroy( signal_fifo ** signals )
{
	delete *signals ; 
	*signals = NULL ; 
}


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions