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

📄 ngfilechangemonitor.cpp

📁 ResOrg 图形化管理Vc项目的资源ID的工具的源代码。 ResOrg - Manage and Renumber Resource Symbol IDs Introduction The
💻 CPP
字号:
////////////////////////////////////////////////////////////////
// CNGFileChangeMonitor Copyright 1999 by Anna-Jayne Metcalfe (code@annasplace.me.uk)
//
//
// NGFileChangeMonitor.cpp : implementation file
//

#include "StdAfx.h"

#include <sys/types.h>
#include <sys/stat.h>

#include "NGFileChangeMonitor.h"


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


/////////////////////////////////////////////////////////////////////////////
// CNGFileChangeMonitor class

//	Static map object used to map from thread data to object instances
//	Needed as the thread function is a static
static	CMapPtrToPtr	g_ThreadParamMap;


/////////////////////////////////////////////////////////////////////////////
// CNGFileChangeMonitor construction/destruction

CNGFileChangeMonitor::CNGFileChangeMonitor(void)
{
	m_pThread	= NULL;
	m_hThread	= NULL;
}


CNGFileChangeMonitor::~CNGFileChangeMonitor(void)
{
	DestroyMonitoringThread();
}


/////////////////////////////////////////////////////////////////////////
//	Helper methods to create/destroy thread for detecting file system changes

//	Structure used to pass data into the worker thread
//	This is needed for the implementation code below ONLY
typedef struct THREADINFO_TAG
{
	HANDLE		hEvent;			// Event handle for terminate notifications
	HWND		hWnd;			// Target window
	UINT		nMsg;			// User defined message to post on file change
	UINT		nID;			// ID if message is WM_COMMAND
	TCHAR		szDir[_MAX_DRIVE + _MAX_DIR];	// Should really be variable length but it works (so far)
	TCHAR		szFile[_MAX_FNAME + _MAX_EXT];	// ditto
	time_t		nLastModTime;	// Time of last modification (as returned by the _stat() function)
} THREADINFO;

typedef THREADINFO* PTHREADINFO;


void CNGFileChangeMonitor::CreateMonitoringThread(	const CString& sPathName,
													HWND hWnd,
													UINT nMsg,
													UINT nID,
													int ePriority)
{
	// Try to access file attributes
	DWORD dwAttribs = ::GetFileAttributes(sPathName);
	struct _stat FileInfo;

	if ( (0xffffffff != dwAttribs) && (0 == _stat(sPathName, &FileInfo)) )
	{
		PTHREADINFO pThreadInfo		= new THREADINFO;	// Thread will delete this for us
		pThreadInfo->hEvent			= m_Event.m_hObject;
		pThreadInfo->hWnd			= hWnd;
		pThreadInfo->nMsg			= nMsg;
		pThreadInfo->nID			= nID;
		pThreadInfo->nLastModTime	= 0;
		pThreadInfo->szDir[0]		= '\0';
		pThreadInfo->szFile[0]		= '\0';

		CString sDir = sPathName;					// Target directory/file
		CString sFile;

		if (FILE_ATTRIBUTE_DIRECTORY & dwAttribs)
		{
			// Given path is a directory	
		}
		else
		{
			// Given path is a file
			// Break pathname down into directory and file names,
			TCHAR szDrive[_MAX_DRIVE];
			TCHAR szDir[_MAX_DIR];
			TCHAR szFname[_MAX_FNAME];
			TCHAR szExt[_MAX_EXT];

			_splitpath(sPathName, szDrive, szDir, szFname, szExt );
			sDir = CString(szDrive) + szDir;		// Target directory
			sFile = CString(szFname) + szExt;		// Target file

			// Get the time of last modification of the file
			// This will be passed to the thread function so it can tell if
			// the file has been changed when a directory change notification
			// is received
			pThreadInfo->nLastModTime = FileInfo.st_mtime;
		}

		// Update the relevant fields in the THREADINFO structure
		strcpy(pThreadInfo->szDir, sDir);
		strcpy(pThreadInfo->szFile, sFile);

		// Create a worker thread to snoop on the file/directory
		// First store the address of the structure in a map so
		// that ThreadFunc (which is a static) can work out
		// which CNGFileChangeMonitor object to pass the call to
		g_ThreadParamMap.SetAt( (LPVOID)pThreadInfo, (LPVOID)this );
		CWinThread* pThread = AfxBeginThread(	CNGFileChangeMonitor::ThreadFunc,
												(LPVOID)pThreadInfo,
												ePriority);
		if (pThread != NULL)
		{
			pThread->m_bAutoDelete	= FALSE;
			m_hThread				= pThread->m_hThread;
			m_pThread				= pThread;
			m_sMonitoredPath		= sFile;
			TRACE1("CNGFileChangeMonitor: Starting notification on %s\n", sFile);
		}
		else
		{
			g_ThreadParamMap.RemoveKey( (LPVOID)pThreadInfo );
			delete pThreadInfo;						// Thread creation failed so we must
		}											// delete the THREADINFO struct ourselves
		if (m_hThread == NULL)
		{
			delete m_pThread;
			m_pThread = NULL;
			TRACE1("CNGFileChangeMonitor: Failed to start notification on %s\n", sFile);
		}
	}
}


void CNGFileChangeMonitor::DestroyMonitoringThread(void)
{
    // Kill file change notification thread
    if (m_pThread)
	{
        m_Event.SetEvent();
        if (WAIT_FAILED != ::WaitForMultipleObjects(1,
													&m_hThread,
													TRUE,
													INFINITE) )
		{
			delete m_pThread;
			m_pThread			= NULL;
			m_hThread			= NULL;
			m_sMonitoredPath	= "";

		}
		else
		{
			TRACE0("CNGFileChangeMonitor: Unable to destroy thread - wait failed\n");
		}		
	}
}



/////////////////////////////////////////////////////////////////////////
// Worker thread function for detecting file changes

UINT CNGFileChangeMonitor::ThreadFunc(LPVOID pParam)
{
	// Lookup corresponding thread object
	CNGFileChangeMonitor* pThread = NULL;

	if ( (!g_ThreadParamMap.Lookup(pParam, (LPVOID&)pThread)) || (!pThread) )
	{
		return 0;
	}
	g_ThreadParamMap.RemoveKey(pParam);

	return pThread->DoThreadFunc(pParam);
}


UINT CNGFileChangeMonitor::DoThreadFunc(LPVOID pParam)
{
	PTHREADINFO pThreadInfo = (PTHREADINFO) pParam;

    // Extract parameters from thread info structure
	CString	sDir			= pThreadInfo->szDir;
	CString	sFile			= pThreadInfo->szFile;
	HANDLE	hEvent			= pThreadInfo->hEvent;
    HWND	hWnd			= pThreadInfo->hWnd;
	UINT	nMsg			= pThreadInfo->nMsg;
	UINT	nID				= pThreadInfo->nID;
	time_t	nLastModTime	= pThreadInfo->nLastModTime;

	// Full pathname (directory and file)
	TCHAR szPath[_MAX_PATH];
	strcpy(szPath, sDir);
	strcat(szPath, sFile);

	// Kill THREADINFO structure now we've got our stuff
	delete pThreadInfo;
	pThreadInfo = NULL;

	// Nobody to notify - don't proceed further
	if (hWnd == NULL)
	{
		return 0;
	}
    // Get a handle to a file change notification object.
	HANDLE hChange = ::FindFirstChangeNotification(	sDir,
													FALSE,
													FILE_NOTIFY_CHANGE_LAST_WRITE |
													FILE_NOTIFY_CHANGE_FILE_NAME |
													FILE_NOTIFY_CHANGE_SIZE);

    // Return now if ::FindFirstChangeNotification() failed.
    if (INVALID_HANDLE_VALUE == hChange)
	{
        return (1);
	}
	//	Create an array of events we will respond to
	HANDLE aHandles[2];
	aHandles[0] = hChange;	// The first event is the file change notification...
	aHandles[1] = hEvent;	// ...and the second tells the thread its time to die...
  

	// Sleep until a file change notification wakes this thread or
    // hEvent (m_Event) becomes set indicating it's time for the thread to end.
    while (TRUE)
	{
		 // Respond to a change notification
		if (WAIT_OBJECT_0 == ::WaitForMultipleObjects (2, aHandles, FALSE, INFINITE))
		{
			// Directory change detected.
			// If a filename was not given and the target window is still there,
			// post a message to let the user know
			if (!::IsWindow(hWnd))
			{
				break;						// Stop monitoring - target window gone
            }

			if (sFile.IsEmpty())			// Monitoring change on directory
			{
				OnFileChange(sDir, hWnd, nMsg, nID);
			}
			else							// Monitoring change on file
			{								// so need to go through the directory and
											// see if the file has changed

				// Get the time of last modification of the file
				// and see if it has changed since the last notification
				// (or that at the time the thread was created if this is the first)
				struct _stat FileInfo;
				if (0 == _stat(szPath, &FileInfo))	// _stat() returns 0 if OK
				{
					// If last modification time is different, file has changed
					// so post a message to the target window and store the new time
					if (FileInfo.st_mtime != nLastModTime)
					{
						OnFileChange(szPath, hWnd, nMsg, nID);

						nLastModTime = FileInfo.st_mtime;
					}
				}
			}
            ::FindNextChangeNotification(hChange);
        }
		else								// Kill this thread (m_Event became signaled)
		{
			break;
		}
    }
    // Close the file change notification handle and return
    ::FindCloseChangeNotification(hChange);

    return 0;
}


BOOL CNGFileChangeMonitor::OnFileChange(const CString& sPath, HWND hWnd, UINT nMsg, UINT nID)
{
	UNREFERENCED_PARAMETER(sPath);

	ASSERT(::IsWindow(hWnd) );

	if (::IsWindow(hWnd) )
	{
		switch (nMsg)
		{
			case WM_COMMAND:		// WM_COMMAND pass back nID
					return ::PostMessage(hWnd, nMsg, nID, 0UL);

			default:				// For WM_USER message pass back the monitored path
									// path as the LPARAM. This should be safe since
									// m_sMonitoredPath is a class member
					return ::PostMessage(hWnd, nMsg, 0, (LPARAM)(LPCTSTR)m_sMonitoredPath);
		}
	}
	return FALSE;
}


/////////////////////////////////////////////////////////////////////////////
// CNGFileChangeMonitor interface


/******************************************************************************
 *	Start monitoring a file or directory for changes
 *
 ******************************************************************************/

BOOL CNGFileChangeMonitor::Start(const CString& sPathName,
								 CWnd* pWnd,
								 UINT nMsg,
								 UINT nID,
								 int ePriority)
{
	if (pWnd != NULL)
	{
		return Start(	sPathName,
						pWnd->GetSafeHwnd(),
						nMsg,
						nID,
						ePriority);
	}
	return FALSE;
}


BOOL CNGFileChangeMonitor::Start(const CString& sPathName,
								 HWND hWnd,
								 UINT nMsg,
								 UINT nID,
								 int ePriority)
{
	if (hWnd != NULL)
	{
		if (m_pThread != NULL)
		{
			Stop();
		}
		CreateMonitoringThread(	sPathName,
								hWnd,
								nMsg,
								nID,
								ePriority);

		return (NULL != m_hThread);
	}
	return FALSE;
}


/******************************************************************************
 *	Stop monitoring a file or directory for changes
 *
 ******************************************************************************/

BOOL CNGFileChangeMonitor::Stop(void)
{
	if (m_pThread != NULL)
	{
		DestroyMonitoringThread();

		return TRUE;
	}
	return FALSE;
}

⌨️ 快捷键说明

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