|
|
#include "stdafx.h"
#include "global.h"
// to include CkdMonINI class definition
#include "ini.h"
#include "SMTP.h"
// The name of current service
// This variable is declared in global.cpp
extern _TCHAR szServiceName[MAX_PATH]; // just to get any kind of error through GetError() routine
// This variable is declared in global.cpp
extern _TCHAR szError[MAX_PATH];
// this is used by LoadINI function also. So it is made global
CkdMonINI kdMonINI;
void kdMon() {
// SMTP object
CSMTP smtpObj;
// This variable is used by IsSignaledToStop() function.
// open the stop event which is created by kdMonSvc
// For any event, the name of the event matters and the handle does not.
HANDLE hStopEvent = NULL;
// open the cszStopEvent which is meant to signal this thread to stop.
// this signalling is done by main service thread when WM_QUIT is received
hStopEvent = OpenEvent( EVENT_ALL_ACCESS, FALSE, // = handle can not be inherited
(LPCTSTR)_T(cszStopEvent)); if ( hStopEvent == NULL ) { GetError(szError); LogFatalEvent(_T("kdMon->OpenEvent: %s"), szError); AddServiceLog(_T("Error: kdMon->OpenEvent: %s\r\n"), szError); goto endkdMon; }
BOOL bLoop; bLoop = TRUE;
while(bLoop) {
AddServiceLog(_T("\r\n- - - - - - @ @ @ @ @ @ @ @ @ @ - - - - - - - - - - - @ @ @ @ @ @ @ @ @ @ @ - - - - - - - \r\n"));
// temperory boolean to receive return values from functions
BOOL bRet; // load the values from INI file
// since INI file is read each time the loop gets executed,
// we can change the running parameters of the service on the fly
// If values loading is not successful then close the service : bLoop = FALSE;
bRet = LoadINI(); if ( bRet == FALSE ) { bLoop = FALSE; goto closeandwait; }
bRet = smtpObj.InitSMTP(); // if SMTP can not be initiated, then do nothing. try in next database cycle.
if ( bRet == FALSE ) { goto closeandwait; }
// generate an array to store failure counts for each server
ULONG *pulFailureCounts; pulFailureCounts = NULL; pulFailureCounts = (ULONG *) malloc (kdMonINI.dwServerCount * sizeof(ULONG)); if ( pulFailureCounts == NULL ) { AddServiceLog(_T("Error: kdMon->malloc: Insufficient memory\r\n")); LogFatalEvent(_T("kdMon->malloc: Insufficient memory")); bLoop = FALSE; goto closeandwait; }
// generate an array to store timestamp for count from each server
ULONG *pulTimeStamps; pulTimeStamps = NULL; pulTimeStamps = (ULONG *) malloc (kdMonINI.dwServerCount * sizeof(ULONG)); if ( pulTimeStamps == NULL ) { AddServiceLog(_T("Error: kdMon->malloc: Insufficient memory\r\n")); LogFatalEvent(_T("kdMon->malloc: Insufficient memory")); bLoop = FALSE; goto closeandwait; }
// load the values from registry for the server to be monitored
// since INI file is read each time the loop gets executed,
// we can change the server names on the fly
// we get counts for each server in pulFailureCounts
// we get corresponding TimeStamps in pulTimeStamps
bRet = ReadRegValues( kdMonINI.ppszServerNameArray, kdMonINI.dwServerCount, pulFailureCounts, pulTimeStamps); if ( bRet == FALSE ) goto closeandwait;
// counter to go through server names
UINT uiServerCtr; for( uiServerCtr = 0; uiServerCtr < kdMonINI.dwServerCount; uiServerCtr++) {
// prepare Log File Name on the server
_TCHAR szKDFailureLogFile[MAX_PATH * 2]; _stprintf(szKDFailureLogFile, _T("\\\\%s\\%s"), kdMonINI.ppszServerNameArray[uiServerCtr], kdMonINI.szDebuggerLogFile);
ULONG ulRet; // scan the log file and get the count of number of lines
ulRet = ScanLogFile(szKDFailureLogFile);
// AddServiceLog(_T("ulRet = %ld\r\n"), ulRet);
if ( ulRet == E_FILE_NOT_FOUND ) { // file not found means there are no Debugger errors
// So put count = 0 and go on with next server
pulFailureCounts[uiServerCtr] = 0; continue; } if ( ulRet == E_PATH_NOT_FOUND ) { // path not found means there is some network error
// So put count = -1 so next time this count wont be valid
// and go on with next server
pulFailureCounts[uiServerCtr] = -1; continue; } // some other error occurred
if ( ulRet == E_OTHER_FILE_ERROR ) { // So put count = -1 so next time this count wont be valid
// and go on with next server
pulFailureCounts[uiServerCtr] = -1; continue; }
ULONG ulNumLines; ulNumLines = ulRet;
// if previous count was -1 i.e. invalid, just put new count and move on
// similar if previous TimeStamp was invalid
if ( (pulFailureCounts[uiServerCtr] == -1) || pulTimeStamps[uiServerCtr] == -1) { pulFailureCounts[uiServerCtr] = ulNumLines; continue; }
// get the current system time
// ulTimeStamp is like 200112171558
ULONG ulCurrentTimeStamp; ulCurrentTimeStamp = GetCurrentTimeStamp(); if ( ulCurrentTimeStamp == -1 ) { pulFailureCounts[uiServerCtr] = ulNumLines; continue; }
// we have kdMonINI.dwRepeatTime in minutes (say 78)
// take out hours and minutes (1 Hr 18 Min)
// between 0112181608 and 0112181726 there is difference of 1 Hr 18 Min
// but decimal difference is 118
// between 0112181650 and 0112181808 there is difference of 1 Hr 18 Min
// but decimal difference is 158
// so we have some calculation here
// what we will do is add the kdMonINI.dwRepeatTime to OldTS
// modify the previous timestamp to do the comparison
ULONG ulModifiedTS; ulModifiedTS = AddTime(pulTimeStamps[uiServerCtr], kdMonINI.dwRepeatTime); AddServiceLog(_T("Server: %s, OldTS: %ld, NewTS: %ld, OldCnt: %ld, NewCnt: %ld, ulModifiedTS = %ld\r\n"), kdMonINI.ppszServerNameArray[uiServerCtr], pulTimeStamps[uiServerCtr], ulCurrentTimeStamp, pulFailureCounts[uiServerCtr], ulNumLines, ulModifiedTS);
// check the timestamp difference. Keep margin of 3
// if the previous timestamp was > dwRepeatTime ago then dont do anything
// just record the new count This case happens when there is a Servername in
// INI, then it is removed for some time and then it is added again
// this helps to send false mails out
if ( ulCurrentTimeStamp > (ulModifiedTS + 3) ) { AddServiceLog(_T("Previous record invalid. ulCurrentTimeStamp: %ld, ulModifiedTS: %ld"), ulCurrentTimeStamp, ulModifiedTS); pulFailureCounts[uiServerCtr] = ulNumLines; continue; }
// check the difference between current and previous counts
ULONG ulFailures; ulFailures = ulNumLines - pulFailureCounts[uiServerCtr]; if ( ulFailures >= kdMonINI.dwDebuggerThreshold ) { AddServiceLog(_T("KD failed. %ld errors in %ld minutes\r\n"), ulFailures, kdMonINI.dwRepeatTime); // fill the mail parameters structure
StructMailParams stMailParams; _tcscpy(stMailParams.szFrom, kdMonINI.szFromMailID); _tcscpy(stMailParams.szTo, kdMonINI.szToMailID); _tcscpy(stMailParams.szServerName, kdMonINI.ppszServerNameArray[uiServerCtr]); stMailParams.ulFailures = ulFailures; stMailParams.ulInterval = kdMonINI.dwRepeatTime; stMailParams.ulCurrentTimestamp = ulCurrentTimeStamp;
BOOL bRet; bRet = smtpObj.SendMail(stMailParams); // dont care even if you were not able to send mail
//if ( bRet == FALSE )
// goto nextserver;
}
// store new count in the array
pulFailureCounts[uiServerCtr] = ulNumLines;
// see if the date has changed, if yes then move the previous logfile to
// new location
// example of date change OldTS: 200112182348, NewTS: 200112190048
// so divide timestamp by 10000 and you get 20011218 and 20011219 compare
ULONG ulOldDate, ulNewDate; ulOldDate = pulTimeStamps[uiServerCtr]/10000; ulNewDate = ulCurrentTimeStamp/10000; if ( (ulNewDate - ulOldDate) >= 1 ) { AddServiceLog(_T("Day changed. Oldday: %ld, Newday: %ld\r\n"), ulOldDate, ulNewDate);
// Log File Name
_TCHAR szKDFailureLogFile[MAX_PATH * 2]; _stprintf(szKDFailureLogFile, _T("\\\\%s\\%s"), kdMonINI.ppszServerNameArray[uiServerCtr], kdMonINI.szDebuggerLogFile);
// now since date has changed, prepare archive filename
_TCHAR szTimeStamp[MAX_PATH]; _ltot(ulOldDate, szTimeStamp, 10); // prepare Archive Log File Name on the server
_TCHAR szKDFailureArchiveFile[MAX_PATH * 2]; _stprintf(szKDFailureArchiveFile, _T("%s\\%s_FailedAddCrash%s.log"), kdMonINI.szDebuggerLogArchiveDir, kdMonINI.ppszServerNameArray[uiServerCtr], szTimeStamp);
AddServiceLog(_T("Moving file (%s -> %s)\r\n"), szKDFailureLogFile, szKDFailureArchiveFile);
// copy file to destination
if ( CopyFile(szKDFailureLogFile, szKDFailureArchiveFile, FALSE) ) { // try to delete the original kd failure log file
if ( DeleteFile(szKDFailureLogFile) ) { // set new count to 0 since log has been moved successfully
pulFailureCounts[uiServerCtr] = 0; } else { GetError(szError); AddServiceLog(_T("Error: kdMon->DeleteFile(%s): %s \r\n"), szKDFailureLogFile, szError); LogEvent(_T("Error: kdMon->DeleteFile(%s): %s"), szKDFailureLogFile, szError); // try to delete the copied file
if ( DeleteFile(szKDFailureArchiveFile) ) { ; } else { GetError(szError); AddServiceLog(_T("Error: kdMon->DeleteFile(%s): %s \r\n"), szKDFailureArchiveFile, szError); LogEvent(_T("Error: kdMon->DeleteFile(%s): %s"), szKDFailureArchiveFile, szError); } } } else { GetError(szError); AddServiceLog(_T("Error: kdMon->CopyFile(%s, %s): %s \r\n"), szKDFailureLogFile, szKDFailureArchiveFile, szError); LogEvent(_T("Error: kdMon->CopyFile(%s, %s): %s"), szKDFailureLogFile, szKDFailureArchiveFile, szError); } } }
// write the values to registry for the servers to be monitored
// counts for each server are in pulFailureCounts
// timestamp is current time
bRet = WriteRegValues( kdMonINI.ppszServerNameArray, kdMonINI.dwServerCount, pulFailureCounts); if ( bRet == FALSE ) goto closeandwait;
closeandwait:
// cleanup SMTP resources
bRet = smtpObj.SMTPCleanup(); if( bRet == FALSE ) { AddServiceLog(_T("Error: smtpObj.SMTPCleanup failed\r\n")); LogFatalEvent(_T("smtpObj.SMTPCleanup failed")); }
// free uiFailureCounts
if (pulFailureCounts != NULL) free(pulFailureCounts);
// free pulTimeStamps
if (pulTimeStamps != NULL) free(pulTimeStamps);
// break the while loop if bLoop is false
if (bLoop == FALSE) { goto endkdMon; }
bRet = IsSignaledToStop(hStopEvent, kdMonINI.dwRepeatTime * 60 * 1000); if (bRet == TRUE) { goto endkdMon; } } // while(bLoop)
endkdMon:
if (hStopEvent != NULL) CloseHandle(hStopEvent); return; }
BOOL IsSignaledToStop(const HANDLE hStopEvent, DWORD dwMilliSeconds) { DWORD dwRetVal; dwRetVal = WaitForSingleObject( hStopEvent, dwMilliSeconds ); if ( dwRetVal == WAIT_FAILED ) { GetError(szError); LogFatalEvent(_T("IsSignaledToStop->WaitForSingleObject: %s"), szError); AddServiceLog(_T("Error: IsSignaledToStop->WaitForSingleObject: %s\r\n"), szError); // thread is supposed to stop now since there is a fatal error
return TRUE; } if ( dwRetVal == WAIT_OBJECT_0 ) { LogEvent(_T("Worker Thread received Stop Event.")); AddServiceLog(_T("Worker Thread received Stop Event.\r\n")); // thread is supposed to stop now since there is a stop event occured
return TRUE; }
// thread is not yet signaled to stop
return FALSE; }
// this procedure loads the values from INI file
BOOL LoadINI() {
DWORD dwRetVal;
//
// prepare INI file path
//
_TCHAR szCurrentDirectory[MAX_PATH]; dwRetVal = GetCurrentDirectory( sizeof(szCurrentDirectory) / sizeof(_TCHAR), (LPTSTR) szCurrentDirectory); if ( dwRetVal == 0 ) { LogFatalEvent(_T("LoadINI->GetCurrentDirectory: %s"), szError); AddServiceLog(_T("Error: LoadINI->GetCurrentDirectory: %s\r\n"), szError); // return FALSE indicating some error has occurred
return FALSE; } _TCHAR szINIFilePath[MAX_PATH]; _stprintf(szINIFilePath, _T("%s\\%s"), szCurrentDirectory, _T(cszkdMonINIFile));
// check if the kdMon INI file is there or not
HANDLE hINIFile; WIN32_FIND_DATA w32FindData = {0}; // try to get the handle to the file
hINIFile = FindFirstFile( (LPCTSTR) szINIFilePath, &w32FindData); // if file is not there then the handle is invalid
if(hINIFile == INVALID_HANDLE_VALUE){ LogFatalEvent(_T("There is no kdMon INI file : %s"), szINIFilePath); AddServiceLog(_T("Error: There is no kdMon INI file : %s \r\n"), szINIFilePath); return FALSE; } else{ FindClose(hINIFile); }
BOOL bRetVal; bRetVal = kdMonINI.LoadValues(szINIFilePath); if ( bRetVal == FALSE ) return bRetVal;
//
// check if values are getting in properly from INI file
//
AddServiceLog(_T("\r\n============== I N I V A L U E S ==============\r\n")); AddServiceLog(_T("szToMailID : %s \r\n"), kdMonINI.szToMailID); AddServiceLog(_T("szFromMailID : %s \r\n"), kdMonINI.szFromMailID); AddServiceLog(_T("dwRepeatTime : %ld \r\n"), kdMonINI.dwRepeatTime); AddServiceLog(_T("szDebuggerLogFile : %s \r\n"), kdMonINI.szDebuggerLogFile); AddServiceLog(_T("szDebuggerLogArchiveDir : %s \r\n"), kdMonINI.szDebuggerLogArchiveDir); AddServiceLog(_T("dwDebuggerThreshold : %ld \r\n"), kdMonINI.dwDebuggerThreshold); AddServiceLog(_T("szServers : %s \r\n"), kdMonINI.szServers); AddServiceLog(_T("dwServerCount : %ld \r\n"), kdMonINI.dwServerCount); for ( UINT i = 0; i < kdMonINI.dwServerCount; i++ ) { AddServiceLog(_T("kdMonINI.ppszServerNameArray[%ld] : %s \r\n"), i, kdMonINI.ppszServerNameArray[i]); } AddServiceLog(_T("\r\n===================================================\r\n"));
// successfully loaded INI file
return TRUE; }
// each server name in ppszNames, get the count and corresponding timestamp
// store the count in the pulCounts array
// store the timestamp in the pulTimeStamps array
BOOL ReadRegValues(_TCHAR **ppszNames, DWORD dwTotalNames, ULONG *pulCounts, ULONG *pulTimeStamps) {
// open HKEY_LOCAL_MACHINE\Software\Microsoft\kdMon registry key
CRegKey keyServerName; LONG lRes; _TCHAR szKeyName[MAX_PATH]; _tcscpy(szKeyName, _T("Software\\Microsoft\\")); _tcscat(szKeyName, szServiceName); lRes = keyServerName.Create(HKEY_LOCAL_MACHINE, szKeyName); if ( lRes != ERROR_SUCCESS ) { AddServiceLog(_T("Error: ReadRegValues->keyServerName.Create: Unable to open the key\r\n")); LogFatalEvent(_T("ReadRegValues->keyServerName.Create: Unable to open the key")); return FALSE; }
// for each server name, get the previous count and timestamp value from registry
for (DWORD i = 0; i < dwTotalNames; i++){ _TCHAR szValue[MAX_PATH]; DWORD dwBufferSize; dwBufferSize = MAX_PATH; lRes = keyServerName.QueryValue(szValue, ppszNames[i], &dwBufferSize); if ( lRes != ERROR_SUCCESS ) { // means there is no such value
AddServiceLog(_T("ReadRegValues->keyServerName.QueryValue: Unable to query value %s\r\n"), ppszNames[i]); LogEvent(_T("ReadRegValues->keyServerName.QueryValue: Unable to query value %s"), ppszNames[i]); // There was no entry for server name in registry
// set the count to -1
pulCounts[i] = -1; // set timestamp to -1
pulTimeStamps[i] = -1; // go on with the next server name
continue; }
// the value got is of the form <count>|<datetime>
// # strtok returns pointer to the next token found in szValue
// # while the pointer is returned, the '|' is replaced by '\0'
// # so if u print strToken then it will print the characters till the null
// # character
// get the first token which is the previous count
_TCHAR* pszToken; pszToken = NULL; pszToken = _tcstok(szValue, _T("|")); if(pszToken == NULL){ AddServiceLog(_T("Error: ReadRegValues: Wrong value retrieved for %s\r\n"), ppszNames[i]); LogEvent(_T("ReadRegValues: Wrong value retrieved for %s"), ppszNames[i]); // Previous count was an invalid value
// set the count to -1
pulCounts[i] = -1; // set timestamp to -1
pulTimeStamps[i] = -1; // go on with the next server name
continue; } // set the count
pulCounts[i] = _ttoi(pszToken);
// get the second token which is the timestamp of the count
pszToken = _tcstok(NULL, _T("|")); if(pszToken == NULL){ AddServiceLog(_T("Error: ReadRegValues: No timestamp found for %s\r\n"), ppszNames[i]); LogEvent(_T("ReadRegValues: No timestamp found for %s"), ppszNames[i]);
// no timestamp found
// set timestamp to -1
pulTimeStamps[i] = -1; // dont do timestamp validation, go on with the next server name
continue; }
// set the timestamp
pulTimeStamps[i] = _ttol(pszToken); }
// for (i = 0; i < dwTotalNames; i++){
// AddServiceLog(_T("%s Value : %ld %ld\r\n"), ppszNames[i], pulCounts[i], pulTimeStamps[i]);
// }
return TRUE; }
// write values in the pulCounts to registry. Timestamp is current timestamp
BOOL WriteRegValues(_TCHAR **ppszNames, DWORD dwTotalNames, ULONG *pulCounts) { // open HKEY_LOCAL_MACHINE\Software\Microsoft\kdMon registry key
CRegKey keyServerName; LONG lRes; _TCHAR szKeyName[MAX_PATH]; _tcscpy(szKeyName, _T("Software\\Microsoft\\")); _tcscat(szKeyName, szServiceName); lRes = keyServerName.Create(HKEY_LOCAL_MACHINE, szKeyName); if ( lRes != ERROR_SUCCESS ) { AddServiceLog(_T("Error: ReadRegValues->keyServerName.Create: Unable to open the key\r\n")); LogFatalEvent(_T("ReadRegValues->keyServerName.Create: Unable to open the key")); return FALSE; }
// for each server name, write the current count and timestamp value in registry
for (DWORD i = 0; i < dwTotalNames; i++){
// prepare the value to write
_TCHAR szValue[MAX_PATH]; // get integer count in a string
_itot(pulCounts[i], szValue, 10); // put delemiter
_tcscat(szValue, _T("|"));
// prepare the timestamp
// get the current system time
// ulTimeStamp is like 200112171558
ULONG ulTimeStamp; ulTimeStamp = GetCurrentTimeStamp();
_TCHAR szTimeStamp[MAX_PATH]; _ltot(ulTimeStamp, szTimeStamp, 10);
// prepare final KeyValue
_tcscat(szValue, szTimeStamp);
lRes = keyServerName.SetValue(szValue, ppszNames[i]); if ( lRes != ERROR_SUCCESS ) { // means there is no value
AddServiceLog(_T("Error: WriteRegValues->keyServerName.SetValue: Unable to set value %s\r\n"), ppszNames[i]); LogFatalEvent(_T("WriteRegValues->keyServerName.SetValue: Unable to set value %s"), ppszNames[i]); return FALSE; }
}
return TRUE; }
ULONG ScanLogFile(_TCHAR *pszFileName) {
ULONG ulRet = -1; HANDLE hFile; hFile = CreateFile( pszFileName, GENERIC_READ, 0, // No sharing of file
NULL, // No security
OPEN_EXISTING, // Open if exist
FILE_ATTRIBUTE_NORMAL, // Normal file
NULL); // No attr. template
if (hFile == INVALID_HANDLE_VALUE) { // DWORD to get an error
DWORD dwError; dwError = GetLastError();
GetError(szError); AddServiceLog(_T("Error: ScanLogFile->CreateFile(%s): %s"), pszFileName, szError); LogEvent(_T("ScanLogFile->CreateFile(%s): %s"), pszFileName, szError);
// ERROR_PATH_NOT_FOUND is Win32 Error Code
// E_PATH_NOT_FOUND is locally defined code
if ( dwError == ERROR_PATH_NOT_FOUND ) { return (ULONG)E_PATH_NOT_FOUND; } if ( dwError == ERROR_FILE_NOT_FOUND ) { return (ULONG)E_FILE_NOT_FOUND; } return (ULONG)E_OTHER_FILE_ERROR; }
DWORD dwPos; // Reach the file start
dwPos = SetFilePointer( hFile, 0, // Low 32 bits of distance to move
NULL, // High 32 bits of distance to move
FILE_BEGIN); // Starting point
// If High Word is NULL, error meas dwPos = INVALID_SET_FILE_POINTER
if(dwPos == INVALID_SET_FILE_POINTER){ GetError(szError); AddServiceLog(_T("Error: ScanLogFile->SetFilePointer: %s\r\n"), szError); LogFatalEvent(_T("ScanLogFile->SetFilePointer: %s"), szError); goto endScanLogFile; }
// to get status of the read operation
// If the function succeeds and the number of bytes read is zero,
// the file pointer was beyond the current end of the file
DWORD dwBytesRead;
// buffer to read from file
// **** THIS NEEDS TO BE char* since the file is in ASCII and not UNICODE
char szBuffer[MAX_PATH * 2];
// count for Number of lines
ULONG ulNumberOfLines; ulNumberOfLines = 0;
// loop till the fileend is reached
while(1) {
BOOL bRet; bRet = ReadFile( hFile, szBuffer, sizeof(szBuffer) * sizeof(char), // number of BYTES to read
&dwBytesRead, // BYTES read
NULL); // OVERLAPPED structure
// return if read failed
if ( bRet == FALSE ) { GetError(szError); AddServiceLog(_T("Error: ScanLogFile->ReadFile(%s): %s\r\n"), pszFileName, szError); LogFatalEvent(_T("ScanLogFile->ReadFile(%s): %s"), pszFileName, szError); goto endScanLogFile; }
// means file end is reached
if ( dwBytesRead == 0 ) { ulRet = ulNumberOfLines; break; }
// **** THIS NEEDS TO BE char* since the file is in ASCII and not UNICODE
char *pszBuffPtr; pszBuffPtr = szBuffer;
// to denote that a line has started
BOOL bLineStarted; bLineStarted = FALSE;
// read buffer one by one till dwBytesRead bytes are read
for ( ; dwBytesRead > 0; dwBytesRead-- ) {
// **** _T('\n') not needed since the file is in ASCII and not UNICODE
// if endof line is encountered and line has started then increase line number
if ( (*pszBuffPtr == '\n') && (bLineStarted == TRUE) ) { ulNumberOfLines++; bLineStarted = FALSE; } else if ( (*pszBuffPtr != '\n') && (*pszBuffPtr != '\t') && (*pszBuffPtr != '\r') && (*pszBuffPtr != ' ') ) { // if a non widespace character is encountered then line has started
bLineStarted = TRUE; }
// goto next character
pszBuffPtr++; } }
endScanLogFile : CloseHandle(hFile); return ulRet; }
ULONG GetCurrentTimeStamp() { // prepare the timestamp
// get the current system time
SYSTEMTIME UniversalTime; GetSystemTime(&UniversalTime);
SYSTEMTIME systime; BOOL bRet; bRet = SystemTimeToTzSpecificLocalTime ( NULL, // current local settings
&UniversalTime, &systime); if ( bRet == 0 ) { GetError(szError); AddServiceLog(_T("Error: GetCurrentTimeStamp->SystemTimeToTzSpecificLocalTime: %s \r\n"), szError); LogFatalEvent(_T("GetCurrentTimeStamp->SystemTimeToTzSpecificLocalTime: %s"), szError); return (ULONG) -1; } // ulTimeStamp is like 200112171558
ULONG ulTimeStamp; ulTimeStamp = 0; ulTimeStamp += systime.wMinute; ulTimeStamp += systime.wHour * 100; ulTimeStamp += systime.wDay * 10000; ulTimeStamp += systime.wMonth * 1000000; ulTimeStamp += (systime.wYear - 2000) * 100000000;
return ulTimeStamp; }
// to add a specific time to a timestamp
ULONG AddTime(ULONG ulTimeStamp, ULONG ulMinutes){ // we have kdMonINI.dwRepeatTime in minutes (say 78)
// take out hours and minutes (1 Hr 18 Min)
// between 0112181608 and 0112181726 there is difference of 1 Hr 18 Min
// but decimal difference is 118
// between 0112181650 and 0112181808 there is difference of 1 Hr 18 Min
// but decimal difference is 158
// so we have some calculation here
// what we will do is add the kdMonINI.dwRepeatTime to OldTS
ULONG ulTmpHr, ulTmpMin; ulTmpHr = (ULONG) (ulMinutes / 60); ulTmpMin = (ULONG) (ulMinutes % 60);
ULONG ulPrevYr, ulPrevMon, ulPrevDate, ulPrevHr, ulPrevMin; ulPrevMin = ulTimeStamp % 100; ulTimeStamp = ulTimeStamp / 100; ulPrevHr = ulTimeStamp % 100; ulTimeStamp = ulTimeStamp / 100; ulPrevDate = ulTimeStamp % 100; ulTimeStamp = ulTimeStamp / 100; ulPrevMon = ulTimeStamp % 100; ulTimeStamp = ulTimeStamp / 100; ulPrevYr = ulTimeStamp % 100;
ULONG ulNewYr, ulNewMon, ulNewDate, ulNewHr, ulNewMin; ulNewYr = ulNewMon = ulNewDate = ulNewHr = ulNewMin = 0; ulNewMin = ulPrevMin + ulTmpMin; ulNewHr = ulPrevHr + ulTmpHr; ulNewDate = ulPrevDate; ulNewMon = ulPrevMon; ulNewYr = ulPrevYr;
if ( ulNewMin >= 60 ) { ulNewHr++; ulNewMin = ulNewMin - 60; }
if ( ulNewHr >= 24 ) { ulNewDate++; ulNewHr = ulNewHr - 24; }
if ( ulPrevMon == 1 || ulPrevMon == 3 || ulPrevMon == 5 || ulPrevMon == 7 || ulPrevMon == 8 || ulPrevMon == 10 || ulPrevMon == 12 ) { if ( ulNewDate >= 32 ) { ulNewMon++; ulNewDate = 1; } } else if ( ulPrevMon == 4 || ulPrevMon == 6 || ulPrevMon == 9 || ulPrevMon == 11 ) { if ( ulNewDate >= 31 ) { ulNewMon++; ulNewDate = 1; } } else if ( ulPrevMon == 2 && (ulPrevYr % 4) == 0 ) { // leap year
if ( ulNewDate >= 30 ) { ulNewMon++; ulNewDate = 1; } } else if ( ulPrevMon == 2 && (ulPrevYr % 4) != 0 ) { // not a leap year
if ( ulNewDate >= 29 ) { ulNewMon++; ulNewDate = 1; } }
if ( ulNewMon >= 13 ) { ulNewYr++; ulNewMon = 1; }
ULONG ulModifiedTS; ulModifiedTS = ulNewYr; ulModifiedTS = ulModifiedTS * 100 + ulNewMon; ulModifiedTS = ulModifiedTS * 100 + ulNewDate; ulModifiedTS = ulModifiedTS * 100 + ulNewHr; ulModifiedTS = ulModifiedTS * 100 + ulNewMin;
return ulModifiedTS; }
|