📄 directorychanges.cpp
字号:
************************************/
{
ASSERT( pChangeHandler );
CSingleLock lock(&m_csDirWatchInfo, TRUE);
ASSERT( lock.IsLocked() );
int nUnwatched = 0;
int nIdx = -1;
CDirWatchInfo * pDirInfo;
//
// go through and unwatch any directory that is
// that is using this pChangeHandler as it's file change notification handler.
//
while( (pDirInfo = GetDirWatchInfo( pChangeHandler, nIdx )) != NULL )
{
VERIFY( pDirInfo->UnwatchDirectory( m_hCompPort ) );
nUnwatched++;
m_DirectoriesToWatch.SetAt(nIdx, NULL);
pDirInfo->DeleteSelf(this);
}
return (BOOL)(nUnwatched != 0);
}
BOOL CDirectoryChangeWatcher::UnwatchDirectoryBecauseOfError(CDirWatchInfo * pWatchInfo)
//
// Called in the worker thread in the case that ReadDirectoryChangesW() fails
// during normal operation. One way to force this to happen is to watch a folder
// using a UNC path and changing that computer's IP address.
//
{
ASSERT( pWatchInfo );
ASSERT( m_dwThreadID == GetCurrentThreadId() );//this should be called from the worker thread only.
BOOL bRetVal = FALSE;
if( pWatchInfo )
{
CSingleLock lock(&m_csDirWatchInfo, TRUE);
ASSERT( lock.IsLocked() );
int nIdx = -1;
if( GetDirWatchInfo(pWatchInfo, nIdx) == pWatchInfo )
{
// we are actually watching this....
//
// Remove this CDirWatchInfo object from the list of watched directories.
//
m_DirectoriesToWatch.SetAt(nIdx, NULL);//mark the space as free for the next watch...
//
// and delete it...
//
pWatchInfo->DeleteSelf(this);
}
}
return bRetVal;
}
int CDirectoryChangeWatcher::AddToWatchInfo(CDirectoryChangeWatcher::CDirWatchInfo * pWatchInfo)
//
//
// To add the CDirWatchInfo * to an array.
// The array is used to keep track of which directories
// are being watched.
//
// Add the ptr to the first non-null slot in the array.
{
CSingleLock lock( &m_csDirWatchInfo, TRUE);
ASSERT( lock.IsLocked() );
//first try to add it to the first empty slot in m_DirectoriesToWatch
int max = m_DirectoriesToWatch.GetSize();
for(int i = 0; i < max; ++i)
{
if( m_DirectoriesToWatch[i] == NULL )
{
m_DirectoriesToWatch[i] = pWatchInfo;
break;
}
}
if( i == max )
{
// there where no empty slots, add it to the end of the array
try{
i = m_DirectoriesToWatch.Add( pWatchInfo );
}
catch(CMemoryException * e){
e->ReportError();
e->Delete();//??? delete this? I thought CMemoryException objects where pre allocated in mfc? -- sample code in msdn does, so will i
i = -1;
}
}
return (BOOL)(i != -1);
}
//
// functions for retrieving the directory watch info based on different parameters
//
CDirectoryChangeWatcher::CDirWatchInfo * CDirectoryChangeWatcher::GetDirWatchInfo(const CString & strDirName, int & ref_nIdx)const
{
if( strDirName.IsEmpty() )// can't be watching a directory if it's you don't pass in the name of it...
return FALSE; //
CSingleLock lock(const_cast<CCriticalSection*>(&m_csDirWatchInfo), TRUE);
int max = m_DirectoriesToWatch.GetSize();
CDirWatchInfo * p = NULL;
for(int i = 0; i < max; ++i )
{
if( (p = m_DirectoriesToWatch[i]) != NULL
&& p->m_strDirName.CompareNoCase( strDirName ) == 0 )
{
ref_nIdx = i;
return p;
}
}
return NULL;//NOT FOUND
}
CDirectoryChangeWatcher::CDirWatchInfo * CDirectoryChangeWatcher::GetDirWatchInfo(CDirectoryChangeWatcher::CDirWatchInfo * pWatchInfo, int & ref_nIdx)const
{
ASSERT( pWatchInfo != NULL );
CSingleLock lock( const_cast<CCriticalSection*>(&m_csDirWatchInfo), TRUE);
int i(0), max = m_DirectoriesToWatch.GetSize();
CDirWatchInfo * p;
for(; i < max; ++i)
{
if( (p = m_DirectoriesToWatch[i]) != NULL
&& p == pWatchInfo )
{
ref_nIdx = i;
return p;
}
}
return NULL;//NOT FOUND
}
CDirectoryChangeWatcher::CDirWatchInfo * CDirectoryChangeWatcher::GetDirWatchInfo(CDirectoryChangeHandler * pChangeHandler, int & ref_nIdx)const
{
ASSERT( pChangeHandler != NULL );
CSingleLock lock( const_cast<CCriticalSection*>(&m_csDirWatchInfo), TRUE);
int i(0),max = m_DirectoriesToWatch.GetSize();
CDirWatchInfo * p;
for( ; i < max; ++i)
{
if( (p = m_DirectoriesToWatch[i]) != NULL
&& p->GetRealChangeHandler() == pChangeHandler )
{
ref_nIdx = i;
return p;
}
}
return NULL;//NOT FOUND
}
long CDirectoryChangeWatcher::ReleaseReferenceToWatcher(CDirectoryChangeHandler * pChangeHandler)
{
ASSERT( pChangeHandler );
return pChangeHandler->ReleaseReferenceToWatcher(this);
}
CDirectoryChangeWatcher::CDirWatchInfo::CDirWatchInfo(HANDLE hDir,
const CString & strDirectoryName,
CDirectoryChangeHandler * pChangeHandler,
DWORD dwChangeFilter,
BOOL bWatchSubDir,
bool bAppHasGUI,
LPCTSTR szIncludeFilter,
LPCTSTR szExcludeFilter,
DWORD dwFilterFlags)
: m_pChangeHandler( NULL ),
m_hDir(hDir),
m_dwChangeFilter( dwChangeFilter ),
m_bWatchSubDir( bWatchSubDir ),
m_strDirName( strDirectoryName ),
m_dwBufLength(0),
m_dwReadDirError(ERROR_SUCCESS),
m_StartStopEvent(FALSE, TRUE), //NOT SIGNALLED, MANUAL RESET
m_RunningState( RUNNING_STATE_NOT_SET )
{
ASSERT( hDir != INVALID_HANDLE_VALUE
&& !strDirectoryName.IsEmpty() );
//
// This object 'decorates' the pChangeHandler passed in
// so that notifications fire in the context a thread other than
// CDirectoryChangeWatcher::MonitorDirectoryChanges()
//
// Supports the include and exclude filters
//
//
m_pChangeHandler = new CDelayedDirectoryChangeHandler( pChangeHandler, bAppHasGUI, szIncludeFilter, szExcludeFilter, dwFilterFlags );
if( m_pChangeHandler )
m_pChangeHandler->SetPartialPathOffset( m_strDirName );//to support FILTERS_CHECK_PARTIAL_PATH..this won't change for the duration of the watch, so set it once... HERE!
ASSERT( m_pChangeHandler );
ASSERT( GetChangeHandler() );
ASSERT( GetRealChangeHandler() );
if( GetRealChangeHandler() )
GetRealChangeHandler()->AddRef();
memset(&m_Overlapped, 0, sizeof(m_Overlapped));
//memset(m_Buffer, 0, sizeof(m_Buffer));
}
CDirectoryChangeWatcher::CDirWatchInfo::~CDirWatchInfo()
{
if( GetChangeHandler() )
{//If this call to CDirectoryChangeHandler::Release() causes m_pChangeHandler to delete itself,
//the dtor for CDirectoryChangeHandler will call CDirectoryChangeWatcher::UnwatchDirectory( CDirectoryChangeHandler * ),
//which will make try to delete this object again.
//if m_pChangeHandler is NULL, it won't try to delete this object again...
CDirectoryChangeHandler * pTmp = SetRealDirectoryChangeHandler( NULL );
if( pTmp )
pTmp->Release();
else{
ASSERT( FALSE );
}
}
CloseDirectoryHandle();
delete m_pChangeHandler;
m_pChangeHandler = NULL;
}
void CDirectoryChangeWatcher::CDirWatchInfo::DeleteSelf(CDirectoryChangeWatcher * pWatcher)
//
// There's a reason for this function!
//
// the dtor is private to enforce that it is used.
//
//
// pWatcher can be NULL only if CDirecotryChangeHandler::ReferencesWatcher() has NOT been called.
// ie: in certain sections of WatchDirectory() it's ok to pass this w/ NULL, but no where else.
//
{
//ASSERT( pWatcher != NULL );
ASSERT( GetRealChangeHandler() );
if( pWatcher )
{
//
//
// Before this object is deleted, the CDirectoryChangeHandler object
// needs to release it's reference count to the CDirectoryChangeWatcher object.
// I might forget to do this since I getting rid of CDirWatchInfo objects
// in more than one place...hence the reason for this function.
//
pWatcher->ReleaseReferenceToWatcher( GetRealChangeHandler() );
}
delete this;
}
CDelayedDirectoryChangeHandler* CDirectoryChangeWatcher::CDirWatchInfo::GetChangeHandler() const
{
return m_pChangeHandler;
}
CDirectoryChangeHandler * CDirectoryChangeWatcher::CDirWatchInfo::GetRealChangeHandler() const
//
// The 'real' change handler is the CDirectoryChangeHandler object
// passed to CDirectoryChangeWatcher::WatchDirectory() -- this is the object
// that really handles the changes.
//
{
ASSERT( m_pChangeHandler );
return m_pChangeHandler->GetRealChangeHandler();
}
CDirectoryChangeHandler * CDirectoryChangeWatcher::CDirWatchInfo::SetRealDirectoryChangeHandler(CDirectoryChangeHandler * pChangeHandler)
//
// Allows you to switch out, at run time, which object really handles the change notifications.
//
{
CDirectoryChangeHandler * pOld = GetRealChangeHandler();
m_pChangeHandler->GetRealChangeHandler() = pChangeHandler;
return pOld;
}
BOOL CDirectoryChangeWatcher::CDirWatchInfo::CloseDirectoryHandle()
//
// Closes the directory handle that was opened in CDirectoryChangeWatcher::WatchDirecotry()
//
//
{
BOOL b = TRUE;
if( m_hDir != INVALID_HANDLE_VALUE )
{
b = CloseHandle(m_hDir);
m_hDir = INVALID_HANDLE_VALUE;
}
return b;
}
DWORD CDirectoryChangeWatcher::CDirWatchInfo::StartMonitor(HANDLE hCompPort)
/*********************************************
Sets the running state of the object to perform the initial call to ReadDirectoryChangesW()
, wakes up the thread waiting on GetQueuedCompletionStatus()
and waits for an event to be set before returning....
The return value is either ERROR_SUCCESS if ReadDirectoryChangesW is successfull,
or is the value of GetLastError() for when ReadDirectoryChangesW() failed.
**********************************************/
{
ASSERT( hCompPort );
//Guard the properties of this object
VERIFY( LockProperties() );
m_RunningState = RUNNING_STATE_START_MONITORING;//set the state member to indicate that the object is to START monitoring the specified directory
PostQueuedCompletionStatus(hCompPort, sizeof(this), (DWORD)this, &m_Overlapped);//make the thread waiting on GetQueuedCompletionStatus() wake up
VERIFY( UnlockProperties() );//unlock this object so that the thread can get at them...
//wait for signal that the initial call
//to ReadDirectoryChanges has been made
DWORD dwWait = 0;
do{
dwWait = WaitForSingleObject(m_StartStopEvent, 10 * 1000);
if( dwWait != WAIT_OBJECT_0 )
{
//
// shouldn't ever see this one....but just in case you do, notify me of the problem wesj@hotmail.com.
//
TRACE(_T("WARNING! Possible lockup detected. FILE: %s Line: %d\n"), _T( __FILE__ ), __LINE__);
}
} while( dwWait != WAIT_OBJECT_0 );
ASSERT( dwWait == WAIT_OBJECT_0 );
m_StartStopEvent.ResetEvent();
return m_dwReadDirError;//This value is set in the worker thread when it first calls ReadDirectoryChangesW().
}
BOOL CDirectoryChangeWatcher::CDirWatchInfo::UnwatchDirectory(HANDLE hCompPort)
/*******************************************
Sets the running state of the object to stop monitoring a directory,
Causes the worker thread to wake up and to stop monitoring the dierctory
********************************************/
{
ASSERT( hCompPort );
//
// Signal that the worker thread is to stop watching the directory
//
if( SignalShutdown(hCompPort) )
{
//and wait for the thread to signal that it has shutdown
return WaitForShutdown();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -