2009/06/20

[程式]目錄監控原始碼

最近更新了顯示程式方式,也好久沒有更新了。

這是我在KWallPaper 中使用的目錄監控Class。

由於在寫這程式時,曾參考上網路上的許多範例,因此在此分享與回饋~

在取得檔案變動時,我是將其變動放入一個queue中,如果直接寫入資料庫,延遲的時間,會造成後面的檔案沒有監控到。

此程式碼還有許多不足之處,歡迎批評指教,謝謝


#include "StdAfx.h"
#include ".\directorymonitor.h"
#include "ImgManager.h"

unsigned __stdcall DirectoryMonitorThreadCallback(LPVOID lpParm)
{
CDirectoryMonitor* pObj = (CDirectoryMonitor*) lpParm;

if( !pObj )
{
_endthreadex( 0 );
return 0;
}

pObj->RunThread();
_endthreadex( 0 );
return 0;
}

CDirectoryMonitor::CDirectoryMonitor( CImgManager* pOwnter ):
m_pOwner(pOwnter),
m_hCompletionPort(NULL),
m_ulCompletionKey(0),
m_hDir(NULL),
m_pBuffer(NULL),
m_nBufferSize(0)
{
memset( &m_Overlapped, 0, sizeof(m_Overlapped) );

}
CDirectoryMonitor::~CDirectoryMonitor(void)
{
if( m_hCompletionPort )
{
//The thread will catch this and exit the thread
PostQueuedCompletionStatus(m_hCompletionPort, 0, 0, NULL);
Sleep(1000);

for( unsigned int i = 0; i < m_nThreadCount; ++i )
{
HANDLE nThread = m_vecThread[i];

//wait for it to exit
WaitForSingleObject(nThread, INFINITE);
SAFE_CLOSEHANDLE(nThread);
}
m_hCompletionPort = NULL;
m_vecThread.clear();
}
SAFE_CLOSEHANDLE(m_hDir);

SAFE_DELETE_ARRAY(m_pBuffer);
m_nBufferSize = 0;
}

bool CDirectoryMonitor::Initialize( const TCHAR* szPath )
{
m_strMoniDir = szPath;

m_hDir = CreateFile( m_strMoniDir.c_str(), // pointer to the file name
FILE_LIST_DIRECTORY, // access (read/write) mode
FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, // share mode
NULL, // security descriptor
OPEN_EXISTING, // how to create
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, // file attributes
NULL // file with attributes to copy
);

if ( INVALID_HANDLE_VALUE == m_hDir )
return false;

SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);

m_nThreadCount = 1; //SystemInfo.dwNumberOfProcessors;

m_hCompletionPort = CreateIoCompletionPort(
m_hDir, // Handle to a file opened for overlapped I/O completion.
NULL, // existed Handle to the I/O completion port.
(ULONG_PTR)&m_ulCompletionKey, // CompletionKey
m_nThreadCount // NumberOfConcurrentThreads
);

if( NULL == m_hCompletionPort )
return false;

m_nBufferSize = 4096;//2*(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH);
m_pBuffer = new char[m_nBufferSize];

if( !_callReadDirectoryChanges() )
return false;

for( unsigned int i = 0; i < m_nThreadCount; ++i)
{
HANDLE nThread = (HANDLE)_beginthreadex( NULL, 0, &::DirectoryMonitorThreadCallback, (LPVOID)this, 0, NULL );

if( NULL != nThread )
{
m_vecThread.push_back( nThread );
}
}

KLOG( LOG_DEBUG, _T("DirectoryMonitor : %s"), m_strMoniDir.c_str() );

return true;
}

void CDirectoryMonitor::RunThread()
{
BOOL bSucceed = FALSE;
DWORD dwBytesReturned = 0;
TCHAR szFileName[MAX_PATH] = {0};
TCHAR szNotiryFileName[MAX_PATH] = {0};
DWORD dwAction = 0;

while(TRUE)
{
::Sleep(1);
LPOVERLAPPED lpOverlapped = &m_Overlapped;
bSucceed = GetQueuedCompletionStatus( m_hCompletionPort, // [in]Handle to the completion port of interest.
&dwBytesReturned, // lpNumberOfBytes
&m_ulCompletionKey, // lpCompletionKey
&lpOverlapped, // lpOverlapped
INFINITE // dwMilliseconds
);

if( NULL == lpOverlapped )
break;

if(!bSucceed || 0 == m_ulCompletionKey )
continue;

FILE_NOTIFY_INFORMATION * pNotify = (FILE_NOTIFY_INFORMATION*)m_pBuffer;
DWORD dwNextEntryOffset = 0;

do
{
pNotify = (FILE_NOTIFY_INFORMATION*)&m_pBuffer[dwNextEntryOffset];

dwNextEntryOffset += pNotify->NextEntryOffset;
dwAction = pNotify->Action;

memset( szNotiryFileName, 0, sizeof(szNotiryFileName));
_tcsncpy( szNotiryFileName, pNotify->FileName, pNotify->FileNameLength);
szNotiryFileName[pNotify->FileNameLength / sizeof(TCHAR) ] = '\0';
_stprintf( szFileName, _T("%s\\%s"), m_strMoniDir.c_str(), szNotiryFileName );

if( m_pOwner )
m_pOwner->NotifyFileChange( dwAction, szFileName );

}while ( 0 != pNotify->NextEntryOffset );

_callReadDirectoryChanges();
}
}

bool CDirectoryMonitor::Release()
{
return true;
}

bool CDirectoryMonitor::_callReadDirectoryChanges()
{
if( m_pBuffer )
{
memset( m_pBuffer, 0, m_nBufferSize );
}

BOOL BRet = ReadDirectoryChangesW( m_hDir, // hDirectory. Handle to the directory to be monitored
m_pBuffer, // [in, out] Pointer to the formatted buffer in which the read results are to be returned.
m_nBufferSize, // [in] Length of the buffer pointed to by the lpBuffer parameter, in bytes.
true, // bWatchSubtree
FILE_NOTIFY_CHANGE_FILE_NAME| // [in] Filter criteria the function checks to determine if the wait operation has completed.
FILE_NOTIFY_CHANGE_DIR_NAME|
FILE_NOTIFY_CHANGE_CREATION,
NULL, // lpBytesReturned. For asynchronous calls, this parameter is undefined.
&m_Overlapped, // [in] Pointer to an OVERLAPPED structure that supplies data to be used during asynchronous operation.
NULL ); // lpCompletionRoutine

return BRet == TRUE ? true : false;
}


以上,歡迎參考~