#include "pch.h"
char g_chFileChangeBuff[4<<10];
DirectoryMonitor::DirectoryMonitor()
: m_nPollInterval(0), m_cFiles(0), m_pargFiles(NULL), m_hCompPort(NULL), m_hDir(NULL), m_pFileNamesBuffer(NULL),
m_pNewestFileCached(NULL)
{
m_szDir[0] = '\0';
m_szDirWithSpec[0] = '\0';
m_overlapped.Internal = 0;
m_overlapped.InternalHigh = 0;
m_overlapped.Offset = 0;
m_overlapped.OffsetHigh = 0;
m_overlapped.hEvent = NULL;
}
DirectoryMonitor::~DirectoryMonitor()
{
if (m_hDir)
CloseHandle(m_hDir);
if (m_pFileNamesBuffer)
delete[] m_pFileNamesBuffer;
if (m_pargFiles)
delete [] m_pargFiles;
}
bool DirectoryMonitor::FilterFile(WIN32_FIND_DATA & finddata)
{
if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
return true;
if (finddata.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
return true;
char * szFileName = finddata.cFileName;
unsigned cLen;
cLen = 11;
assert(strlen("Artwork.ini") == cLen);
if (_strnicmp(szFileName, "Artwork.ini", cLen) == 0)
return true;
return false; }
BOOL DirectoryMonitor::SetupMonitor(LPCSTR szDir, int nPollInterval)
{
m_nPollInterval = nPollInterval;
WIN32_FIND_DATA finddata;
HANDLE hsearchFiles = 0;
m_cFiles = 0;
int cbValue = strlen(szDir);
lstrcpy(m_szDir, szDir);
if (cbValue < 1 || '\\' != szDir[cbValue - 1]) {
m_szDir[cbValue++] = '\\';
m_szDir[cbValue] = '\0';
}
memcpy(m_szDirWithSpec, m_szDir, cbValue+1);
m_szDirWithSpec[cbValue++] = '*';
m_szDirWithSpec[cbValue] = '\0';
int cFiles = 0;
int cFileNameBufferBytes = 0;
hsearchFiles = FindFirstFile(m_szDirWithSpec, &finddata);
if (INVALID_HANDLE_VALUE == hsearchFiles)
{
return false;
}
while (INVALID_HANDLE_VALUE != hsearchFiles)
{
if (!FilterFile(finddata))
{
cFiles++;
cFileNameBufferBytes += strlen(finddata.cFileName) + 1;
}
if (!FindNextFile(hsearchFiles, &finddata))
{
FindClose(hsearchFiles);
hsearchFiles = INVALID_HANDLE_VALUE;
}
}
m_cFiles = cFiles;
if (m_pargFiles)
delete [] m_pargFiles;
m_pargFiles = new FileChangeInfo[cFiles];
if (m_pFileNamesBuffer)
delete[] m_pFileNamesBuffer;
m_pFileNamesBuffer = new char[cFileNameBufferBytes];
char* pNextSlot = m_pFileNamesBuffer;
char* pEnd = m_pFileNamesBuffer + cFileNameBufferBytes;
hsearchFiles = FindFirstFile(m_szDirWithSpec, &finddata); for(int i=0; (i < m_cFiles) && (INVALID_HANDLE_VALUE != hsearchFiles);)
{
if (!FilterFile(finddata))
{
int cbFileName = lstrlen(finddata.cFileName) + 1;
m_pargFiles[i].szFileName = pNextSlot;
pNextSlot += cbFileName;
if(pNextSlot > pEnd)
{
_AGCModule.TriggerEvent(NULL, AllsrvEventID_ArtChangedInInit, "", -1, -1, -1, 0);
return false;
}
CopyMemory(m_pargFiles[i].szFileName, finddata.cFileName, cbFileName);
m_pargFiles[i].ftLastWriteTime = finddata.ftLastWriteTime;
m_pargFiles[i].cFileSize = finddata.nFileSizeLow; i++;
}
if (!FindNextFile(hsearchFiles, &finddata))
{
FindClose(hsearchFiles);
hsearchFiles = INVALID_HANDLE_VALUE;
}
}
FindClose(hsearchFiles);
if (m_hDir)
CloseHandle(m_hDir);
m_hDir = CreateFile( m_szDir,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
m_hCompPort = CreateIoCompletionPort(m_hDir, NULL, NULL, 0);
ZAssert(m_hDir != INVALID_HANDLE_VALUE);
DWORD dwBytesReturned = 0;
if (IsWinNT())
{
ReadDirectoryChangesW(m_hDir,
g_chFileChangeBuff,
sizeof(g_chFileChangeBuff),
TRUE,
FILE_NOTIFY_CHANGE_LAST_WRITE,
&dwBytesReturned,
&m_overlapped,
NULL);
}
return true;
}
void DirectoryMonitor::CheckForFileChanges()
{
DWORD dwBytesTransferred;
LPOVERLAPPED pOverlapped = &m_overlapped;
DWORD dwCompletionKey;
static char szPrevFileName[c_cbFileName]; if (GetQueuedCompletionStatus(m_hCompPort, &dwBytesTransferred, &dwCompletionKey, &pOverlapped, 0))
{
DWORD cbOffset;
PFILE_NOTIFY_INFORMATION pfni = (PFILE_NOTIFY_INFORMATION) g_chFileChangeBuff;
do
{
char szFileName[c_cbFileName];
WideCharToMultiByte(CP_OEMCP, 0, pfni->FileName, -1, szFileName,
sizeof(szFileName), NULL, NULL);
cbOffset = pfni->NextEntryOffset;
if(lstrcmp(szPrevFileName, szFileName)) {
if (pfni->Action == FILE_ACTION_MODIFIED)
{
lstrcpy(szPrevFileName, szFileName);
int iFile = 0;
for (iFile = 0; iFile < m_cFiles; iFile++)
{
if (!lstrcmpi(m_pargFiles[iFile].szFileName, szFileName)) {
char szFullPath[128];
lstrcpy(szFullPath, m_szDir);
lstrcat(szFullPath, "\\");
lstrcat(szFullPath, szFileName);
HANDLE hFile = CreateFile(szFullPath, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
BY_HANDLE_FILE_INFORMATION FileInfo;
GetFileInformationByHandle(hFile, &FileInfo);
m_pargFiles[iFile].ftLastWriteTime = FileInfo.ftLastWriteTime;
m_pargFiles[iFile].cFileSize = FileInfo.nFileSizeLow; CloseHandle(hFile);
}
}
}
}
else szPrevFileName[0] = 0;
pfni = (PFILE_NOTIFY_INFORMATION)((LPBYTE) pfni + cbOffset);
} while( cbOffset );
if (IsWinNT())
{
ReadDirectoryChangesW(m_hDir,
g_chFileChangeBuff,
sizeof(g_chFileChangeBuff),
TRUE,
FILE_NOTIFY_CHANGE_LAST_WRITE,
&cbOffset, &m_overlapped,
NULL);
}
}
}
#if 0
CheckForChangedFiles();
#endif
bool DirectoryMonitor::IterateFiles(int nType, FILETIME* pft, LPIFFCIPROC FileChangeCallback, void* pData)
{
bool bAnyMatches = false;
m_pNewestFileCached = NULL;
for (int iFile = 0; iFile < m_cFiles; iFile++)
{
DWORD dwHighFile = m_pargFiles[iFile].ftLastWriteTime.dwHighDateTime;
DWORD dwLowFile = m_pargFiles[iFile].ftLastWriteTime.dwLowDateTime;
BOOL bMatch = false;
switch(nType)
{
case edmNewerThan:
if (dwHighFile > pft->dwHighDateTime || (dwHighFile == pft->dwHighDateTime && dwLowFile > pft->dwLowDateTime))
bMatch = true;
break;
case edmEqualTo:
if (dwHighFile == pft->dwHighDateTime && dwLowFile == pft->dwLowDateTime)
bMatch = true;
break;
case edmOlderThan:
if (dwHighFile < pft->dwHighDateTime || (dwHighFile == pft->dwHighDateTime && dwLowFile < pft->dwLowDateTime))
bMatch = true;
break;
}
if (bMatch)
{
bAnyMatches = true;
if (!FileChangeCallback(&m_pargFiles[iFile], pData)) return false; }
}
return bAnyMatches;
}
FileChangeInfo* DirectoryMonitor::GetNewestFile()
{
if (m_pNewestFileCached == NULL)
{
DWORD dwHighFile = (DWORD)0;
DWORD dwLowFile = (DWORD)0;
for (int iFile = 0; iFile < m_cFiles; iFile++)
{
if (
m_pargFiles[iFile].ftLastWriteTime.dwHighDateTime > dwHighFile ||
(
m_pargFiles[iFile].ftLastWriteTime.dwHighDateTime == dwHighFile &&
m_pargFiles[iFile].ftLastWriteTime.dwLowDateTime > dwLowFile
)
)
{
dwHighFile = m_pargFiles[iFile].ftLastWriteTime.dwHighDateTime;
dwLowFile = m_pargFiles[iFile].ftLastWriteTime.dwLowDateTime;
m_pNewestFileCached = &m_pargFiles[iFile];
}
}
}
return m_pNewestFileCached;
}
FileChangeInfo* DirectoryMonitor::GetOldestFile()
{
assert(0); return 0; }