753 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			753 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "stdafx.h"
 | |
| #include "Monitor.h"
 | |
| #include "Lock.h"
 | |
| #include "MyDebug.h"
 | |
| #include "pudebug.h"
 | |
| #include <process.h>
 | |
| 
 | |
| #ifdef DBG
 | |
| #undef THIS_FILE
 | |
| static char THIS_FILE[]=__FILE__;
 | |
| #define new DEBUG_NEW
 | |
| #endif
 | |
| 
 | |
| static String FileToDir( const String& );
 | |
| 
 | |
| // function objects for comparisons
 | |
| struct DirCompare
 | |
| {
 | |
|     DirCompare( const String& strDir )
 | |
|         :   m_strDir( strDir ) {}
 | |
|     bool operator()( CMonitorDirPtr& pDir )
 | |
|     {
 | |
|         return ( m_strDir == pDir->Dir() );
 | |
|     }
 | |
|     String m_strDir;
 | |
| };
 | |
| 
 | |
| struct FileCompare
 | |
| {
 | |
|     FileCompare( const String& strFile )
 | |
|         :   m_strFile( strFile ) {}
 | |
|     bool operator()( const CMonitorFilePtr& pFile )
 | |
|     {
 | |
|         return ( m_strFile == pFile->FileName() );
 | |
|     }
 | |
|     String m_strFile;
 | |
| };
 | |
| 
 | |
| struct RegKeyCompare
 | |
| {
 | |
|     RegKeyCompare( HKEY hKey, const String strSubKey )
 | |
|         :   m_hKey(hKey), m_strSubKey( strSubKey ) {}
 | |
|     bool operator()( const CMonitorRegKeyPtr& pRegKey )
 | |
|     {
 | |
|         bool rc = false;
 | |
|         if ( m_hKey == pRegKey->m_hBaseKey )
 | |
|         {
 | |
|             rc = ( m_strSubKey == pRegKey->m_strKey );
 | |
|         }
 | |
|         return rc;
 | |
|     }
 | |
|     const HKEY      m_hKey;
 | |
|     const String   m_strSubKey;
 | |
| };
 | |
| 
 | |
| 
 | |
| String
 | |
| FileToDir(
 | |
|     const String&  strFile )
 | |
| {
 | |
|     String strDir;
 | |
|     String::size_type pos = strFile.find_last_of( _T('\\') );
 | |
|     if ( pos != String::npos )
 | |
|     {
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         pos = strFile.find_first_of( _T(':') );
 | |
|         if ( pos != String::npos )
 | |
|         {
 | |
|             pos++;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if ( pos != String::npos )
 | |
|     {
 | |
|         strDir = strFile.substr( 0, pos );
 | |
|     }
 | |
|     return strDir;
 | |
| }
 | |
| 
 | |
| //---------------------------------------------------------------------------
 | |
| //  CMonitorFile
 | |
| //---------------------------------------------------------------------------
 | |
| CMonitorFile::CMonitorFile(
 | |
|     const String&              strFile,
 | |
|     const CMonitorNotifyPtr&    pNotify )
 | |
|     :   m_strFile( strFile ),
 | |
|         m_pNotify( pNotify )
 | |
| {
 | |
|     GetFileTime( m_ft );
 | |
| }
 | |
| 
 | |
| CMonitorFile::~CMonitorFile()
 | |
| {
 | |
| }
 | |
| 
 | |
| const String&
 | |
| CMonitorFile::FileName() const
 | |
| {
 | |
|     return m_strFile;
 | |
| }
 | |
| 
 | |
| bool
 | |
| CMonitorFile::GetFileTime(
 | |
|     FILETIME&   ft )
 | |
| {
 | |
|     bool                        rc = false;
 | |
|     WIN32_FILE_ATTRIBUTE_DATA   fileInfo;
 | |
| 
 | |
|     if (GetFileAttributesEx(m_strFile.c_str(),
 | |
|                             GetFileExInfoStandard,
 | |
|                             (LPVOID)&fileInfo)) {
 | |
|         ft = fileInfo.ftLastWriteTime;
 | |
|         rc = true;
 | |
|     }
 | |
| 
 | |
|     return rc;
 | |
| }
 | |
| 
 | |
| bool
 | |
| CMonitorFile::CheckNotify()
 | |
| {
 | |
|     bool rc = false;
 | |
| 
 | |
|     FILETIME ft;
 | |
| 
 | |
|     if ( (GetFileTime( ft) == false) || (::CompareFileTime( &ft, &m_ft ) != 0) )
 | |
|     {
 | |
|         ATLTRACE( _T("File %s has changed...notifying\n"), m_strFile.c_str() );
 | |
|         if ( m_pNotify.IsValid() )
 | |
|         {
 | |
|             m_pNotify->Notify();
 | |
|         }
 | |
|         rc = true;
 | |
|     }
 | |
|     m_ft = ft;
 | |
|     return rc;
 | |
| }
 | |
| 
 | |
| 
 | |
| //---------------------------------------------------------------------------
 | |
| //  CMonitorDir
 | |
| //---------------------------------------------------------------------------
 | |
| CMonitorDir::CMonitorDir(
 | |
|     const String&  strDir )
 | |
|     :   m_strDir( strDir )
 | |
| {
 | |
|     m_hNotification = ::FindFirstChangeNotification(
 | |
|         m_strDir.c_str(),
 | |
|         FALSE,
 | |
|         FILE_NOTIFY_CHANGE_LAST_WRITE );
 | |
| }
 | |
| 
 | |
| CMonitorDir::~CMonitorDir()
 | |
| {
 | |
|     m_files.clear();
 | |
|     ::FindCloseChangeNotification( m_hNotification );
 | |
| }
 | |
| 
 | |
| void
 | |
| CMonitorDir::AddFile(
 | |
|     const String&              strFile,
 | |
|     const CMonitorNotifyPtr&    pNotify )
 | |
| {
 | |
| //    ATLTRACE( _T("Monitoring file %s\n"), strFile.c_str() );
 | |
|     m_files.push_back( new CMonitorFile( strFile, pNotify ) );
 | |
| }
 | |
| 
 | |
| void
 | |
| CMonitorDir::RemoveFile(
 | |
|     const String&   strFile )
 | |
| {
 | |
|     TVector<CMonitorFilePtr>::iterator iter = find_if(
 | |
|         m_files.begin(),
 | |
|         m_files.end(),
 | |
|         FileCompare( strFile ) );
 | |
|     if ( iter != m_files.end() )
 | |
|     {
 | |
| //        ATLTRACE( _T("Stopped monitoring file %s\n"), strFile.c_str() );
 | |
|         m_files.erase( iter );
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| //        ATLTRACE( _T("Not monitoring file %s\n"), strFile.c_str() );
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| CMonitorDir::Notify()
 | |
| {
 | |
|     for ( UINT i = 0; i < m_files.size(); i++ )
 | |
|     {
 | |
|         m_files[i]->CheckNotify();
 | |
|     }
 | |
|     ::FindNextChangeNotification( m_hNotification );
 | |
| }
 | |
| 
 | |
| ULONG
 | |
| CMonitorDir::NumFiles() const
 | |
| {
 | |
|     return m_files.size();
 | |
| }
 | |
| 
 | |
| HANDLE
 | |
| CMonitorDir::NotificationHandle() const
 | |
| {
 | |
|     return m_hNotification;
 | |
| }
 | |
| 
 | |
| const String&
 | |
| CMonitorDir::Dir() const
 | |
| {
 | |
|     return m_strDir;
 | |
| }
 | |
| 
 | |
| //---------------------------------------------------------------------------
 | |
| //  CMonitorRegKey
 | |
| //---------------------------------------------------------------------------
 | |
| CMonitorRegKey::CMonitorRegKey(
 | |
|     HKEY                        hBaseKey,
 | |
|     const String&              strKey,
 | |
|     const CMonitorNotifyPtr&    pNotify )
 | |
|     :   m_hEvt(NULL),
 | |
|         m_hKey(NULL),
 | |
|         m_pNotify( pNotify ),
 | |
|         m_strKey( strKey ),
 | |
|         m_hBaseKey( hBaseKey )
 | |
| {
 | |
|     LONG l = ::RegOpenKeyEx(
 | |
|         hBaseKey,
 | |
|         strKey.c_str(),
 | |
|         0,
 | |
|         KEY_NOTIFY,
 | |
|         &m_hKey );
 | |
|     if ( l == ERROR_SUCCESS )
 | |
|     {
 | |
|         m_hEvt = IIS_CREATE_EVENT(
 | |
|                      "CMonitorRegKey::m_hEvt",
 | |
|                      this,
 | |
|                      TRUE,
 | |
|                      FALSE
 | |
|                      );
 | |
|         if ( m_hEvt != NULL )
 | |
|         {
 | |
| #if 0   // not available in Win95
 | |
|             // ask for notification when the key changes
 | |
|             l = ::RegNotifyChangeKeyValue(
 | |
|                 m_hKey,
 | |
|                 FALSE,
 | |
|                 REG_NOTIFY_CHANGE_LAST_SET,
 | |
|                 m_hEvt,
 | |
|                 TRUE );
 | |
|             if ( l == ERROR_SUCCESS )
 | |
|             {
 | |
|                 // okay
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ATLTRACE( _T("Couldn't get reg key notification\n") );
 | |
|             }
 | |
| #endif // if 0
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             ATLTRACE( _T("Couldn't create event\n") );
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         ATLTRACE( _T("Couldn't open subkey: %s\n"), strKey.c_str() );
 | |
|     }
 | |
| }
 | |
| 
 | |
| CMonitorRegKey::~CMonitorRegKey()
 | |
| {
 | |
|     ::RegCloseKey( m_hKey );
 | |
|     ::CloseHandle( m_hEvt );
 | |
| }
 | |
| 
 | |
| void
 | |
| CMonitorRegKey::Notify()
 | |
| {
 | |
|     if ( m_pNotify.IsValid() )
 | |
|     {
 | |
|         m_pNotify->Notify();
 | |
|     }
 | |
|     ::ResetEvent( m_hEvt );
 | |
| #if 0 // not available in Win95
 | |
|     ::RegNotifyChangeKeyValue(
 | |
|         m_hKey,
 | |
|         FALSE,
 | |
|         REG_NOTIFY_CHANGE_LAST_SET,
 | |
|         m_hEvt,
 | |
|         TRUE );
 | |
| #endif
 | |
| }
 | |
| 
 | |
| HANDLE
 | |
| CMonitorRegKey::NotificationHandle() const
 | |
| {
 | |
|     return m_hEvt;
 | |
| }
 | |
| 
 | |
| //---------------------------------------------------------------------------
 | |
| //  CMonitor
 | |
| //---------------------------------------------------------------------------
 | |
| 
 | |
| #include <irtldbg.h>
 | |
| 
 | |
| CMonitor::CMonitor()
 | |
|     :   m_hevtBreak( NULL ),
 | |
|         m_hevtShutdown( NULL ),
 | |
|         m_hThread( NULL ),
 | |
|         m_bRunning( false ),
 | |
|         m_bStopping( false )
 | |
| #ifdef STRING_TRACE_LOG
 | |
|         , m_stl(100, 1000)
 | |
| #endif
 | |
| {
 | |
|     SET_CRITICAL_SECTION_SPIN_COUNT(&m_cs.m_sec, IIS_DEFAULT_CS_SPIN_COUNT);
 | |
|     STL_PRINTF("Created monitor, %p", this);
 | |
| #ifdef STRING_TRACE_LOG
 | |
|     IrtlTrace("Monitor::m_stl = %p\n", &m_stl);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| CMonitor::~CMonitor()
 | |
| {
 | |
|     StopAllMonitoring();
 | |
|     if ( m_hevtBreak != NULL )
 | |
|     {
 | |
|         ::CloseHandle( m_hevtBreak );
 | |
|     }
 | |
|     if ( m_hevtShutdown != NULL )
 | |
|     {
 | |
|         ::CloseHandle( m_hevtShutdown );
 | |
|     }
 | |
|     if ( m_hThread != NULL )
 | |
|     {
 | |
|         ::CloseHandle( m_hThread );
 | |
|     }
 | |
|     STL_PRINTF("Destroying monitor, %p", this);
 | |
| }
 | |
| 
 | |
| void
 | |
| CMonitor::MonitorFile(
 | |
|     LPCTSTR                     szFile,
 | |
|     const CMonitorNotifyPtr&    pMonNotify )
 | |
| {
 | |
|     CLock l(m_cs);
 | |
| 
 | |
|     if (m_bStopping)
 | |
|         return;
 | |
| 
 | |
|     STL_PRINTF("MonitorFile(%s), Run=%d, Stop=%d, Thread=%p",
 | |
|                szFile, (int) m_bRunning, (int) m_bStopping, m_hThread);
 | |
| 
 | |
|     String strFile( szFile );
 | |
|     String strDir = FileToDir( strFile );
 | |
| 
 | |
|     CMonitorDirPtr pDir;
 | |
|     TVector<CMonitorDirPtr>::iterator iter = find_if(
 | |
|         m_dirs.begin(),
 | |
|         m_dirs.end(),
 | |
|         DirCompare( strDir ) );
 | |
|     if ( iter == m_dirs.end() )
 | |
|     {
 | |
| //        ATLTRACE( _T("Request to monitor new directory: %s\n"), strDir.c_str() );
 | |
|         pDir = new CMonitorDir( strDir );
 | |
|         m_dirs.push_back( pDir );
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         pDir = (*iter);
 | |
|     }
 | |
| 
 | |
|     if ( pDir.IsValid() )
 | |
|     {
 | |
|         pDir->AddFile( strFile, pMonNotify );
 | |
|         if ( !m_bRunning )
 | |
|         {
 | |
|             StartUp();
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             ::SetEvent( m_hevtBreak );
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| CMonitor::StopMonitoringFile(
 | |
|     LPCTSTR szFile )
 | |
| {
 | |
|     String strFile( szFile );
 | |
|     String strDir = FileToDir( strFile );
 | |
| 
 | |
|     CLock l(m_cs);
 | |
| 
 | |
|     if (m_bStopping)
 | |
|         return;
 | |
| 
 | |
|     STL_PRINTF("StopMonitoringFile(%s), Run=%d, Stop=%d, Thread=%p",
 | |
|                szFile, (int) m_bRunning, (int) m_bStopping, m_hThread);
 | |
| 
 | |
|     TVector<CMonitorDirPtr>::iterator iter = find_if(
 | |
|         m_dirs.begin(),
 | |
|         m_dirs.end(),
 | |
|         DirCompare( strDir ) );
 | |
|     if ( iter != m_dirs.end() )
 | |
|     {
 | |
|         if ( (*iter).IsValid() )
 | |
|         {
 | |
|             (*iter)->RemoveFile( strFile );
 | |
|             if ( (*iter)->NumFiles() == 0 )
 | |
|             {
 | |
|                 // no more files to monitor in this directory, remove it
 | |
|                 m_dirs.erase(iter);
 | |
|                 ::SetEvent( m_hevtBreak );
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| //        ATLTRACE( _T("Not monitorying file %s\n"), szFile );
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| CMonitor::MonitorRegKey(
 | |
|     HKEY                        hBaseKey,
 | |
|     LPCTSTR                     szSubKey,
 | |
|     const CMonitorNotifyPtr&    pNotify )
 | |
| {
 | |
|     String strSubKey = szSubKey;
 | |
| 
 | |
| //    ATLTRACE( _T( "Request to monitor new key: %s\n"), szSubKey );
 | |
| 
 | |
|     CLock l(m_cs);
 | |
| 
 | |
|     if (m_bStopping)
 | |
|         return;
 | |
| 
 | |
|     if ( find_if(
 | |
|             m_regKeys.begin(),
 | |
|             m_regKeys.end(),
 | |
|             RegKeyCompare( hBaseKey, szSubKey ) )
 | |
|         == m_regKeys.end() )
 | |
|     {
 | |
|         // not already begin monitored, add a new one
 | |
|         CMonitorRegKeyPtr pRegKey = new CMonitorRegKey( hBaseKey, szSubKey, pNotify );
 | |
|         m_regKeys.push_back(pRegKey);
 | |
| 
 | |
|         // either start the monitoring thread or, inform it of a new key to monitor
 | |
|         if ( !m_bRunning )
 | |
|         {
 | |
|             StartUp();
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             ::SetEvent( m_hevtBreak );
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| CMonitor::StopMonitoringRegKey(
 | |
|     HKEY    hBaseKey,
 | |
|     LPCTSTR szSubKey )
 | |
| {
 | |
|     String strSubKey = szSubKey;
 | |
| 
 | |
|     CLock l(m_cs);
 | |
| 
 | |
|     if (m_bStopping)
 | |
|         return;
 | |
| 
 | |
|     TVector<CMonitorRegKeyPtr>::iterator iter = find_if(
 | |
|         m_regKeys.begin(),
 | |
|         m_regKeys.end(),
 | |
|         RegKeyCompare( hBaseKey, szSubKey ) );
 | |
|     if ( iter != m_regKeys.end() )
 | |
|     {
 | |
| //        ATLTRACE( _T( "Stopping monitoring of key: %s\n"), szSubKey );
 | |
|         m_regKeys.erase( iter );
 | |
|         ::SetEvent( m_hevtBreak );
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| //        ATLTRACE( _T("Not monitoring key: %s\n"), szSubKey );
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| CMonitor::StopAllMonitoring()
 | |
| {
 | |
|     m_cs.Lock();
 | |
| 
 | |
|     STL_PRINTF("StopAllMonitoring, Run=%d, Stop=%d, Thread=%p",
 | |
|                (int) m_bRunning, (int) m_bStopping, m_hThread);
 | |
| 
 | |
|     if ( m_bRunning )
 | |
|     {
 | |
| // clear all types of nodes here
 | |
|         m_bStopping = true;
 | |
|         m_regKeys.clear();
 | |
|         m_dirs.clear();
 | |
|         m_cs.Unlock(); // must unlock or DoMonitoring will deadlock
 | |
| 
 | |
|         ::SetEvent( m_hevtShutdown );
 | |
|         ::WaitForSingleObject( m_hThread, INFINITE );
 | |
| 
 | |
|         m_cs.Lock();
 | |
|         ::CloseHandle( m_hThread );
 | |
|         m_hThread = NULL;
 | |
|         m_bRunning = false;
 | |
|         m_bStopping = false;
 | |
|     }
 | |
|     m_cs.Unlock();
 | |
| }
 | |
| 
 | |
| 
 | |
| bool
 | |
| CMonitor::StartUp()
 | |
| {
 | |
|     CLock l(m_cs);
 | |
| 
 | |
|     bool rc = false;
 | |
| 
 | |
|     STL_PRINTF("Startup, Run=%d, Stop=%d, Thread=%p",
 | |
|                (int) m_bRunning, (int) m_bStopping, m_hThread);
 | |
| 
 | |
|     if (m_bStopping)
 | |
|         return false;
 | |
| 
 | |
|     // Have we already started the thread?
 | |
|     if (m_bRunning)
 | |
|     {
 | |
|         _ASSERT(m_hevtBreak != NULL);
 | |
|         _ASSERT(m_hevtShutdown != NULL);
 | |
|         _ASSERT(m_hThread != NULL);
 | |
| 
 | |
|         // Notify the thread that something has changed
 | |
|         ::SetEvent( m_hevtBreak );
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     _ASSERT(m_hThread == NULL);
 | |
| 
 | |
|     if ( m_hevtBreak == NULL )
 | |
|     {
 | |
|         m_hevtBreak = IIS_CREATE_EVENT(
 | |
|                           "CMonitor::m_hevtBreak",
 | |
|                           this,
 | |
|                           FALSE,    // auto event
 | |
|                           FALSE
 | |
|                           );
 | |
|     }
 | |
| 
 | |
|     if ( m_hevtShutdown == NULL )
 | |
|     {
 | |
|         m_hevtShutdown = IIS_CREATE_EVENT(
 | |
|                           "CMonitor::m_hevtShutdown",
 | |
|                           this,
 | |
|                           FALSE,    // auto event
 | |
|                           FALSE
 | |
|                           );
 | |
|     }
 | |
| 
 | |
|     if ( m_hevtBreak != NULL )
 | |
|     {
 | |
|         unsigned int iThreadID;
 | |
| 
 | |
| #if DBG
 | |
|         if( m_hThread != NULL || m_bRunning)
 | |
|         {
 | |
|             DebugBreak();
 | |
|         }
 | |
| #endif
 | |
| 
 | |
|         m_hThread = (HANDLE)_beginthreadex(
 | |
|             NULL,
 | |
|             0,
 | |
|             ThreadFunc,
 | |
|             this,
 | |
|             0,
 | |
|             &iThreadID );
 | |
| 
 | |
|         STL_PRINTF("Startup, Thread=%p, Break=%p, Shutdown=%p",
 | |
|                    m_hThread, m_hevtBreak, m_hevtShutdown);
 | |
| 
 | |
|         if ( m_hThread != NULL )
 | |
|         {
 | |
|             ATLTRACE( _T("Started monitor (%p) thread %p\n"),
 | |
|                       this, m_hThread );
 | |
|             m_bRunning = true;
 | |
|             rc = true;
 | |
|         }
 | |
|     }
 | |
|     return rc;
 | |
| }
 | |
| 
 | |
| DWORD
 | |
| CMonitor::DoMonitoring()
 | |
| {
 | |
|     HANDLE* phEvt = NULL;
 | |
|     TVector<CMonitorNodePtr> nodes;
 | |
| 
 | |
|     while ( 1 )
 | |
|     {
 | |
|         DWORD dwTimeOut = INFINITE;
 | |
| 
 | |
|         if ( phEvt == NULL )
 | |
|         {
 | |
|             CLock l(m_cs);
 | |
| 
 | |
|             // build the complete list of monitored nodes
 | |
|             nodes.clear();
 | |
|             nodes.insert( nodes.end(), m_dirs.begin(), m_dirs.end() );
 | |
|             nodes.insert( nodes.end(), m_regKeys.begin(), m_regKeys.end() );
 | |
| // insert other types of nodes to monitor here
 | |
| 
 | |
|             // Lazily shut down if there are no nodes to monitor
 | |
|             if ( nodes.size() == 0 )
 | |
|             {
 | |
|                 // Since thread creation and destruction is a fairly
 | |
|                 // expensive operation, wait for 5 minutes before killing
 | |
|                 // thread
 | |
|                 dwTimeOut = 5 * 60 * 1000;
 | |
|             }
 | |
| 
 | |
|             // now create the array of event handles
 | |
|             phEvt = new HANDLE[ nodes.size() + 2 ];
 | |
|             phEvt[ 0 ] = m_hevtBreak;
 | |
|             phEvt[ 1 ] = m_hevtShutdown;
 | |
|             for ( UINT i = 0; i < nodes.size(); i++ )
 | |
|             {
 | |
|                 phEvt[i+2] = nodes[i]->NotificationHandle();
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|             STL_PUTS("phEvt != NULL");
 | |
| 
 | |
|         DWORD dw = ::WaitForMultipleObjects(
 | |
|             nodes.size() + 2,
 | |
|             phEvt,
 | |
|             FALSE, // any event will do
 | |
|             dwTimeOut );
 | |
| 
 | |
|         if ( dw == WAIT_TIMEOUT)
 | |
|         {
 | |
|             STL_PUTS("WAIT_TIMEOUT");
 | |
|             if ( nodes.size() == 0 )
 | |
|             {
 | |
|                 STL_PRINTF("Nothing to watch: Shutting down, Stopping=%d",
 | |
|                            (int) m_bStopping);
 | |
|                 ATLTRACE( _T("Nothing to watch... ")
 | |
|                           _T("stopping monitoring (%p) thread %p\n"),
 | |
|                           this, m_hThread);
 | |
|                 m_bRunning = false;
 | |
|                 ::CloseHandle( m_hThread );
 | |
|                 m_hThread = NULL;
 | |
|                 return 0;
 | |
|             }
 | |
|         }
 | |
|         // Was one of the events in phEvt signalled?
 | |
|         C_ASSERT( WAIT_OBJECT_0 == 0 );
 | |
|         if ( dw < ( WAIT_OBJECT_0 + nodes.size() + 2 ) )
 | |
|         {
 | |
|             CLock l(m_cs);
 | |
| 
 | |
|             if ( dw >= WAIT_OBJECT_0 + 2)
 | |
|             {
 | |
|                 // a monitored item has changed
 | |
|                 nodes[ dw - ( WAIT_OBJECT_0 + 2 ) ]->Notify();
 | |
|                 STL_PRINTF("Notifying object %d", dw - (WAIT_OBJECT_0 + 2));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // m_hevtBreak or m_hevtShutdown were signalled.  If
 | |
|                 // m_hevtBreak, then there was a manual break, and a node
 | |
|                 // was probably added or removed, so the vector of nodes
 | |
|                 // needs to be regenerated
 | |
|                 nodes.clear();
 | |
|                 delete[] phEvt;
 | |
|                 phEvt = NULL;
 | |
| 
 | |
|                 // m_hevtShutdown was signalled
 | |
|                 if ( dw == WAIT_OBJECT_0 + 1)
 | |
|                 {
 | |
|                     _ASSERT(m_bStopping);
 | |
|                     STL_PRINTF("Shutting down, Stopping=%d",
 | |
|                                (int) m_bStopping);
 | |
| 
 | |
|                     ATLTRACE(_T("Shutting down monitoring (%p) thread %p\n"),
 | |
|                               this, m_hThread);
 | |
|                     m_bRunning = false;
 | |
|                     // Must NOT CloseHandle(m_hThread) because
 | |
|                     // StopAllMonitoring is waiting on it
 | |
|                     return 0;
 | |
|                 }
 | |
|                 else
 | |
|                     STL_PUTS("m_hevtBreak");
 | |
|             }
 | |
|         }
 | |
|         else if ( dw == WAIT_FAILED )
 | |
|         {
 | |
|             CLock l(m_cs);
 | |
| 
 | |
|             // something's wrong, we'll just clean up and exit
 | |
|             DWORD err = ::GetLastError();
 | |
|             ATLTRACE( _T("CMonitor: WaitForMultipleObjects error: 0x%x\n"),
 | |
|                       err );
 | |
|             ATLTRACE( _T( "CMonitor: abandoning wait thread\n") );
 | |
|             nodes.clear();
 | |
|             delete[] phEvt;
 | |
|             phEvt = NULL;
 | |
| 
 | |
|             m_dirs.clear();
 | |
|             m_regKeys.clear();
 | |
|             m_bRunning = false;
 | |
|             ::CloseHandle( m_hThread );
 | |
|             m_hThread = NULL;
 | |
| 
 | |
|             return err;
 | |
|         }
 | |
|     }   // end infinite while
 | |
| }
 | |
| 
 | |
| 
 | |
| unsigned
 | |
| __stdcall
 | |
| CMonitor::ThreadFunc(
 | |
|     void* pv)
 | |
| {
 | |
|     CMonitor* pMon = (CMonitor*) pv;
 | |
|     DWORD rc = -1;
 | |
|     try
 | |
|     {
 | |
|         if ( pMon )
 | |
|         {
 | |
|             rc = pMon->DoMonitoring();
 | |
|         }
 | |
|     }
 | |
|     catch( ... )
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     _endthreadex(rc);
 | |
|     return rc;
 | |
| }
 |