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

📄 delayeddirectorychangehandler.cpp

📁 局域网来访者IP监视以及文件修改监视: 1.监听常用的局域网访问工具
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// DelayedDirectoryChangeHandler.cpp: implementation of the CDelayedDirectoryChangeHandler2 class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DirectoryChanges.h"
#include "DelayedDirectoryChangeHandler.h"
#include <process.h>//for _beginthreadex

#include <shlwapi.h>				 // for PathMatchSpec
#pragma comment( lib, "shlwapi.lib") // function


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

#define UWM_DELAYED_DIRECTORY_NOTIFICATION (WM_APP+1024)


HINSTANCE GetInstanceHandle()
{
	return (HINSTANCE)GetModuleHandle(NULL);
	// ASSERT( AfxGetInstanceHandle() == (HINSTANCE)GetModuleHandle(NULL) ); <-- true for building .exe's 
	//NOTE: In Dll's using shared MFC, AfxGetInstanceHandle() != (HINSTANCE)GetModuleHandle(NULL)...
	//don't know if this is the case for dll's using static MFC
}
static inline bool IsEmptyString(LPCTSTR sz)
{
	return (bool)(sz==NULL || *sz == 0);
}
/*********************************************************
  PathMatchSpec() requires IE 4.0 or greater on NT...
  if running on NT 4.0 w/ out IE 4.0, then uses this function instead.

  Based on code by Jack Handy:
  http://www.codeproject.com/string/wildcmp.asp

  Changed slightly to match the PathMatchSpec signature, be unicode compliant & to ignore case by myself.
  
*********************************************************/

#define _TESTING_WILDCMP_ONLY_ 

BOOL STDAPICALLTYPE wildcmp(LPCTSTR string, LPCTSTR wild ) 
{
	const TCHAR *cp, *mp;
	cp = mp = NULL;
	
	while ((*string) && (*wild != _T('*'))) 
	{
		if ((_toupper(*wild) != _toupper(*string)) && (*wild != _T('?'))) 
		{
			return FALSE;
		}
		wild++;
		string++;
	}
		
	while (*string) 
	{
		if (*wild == _T('*')) 
		{
			if (!*++wild) 
			{
				return TRUE;
			}
			mp = wild;
			cp = string+1;
		} 
		else 
		if ((_toupper(*wild) == _toupper(*string)) || (*wild == _T('?'))) 
		{
			wild++;
			string++;
		} 
		else 
		{
			wild = mp;
			string = cp++;
		}
	}
		
	while (*wild == _T('*')) 
	{
		wild++;
	}
	return (!*wild)? TRUE : FALSE;
}

//////////////////////////////////////////////////////////////////////////
//
//CDirChangeNotification member functions:
//
CDirChangeNotification::CDirChangeNotification(CDelayedDirectoryChangeHandler *	pDelayedHandler, DWORD dwPartialPathOffset)
:m_pDelayedHandler( pDelayedHandler )
,m_szFileName1(NULL)
,m_szFileName2(NULL)
,m_dwError(0UL)
,m_dwPartialPathOffset(dwPartialPathOffset)
{
	ASSERT( pDelayedHandler );
}

CDirChangeNotification::~CDirChangeNotification()
{
	if( m_szFileName1 ) free(m_szFileName1), m_szFileName1 = NULL;
	if( m_szFileName2 ) free(m_szFileName2), m_szFileName2 = NULL;
}

void CDirChangeNotification::DispatchNotificationFunction()
{
	ASSERT( m_pDelayedHandler );
	if( m_pDelayedHandler )
		m_pDelayedHandler->DispatchNotificationFunction( this );
}

void CDirChangeNotification::PostOn_FileAdded(LPCTSTR szFileName)
{
	ASSERT( szFileName );
	m_eFunctionToDispatch	= eOn_FileAdded;
	m_szFileName1			= _tcsdup( szFileName) ;
	//
	// post the message so it'll be dispatch by another thread.
	PostNotification();

}
void CDirChangeNotification::PostOn_FileRemoved(LPCTSTR szFileName)
{
	ASSERT( szFileName );
	m_eFunctionToDispatch	= eOn_FileRemoved;
	m_szFileName1			= _tcsdup( szFileName) ;
	//
	// post the message so it'll be dispatched by another thread.
	PostNotification();
	
}
void CDirChangeNotification::PostOn_FileNameChanged(LPCTSTR szOldName, LPCTSTR szNewName)
{
	ASSERT( szOldName && szNewName );

	m_eFunctionToDispatch	= eOn_FileNameChanged;
	m_szFileName1			= _tcsdup( szOldName) ;
	m_szFileName2			= _tcsdup( szNewName) ;
	//
	// post the message so it'll be dispatched by another thread.
	PostNotification();
	
}

void CDirChangeNotification::PostOn_FileModified(LPCTSTR szFileName)
{
	ASSERT( szFileName );

	m_eFunctionToDispatch	= eOn_FileModified;
	m_szFileName1			= _tcsdup( szFileName );
	//
	// post the message so it'll be dispatched by another thread.
	PostNotification();
}

void CDirChangeNotification::PostOn_ReadDirectoryChangesError(DWORD dwError, LPCTSTR szDirectoryName)
{
	ASSERT( szDirectoryName );

	m_eFunctionToDispatch = eOn_ReadDirectoryChangesError;
	m_dwError			  = dwError;
	m_szFileName1		  = _tcsdup(szDirectoryName);
	//
	// post the message so it'll be dispatched by the another thread.
	PostNotification();
	
}

void CDirChangeNotification::PostOn_WatchStarted(DWORD dwError, LPCTSTR szDirectoryName)
{
	ASSERT( szDirectoryName );

	m_eFunctionToDispatch = eOn_WatchStarted;
	m_dwError			  =	dwError;
	m_szFileName1		  = _tcsdup(szDirectoryName);

	PostNotification();
}

void CDirChangeNotification::PostOn_WatchStopped(LPCTSTR szDirectoryName)
{
	ASSERT( szDirectoryName );

	m_eFunctionToDispatch = eOn_WatchStopped;
	m_szFileName1		  = _tcsdup(szDirectoryName);

	PostNotification();
}

void CDirChangeNotification::PostNotification()
{
	ASSERT( m_pDelayedHandler );
	if( m_pDelayedHandler )
		m_pDelayedHandler->PostNotification( this );
}

static LRESULT CALLBACK DelayedNotificationWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
//
//	This is the wndproc for the notification window
//
//	it's here to dispatch the notifications to the client
//
{
	if( message == UWM_DELAYED_DIRECTORY_NOTIFICATION )
	{
		CDirChangeNotification * pNotification = reinterpret_cast<CDirChangeNotification*>(lParam);
		ASSERT(  pNotification );
		if( pNotification )
		{
			DWORD dwEx(0);
			__try{
				pNotification->DispatchNotificationFunction();
			}
			__except(dwEx = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER){
				//An exception was raised:
				//
				//	Likely cause: there was a problem creating the CDelayedDirectoryChangeHandler::m_hWatchStoppedDispatchedEvent object
				//	and the change handler object was deleted before the notification could be dispatched to this function.
				//
				//  or perhaps, somebody's implementation of an overridden function caused an exception
				TRACE(_T("Following exception occurred: %d -- File: %s Line: %d\n"), dwEx, _T(__FILE__), __LINE__);
			}
		}
		
		return 0UL;
	}
	else
		return DefWindowProc(hWnd,message,wParam,lParam);
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//
//CDelayedNotificationWindow static member vars:
//
long CDelayedNotificationWindow::s_nRefCnt = 0L;
HWND CDelayedNotificationWindow::s_hWnd = NULL;
BOOL CDelayedNotificationWindow::s_bRegisterWindow = FALSE;
//
//
long CDelayedNotificationWindow::AddRef()//creates window for first time if necessary
{
	if( InterlockedIncrement(&s_nRefCnt) == 1
		||	!::IsWindow( s_hWnd ) )
	{
		TRACE(_T("CDelayedNotificationWindow -- Creating the notification window\n"));
		VERIFY( CreateNotificationWindow() );
	}
	return s_nRefCnt;
}

long CDelayedNotificationWindow::Release()//destroys window for last time if necessary
{
	long nRefCnt = -1;
	if( (nRefCnt = InterlockedDecrement(&s_nRefCnt)) == 0 )
	{
		//no body else using the window so destroy it?
		TRACE(_T("CDelayedNotificationWindow -- Destroying the notification window\n"));
		DestroyWindow( s_hWnd );
		s_hWnd = NULL;
	}
	return nRefCnt;
}
BOOL CDelayedNotificationWindow::RegisterWindowClass(LPCTSTR szClassName)
//
//	registers our own window class to use as the hidden notification window.
//
{
	WNDCLASS wc = {0};
	
	wc.style = 0;
	wc.hInstance		= GetInstanceHandle();
	wc.lpszClassName	= szClassName;
	wc.hbrBackground	= (HBRUSH)GetStockObject( WHITE_BRUSH );
	wc.lpfnWndProc		= DelayedNotificationWndProc;
	
	ATOM ant = RegisterClass( &wc );
	if( ant == NULL )
	{
		TRACE(_T("CDirChangeNotification::RegisterWindowClass - RegisterClass failed: %d\n"), GetLastError());
	}
	return (BOOL)(ant!= NULL);
	
}

BOOL CDelayedNotificationWindow::CreateNotificationWindow()
//
//	Create the hidden notification windows.
//
{
	TCHAR szClassName[] = _T("Delayed_Message_Sender");
	if( !s_bRegisterWindow )
		s_bRegisterWindow = RegisterWindowClass(szClassName);
	s_hWnd 	= CreateWindowEx(0, szClassName, _T("DelayedWnd"),0,0,0,0,0, NULL, 0, 
							GetInstanceHandle(), NULL);
	if( s_hWnd == NULL )
	{
		TRACE(_T("Unable to create notification window! GetLastError(): %d\n"), GetLastError());
		TRACE(_T("File: %s Line: %d\n"), _T(__FILE__), __LINE__);
	}
	
	return (BOOL)(s_hWnd != NULL);
}
void CDelayedNotificationWindow::PostNotification(CDirChangeNotification * pNotification)
//
//	Posts a message to a window created in the main 
//	thread.
//	The main thread catches this message, and dispatches it in 
//	the context of the main thread.
//
{
	ASSERT( pNotification );
	ASSERT( s_hWnd );
	ASSERT( ::IsWindow( s_hWnd ) );

	PostMessage(s_hWnd, 
				UWM_DELAYED_DIRECTORY_NOTIFICATION, 
				0, 
				reinterpret_cast<LPARAM>( pNotification ));

//  if you don't want the notification delayed, 
//  
//	if( false )
//	{
//		pNotification->DispatchNotificationFunction();
//	}
}

/////////////////////////////////////////////////////////
//	CDelayedNoticationThread
//
long	CDelayedNotificationThread::s_nRefCnt = 0L;
HANDLE	CDelayedNotificationThread::s_hThread = NULL;
DWORD	CDelayedNotificationThread::s_dwThreadID = 0UL;

void CDelayedNotificationThread::PostNotification(CDirChangeNotification * pNotification)
{
	ASSERT( s_hThread != NULL );
	ASSERT( s_dwThreadID != 0 );

	if(
		!PostThreadMessage(s_dwThreadID, 
						   UWM_DELAYED_DIRECTORY_NOTIFICATION, 
						   0, 
						   reinterpret_cast<LPARAM>(pNotification))
	  )
	{
		//Note, this can sometimes fail.
		//Will fail if: s_dwThreadID references a invalid thread id(the thread has died for example)
		// OR will fail if the thread doesn't have a message queue.
		//
		//	This was failing because the thread had not been fully started by the time PostThreadMessage had been called
		//
		//Note: if this fails, it creates a memory leak because
		//the CDirChangeNotification object that was allocated and posted
		//to the thread is actually never going to be dispatched and then deleted.... it's
		//hanging in limbo.....

		//
		//	The fix for this situation was to force the thread that starts
		//	this worker thread to wait until the worker thread was fully started before
		//	continueing.  accomplished w/ an event... also.. posting a message to itself before signalling the 
		//  'spawning' thread that it was started ensured that there was a message pump
		//  associated w/ the worker thread by the time PostThreadMessage was called.
		TRACE(_T("PostThreadMessage() failed while posting to thread id: %d! GetLastError(): %d%s\n"), s_dwThreadID, GetLastError(), GetLastError() == ERROR_INVALID_THREAD_ID? _T("(ERROR_INVALID_THREAD_ID)") : _T(""));
	}
}

bool CDelayedNotificationThread::StartThread()
{
	TRACE(_T("CDelayedNotificationThread::StartThread()\n"));
	ASSERT( s_hThread == NULL 
		&&	s_dwThreadID == 0 );
	s_hThread = (HANDLE)_beginthreadex(NULL,0, 
								ThreadFunc, this, 0, (UINT*) &s_dwThreadID);
	if( s_hThread )
		WaitForThreadStartup();

	return s_hThread == NULL ? false : true;

}

bool CDelayedNotificationThread::StopThread()
{
	TRACE(_T("CDelayedNotificationThread::StopThread()\n"));
	if( s_hThread != NULL 
	&&	s_dwThreadID != 0 )
	{
		PostThreadMessage(s_dwThreadID, WM_QUIT, 0,0);

		WaitForSingleObject(s_hThread, INFINITE);
		CloseHandle(s_hThread);
		s_hThread	 = NULL;
		s_dwThreadID = 0UL;
		return true;
	}
	return true;//already shutdown
}

UINT __stdcall CDelayedNotificationThread::ThreadFunc(LPVOID lpvThis)
{
	//UNREFERENCED_PARAMETER( lpvThis );
	//
	//	Implements a simple message pump
	//
	CDelayedNotificationThread * pThis = reinterpret_cast<CDelayedNotificationThread*>(lpvThis);
	ASSERT( pThis );

	//
	//	Insure that this thread has a message queue by the time another
	//	thread gets control and tries to use PostThreadMessage
	//	problems can happen if someone tries to use PostThreadMessage
	//	in between the time pThis->SignalThreadStartup() is called,
	//	and the first call to GetMessage();

	::PostMessage(NULL, WM_NULL, 0,0);//if this thread didn't have a message queue before this, it does now.


	//
	//
	//	Signal that this thread has started so that StartThread can continue.
	//
	if( pThis ) pThis->SignalThreadStartup();

	TRACE(_T("CDelayedNotificationThread::ThreadFunc() ThreadID: %d -- Starting\n"), GetCurrentThreadId());
	MSG msg;
	do{
		while( GetMessage(&msg, NULL, 0,0) )//note GetMessage() can return -1, but only if i give it a bad HWND.(HWND for another thread for example)..i'm not giving an HWND, so no problemo here.
		{
			if( msg.message == UWM_DELAYED_DIRECTORY_NOTIFICATION )
			{
				CDirChangeNotification * pNotification = 
								reinterpret_cast<CDirChangeNotification *>( msg.lParam );
				DWORD dwEx(0UL);

				__try{
				if( pNotification )
					pNotification->DispatchNotificationFunction();
				}
				__except(dwEx = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER){
				//An exception was raised:
				//
				//	Likely causes: 
				//		* There was a problem creating the CDelayedDirectoryChangeHandler::m_hWatchStoppedDispatchedEvent object
				//			and the change handler object was deleted before the notification could be dispatched to this function.
				//
				//		* Somebody's implementation of an overridden virtual function caused an exception
				TRACE(_T("The following exception occurred: %d -- File: %s Line: %d\n"), dwEx, _T(__FILE__), __LINE__);
				}
			}
			else
			if( msg.message == WM_QUIT )
			{
				break;
			}
		}
	}while( msg.message != WM_QUIT );
	TRACE(_T("CDelayedNotificationThread::ThreadFunc() exiting. ThreadID: %d\n"), GetCurrentThreadId());
	return 0;
}

long CDelayedNotificationThread::AddRef()
{

⌨️ 快捷键说明

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