⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 directorychanges.cpp

📁 局域网来访者IP监视以及文件修改监视: 1.监听常用的局域网访问工具
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	}
}

DWORD CDirectoryChangeWatcher::SetFilterFlags(DWORD dwFilterFlags)
//
//	SetFilterFlags()
//	
//	sets filter behavior for directories watched AFTER this function has been called.
//
//
//
{
	DWORD dwOld = m_dwFilterFlags;
	m_dwFilterFlags = dwFilterFlags;
	if( m_dwFilterFlags == 0 )
		m_dwFilterFlags = FILTERS_DEFAULT_BEHAVIOR;//the default.
	return dwOld;
}

BOOL CDirectoryChangeWatcher::IsWatchingDirectory(const CString & strDirName)const
/*********************************************
  Determines whether or not a directory is being watched

  be carefull that you have the same name path name, including the backslash
  as was used in the call to WatchDirectory().

	  ie:	
			"C:\\Temp"
		is different than
			"C:\\Temp\\"
**********************************************/
{
	CSingleLock lock( const_cast<CCriticalSection*>(&m_csDirWatchInfo), TRUE);
	ASSERT( lock.IsLocked() );
	int i;
	if( GetDirWatchInfo(strDirName, i) )
		return TRUE;
	return FALSE;
}

int	CDirectoryChangeWatcher::NumWatchedDirectories()const
{
	CSingleLock lock(const_cast<CCriticalSection*>(&m_csDirWatchInfo), TRUE);
	ASSERT( lock.IsLocked() );
	int nCnt(0),max = m_DirectoriesToWatch.GetSize();
	for(int i(0); i < max; ++i)
	{
		if( m_DirectoriesToWatch[i] != NULL )//array may contain NULL elements.
			nCnt++;
	}

	return nCnt;
}

DWORD CDirectoryChangeWatcher::WatchDirectory(const CString & strDirToWatch, 
									   DWORD dwChangesToWatchFor, 
									   CDirectoryChangeHandler * pChangeHandler,
									   BOOL bWatchSubDirs /*=FALSE*/,
									   LPCTSTR szIncludeFilter /*=NULL*/,
									   LPCTSTR szExcludeFilter /*=NULL*/
									   )
/*************************************************************
FUNCTION:	WatchDirectory(const CString & strDirToWatch,   --the name of the directory to watch
						   DWORD dwChangesToWatchFor, --the changes to watch for see dsk docs..for ReadDirectoryChangesW
						   CDirectoryChangeHandler * pChangeHandler -- handles changes in specified directory
						   BOOL bWatchSubDirs      --specified to watch sub directories of the directory that you want to watch
						   )

PARAMETERS:
		const CString & strDirToWatch -- specifies the path of the directory to watch.
		DWORD dwChangesToWatchFor	-- specifies flags to be passed to ReadDirectoryChangesW()
		CDirectoryChangeHandler *	-- ptr to an object which will handle notifications of file changes.
		BOOL bWatchSubDirs			-- specifies to watch subdirectories.
		LPCTSTR szIncludeFilter		-- A file pattern string for files that you wish to receive notifications
									   for. See Remarks.
		LPCTSTR szExcludeFilter		-- A file pattern string for files that you do not wish to receive notifications for. See Remarks

	Starts watching the specified directory(and optionally subdirectories) for the specified changes

	When specified changes take place the appropriate CDirectoryChangeHandler::On_Filexxx() function is called.

	dwChangesToWatchFor can be a combination of the following flags, and changes map out to the 
	following functions:
	FILE_NOTIFY_CHANGE_FILE_NAME    -- CDirectoryChangeHandler::On_FileAdded()
									   CDirectoryChangeHandler::On_FileNameChanged, 
									   CDirectoryChangeHandler::On_FileRemoved
	FILE_NOTIFY_CHANGE_DIR_NAME     -- CDirectoryChangeHandler::On_FileNameAdded(), 
									   CDirectoryChangeHandler::On_FileRemoved
	FILE_NOTIFY_CHANGE_ATTRIBUTES   -- CDirectoryChangeHandler::On_FileModified
	FILE_NOTIFY_CHANGE_SIZE         -- CDirectoryChangeHandler::On_FileModified
	FILE_NOTIFY_CHANGE_LAST_WRITE   -- CDirectoryChangeHandler::On_FileModified
	FILE_NOTIFY_CHANGE_LAST_ACCESS  -- CDirectoryChangeHandler::On_FileModified
	FILE_NOTIFY_CHANGE_CREATION     -- CDirectoryChangeHandler::On_FileModified
	FILE_NOTIFY_CHANGE_SECURITY     -- CDirectoryChangeHandler::On_FileModified?
	

	Returns ERROR_SUCCESS if the directory will be watched, 
	or a windows error code if the directory couldn't be watched.
	The error code will most likely be related to a call to CreateFile(), or 
	from the initial call to ReadDirectoryChangesW().  It's also possible to get an
	error code related to being unable to create an io completion port or being unable 
	to start the worker thread.

	This function will fail if the directory to be watched resides on a 
	computer that is not a Windows NT/2000/XP machine.


	You can only have one watch specified at a time for any particular directory.
	Calling this function with the same directory name will cause the directory to be 
	unwatched, and then watched again(w/ the new parameters that have been passed in).  

**************************************************************/
{
	ASSERT( dwChangesToWatchFor != 0);

	if( strDirToWatch.IsEmpty()
	||  dwChangesToWatchFor == 0 
	||  pChangeHandler == NULL )
	{
		TRACE(_T("ERROR: You've passed invalid parameters to CDirectoryChangeWatcher::WatchDirectory()\n"));
		::SetLastError(ERROR_INVALID_PARAMETER);
		return ERROR_INVALID_PARAMETER;
	}

	
	//double check that it's really a directory
	if( !IsDirectory( strDirToWatch ) )
	{
		TRACE(_T("ERROR: CDirectoryChangeWatcher::WatchDirectory() -- %s is not a directory!\n"), strDirToWatch);
		::SetLastError(ERROR_BAD_PATHNAME);
		return ERROR_BAD_PATHNAME;
	}

	//double check that this directory is not already being watched....
	//if it is, then unwatch it before restarting it...
	if( IsWatchingDirectory( strDirToWatch) )
	{
		VERIFY( 
			UnwatchDirectory( strDirToWatch ) 
			);
	}
	//
	//
	//	Reference this singleton so that privileges for this process are enabled 
	//	so that it has required permissions to use the ReadDirectoryChangesW API, etc.
	//
	CPrivilegeEnabler::Instance();
	//
	//open the directory to watch....
	HANDLE hDir = CreateFile(strDirToWatch, 
								FILE_LIST_DIRECTORY, 
								FILE_SHARE_READ | FILE_SHARE_WRITE ,//| FILE_SHARE_DELETE, <-- removing FILE_SHARE_DELETE prevents the user or someone else from renaming or deleting the watched directory. This is a good thing to prevent.
								NULL, //security attributes
								OPEN_EXISTING,
								FILE_FLAG_BACKUP_SEMANTICS | //<- the required priviliges for this flag are: SE_BACKUP_NAME and SE_RESTORE_NAME.  CPrivilegeEnabler takes care of that.
                                FILE_FLAG_OVERLAPPED, //OVERLAPPED!
								NULL);
	if( hDir == INVALID_HANDLE_VALUE )
	{
		DWORD dwError = GetLastError();
		TRACE(_T("CDirectoryChangeWatcher::WatchDirectory() -- Couldn't open directory for monitoring. %d\n"), dwError);
		::SetLastError(dwError);//who knows if TRACE will cause GetLastError() to return success...probably won't, but set it manually just for fun.
		return dwError;
	}
	//opened the dir!
	
	CDirWatchInfo * pDirInfo = new CDirWatchInfo( hDir, strDirToWatch, pChangeHandler, dwChangesToWatchFor, bWatchSubDirs, m_bAppHasGUI, szIncludeFilter, szExcludeFilter, m_dwFilterFlags);
	if( !pDirInfo )
	{
		TRACE(_T("WARNING: Couldn't allocate a new CDirWatchInfo() object --- File: %s Line: %d\n"), _T( __FILE__ ), __LINE__);
		CloseHandle( hDir );
		::SetLastError(ERROR_OUTOFMEMORY);
		return ERROR_OUTOFMEMORY;
	}
	
	//create a IO completion port/or associate this key with
	//the existing IO completion port
	m_hCompPort = CreateIoCompletionPort(hDir, 
										m_hCompPort, //if m_hCompPort is NULL, hDir is associated with a NEW completion port,
													 //if m_hCompPort is NON-NULL, hDir is associated with the existing completion port that the handle m_hCompPort references
										(DWORD)pDirInfo, //the completion 'key'... this ptr is returned from GetQueuedCompletionStatus() when one of the events in the dwChangesToWatchFor filter takes place
										0);
	if( m_hCompPort == NULL )
	{
		TRACE(_T("ERROR -- Unable to create I/O Completion port! GetLastError(): %d File: %s Line: %d"), GetLastError(), _T( __FILE__ ), __LINE__ );
		DWORD dwError = GetLastError();
		pDirInfo->DeleteSelf( NULL );
		::SetLastError(dwError);//who knows what the last error will be after i call pDirInfo->DeleteSelf(), so set it just to make sure
		return dwError;
	}
	else
	{//completion port created/directory associated w/ it successfully

		//if the thread isn't running start it....
		//when the thread starts, it will call ReadDirectoryChangesW and wait 
		//for changes to take place
		if( m_hThread == NULL )
		{
			//start the thread
			CWinThread * pThread = AfxBeginThread(MonitorDirectoryChanges, this);
			if( !pThread )
			{//couldn't create the thread!
				TRACE(_T("CDirectoryChangeWatcher::WatchDirectory()-- AfxBeginThread failed!\n"));
				pDirInfo->DeleteSelf( NULL );
				return (GetLastError() == ERROR_SUCCESS)? ERROR_MAX_THRDS_REACHED : GetLastError();
			}
			else
			{
				m_hThread	 = pThread->m_hThread;
				m_dwThreadID = pThread->m_nThreadID;
				pThread->m_bAutoDelete = TRUE;//pThread is deleted when thread ends....it's TRUE by default(for CWinThread ptrs returned by AfxBeginThread(threadproc, void*)), but just makin sure.
				
			}
		}
		if( m_hThread != NULL )
		{//thread is running, 
			//signal the thread to issue the initial call to
			//ReadDirectoryChangesW()
		   DWORD dwStarted = pDirInfo->StartMonitor( m_hCompPort );

		   if( dwStarted != ERROR_SUCCESS )
		   {//there was a problem!
			   TRACE(_T("Unable to watch directory: %s -- GetLastError(): %d\n"), dwStarted);
			   pDirInfo->DeleteSelf( NULL );
				::SetLastError(dwStarted);//I think this'll set the Err object in a VB app.....
			   return dwStarted;
		   }
		   else
		   {//ReadDirectoryChangesW was successfull!
				//add the directory info to the first empty slot in the array

				//associate the pChangeHandler with this object
				pChangeHandler->ReferencesWatcher( this );//reference is removed when directory is unwatched.
				//CDirWatchInfo::DeleteSelf() must now be called w/ this CDirectoryChangeWatcher pointer becuse
				//of a reference count

				//save the CDirWatchInfo* so I'll be able to use it later.
				VERIFY( AddToWatchInfo( pDirInfo ) );
				SetLastError(dwStarted);
				return dwStarted;
		   }

		}
		else
		{
			ASSERT(FALSE);//control path shouldn't get here
			::SetLastError(ERROR_MAX_THRDS_REACHED);
			return ERROR_MAX_THRDS_REACHED;
		}
		
	}
	ASSERT( FALSE );//shouldn't get here.
}

BOOL CDirectoryChangeWatcher::UnwatchAllDirectories()
{
	
	//unwatch all of the watched directories
	//delete all of the CDirWatchInfo objects,
	//kill off the worker thread
	if( m_hThread != NULL )
	{
		ASSERT( m_hCompPort != NULL );
		
		CSingleLock lock( &m_csDirWatchInfo, TRUE);
		ASSERT( lock.IsLocked() );

		CDirWatchInfo * pDirInfo;
		//Unwatch each of the watched directories
		//and delete the CDirWatchInfo associated w/ that directory...
		int max = m_DirectoriesToWatch.GetSize();
		for(int i = 0; i < max; ++i)
		{
			if( (pDirInfo = m_DirectoriesToWatch[i]) != NULL )
			{
				VERIFY( pDirInfo->UnwatchDirectory( m_hCompPort ) );

				m_DirectoriesToWatch.SetAt(i, NULL)	;
				pDirInfo->DeleteSelf(this);
			}
			
		}
		m_DirectoriesToWatch.RemoveAll();
		//kill off the thread
		PostQueuedCompletionStatus(m_hCompPort, 0, 0, NULL);//The thread will catch this and exit the thread
		//wait for it to exit
		WaitForSingleObject(m_hThread, INFINITE);
		//CloseHandle( m_hThread );//Since thread was started w/ AfxBeginThread() this handle is closed automatically, closing it again will raise an exception
		m_hThread = NULL;
		m_dwThreadID = 0UL;		

		//close the completion port...
		CloseHandle( m_hCompPort );
		m_hCompPort = NULL;


		return TRUE;
	}
	else
	{
#ifdef _DEBUG
		//make sure that there aren't any 
		//CDirWatchInfo objects laying around... they should have all been destroyed 
		//and removed from the array m_DirectoriesToWatch
		if( m_DirectoriesToWatch.GetSize() > 0 )
		{
			for(int i = 0; i < m_DirectoriesToWatch.GetSize(); ++i)
			{
				ASSERT( m_DirectoriesToWatch[i] == NULL );
			}
		}
#endif
	}
	return FALSE;
}

BOOL CDirectoryChangeWatcher::UnwatchDirectory(const CString & strDirToStopWatching)
/***************************************************************
FUNCTION:	UnwatchDirectory(const CString & strDirToStopWatching -- if this directory is being watched, the watch is stopped

****************************************************************/
{
	BOOL bRetVal = FALSE;



	if( m_hCompPort != NULL )//The io completion port must be open
	{
		ASSERT( !strDirToStopWatching.IsEmpty() );
		
		CSingleLock lock(&m_csDirWatchInfo, TRUE);
		ASSERT( lock.IsLocked() );	
		int nIdx = -1;
		CDirWatchInfo * pDirInfo = GetDirWatchInfo(strDirToStopWatching, nIdx);
		if( pDirInfo != NULL
		&&	nIdx != -1 )
		{

			//stop watching this directory
			VERIFY( pDirInfo->UnwatchDirectory( m_hCompPort ) );

			//cleanup the object used to watch the directory
			m_DirectoriesToWatch.SetAt(nIdx, NULL);
			pDirInfo->DeleteSelf(this);
			bRetVal = TRUE;
		}
	}

	return bRetVal;
}

BOOL CDirectoryChangeWatcher::UnwatchDirectory(CDirectoryChangeHandler * pChangeHandler)
/************************************

  This function is called from the dtor of CDirectoryChangeHandler automatically,
  but may also be called by a programmer because it's public...
  
  A single CDirectoryChangeHandler may be used for any number of watched directories.

  Unwatch any directories that may be using this 
  CDirectoryChangeHandler * pChangeHandler to handle changes to a watched directory...
  
  The CDirWatchInfo::m_pChangeHandler member of objects in the m_DirectoriesToWatch
  array will == pChangeHandler if that handler is being used to handle changes to a directory....

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -