Click here to Skip to main content
15,882,055 members
Articles / Desktop Programming / MFC

CDirectoryChangeWatcher - ReadDirectoryChangesW all wrapped up

Rate me:
Please Sign up or sign in to vote.
4.92/5 (114 votes)
11 May 2002 2.1M   39.4K   365  
This class wraps up ReadDirectoryChangesW.
// DelayedDirectoryChangeHandler.cpp: implementation of the CDelayedDirectoryChangeHandler2 class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DirectoryChanges.h"
#include "DelayedDirectoryChangeHandler.h"

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

#define UWM_DELALAYED_DIRECTORY_NOTIFICATION (WM_APP+1024)
//
//CDelayedDirectoryChangeNotification member functions:
//
CDelayedDirectoryChangeNotification::CDelayedDirectoryChangeNotification(CDelayedDirectoryChangeHandler *	pDelayedHandler)
:m_pDelayedHandler( pDelayedHandler )
,m_strFileName1()
,m_strFileName2()
,m_dwError(0UL)
{
	ASSERT( pDelayedHandler );
}

CDelayedDirectoryChangeNotification::~CDelayedDirectoryChangeNotification()
{
}
void CDelayedDirectoryChangeNotification::DispatchNotificationFunction()
{

	ASSERT( m_pDelayedHandler );
	if( m_pDelayedHandler )
		m_pDelayedHandler->DispatchNotificationFunction( this );
}

void CDelayedDirectoryChangeNotification::PostOn_FileAdded(const CString & strFileName)
{
	m_eFunctionToDispatch = eOn_FileAdded;
	m_strFileName1 = strFileName;
	//
	// post the message so it'll be dispatch by the main thread.
	PostNotification();

}
void CDelayedDirectoryChangeNotification::PostOn_FileRemoved(const CString & strFileName)
{
	m_eFunctionToDispatch = eOn_FileRemoved;
	m_strFileName1 = strFileName;
	//
	// post the message so it'll be dispatch by the main thread.
	PostNotification();
	
}
void CDelayedDirectoryChangeNotification::PostOn_FileNameChanged(const CString & strOldName, const CString & strNewName)
{
	m_eFunctionToDispatch = eOn_FileRenamed;
	m_strFileName1 = strOldName;
	m_strFileName2 = strNewName;
	//
	// post the message so it'll be dispatch by the main thread.
	PostNotification();
	
}

void CDelayedDirectoryChangeNotification::PostOn_FileModified(const CString & strFileName)
{
	m_eFunctionToDispatch = eOn_FileModified;
	m_strFileName1 = strFileName;
	//
	// post the message so it'll be dispatch by the main thread.
	PostNotification();
}

void CDelayedDirectoryChangeNotification::PostOn_ReadDirectoryChangesError(DWORD dwError)
{
	m_eFunctionToDispatch = eOn_ReadDirectoryChangesError;
	m_dwError = dwError;
	//
	// post the message so it'll be dispatch by the main thread.
	PostNotification();
	
}

void CDelayedDirectoryChangeNotification::PostNotification()
{
	ASSERT( m_pDelayedHandler );
	if( m_pDelayedHandler )
		m_pDelayedHandler->m_DelayWindow.PostNotification( this );
}


static LRESULT CALLBACK DelayedNotificationWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
//
//	This is the wndproc for the notification window
//
//	it's here to dispatch the notifications to the client
//
{
	if( message == UWM_DELALAYED_DIRECTORY_NOTIFICATION )
	{
		CDelayedDirectoryChangeNotification * pNotification = reinterpret_cast<CDelayedDirectoryChangeNotification*>(lParam);
		ASSERT(  pNotification );
		if( pNotification )
		{
			pNotification->DispatchNotificationFunction();
		}
		
		return 0UL;
	}
	else
		return DefWindowProc(hWnd,message,wParam,lParam);
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//
//CDelayedDirectoryChangeNotification::CDelayedNotificationWindow static member vars:
//
long CDelayedDirectoryChangeHandler::CDelayedNotificationWindow::s_nRefCnt = 0L;
HWND CDelayedDirectoryChangeHandler::CDelayedNotificationWindow::s_hWnd = NULL;
BOOL CDelayedDirectoryChangeHandler::CDelayedNotificationWindow::s_bRegisterWindow = FALSE;
//
//
long CDelayedDirectoryChangeHandler::CDelayedNotificationWindow::AddRef()//creates window for first time if necessary
{
	if( InterlockedIncrement(&s_nRefCnt) == 1
		||	!::IsWindow( s_hWnd ) )
	{
		TRACE(_T("CDelayedDirectoryChangeHandler::CDelayedNotificationWindow -- Creating the notification window\n"));
		VERIFY( CreateNotificationWindow() );
	}
	return s_nRefCnt;
}

long CDelayedDirectoryChangeHandler::CDelayedNotificationWindow::Release()//destroys window for last time if necessary
{
	long nRefCnt = -1;
	if( (nRefCnt = InterlockedDecrement(&s_nRefCnt)) == 0 )
	{
		//no body else using the window so destroy it?
		TRACE(_T("CDelayedDirectoryChangeHandler::CDelayedNotificationWindow -- Destroying the notification window\n"));
		DestroyWindow( s_hWnd );
		s_hWnd = NULL;
	}
	return nRefCnt;
}
BOOL CDelayedDirectoryChangeHandler::CDelayedNotificationWindow::RegisterWindowClass(LPCTSTR szClassName)
//
//	registers our own window class to use as the hidden notification window.
//
{
	WNDCLASS wc = {0};
	
	wc.style = 0;
	wc.hInstance		= AfxGetInstanceHandle();
	wc.lpszClassName	= szClassName;
	wc.hbrBackground	= (HBRUSH)GetStockObject( WHITE_BRUSH );
	wc.lpfnWndProc		= DelayedNotificationWndProc;
	
	ATOM ant = RegisterClass( &wc );
	if( ant == NULL )
	{
		TRACE(_T("CDelayedDirectoryChangeNotification::RegisterWindowClass - RegisterClass failed: %d\n"), GetLastError());
	}
	return (BOOL)(ant!= NULL);
	
}

BOOL CDelayedDirectoryChangeHandler::CDelayedNotificationWindow::CreateNotificationWindow()
//
//	Create the hidden notification windows.
//
{
	TCHAR szClassName[] = _T("Delayed_Message_Sender");
	if( !s_bRegisterWindow )
		s_bRegisterWindow = RegisterWindowClass(szClassName);
	s_hWnd 	= CreateWindowEx(0, szClassName, _T("DelayedWnd"),0,0,0,0,0, NULL, 0, 
		AfxGetInstanceHandle(), NULL);
	if( s_hWnd == NULL )
	{
		TRACE(_T("Unable to create notification window! GetLastError(): %d\n"), GetLastError());
		TRACE(_T("File: %s Line: %d\n"), _T(__FILE__), __LINE__);
	}
	
	return (BOOL)(s_hWnd != NULL);
}
void CDelayedDirectoryChangeHandler::CDelayedNotificationWindow::PostNotification(CDelayedDirectoryChangeNotification * pNotification)
//
//	Posts a message to a window created in the main 
//	thread.
//	The main thread catches this message, and dispatches it in 
//	the context of the main thread.
//
{
	ASSERT( pNotification );
	ASSERT( s_hWnd );
	ASSERT( ::IsWindow( s_hWnd ) );

	PostMessage(s_hWnd, 
				UWM_DELALAYED_DIRECTORY_NOTIFICATION, 
				0, 
				reinterpret_cast<LPARAM>( pNotification ));

//  if you don't want the notification delayed, 
//  
//	if( false )
//	{
//		pNotification->DispatchNotificationFunction();
//	}
}
///////////////////////////////////////////////////////
//construction destruction
CDelayedDirectoryChangeHandler::CDelayedDirectoryChangeHandler(CDirectoryChangeHandler * pRealHandler)
: m_DelayWindow()
 ,m_pRealHandler( pRealHandler )
{
	ASSERT( m_pRealHandler );
}

CDelayedDirectoryChangeHandler::~CDelayedDirectoryChangeHandler()
{
}


CDelayedDirectoryChangeNotification * CDelayedDirectoryChangeHandler::GetNotificationObject()
//
//	Maybe in future I'll keep a pool of these 
//	objects around to increase performance...
//	using objects from a cache will be faster 
//	than allocated and destroying a new one each time.
//	
//  
{
	ASSERT( m_pRealHandler );
	return new CDelayedDirectoryChangeNotification(this);
}

void CDelayedDirectoryChangeHandler::DisposeOfNotification(CDelayedDirectoryChangeNotification * pNotification)
{
	delete pNotification;
}

//These functions are called when the directory to watch has had a change made to it
void CDelayedDirectoryChangeHandler::On_FileAdded(const CString & strFileName)
{
	CDelayedDirectoryChangeNotification * p = GetNotificationObject();
	ASSERT( p );
	if( p )
		p->PostOn_FileAdded( strFileName );
}

void CDelayedDirectoryChangeHandler::On_FileRemoved(const CString & strFileName)
{
	CDelayedDirectoryChangeNotification * p = GetNotificationObject();
	ASSERT( p );
	if( p )
		p->PostOn_FileRemoved( strFileName );
}

void CDelayedDirectoryChangeHandler::On_FileModified(const CString & strFileName)
{
	CDelayedDirectoryChangeNotification * p = GetNotificationObject();
	ASSERT( p );
	if( p )
		p->PostOn_FileModified( strFileName );
}

void CDelayedDirectoryChangeHandler::On_FileNameChanged(const CString & strOldFileName, const CString & strNewFileName)
{
	CDelayedDirectoryChangeNotification * p = GetNotificationObject();	
	ASSERT( p );
	if( p )
		p->PostOn_FileNameChanged( strOldFileName, strNewFileName );
}

void CDelayedDirectoryChangeHandler::On_ReadDirectoryChangesError(DWORD dwError)
{
	CDelayedDirectoryChangeNotification * p = GetNotificationObject();
	ASSERT( p );
	if( p )
		p->PostOn_ReadDirectoryChangesError( dwError );
}

void CDelayedDirectoryChangeHandler::DispatchNotificationFunction(CDelayedDirectoryChangeNotification * pNotification)
/*****************************************************
	This function is called when we want the notification to execute.

	
******************************************************/
{
	ASSERT( m_pRealHandler );
	ASSERT( pNotification );
	if( pNotification && m_pRealHandler )
	{
		switch( pNotification->m_eFunctionToDispatch )
		{
		case CDelayedDirectoryChangeNotification::eOn_FileAdded:
			
			m_pRealHandler->On_FileAdded( pNotification->m_strFileName1 ); 
			break;
			
		case CDelayedDirectoryChangeNotification::eOn_FileRemoved:
			
			m_pRealHandler->On_FileRemoved( pNotification->m_strFileName1 );
			break;
			
		case CDelayedDirectoryChangeNotification::eOn_FileRenamed:
			
			m_pRealHandler->On_FileNameChanged( pNotification->m_strFileName1, pNotification->m_strFileName2 );
			break;
			
		case CDelayedDirectoryChangeNotification::eOn_FileModified:
			
			m_pRealHandler->On_FileModified( pNotification->m_strFileName1 );
			break;
			
		case CDelayedDirectoryChangeNotification::eOn_ReadDirectoryChangesError:
			
			m_pRealHandler->On_ReadDirectoryChangesError( pNotification->m_dwError );
			break;
			
		case CDelayedDirectoryChangeNotification::eFunctionNotDefined:
		default:
			break;
		}
		
		//
		// deletes or releases the notification object from memory/use
		//
		DisposeOfNotification(pNotification);
	}	
}

void CDelayedDirectoryChangeHandler::SetChangedDirectoryName(const CString & strChangedDirName)
{
	ASSERT( m_pRealHandler );
	CDirectoryChangeHandler::SetChangedDirectoryName(strChangedDirName);
	if( m_pRealHandler )
		m_pRealHandler->SetChangedDirectoryName( strChangedDirName );
}
const CString & CDelayedDirectoryChangeHandler::GetChangedDirectoryName() const
{
	if( m_pRealHandler )
		return m_pRealHandler->GetChangedDirectoryName();
	return CDirectoryChangeHandler::GetChangedDirectoryName();
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
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