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

📄 directorychanges.cpp

📁 局域网来访者IP监视以及文件修改监视: 1.监听常用的局域网访问工具
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// DirectoryChanges.cpp: implementation of the CDirectoryChangeWatcher and CDirectoryChangeHandler classes.
//
///////////////////////////////////////////////////////////////////
///

/***********************************************************

  Author:	Wes Jones wesj@hotmail.com

  File:		DirectoryChanges.cpp

  Latest Changes:

		11/22/2001	--	Fixed bug causing file name's to be truncated if
						longer than 130 characters. Fixed CFileNotifyInformation::GetFileName()
						Thanks to Edric(uo_edric@hotmail.com) for pointing this out.

						Added code to enable process privileges when CDirectoryChangeWatcher::WatchDirectory() 
						is first called.	See docuementation API for ReadDirectoryChangesW() for more information of required privileges.
						
						  Currently enables these privileges: (11/22/2001)
							SE_BACKUP_NAME
							SE_CHANGE_NOTIFY_NAME 
							SE_RESTORE_NAME(02/09/2002)
						Implemented w/ helper class CPrivilegeEnabler.

		11/23/2001		Added classes so that all notifications are handled by the
						same thread that called CDirectoryChangeWatcher::WatchDirectory(),
						ie: the main thread.
						CDirectoryChangeHandler::On_Filexxxx() functions are now called in the 
						context of the main thread instead of the worker thread.

						This is good for two reasons:
						1: The worker thread spends less time handling each notification.
							The worker thread simply passes the notification to the main thread,
							which does the processing.
							This means that each file change notification is handled as fast as possible
							and ReadDirectoryChangesW() can be called again to receive more notifications
							faster.

						2:	This makes it easier to make an ActiveX or ATL object with this class
							because the events that are fired, fire in the context of the main thread.
							The fact that I'm using a worker thread w/ this class is totally 
							transparent to a client user.
							If I decide to turn this app into an ActiveX or ATL object
							I don't have to worry about wierd COM rules and multithreading issues,
							and neither does the client, be the client a VB app, C++ app, Delphi app, or whatever.

						Implemented with CDelayedDirectoryChangeHandler in DirectoryChangeHandler.h/.cpp

		02/06/2002	  Fixed a bug that would cause an application to hang.
						If ReadDirectoryChangesW was to fail during normal operation,
						the short story is that the application would hang
						when it called CDirectoryChangeWatcher::UnwatchDirectory(const CString & )

						One way to reproduce this behavior on the old code
						is to watch a directory using a UNC path, and then change the IP
						address of that machine while the watch was running.  Exitting 
						the app after this would cause it to hang.

						Steps to reproduce it:

						1) Assume that the computer running the code is
							named 'ThisComputer' and there is a shared folder named 'FolderName'


						2) Start a watch on a folder using a UNC path:  ie: \\ThisComputer\FolderName
						
						  eg:	CDirectoryChangeWatcher	watcher;
							 
								watcher.WatchDirectory(_T("\\\\ThisComputer\\FolderName",/ * other parameters * /)
							
						3)  Change the IP address of 'ThisComputer'

							   ** ReadDirectoryChangesW() will fail some point after this.
						
		
						4)  Exit the application... it may hang.


						Anyways, that's what the bug fix is for.


		02/06/2002	New side effects for CDirectoryChangeHandler::On_ReadDirectoryChangeError()

					If CDirectoryChangeHandler::On_ReadDirectoryChangeError() is ever executed
					the directory that you are watching will have been unwatched automatically due
					to the error condition.

					A call to CDirectoryChangeWatcher::IsWatchingDirectory() will fail because the directory
					is no longer being watched. You'll need to re-watch that directory.

		02/09/2002	Added a parameter to CDirectoryChangeHandler::On_ReadDirectoryChangeError()

					Added the parameter: const CString & strDirectoryName
					The new signature is now:
							virtual void CDirectoryChangeHandler::On_ReadDirectoryChangeError(DWORD dwError, const CString & strDirectoryName);

					This new parameter gives you the name of the directory that the error occurred on.

		04/25/2002  Provided a way to get around the requirement of a message pump.
					A console app can now use this w/out problems by passing false
					to the constructor of CDirectoryChangeWatcher. 
					An app w/ a message pump can also pass false if it so desires w/out problems.

		04/25/2002	Added two new virtual functions to CDirectoryChangeHandler

					Added:
							On_WatchStarted(DWORD dwError, const CString & strDirectoryName)
							On_WatchStopped(const CString & strDirectoryName);
					See header file for details.

		04/27/2002	Added new function to CDirectoryChangeHandler:

					Added virtual bool On_FilterNotification(DWORD dwNotifyAction, LPCTSTR szFileName, LPCTSTR szNewFileName)

					This function is called before any notification function, and allows the 
					CDirectoryChangeHandler derived class to ignore file notifications 
					by performing a programmer defined test.
					By ignore, i mean that 
						On_FileAdded(), On_FileRemoved(), On_FileModified(), or On_FileNameChanged()
						will NOT be called if this function returns false.

					The default implementation always returns true, signifying that ALL notifications
					are to be called.


		04/27/2002  Added new Parameters to CDirectoryChangeWatcher::WatchDirectory()

					The new parameters are: 
										LPCTSTR szIncludeFilter 
										LPCTSTR szExcludeFilter
					Both parameters are defaulted to NULL.
					Signature is now:
					CDirectoryChangeWatcher::WatchDirectory(const CString & strDirToWatch, 
															DWORD dwChangesToWatchFor, 
															CDirectoryChangeHandler * pChangeHandler, 
															BOOL bWatchSubDirs = FALSE,
															LPCTSTR szIncludeFilter = NULL,
															LPCTSTR szExcludeFilter = NULL)

		04/27/2002	Added support for include and exclude filters.
					These filters allow you to receive notifications for just the files you
					want... ie: you can specify that you only want to receive notifications
					for changes to "*.txt" files or some other such file filter.

					NOTE: This feature is implemented w/ the PathMatchSpec() api function
					which is only available on NT4.0 if Internet Explorer 4.0 or above is installed.
					See MSDN for PathMatchSpec().  Win2000, and XP do not have to worry about it.

					Filter specifications:
					   Accepts wild card characters * and ?, just as you're used to for the DOS dir command.
					   It is possible to specify multiple extenstions in the filter by separating each filter spec
					   with a semi-colon. 
					   eg: "*.txt;*.tmp;*.log"  <-- this filter specifies all .txt, .tmp, & .log files

					

					Filters are passed as parameters to CDirectoryChangeWatcher::WatchDirectory()

					NOTE: The filters you specify take precedence over CDirectoryChangeHandler::On_FilterNotification().
						  This means that if the file name does not pass the filters that you specify
						  when the watch is started, On_FilterNotification() will not be called.
						  Filter specifications are case insensitive, ie: ".tmp" and ".TMP" are the same


					FILTER TYPES:
							Include Filter:
										If you specify an include filter, you are specifying that you
										only want to receive notifications for specific file types.
										eg: "*.log" means that you only want notifications for changes 
											to files w/ an exention of ".log". 
											Changes to ALL OTHER other file types are ignored.
										An empty, or not specified include filter means that you want
										notifications for changes of ALL file types.
							Exclude filter:

										If you specify an exclude filter, you are specifying that
										you do not wish to receive notifications for a specific type of file or files.
										eg: "*.tmp" would mean that you do not want any notifications 
											regarding files that end w/ ".tmp"
										An empty, or not specified exclude filter means that
										you do not wish to exclude any file notifications.





		
					
************************************************************/

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

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
//
//	Fwd Declares & #define's
//
//
//
// Helper classes
class CPrivilegeEnabler;	 //for use w/ enabling process priveledges when this code is first used. It's a singleton.

class CFileNotifyInformation;//helps CDirectoryChangeWatcher class notify CDirectoryChangeHandler class of changes to files. 

class CDelayedDirectoryChangeHandler;	//	Helps all notifications become handled by the main
										//	thread, or a worker thread depending upon a value passed to the 
										//	constructor of CDirectoryChangeWatcher.
										//	
										//	For notifications to fire in the main thread, your app must have a message pump.
										//
										//  The 'main' thread is the one that called CDirectoryChangeWatcher::WatchDirectory()

// Helper functions
static BOOL	EnablePrivilege(LPCTSTR pszPrivName, BOOL fEnable = TRUE);
static bool IsDirectory(const CString & strPath);
/////////////////////////////////////////////////////////////////////
//	Helper functions.
BOOL	EnablePrivilege(LPCTSTR pszPrivName, BOOL fEnable /*= TRUE*/) 
//
//	I think this code is from a Jeffrey Richter book...
//
//	Enables user priviledges to be set for this process.
//	
//	Process needs to have access to certain priviledges in order
//	to use the ReadDirectoryChangesW() API.  See documentation.
{    
	BOOL fOk = FALSE;    
	// Assume function fails    
	HANDLE hToken;    
	// Try to open this process's access token    
	if (OpenProcessToken(GetCurrentProcess(), 		
					TOKEN_ADJUST_PRIVILEGES, &hToken)) 	
	{        
		// privilege        
		TOKEN_PRIVILEGES tp = { 1 };        

		if( LookupPrivilegeValue(NULL, pszPrivName,  &tp.Privileges[0].Luid) )
		{
			tp.Privileges[0].Attributes = fEnable ?  SE_PRIVILEGE_ENABLED : 0;

			AdjustTokenPrivileges(hToken, FALSE, &tp, 			      
									sizeof(tp), NULL, NULL);

			fOk = (GetLastError() == ERROR_SUCCESS);		
		}
		CloseHandle(hToken);	
	}	
	return(fOk);
}

static bool IsDirectory(const CString & strPath)
//
//  Returns: bool
//		true if strPath is a path to a directory
//		false otherwise.
//
{
	DWORD dwAttrib	= GetFileAttributes( strPath );
	return static_cast<bool>( ( dwAttrib != 0xffffffff 
							&&	(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) );

		
}
///////////////////////////////////////////////
//Helper class:

class CFileNotifyInformation 
/*******************************

A Class to more easily traverse the FILE_NOTIFY_INFORMATION records returned 
by ReadDirectoryChangesW().

FILE_NOTIFY_INFORMATION is defined in Winnt.h as: 

 typedef struct _FILE_NOTIFY_INFORMATION {
    DWORD NextEntryOffset;
	DWORD Action;
    DWORD FileNameLength;
    WCHAR FileName[1];
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;	

  ReadDirectoryChangesW basically puts x amount of these records in a 
  buffer that you specify.
  The FILE_NOTIFY_INFORMATION structure is a 'dynamically sized' structure (size depends on length
  of the file name (+ sizeof the DWORDs in the struct))

  Because each structure contains an offset to the 'next' file notification
  it is basically a singly linked list.  This class treats the structure in that way.
  

  Sample Usage:
  BYTE Read_Buffer[ 4096 ];

  ...
  ReadDirectoryChangesW(...Read_Buffer, 4096,...);
  ...

  CFileNotifyInformation notify_info( Read_Buffer, 4096);
  do{
	    switch( notify_info.GetAction() )
		{
		case xx:
		    notify_info.GetFileName();
		}

  while( notify_info.GetNextNotifyInformation() );
  
********************************/
{
public:
	CFileNotifyInformation( BYTE * lpFileNotifyInfoBuffer, DWORD dwBuffSize)
	: m_pBuffer( lpFileNotifyInfoBuffer ),
	  m_dwBufferSize( dwBuffSize )
	{
		ASSERT( lpFileNotifyInfoBuffer && dwBuffSize );
		
		m_pCurrentRecord = (PFILE_NOTIFY_INFORMATION) m_pBuffer;
	}

	
	BOOL GetNextNotifyInformation();
	
	BOOL CopyCurrentRecordToBeginningOfBuffer(OUT DWORD & ref_dwSizeOfCurrentRecord);

	DWORD	GetAction() const;//gets the type of file change notifiation
	CString GetFileName()const;//gets the file name from the FILE_NOTIFY_INFORMATION record
	CString GetFileNameWithPath(const CString & strRootPath) const;//same as GetFileName() only it prefixes the strRootPath into the file name

	
protected:
	BYTE * m_pBuffer;//<--all of the FILE_NOTIFY_INFORMATION records 'live' in the buffer this points to...
	DWORD  m_dwBufferSize;
	PFILE_NOTIFY_INFORMATION m_pCurrentRecord;//this points to the current FILE_NOTIFY_INFORMATION record in m_pBuffer
	
};

BOOL CFileNotifyInformation::GetNextNotifyInformation()
/***************
  Sets the m_pCurrentRecord to the next FILE_NOTIFY_INFORMATION record.

  Even if this return FALSE, (unless m_pCurrentRecord is NULL)
  m_pCurrentRecord will still point to the last record in the buffer.
****************/
{
	if( m_pCurrentRecord 
	&&	m_pCurrentRecord->NextEntryOffset != 0UL)//is there another record after this one?
	{
		//set the current record to point to the 'next' record
		PFILE_NOTIFY_INFORMATION pOld = m_pCurrentRecord;
		m_pCurrentRecord = (PFILE_NOTIFY_INFORMATION) ((LPBYTE)m_pCurrentRecord + m_pCurrentRecord->NextEntryOffset);

		ASSERT( (DWORD)((BYTE*)m_pCurrentRecord - m_pBuffer) < m_dwBufferSize);//make sure we haven't gone too far

		if( (DWORD)((BYTE*)m_pCurrentRecord - m_pBuffer) > m_dwBufferSize )
		{
			//we've gone too far.... this data is hosed.

⌨️ 快捷键说明

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