404 lines
9.7 KiB
C++
404 lines
9.7 KiB
C++
|
#include "StdAfx.h"
|
||
|
#include "MonitorThread.h"
|
||
|
#include <Folders.h>
|
||
|
|
||
|
|
||
|
namespace nsMonitorThread
|
||
|
{
|
||
|
|
||
|
_bstr_t __stdcall GetLogFolder(LPCTSTR pszLog);
|
||
|
bool __stdcall OpenFile(LPCTSTR pszFile, HANDLE& hFile, FILETIME ftFile, bool bDontCheckLastWriteTime = false);
|
||
|
bool __stdcall IsLastWriteTimeUpdated(HANDLE hFile, FILETIME& ftFile);
|
||
|
void __stdcall DisplayFile(HANDLE hFile);
|
||
|
bool __stdcall CheckBeginTime(LPCTSTR pszFile, FILETIME ftFile, bool& bNeedCheckMonitorBeginTime);
|
||
|
|
||
|
}
|
||
|
|
||
|
using namespace nsMonitorThread;
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// MonitorThread Class
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
// Constructor
|
||
|
|
||
|
CMonitorThread::CMonitorThread() :
|
||
|
m_strMigrationLog(GetMigrationLogPath()),
|
||
|
m_hMigrationLog(INVALID_HANDLE_VALUE),
|
||
|
m_strDispatchLog(GetDispatchLogPath()),
|
||
|
m_hDispatchLog(INVALID_HANDLE_VALUE),
|
||
|
m_bDontNeedCheckMonitorBeginTime(FALSE)
|
||
|
{
|
||
|
FILETIME ft;
|
||
|
SYSTEMTIME st;
|
||
|
|
||
|
GetSystemTime(&st);
|
||
|
|
||
|
if (SystemTimeToFileTime(&st, &ft))
|
||
|
{
|
||
|
m_ftMigrationLogLastWriteTime = ft;
|
||
|
m_ftDispatchLogLastWriteTime = ft;
|
||
|
m_ftMonitorBeginTime = ft;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_ftMigrationLogLastWriteTime.dwLowDateTime = 0;
|
||
|
m_ftMigrationLogLastWriteTime.dwHighDateTime = 0;
|
||
|
m_ftDispatchLogLastWriteTime.dwLowDateTime = 0;
|
||
|
m_ftDispatchLogLastWriteTime.dwHighDateTime = 0;
|
||
|
m_ftMonitorBeginTime.dwLowDateTime = 0;
|
||
|
m_ftMonitorBeginTime.dwHighDateTime = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Destructor
|
||
|
|
||
|
CMonitorThread::~CMonitorThread()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
// Start Method
|
||
|
|
||
|
void CMonitorThread::Start()
|
||
|
{
|
||
|
CThread::StartThread();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Stop Method
|
||
|
|
||
|
void CMonitorThread::Stop()
|
||
|
{
|
||
|
CThread::StopThread();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Run Method
|
||
|
|
||
|
void CMonitorThread::Run()
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
// position file pointer at end of dispatch log as this log is always appended to
|
||
|
|
||
|
ProcessDispatchLog(true); // binitialize is true, bCheckModifyTime is default to true
|
||
|
|
||
|
_bstr_t strMigration = GetLogFolder(m_strMigrationLog);
|
||
|
_bstr_t strDispatch = GetLogFolder(m_strDispatchLog);
|
||
|
|
||
|
HANDLE hHandles[3] = { StopEvent(), NULL, NULL };
|
||
|
|
||
|
// obtain change notification handle for migration log folder
|
||
|
// note that an invalid handle value is returned if the folder does not exist
|
||
|
|
||
|
HANDLE hMigrationChange = INVALID_HANDLE_VALUE;
|
||
|
HANDLE hDispatchChange = INVALID_HANDLE_VALUE;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
hMigrationChange = FindFirstChangeNotification(strMigration, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_LAST_WRITE);
|
||
|
|
||
|
if (hMigrationChange != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
while (WaitForSingleObject(hHandles[0], 1000) == WAIT_TIMEOUT);
|
||
|
|
||
|
// if valid change notification handle then...
|
||
|
|
||
|
if (hMigrationChange != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
DWORD dwHandleCount = 2;
|
||
|
hHandles[1] = hMigrationChange;
|
||
|
|
||
|
// until stop event is signaled...
|
||
|
|
||
|
for (bool bWait = true; bWait;)
|
||
|
{
|
||
|
// if change notification handle for dispatch log has not been obtained...
|
||
|
|
||
|
if (hDispatchChange == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
hDispatchChange = FindFirstChangeNotification(strDispatch, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_LAST_WRITE);
|
||
|
|
||
|
if (hDispatchChange != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
dwHandleCount = 3;
|
||
|
hHandles[1] = hDispatchChange;
|
||
|
hHandles[2] = hMigrationChange;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// process signaled event
|
||
|
|
||
|
switch (WaitForMultipleObjects(dwHandleCount, hHandles, FALSE, INFINITE))
|
||
|
{
|
||
|
case WAIT_OBJECT_0:
|
||
|
{
|
||
|
bWait = false;
|
||
|
break;
|
||
|
}
|
||
|
case WAIT_OBJECT_0 + 1:
|
||
|
{
|
||
|
if (dwHandleCount == 2)
|
||
|
{
|
||
|
ProcessMigrationLog();
|
||
|
FindNextChangeNotification(hMigrationChange);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ProcessDispatchLog(); // use default parameter values
|
||
|
FindNextChangeNotification(hDispatchChange);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case WAIT_OBJECT_0 + 2:
|
||
|
{
|
||
|
ProcessMigrationLog();
|
||
|
FindNextChangeNotification(hMigrationChange);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
bWait = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// close change notification handles
|
||
|
|
||
|
if (hDispatchChange != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
FindCloseChangeNotification(hDispatchChange);
|
||
|
}
|
||
|
|
||
|
if (hMigrationChange != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
FindCloseChangeNotification(hMigrationChange);
|
||
|
}
|
||
|
|
||
|
// process logs one last time to display end of logs
|
||
|
|
||
|
ProcessDispatchLog(false, false); // bInitialize is false, bCheckModifyTime is false
|
||
|
ProcessMigrationLog(false);
|
||
|
|
||
|
// close file handles
|
||
|
|
||
|
if (m_hDispatchLog != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
CloseHandle(m_hDispatchLog);
|
||
|
}
|
||
|
|
||
|
if (m_hMigrationLog != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
CloseHandle(m_hMigrationLog);
|
||
|
}
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// ProcessMigrationLog Method
|
||
|
|
||
|
void CMonitorThread::ProcessMigrationLog(bool bCheckModifyTime)
|
||
|
{
|
||
|
// first make sure that the last written time of the file is greater than the monitor start time, so
|
||
|
// we can be certain that we are actually reading the most recent log file.
|
||
|
|
||
|
if(m_bDontNeedCheckMonitorBeginTime || CheckBeginTime(m_strMigrationLog, m_ftMonitorBeginTime, m_bDontNeedCheckMonitorBeginTime))
|
||
|
{
|
||
|
if (OpenFile(m_strMigrationLog, m_hMigrationLog, m_ftMigrationLogLastWriteTime))
|
||
|
{
|
||
|
if(bCheckModifyTime)
|
||
|
{
|
||
|
if (IsLastWriteTimeUpdated(m_hMigrationLog, m_ftMigrationLogLastWriteTime))
|
||
|
{
|
||
|
DisplayFile(m_hMigrationLog);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DisplayFile(m_hMigrationLog);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// ProcessDispatchLog Method
|
||
|
|
||
|
void CMonitorThread::ProcessDispatchLog(bool bInitialize, bool bCheckModifyTime)
|
||
|
{
|
||
|
if (OpenFile(m_strDispatchLog, m_hDispatchLog, m_ftDispatchLogLastWriteTime, bInitialize))
|
||
|
{
|
||
|
if (bInitialize)
|
||
|
{
|
||
|
SetFilePointer(m_hDispatchLog, 0, NULL, FILE_END);
|
||
|
}
|
||
|
|
||
|
if(bCheckModifyTime)
|
||
|
{
|
||
|
if (IsLastWriteTimeUpdated(m_hDispatchLog, m_ftDispatchLogLastWriteTime))
|
||
|
{
|
||
|
DisplayFile(m_hDispatchLog);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DisplayFile(m_hDispatchLog);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
namespace nsMonitorThread
|
||
|
{
|
||
|
|
||
|
|
||
|
_bstr_t __stdcall GetLogFolder(LPCTSTR pszLog)
|
||
|
{
|
||
|
_TCHAR szPath[_MAX_PATH];
|
||
|
_TCHAR szDrive[_MAX_DRIVE];
|
||
|
_TCHAR szDir[_MAX_DIR];
|
||
|
|
||
|
if (pszLog)
|
||
|
{
|
||
|
_tsplitpath(pszLog, szDrive, szDir, NULL, NULL);
|
||
|
_tmakepath(szPath, szDrive, szDir, NULL, NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
szPath[0] = _T('\0');
|
||
|
}
|
||
|
|
||
|
return szPath;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool __stdcall OpenFile(LPCTSTR pszFile, HANDLE& hFile, FILETIME ftFile, bool bDontCheckLastWriteTime)
|
||
|
{
|
||
|
HANDLE h = hFile;
|
||
|
|
||
|
if (h == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
h = CreateFile(
|
||
|
pszFile,
|
||
|
GENERIC_READ,
|
||
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if (h != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
FILETIME ft = ftFile;
|
||
|
|
||
|
if (bDontCheckLastWriteTime || IsLastWriteTimeUpdated(h, ft))
|
||
|
{
|
||
|
_TCHAR ch;
|
||
|
DWORD cb;
|
||
|
|
||
|
if (ReadFile(h, &ch, sizeof(ch), &cb, NULL) && (cb >= sizeof(ch)))
|
||
|
{
|
||
|
if (ch != _T('\xFEFF'))
|
||
|
{
|
||
|
SetFilePointer(h, 0, NULL, FILE_BEGIN);
|
||
|
}
|
||
|
|
||
|
hFile = h;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CloseHandle(h);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CloseHandle(h);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (hFile != INVALID_HANDLE_VALUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
bool __stdcall IsLastWriteTimeUpdated(HANDLE hFile, FILETIME& ftFile)
|
||
|
{
|
||
|
bool bUpdated = false;
|
||
|
|
||
|
BY_HANDLE_FILE_INFORMATION bhfi;
|
||
|
|
||
|
if (GetFileInformationByHandle(hFile, &bhfi))
|
||
|
{
|
||
|
if (CompareFileTime(&bhfi.ftLastWriteTime, &ftFile) > 0)
|
||
|
{
|
||
|
ftFile = bhfi.ftLastWriteTime;
|
||
|
bUpdated = true;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return bUpdated;
|
||
|
}
|
||
|
|
||
|
|
||
|
void __stdcall DisplayFile(HANDLE hFile)
|
||
|
{
|
||
|
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||
|
DWORD dwBytesRead;
|
||
|
DWORD dwCharsWritten;
|
||
|
_TCHAR szBuffer[1024];
|
||
|
|
||
|
while (ReadFile(hFile, szBuffer, sizeof(szBuffer), &dwBytesRead, NULL) && (dwBytesRead > 0))
|
||
|
{
|
||
|
WriteConsole(hStdOut, szBuffer, dwBytesRead / sizeof(_TCHAR), &dwCharsWritten, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool __stdcall CheckBeginTime(LPCTSTR pszFile, FILETIME ftFile, bool& bDontNeedCheckMonitorBeginTime)
|
||
|
{
|
||
|
bool bLatestFile = false;
|
||
|
HANDLE h = INVALID_HANDLE_VALUE;
|
||
|
|
||
|
// Make sure that the monitor open the correct log file, not the old one
|
||
|
h = CreateFile(
|
||
|
pszFile,
|
||
|
0,
|
||
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
// if we fail to get the file handle, we will treat the file as not the newest one
|
||
|
if(h != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
// compare the monitor begin time with the last write time of the log file
|
||
|
bLatestFile = IsLastWriteTimeUpdated(h, ftFile);
|
||
|
|
||
|
CloseHandle(h);
|
||
|
|
||
|
// mark the bDontNeedCheckMonitorBeginTime, so we don't have to go through this next time
|
||
|
bDontNeedCheckMonitorBeginTime = bLatestFile;
|
||
|
}
|
||
|
|
||
|
return bLatestFile;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|