Download demo executable - 17 Kb
Download source files - 43 Kb
The Event Viewer is intended to be run under WindowsNT System Manager (check the submission with the same name).
This sample application uses (more or less) the same policy regarding MDI, child dialog encapsulation, controls etc.,
and these things are treated there. In this article you can see two thread routines which you may find interesting.
1. The first is the routine which enumerates event entries, FillEventLogList
.
The structure passed as parameter to this thread routine is
typedef struct _tagEVENTLOGFILTER
{
BOOL fApplication;
BOOL fSecurity;
BOOL fSystem;
BOOL fCustom;
TCHAR lpszComputerName[_MAX_PATH + 1];
HWND hwndLV;
HWND hwndDlg;
HWND hwndProgr;
HANDLE hCancelEvent;
HANDLE hCloseEvent;
unsigned uThreadId;
TCHAR lpszCustomEventFileName[_MAX_PATH + 1];
} EVENTLOGFILTER, *LPEVENTLOGFILTER;
The routine looks like this:
unsigned int __stdcall
FillEventLogList(LPVOID lpParam)
{
EVENTLOGFILTER *pelf = 0;
int nRetVal = 0;
HWND hParentWnd = 0, hwndDlg = 0, hwndLV = 0, hwndProgr = 0;
HANDLE hEventLog = 0;
DWORD dwEventLogRecords = 0, dwOldestEventLogRecord = 0, dwEvLogCounter = 0, dwNumberOfBytesToRead = 0,
dwBytesRead = 0, dwMinNumberOfBytesNeeded = 0, dwCancel = 0, dwClose = 0;
LPVOID lpEventLogRecordBuffer = 0;
TCHAR chFakeBuffer;
BOOL bRetVal = FALSE;
BOOL fExit = FALSE;
UINT uStep = 0, uStepAt = 0, uPos = 0, uOffset = 0;
TCHAR lpUNCServerName[_MAX_PATH + 1], lpszEventLogSourceName[_MAX_PATH + 1], lpszErrMsg[1024];
pelf = (EVENTLOGFILTER *)lpParam;
hwndDlg = pelf->hwndDlg;
hwndLV = pelf->hwndLV;
hwndProgr = pelf->hwndProgr;
hParentWnd = GetParent(hwndDlg);
SetWindowLong(hParentWnd, GWL_USERDATA, (LONG)pelf);
MDIChild_ResizeDlg(hwndDlg, TRUE);
wsprintf(lpUNCServerName, _T("\\\\%s"), pelf->lpszComputerName);
if(g_fApplication)
_tcscpy(lpszEventLogSourceName, _T("Application"));
else if(g_fSystem)
_tcscpy(lpszEventLogSourceName, _T("System"));
else if(g_fSecurity)
_tcscpy(lpszEventLogSourceName, _T("Security"));
else if(g_fCustom)
_tcscpy(lpszEventLogSourceName, pelf->lpszCustomEventFileName);
else
{
nRetVal = -1;
goto _cleanup_;
}
dwCancel = WaitForSingleObject(pelf->hCancelEvent, 0);
dwClose = WaitForSingleObject(pelf->hCloseEvent, 0);
while(!fExit)
{
if(g_fCustom)
hEventLog = OpenBackupEventLog((LPCTSTR)lpUNCServerName, (LPCTSTR)lpszEventLogSourceName);
else
hEventLog = OpenEventLog((LPCTSTR)lpUNCServerName, (LPCTSTR)lpszEventLogSourceName);
if(hEventLog)
{
if(GetNumberOfEventLogRecords(hEventLog, &dwEventLogRecords) &&
GetOldestEventLogRecord(hEventLog, &dwOldestEventLogRecord))
{
SendMessage(hwndProgr, PBM_SETRANGE, (WPARAM)0, (LPARAM)MAKELPARAM(0, 100));
uStepAt = (dwEventLogRecords / 100) + 1;
for(dwEvLogCounter = dwOldestEventLogRecord;
dwEvLogCounter < (dwOldestEventLogRecord + dwEventLogRecords);
dwEvLogCounter++)
{
uStep++;
if(uStep % uStepAt == 0)
hwndProgr && SendMessage(hwndProgr, PBM_SETPOS, (WPARAM)++uPos, 0);
dwCancel = WaitForSingleObject(pelf->hCancelEvent, 0);
if(dwCancel == WAIT_OBJECT_0)
goto _canceled_;
dwClose = WaitForSingleObject(pelf->hCloseEvent, 0);
if(dwClose == WAIT_OBJECT_0)
goto _close_;
lpEventLogRecordBuffer = (LPVOID)&chFakeBuffer;
dwNumberOfBytesToRead = 1;
dwMinNumberOfBytesNeeded = 1;
_retry_:
bRetVal = ReadEventLog(hEventLog, EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ, dwEvLogCounter,
lpEventLogRecordBuffer, dwNumberOfBytesToRead, &dwBytesRead, &dwMinNumberOfBytesNeeded);
if(!bRetVal)
{
g_dwLastError = GetLastError();
if(g_dwLastError == ERROR_INSUFFICIENT_BUFFER)
{
lpEventLogRecordBuffer = (LPVOID)GlobalAlloc(GPTR, dwMinNumberOfBytesNeeded);
if(lpEventLogRecordBuffer == (void *)0)
goto _allocationfailure_;
dwNumberOfBytesToRead = dwMinNumberOfBytesNeeded;
goto _retry_;
}
else
goto _unknownerror_;
}
else
{
PEVENTLOGRECORD pELR = 0;
TCHAR *lpszSourceName = 0, lpszUserName[_MAX_PATH + 1], *lpszComputerName = 0,
lpszRefDomainName[_MAX_PATH + 1], *szSIDType = 0, *szSIDName = 0, sz2[32],
*szExpandedString = 0, szSubmitTime[32], szWriteTime[32];
DWORD dwSourceNameLen = 0, dwComputerNameLen = 0, cbName = _MAX_PATH + 1,
cbRefDomainName = _MAX_PATH + 1, dwSIDTypeLen = 0, dwSidSize = 0, dwEventTypeLen = 0;
PSID pUserSID = 0;
SID_NAME_USE _SidNameUse = (SID_NAME_USE)(SidTypeUser - 1);
BOOL bRetVal = FALSE;
LPBYTE pStrings = 0, pData = 0;
UINT x = 0, uSize, uStringOffset, uStepOfString = 0, uImage = 0;
pELR = (PEVENTLOGRECORD)lpEventLogRecordBuffer;
uOffset = sizeof(EVENTLOGRECORD);
lpszSourceName = (TCHAR *)GlobalAlloc(GPTR, (_MAX_PATH + 1) * sizeof(TCHAR));
strcpy(lpszSourceName, (LPTSTR)((LPBYTE)pELR + uOffset));
dwSourceNameLen = strlen(lpszSourceName);
uOffset += strlen(lpszSourceName) + sizeof(TCHAR);
lpszComputerName = (TCHAR *)GlobalAlloc(GPTR, (_MAX_PATH + 1) * sizeof(TCHAR));
strcpy(lpszComputerName, (LPTSTR)((LPBYTE)pELR + uOffset));
dwComputerNameLen = strlen(lpszComputerName);
uOffset += strlen(lpszComputerName) + sizeof(TCHAR);
dwSIDTypeLen = 32;
szSIDType = (TCHAR *)GlobalAlloc(GPTR, (dwSIDTypeLen + 1) * sizeof(TCHAR));
if(pELR->UserSidLength > 0)
{
pUserSID = (SID *)GlobalAlloc(GPTR, pELR->UserSidLength);
memcpy(pUserSID, (PSID)((LPBYTE)pELR + pELR->UserSidOffset), pELR->UserSidLength);
cbName = cbRefDomainName = _MAX_PATH + 1;
*lpszRefDomainName = *lpszUserName = '\0';
bRetVal = LookupAccountSid(0, pUserSID,
lpszUserName, &cbName,
lpszRefDomainName, &cbRefDomainName,
&_SidNameUse);
if(bRetVal)
{
if(bRetVal)
{
dwSIDTypeLen = 32;
GetNameUse(_SidNameUse, szSIDType, &dwSIDTypeLen);
dwSidSize = (15 + 12 + (12 * (*GetSidSubAuthorityCount(pUserSID))) + 1) * sizeof(TCHAR);
szSIDName = (TCHAR *)GlobalAlloc(GPTR, (dwSidSize + 1) * sizeof(TCHAR));
ConvertSid(pUserSID, szSIDName, &dwSidSize);
}
else
{
strcpy(lpszRefDomainName, "N/A");
strcpy(lpszUserName, "N/A");
strcpy(szSIDType, "N/A");
}
}
else
{
}
}
else
{
strcpy(lpszRefDomainName, "N/A");
strcpy(lpszUserName, "N/A");
strcpy(szSIDType, "N/A");
}
uSize = 0, uStringOffset = pELR->StringOffset;
uSize = pELR->DataOffset - pELR->StringOffset;
if(uSize > 0)
{
pStrings = (LPBYTE)GlobalAlloc(GPTR, uSize * sizeof(BYTE));
memcpy(pStrings, (LPBYTE)pELR + uStringOffset, uSize);
uStepOfString = 0;
szExpandedString = (TCHAR *)GlobalAlloc(GPTR, (uSize + MAX_MSG_LENGTH) * sizeof(TCHAR));
for(x = 0; x < pELR->NumStrings; x++)
{
if(x == 0)
{
strcpy(szExpandedString, (TCHAR *)pStrings + uStepOfString);
if(x < (UINT)pELR->NumStrings - 1)
strcat(szExpandedString, ",");
}
else
strcat(szExpandedString, (TCHAR *)pStrings + uStepOfString);
uStepOfString = strlen((TCHAR *)pStrings + uStepOfString) + 1;
}
}
pData = (LPBYTE)GlobalAlloc(GPTR, pELR->DataLength * sizeof(BYTE));
memcpy(pData, (LPBYTE)((LPBYTE)pELR + pELR->DataOffset), pELR->DataLength);
dwEventTypeLen = 32;
GetEventLogType(sz2, pELR->EventType, &dwEventTypeLen);
GetEventLogImage(&uImage, pELR->EventType);
lstrcpyn(szSubmitTime, asctime(localtime((time_t *)&(pELR->TimeGenerated))), 25);
lstrcpyn(szWriteTime, asctime(localtime((time_t *)&(pELR->TimeWritten))), 25);
InsertRowInList(hwndLV, 9, &dwEvLogCounter,
lpszSourceName,
lpszUserName,
szSIDName,
lpszRefDomainName,
sz2, uImage,
szSubmitTime, szWriteTime);
SafeDeletePointer(pData, pELR->DataLength);
SafeDeletePointer(szExpandedString, uSize);
SafeDeletePointer(pStrings, pELR->DataOffset - pELR->StringOffset);
SafeDeletePointer(szSIDName, dwSidSize + 1);
SafeDeletePointer(szSIDType, dwSIDTypeLen + 1);
SafeDeletePointer(lpszSourceName, dwSourceNameLen);
SafeDeletePointer(lpszComputerName, dwComputerNameLen);
SafeDeletePointer(pUserSID, pELR->UserSidLength);
SafeDeletePointer(lpEventLogRecordBuffer, dwNumberOfBytesToRead);
}
}
goto _cleanup_;
}
else
ReportLastError(0, 0, TRUE);
_unknownerror_:
ReportLastError(lpszErrMsg, 0, TRUE);
goto _cleanup_;
_allocationfailure_:
LoadString(g_hInstance, IDS_ERR_ALLOCATIONFAILURE, lpszErrMsg, 1024);
MessageBox(0, lpszErrMsg, 0, MB_OK | MB_ICONSTOP);
goto _cleanup_;
_canceled_:
nRetVal = 1;
goto _cleanup_;
_close_:
nRetVal = 2;
goto _cleanup_;
_cleanup_:
fExit = TRUE;
CloseEventLog(hEventLog);
hEventLog = 0;
}
else
{
fExit = TRUE;
ReportLastError(0, 0, TRUE);
}
}
if(nRetVal != 2)
{
if(IsWindow(hwndDlg))
MDIChild_ResizeDlg(hwndDlg, FALSE);
if(IsWindow(hParentWnd))
SetWindowLong(hParentWnd, GWL_USERDATA, (LONG)0);
}
CloseHandle(pelf->hCancelEvent);
CloseHandle(pelf->hCloseEvent);
GlobalFree(pelf);
pelf = 0;
return nRetVal;
}
The key to understanding this king of enumeration and especially the using of structure PEVENTLOGRECORD
resides in its definition:
typedef struct _EVENTLOGRECORD {
DWORD Length;
DWORD Reserved;
DWORD RecordNumber;
DWORD TimeGenerated;
DWORD TimeWritten;
DWORD EventID;
WORD EventType;
WORD NumStrings;
WORD EventCategory;
WORD ReservedFlags;
DWORD ClosingRecordNumber;
DWORD StringOffset;
DWORD UserSidLength;
DWORD UserSidOffset;
DWORD DataLength;
DWORD DataOffset;
} EVENTLOGRECORD;
Because this is a variable-length structure, the using of offsets, conversion and allocations seems to me the best approach. (By the way, spending more time
you can easily rewrite a better routine).
Also, you could spend some time reading the ConvertSid
function, which retrieves the name of SID looking in
some weird registry key. Again you have to deal with a nonstandard structure, SID
, which cannot be manipulated manually, but only using the
API specific routines.
BOOL
ConvertSid(PSID pSid, LPTSTR pszSidText, LPDWORD dwBufferLen)
{
DWORD dwSubAuthorities;
DWORD dwSidRev = SID_REVISION;
DWORD dwCounter;
DWORD dwSidSize;
PSID_IDENTIFIER_AUTHORITY psia;
if(!IsValidSid(pSid))
return FALSE;
psia = GetSidIdentifierAuthority(pSid);
dwSubAuthorities =* GetSidSubAuthorityCount(pSid);
dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
if (*dwBufferLen < dwSidSize)
{
*dwBufferLen = dwSidSize;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
dwSidSize=wsprintf(pszSidText, TEXT("S-%lu-"), dwSidRev );
if((psia->Value[0] != 0) || (psia->Value[1] != 0))
dwSidSize += wsprintf(pszSidText + lstrlen(pszSidText),
TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
(USHORT)psia->Value[0],
(USHORT)psia->Value[1],
(USHORT)psia->Value[2],
(USHORT)psia->Value[3],
(USHORT)psia->Value[4],
(USHORT)psia->Value[5]);
else
dwSidSize += wsprintf(pszSidText + lstrlen(pszSidText),
TEXT("%lu"),
(ULONG)(psia->Value[5] ) +
(ULONG)(psia->Value[4] << 8) +
(ULONG)(psia->Value[3] << 16) +
(ULONG)(psia->Value[2] << 24) );
for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
dwSidSize+=wsprintf(pszSidText + dwSidSize, TEXT("-%lu"), *GetSidSubAuthority(pSid, dwCounter));
return TRUE;
}
Double-clicking on an event log entry represented by a row in list, the data window appears, showing more detailed data about the entry you choose. You have to
excuse me for the resize problems (sometimes - or I must say often? - resizing parent data window does not resize encapsulated dialog). Again, the job is done via
another thread, which use the EVENTID
structure
typedef struct _tagEVENTID
{
TCHAR lpszMachineName[_MAX_PATH + 1];
TCHAR lpszEventName[_MAX_PATH + 1];
DWORD dwEventId;
HWND hwndDlg;
} EVENTID, *LPEVENTID;
which simply identifies the record entry, and the routine:
unsigned int __stdcall
ShowEventData(LPVOID lpParam)
{
LPEVENTID peid = (LPEVENTID)lpParam;
int nRetVal = 0;
HWND hwndDlg = peid->hwndDlg;
HWND hwndEditStrings = GetDlgItem(hwndDlg, IDE_STRINGS);
HWND hwndEditData = GetDlgItem(hwndDlg, IDE_DATA);
DWORD dwRecId = peid->dwEventId;
TCHAR lpUNCServerName[_MAX_PATH + 1];
TCHAR lpSourceName[_MAX_PATH + 1];
HANDLE hEventLog = 0;
DWORD dwEventLogRecords = 0;
DWORD dwOldestEventLogRecord = 0;
DWORD dwEvLogCounter = 0;
LPVOID lpEventLogRecordBuffer = 0;
char chFakeBuffer = ' ';
DWORD dwNumberOfBytesToRead = 0;
DWORD dwBytesRead = 0;
DWORD dwMinNumberOfBytesNeeded = 0;
BOOL bRetVal = FALSE;
TCHAR lpszEventLogSourceName[_MAX_PATH + 1];
wsprintf(lpUNCServerName, _T("\\\\%s"), peid->lpszMachineName);
wsprintf(lpSourceName, _T("%s"), peid->lpszEventName);
if(g_fApplication)
_tcscpy(lpszEventLogSourceName, _T("Application"));
else if(g_fSystem)
_tcscpy(lpszEventLogSourceName, _T("System"));
else if(g_fSecurity)
_tcscpy(lpszEventLogSourceName, _T("Security"));
else
{
nRetVal = -1;
goto _cleanup_;
}
hEventLog = OpenEventLog((LPCTSTR)lpUNCServerName, (LPCTSTR)lpszEventLogSourceName);
if(hEventLog)
{
if(GetNumberOfEventLogRecords(hEventLog, &dwEventLogRecords) &&
GetOldestEventLogRecord(hEventLog, &dwOldestEventLogRecord))
{
for(dwEvLogCounter = dwOldestEventLogRecord;
dwEvLogCounter <= (dwOldestEventLogRecord + dwEventLogRecords);
dwEvLogCounter++)
{
if(dwEvLogCounter != dwRecId)
continue;
lpEventLogRecordBuffer = (LPVOID)&chFakeBuffer;
dwNumberOfBytesToRead = 1;
dwMinNumberOfBytesNeeded = 0;
_retry_:
bRetVal = ReadEventLog(hEventLog, EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ,
dwEvLogCounter, lpEventLogRecordBuffer, dwNumberOfBytesToRead,
&dwBytesRead, &dwMinNumberOfBytesNeeded);
if(!bRetVal)
{
g_dwLastError = GetLastError();
if(g_dwLastError == ERROR_INSUFFICIENT_BUFFER)
{
lpEventLogRecordBuffer = (LPVOID)GlobalAlloc(GPTR, dwMinNumberOfBytesNeeded);
if(lpEventLogRecordBuffer == (void *)0)
goto _allocationfailure_;
dwNumberOfBytesToRead = dwMinNumberOfBytesNeeded;
goto _retry_;
}
else
goto _unknownerror_;
}
else
{
PEVENTLOGRECORD pELR = 0;
LPBYTE pData = 0;
HMODULE hModule = 0;
TCHAR szExeFile[_MAX_PATH + 1], szExeFilePath[_MAX_PATH + 1];
HKEY hk = (HKEY)0;
TCHAR szKeyName[_MAX_PATH + 1];
DWORD dwMaxPath;
DWORD dwType;
LPBYTE pStrings = 0;
UINT uStringOffset;
TCHAR *szExpandedString;
LPVOID lpszBuffer = 0;
pELR = (PEVENTLOGRECORD)lpEventLogRecordBuffer;
pData = (LPBYTE)GlobalAlloc(GPTR, pELR->DataLength * sizeof(BYTE));
memcpy(pData, (LPBYTE)((LPBYTE)pELR + pELR->DataOffset), pELR->DataLength);
{
UINT x, uStepOfString = 0;
pStrings = (LPBYTE)GlobalAlloc(GPTR, pELR->DataOffset - pELR->StringOffse
* sizeof(BYTE));
memcpy(pStrings, (LPBYTE)pELR + pELR->StringOffset, pELR->DataOffset
- pELR->StringOffset);
szExpandedString = (TCHAR *)GlobalAlloc(GPTR, (pELR->DataOffset
- pELR->StringOffset + 1024) * sizeof(TCHAR));
for(x = 0; x < pELR->NumStrings; x++)
{
if(x == 0)
{
strcpy(szExpandedString, (TCHAR *)pStrings + uStepOfString);
if(x < (UINT)pELR->NumStrings - 1)
strcat(szExpandedString, ",");
}
else
strcat(szExpandedString, (TCHAR *)pStrings + uStepOfString);
uStepOfString = strlen((TCHAR *)pStrings + uStepOfString) + 1;
}
wsprintf(szKeyName, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s"),
lpszEventLogSourceName, peid->lpszEventName);
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0L, KEY_READ, &hk) == NOERROR)
{
dwMaxPath = _MAX_PATH + 1;
if(RegQueryValueEx(hk, _T("EventMessageFile"), 0, &dwType,
(LPBYTE)szExeFile, &dwMaxPath) == NOERROR)
{
if(ExpandEnvironmentStrings(szExeFile, szExeFilePath, _MAX_PATH + 1) == 0)
strcpy(szExeFilePath, szExeFile);
hModule = LoadLibraryEx(szExeFilePath, 0, DONT_RESOLVE_DLL_REFERENCES);
if(hModule)
{
TCHAR **_sz = (TCHAR**)GlobalAlloc(GPTR, (pELR->NumStrings)
* sizeof(TCHAR *));
register UINT z;
uStringOffset = 0;
for(z = 0; z < pELR->NumStrings; z++)
{
_sz[z] = (TCHAR *)GlobalAlloc(GPTR,
(strlen((TCHAR *)pStrings + uStringOffset) + 1) * sizeof(TCHAR));
strcpy(_sz[z], (TCHAR *)pStrings + uStringOffset);
uStringOffset += strlen((TCHAR *)pStrings + uStringOffset) + 1;
}
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
hModule, pELR->EventID, 0, (LPTSTR)&lpszBuffer, 1024,
_sz
);
for(z = 0; z < pELR->NumStrings; z++)
{
SafeDeletePointer(_sz[z], strlen(_sz[z]));
_sz[z] = 0;
}
SafeDeletePointer(_sz, (pELR->NumStrings) * sizeof(TCHAR *));
_sz = 0;
if(lpszBuffer)
{
strcpy(szExpandedString, (TCHAR *)lpszBuffer);
uStringOffset = strlen(szExpandedString);
}
if(lpszBuffer)
LocalFree(lpszBuffer);
FreeLibrary(hModule);
}
}
RegCloseKey(hk);
}
SendMessage(hwndEditStrings, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)szExpandedString);
SafeDeletePointer(szExpandedString, strlen(szExpandedString));
}
{
TCHAR _str[1024];
_tcscpy(_str, _T(""));
if(pELR->DataLength > 0)
{
register UINT x;
for(x = 0; x < pELR->DataLength; x += 8)
{
TCHAR _strAux[1024];
register UINT y;
wsprintf(_strAux, "%.4x: ", x);
_tcscat(_str, _strAux);
for(y = x; y < x + 8; y++)
{
wsprintf(_strAux, "%.2x ", pData[y]);
_tcscat(_str, _strAux);
}
_tcscat(_str, _T(" "));
for(y = x; y < x + 8; y++)
{
if(!isprint((int)pData[y]))
_tcscat(_str, _T("."));
else
{
TCHAR s[2];
s[0] = (TCHAR)pData[y];
s[1] = '\0';
_tcscat(_str, s);
}
}
_tcscat(_str, _T("\r\n"));
}
}
else
_tcscat(_str, _T("No data available."));
SendMessage(hwndEditData, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)_str);
}
}
}
goto _cleanup_;
}
else
ReportLastError(0, 0, TRUE);
_unknownerror_:
MessageBox(0, TEXT("Unknown error."), 0, MB_OK | MB_ICONSTOP);
goto _cleanup_;
_allocationfailure_:
MessageBox(0, TEXT("Allocation failure."), 0, MB_OK | MB_ICONSTOP);
goto _cleanup_;
_cleanup_:
CloseEventLog(hEventLog);
hEventLog = 0;
}
else
ReportLastError(0, 0, TRUE);
#pragma warning(disable:4127)
SafeDeletePointer(peid, sizeof(EVENTID));
return 0L;
}
Although the string
szExpandedString
is allocated with only 1024 length (so can truncate sometimes thre REAL value), again you can easily
replace with the correct size doing some checkings before. The construction key is now a registry key specific to the record entry, located under
SYSTEM\CurrentControlSet\Sevices\EventLog
key. If opening of this key succeeds and the call of
ExpandEnvironmentStrings
leads to the
binary file where
.mc
message entry resides, then a
LoadLibraryEx
call with the
DONT_RESOLVE_DLL_REFERENCES
flag set (to do not load other DLLs, but rather resource section) will lead us to the necessary .mc resource entry,
which is a entry in the message table (usually created with message compiler tool). Now, the call
FormatMessage
(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
hModule,
pELR->EventID,
0,
(LPTSTR)&lpszBuffer,
1024,
_sz
);
will offers us the message bound with this particular event log entry. The rest is history (hexa formatting, dialog stuff).