Author: khornicek
Date: Tue Feb 7 22:33:02 2017
New Revision: 73749
URL:
http://svn.reactos.org/svn/reactos?rev=73749&view=rev
Log:
[EVENTVWR]
- Attempt to speed up loading and displaying logs in EnumEventsThread:
- Rewriting the code fix an infinite loop that could happen under low memory conditions
(this potentially speeds things up quite a lot).
- Remove ListView subclassing - sorry Hermès but not only it keeps constantly redrawing
under Windows but also adds too much overhead.
- Don't read the event log records one by one but in chunks of roughly 0x7ffff bytes
(maximum size allowed).
- Use poor man's "caching" of the event user name (optimizing/caching rest
of the stuff in the loop didn't yield any significant speed up).
Result: Loading ~40000 records under Win7 went from 4.5 minutes to 65 seconds.
Modified:
trunk/reactos/base/applications/mscutils/eventvwr/eventvwr.c
Modified: trunk/reactos/base/applications/mscutils/eventvwr/eventvwr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/mscutils…
==============================================================================
--- trunk/reactos/base/applications/mscutils/eventvwr/eventvwr.c [iso-8859-1] (original)
+++ trunk/reactos/base/applications/mscutils/eventvwr/eventvwr.c [iso-8859-1] Tue Feb 7
22:33:02 2017
@@ -124,7 +124,6 @@
ATOM MyRegisterClass(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
-VOID ExitInstance(HINSTANCE);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR EventLogProperties(HINSTANCE, HWND, PEVENTLOGFILTER);
INT_PTR CALLBACK EventDetails(HWND, UINT, WPARAM, LPARAM);
@@ -226,8 +225,6 @@
CloseHandle(hStartEnumEvent);
if (hStartStopEnumEvent)
CloseHandle(hStartStopEnumEvent);
-
- ExitInstance(hInstance);
Quit:
FreeLibrary(hRichEdit);
@@ -1091,9 +1088,10 @@
if (!Success)
{
if (pevlr->EventCategory != 0)
+ {
StringCchPrintfW(CategoryName, MAX_PATH, L"(%lu)",
pevlr->EventCategory);
- else
- LoadStringW(hInst, IDS_NONE, CategoryName, MAX_PATH);
+ Success = TRUE;
+ }
}
return Success;
@@ -1263,18 +1261,30 @@
BOOL
GetEventUserName(IN PEVENTLOGRECORD pelr,
+ IN OUT PSID pLastSid,
OUT PWCHAR pszUser) // TODO: Add IN DWORD BufLen
{
- PSID pSid;
+ PSID pCurrentSid;
PWSTR StringSid;
WCHAR szName[1024];
WCHAR szDomain[1024];
SID_NAME_USE peUse;
DWORD cchName = ARRAYSIZE(szName);
DWORD cchDomain = ARRAYSIZE(szDomain);
+ BOOL Success;
/* Point to the SID */
- pSid = (PSID)((LPBYTE)pelr + pelr->UserSidOffset);
+ pCurrentSid = (PSID)((LPBYTE)pelr + pelr->UserSidOffset);
+
+ if (!IsValidSid(pCurrentSid))
+ {
+ pLastSid = NULL;
+ return FALSE;
+ }
+ else if (pLastSid && EqualSid(pLastSid, pCurrentSid))
+ {
+ return TRUE;
+ }
/* User SID */
if (pelr->UserSidLength > 0)
@@ -1286,7 +1296,7 @@
* 'pszUser', otherwise we return an error.
*/
if (LookupAccountSidW(NULL, // FIXME: Use computer name? From the particular
event?
- pSid,
+ pCurrentSid,
szName,
&cchName,
szDomain,
@@ -1294,13 +1304,11 @@
&peUse))
{
StringCchCopyW(pszUser, MAX_PATH, szName);
- return TRUE;
- }
- else if (ConvertSidToStringSidW(pSid, &StringSid))
- {
- BOOL Success;
-
- /* Copy the string only if the user-provided buffer is small enough */
+ Success = TRUE;
+ }
+ else if (ConvertSidToStringSidW(pCurrentSid, &StringSid))
+ {
+ /* Copy the string only if the user-provided buffer is big enough */
if (wcslen(StringSid) + 1 <= MAX_PATH) // + 1 for NULL-terminator
{
StringCchCopyW(pszUser, MAX_PATH, StringSid);
@@ -1314,12 +1322,12 @@
/* Free the allocated buffer */
LocalFree(StringSid);
-
- return Success;
- }
- }
-
- return FALSE;
+ }
+ }
+
+ pLastSid = Success ? pCurrentSid : NULL;
+
+ return Success;
}
@@ -1422,14 +1430,18 @@
ULONG LogIndex;
HANDLE hEventLog;
- PEVENTLOGRECORD pevlr, pevlrTmp = NULL;
- DWORD dwRead, dwNeeded; // , dwThisRecord;
+ PEVENTLOGRECORD pEvlr;
+ PBYTE pEvlrEnd;
+ PBYTE pEvlrBuffer;
+ DWORD dwWanted, dwRead, dwNeeded, dwStatus = ERROR_SUCCESS;
DWORD dwTotalRecords = 0, dwCurrentRecord = 0;
DWORD dwFlags, dwMaxLength;
size_t cchRemaining;
LPWSTR lpszSourceName;
LPWSTR lpszComputerName;
BOOL bResult = TRUE; /* Read succeeded */
+ HANDLE hProcessHeap = GetProcessHeap();
+ PSID pLastSid = NULL;
UINT uStep = 0, uStepAt = 0, uPos = 0;
@@ -1441,7 +1453,9 @@
WCHAR szEventTypeText[MAX_LOADSTRING];
WCHAR szCategoryID[MAX_PATH];
WCHAR szUsername[MAX_PATH];
+ WCHAR szNoUsername[MAX_PATH];
WCHAR szCategory[MAX_PATH];
+ WCHAR szNoCategory[MAX_PATH];
PWCHAR lpTitleTemplateEnd;
SYSTEMTIME time;
@@ -1500,131 +1514,119 @@
}
/* Set up the event records cache */
- g_RecordPtrs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwTotalRecords *
sizeof(*g_RecordPtrs));
+ g_RecordPtrs = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwTotalRecords *
sizeof(*g_RecordPtrs));
if (!g_RecordPtrs)
{
// ShowLastWin32Error();
- goto Cleanup;
+ goto Quit;
}
g_TotalRecords = dwTotalRecords;
if (WaitForSingleObject(hStopEnumEvent, 0) == WAIT_OBJECT_0)
goto Quit;
+ LoadStringW(hInst, IDS_NOT_AVAILABLE, szNoUsername, ARRAYSIZE(szNoUsername));
+ LoadStringW(hInst, IDS_NONE, szNoCategory, ARRAYSIZE(szNoCategory));
+
ProgressBar_SetRange(hwndStatusProgress, MAKELPARAM(0, 100));
uStepAt = (dwTotalRecords / 100) + 1;
- dwFlags = EVENTLOG_SEQUENTIAL_READ |
- (NewestEventsFirst ? EVENTLOG_FORWARDS_READ
- : EVENTLOG_BACKWARDS_READ);
-
- while (dwCurrentRecord < dwTotalRecords)
- {
- //
- // NOTE: We always allocate the minimum size for 1 record, and if
- // the ReadEventLog call fails (it always will anyway), we reallocate
- // the record pointer to be able to hold just 1 record, and then we
- // redo that for each event.
- // This is obviously not at all efficient (in terms of numbers of
- // ReadEventLog calls), since ReadEventLog can fill the buffer with
- // as many records they can fit completely in the buffer.
- //
-
- pevlr = HeapAlloc(GetProcessHeap(), 0, sizeof(*pevlr));
- if (!pevlr)
- {
- /* Cannot allocate, just skip the event */
+ dwFlags = EVENTLOG_SEQUENTIAL_READ | (NewestEventsFirst ? EVENTLOG_FORWARDS_READ :
EVENTLOG_BACKWARDS_READ);
+
+ /* 0x7ffff is the maximum buffer size ReadEventLog will accept */
+ dwWanted = 0x7ffff;
+ pEvlr = HeapAlloc(hProcessHeap, 0, dwWanted);
+
+ if (!pEvlr)
+ goto Quit;
+
+ while (dwStatus == ERROR_SUCCESS)
+ {
+ bResult = ReadEventLogW(hEventLog, dwFlags, 0, pEvlr, dwWanted, &dwRead,
&dwNeeded);
+ dwStatus = GetLastError();
+
+ if (!bResult && dwStatus == ERROR_INSUFFICIENT_BUFFER)
+ {
+ pEvlr = HeapReAlloc(hProcessHeap, 0, pEvlr, dwNeeded);
+ dwWanted = dwNeeded;
+
+ if (!pEvlr)
+ break;
+
+ bResult = ReadEventLogW(hEventLog, dwFlags, 0, pEvlr, dwNeeded, &dwRead,
&dwNeeded);
+
+ if (!bResult)
+ break;
+ }
+ else if (!bResult)
+ {
+ /* exit on other errors (ERROR_HANDLE_EOF) */
+ break;
+ }
+
+ pEvlrBuffer = (LPBYTE)pEvlr;
+ pEvlrEnd = pEvlrBuffer + dwRead;
+
+ while (pEvlrBuffer < pEvlrEnd)
+ {
+ PEVENTLOGRECORD pEvlrTmp = (PEVENTLOGRECORD)pEvlrBuffer;
+ PWSTR lpszUsername, lpszCategoryName;
g_RecordPtrs[dwCurrentRecord] = NULL;
- // --dwTotalRecords;
- continue;
- }
- g_RecordPtrs[dwCurrentRecord] = pevlr;
-
- bResult = ReadEventLogW(hEventLog, // Event log handle
- dwFlags, // Sequential read
- 0, // Ignored for sequential read
- pevlr, // Pointer to buffer
- sizeof(*pevlr), // Size of buffer
- &dwRead, // Number of bytes read
- &dwNeeded); // Bytes in the next record
- if (!bResult && (GetLastError () == ERROR_INSUFFICIENT_BUFFER))
- {
- pevlrTmp = HeapReAlloc(GetProcessHeap(), 0, pevlr, dwNeeded);
- if (!pevlrTmp)
- {
- /* Cannot reallocate, just skip the event */
- HeapFree(GetProcessHeap(), 0, pevlr);
- g_RecordPtrs[dwCurrentRecord] = NULL;
- // --dwTotalRecords;
- continue;
- }
- pevlr = pevlrTmp;
- g_RecordPtrs[dwCurrentRecord] = pevlr;
-
- ReadEventLogW(hEventLog, // event log handle
- dwFlags, // read flags
- 0, // offset; default is 0
- pevlr, // pointer to buffer
- dwNeeded, // size of buffer
- &dwRead, // number of bytes read
- &dwNeeded); // bytes in next record
- }
-
- while (dwRead > 0)
- {
+
// ProgressBar_StepIt(hwndStatusProgress);
uStep++;
- if(uStep % uStepAt == 0)
+ if (uStep % uStepAt == 0)
{
++uPos;
ProgressBar_SetPos(hwndStatusProgress, uPos);
}
- if (WaitForSingleObject(hStopEnumEvent, 0) == WAIT_OBJECT_0)
+ if (WaitForSingleObject(hStopEnumEvent, 0) == WAIT_OBJECT_0)
goto Quit;
/* Filter by event type */
- if (!FilterByType(EventLogFilter, pevlr))
+ if (!FilterByType(EventLogFilter, pEvlrTmp))
goto SkipEvent;
/* Get the event source name and filter it */
- lpszSourceName = (LPWSTR)((LPBYTE)pevlr + sizeof(EVENTLOGRECORD));
+ lpszSourceName = (LPWSTR)(pEvlrBuffer + sizeof(EVENTLOGRECORD));
if (!FilterByString(EventLogFilter->Sources, lpszSourceName))
goto SkipEvent;
/* Get the computer name and filter it */
- lpszComputerName = (LPWSTR)((LPBYTE)pevlr + sizeof(EVENTLOGRECORD) +
(wcslen(lpszSourceName) + 1) * sizeof(WCHAR));
+ lpszComputerName = (LPWSTR)((LPBYTE)pEvlrBuffer + sizeof(EVENTLOGRECORD) +
(wcslen(lpszSourceName) + 1) * sizeof(WCHAR));
if (!FilterByString(EventLogFilter->ComputerNames, lpszComputerName))
goto SkipEvent;
/* Compute the event time */
- EventTimeToSystemTime(pevlr->TimeWritten, &time);
+ EventTimeToSystemTime(pEvlrTmp->TimeWritten, &time);
GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL,
szLocalDate, ARRAYSIZE(szLocalDate));
GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &time, NULL, szLocalTime,
ARRAYSIZE(szLocalTime));
- LoadStringW(hInst, IDS_NOT_AVAILABLE, szUsername, ARRAYSIZE(szUsername));
- LoadStringW(hInst, IDS_NONE, szCategory, ARRAYSIZE(szCategory));
-
/* Get the username that generated the event, and filter it */
- GetEventUserName(pevlr, szUsername);
- if (!FilterByString(EventLogFilter->Users, szUsername))
+ lpszUsername = GetEventUserName(pEvlrTmp, pLastSid, szUsername) ? szUsername
: szNoUsername;
+
+ if (!FilterByString(EventLogFilter->Users, lpszUsername))
goto SkipEvent;
// TODO: Filter by event ID and category
-
- GetEventType(pevlr->EventType, szEventTypeText);
- GetEventCategory(EventLog->LogName, lpszSourceName, pevlr, szCategory);
-
- StringCbPrintfW(szEventID, sizeof(szEventID), L"%u",
(pevlr->EventID & 0xFFFF));
- StringCbPrintfW(szCategoryID, sizeof(szCategoryID), L"%u",
pevlr->EventCategory);
+ GetEventType(pEvlrTmp->EventType, szEventTypeText);
+
+ lpszCategoryName = GetEventCategory(EventLog->LogName, lpszSourceName,
pEvlrTmp, szCategory) ? szCategory : szNoCategory;
+
+ StringCbPrintfW(szEventID, sizeof(szEventID), L"%u",
(pEvlrTmp->EventID & 0xFFFF));
+ StringCbPrintfW(szCategoryID, sizeof(szCategoryID), L"%u",
pEvlrTmp->EventCategory);
+
+ g_RecordPtrs[dwCurrentRecord] = HeapAlloc(hProcessHeap, 0,
pEvlrTmp->Length);
+ RtlCopyMemory(g_RecordPtrs[dwCurrentRecord], pEvlrTmp, pEvlrTmp->Length);
lviEventItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
lviEventItem.iItem = 0;
lviEventItem.iSubItem = 0;
- lviEventItem.lParam = (LPARAM)pevlr;
+ lviEventItem.lParam = (LPARAM)g_RecordPtrs[dwCurrentRecord];
lviEventItem.pszText = szEventTypeText;
- switch (pevlr->EventType)
+ switch (pEvlrTmp->EventType)
{
case EVENTLOG_SUCCESS:
case EVENTLOG_INFORMATION_TYPE:
@@ -1653,20 +1655,21 @@
ListView_SetItemText(hwndListView, lviEventItem.iItem, 1, szLocalDate);
ListView_SetItemText(hwndListView, lviEventItem.iItem, 2, szLocalTime);
ListView_SetItemText(hwndListView, lviEventItem.iItem, 3, lpszSourceName);
- ListView_SetItemText(hwndListView, lviEventItem.iItem, 4, szCategory);
+ ListView_SetItemText(hwndListView, lviEventItem.iItem, 4, lpszCategoryName);
ListView_SetItemText(hwndListView, lviEventItem.iItem, 5, szEventID);
- ListView_SetItemText(hwndListView, lviEventItem.iItem, 6, szUsername);
+ ListView_SetItemText(hwndListView, lviEventItem.iItem, 6, lpszUsername);
ListView_SetItemText(hwndListView, lviEventItem.iItem, 7, lpszComputerName);
SkipEvent:
- dwRead -= pevlr->Length;
- pevlr = (PEVENTLOGRECORD)((LPBYTE) pevlr + pevlr->Length);
- }
-
- dwCurrentRecord++;
+ pEvlrBuffer += pEvlrTmp->Length;
+ dwCurrentRecord++;
+ }
}
Quit:
+
+ if (pEvlr)
+ HeapFree(hProcessHeap, 0, pEvlr);
/* Close the event log */
CloseEventLog(hEventLog);
@@ -2405,135 +2408,6 @@
return;
}
-
-/*
- * ListView subclassing to handle WM_PAINT messages before and after they are
- * handled by the ListView window itself. We cannot use at this level the
- * custom-drawn notifications that are more suitable for drawing elements
- * inside the ListView.
- */
-static WNDPROC orgListViewWndProc = NULL;
-static BOOL IsLoading = FALSE;
-
-LRESULT CALLBACK
-ListViewWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- switch (uMsg)
- {
- case LVM_PROGRESS:
- {
- /* TRUE: Create the dialog; FALSE: Destroy the dialog */
- IsLoading = !!(BOOL)lParam;
- return IsLoading;
- }
-
- case WM_PAINT:
- {
- /* This code is adapted from:
http://www.codeproject.com/Articles/216/Indicating-an-empty-ListView */
-
- int nItemCount;
-
- PAINTSTRUCT ps;
- HDC hDC;
- HWND hwndHeader;
- RECT rc, rcH;
- COLORREF crTextOld, crTextBkOld;
- NONCLIENTMETRICSW ncm;
- HFONT hFont, hFontOld;
- LPWSTR lpszString;
-
- nItemCount = ListView_GetItemCount(hWnd);
- if (!IsLoading && nItemCount > 0)
- break;
-
- /*
- * NOTE:
- * We could have used lpNMCustomDraw->nmcd.rc for the rectangle,
- * but this one actually holds the rectangle of the list view
- * that is being currently repainted, so that it can be smaller
- * than the list view proper. This is especially true when using
- * COMCTL32.DLL version <= 6.0 .
- */
-
- GetClientRect(hWnd, &rc);
- hwndHeader = ListView_GetHeader(hWnd);
- if (hwndHeader)
- {
- /* Note that we could also use Header_GetItemRect() */
- GetClientRect(hwndHeader, &rcH);
- rc.top += rcH.bottom;
- }
-
- /* Add some space between the top of the list view and the text */
- rc.top += 10;
-
- BeginPaint(hWnd, &ps);
- /*
- * NOTE: Using a secondary hDC (and not the ps.hdc) gives the strange
- * property that the text is always recentered on the current view of
- * the window, instead of being scrolled together with the contents of
- * the list view...
- */
- // hDC = ps.hdc;
- hDC = GetDC(hWnd);
-
- /*
- * NOTE: We could have kept lpNMCustomDraw->clrText and
- * lpNMCustomDraw->clrTextBk, but they usually do not contain
- * the correct default colors for the items / default text.
- */
- crTextOld =
- SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
- crTextBkOld =
- SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
-
- // FIXME: Cache the font?
- ncm.cbSize = sizeof(ncm);
- hFont = NULL;
- if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
- sizeof(ncm), &ncm, 0))
- {
- hFont = CreateFontIndirectW(&ncm.lfMessageFont);
- }
- if (!hFont)
- hFont = GetStockFont(DEFAULT_GUI_FONT);
-
- hFontOld = (HFONT)SelectObject(hDC, hFont);
-
- FillRect(hDC, &rc, GetSysColorBrush(COLOR_WINDOW));
-
- if (nItemCount <= 0)
- lpszString = szEmptyList;
- else // if (IsLoading)
- lpszString = szLoadingWait;
-
- DrawTextW(hDC,
- lpszString,
- -1,
- &rc,
- DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_NOCLIP);
-
- SelectObject(hDC, hFontOld);
- if (hFont)
- DeleteObject(hFont);
-
- SetBkColor(hDC, crTextBkOld);
- SetTextColor(hDC, crTextOld);
-
- ReleaseDC(hWnd, hDC);
- EndPaint(hWnd, &ps);
-
- break;
- }
-
- // case WM_ERASEBKGND:
- // break;
- }
-
- /* Continue with default message processing */
- return CallWindowProcW(orgListViewWndProc, hWnd, uMsg, wParam, lParam);
-}
-
BOOL
InitInstance(HINSTANCE hInstance,
int nCmdShow)
@@ -2748,11 +2622,6 @@
lvc.pszText = szTemp;
ListView_InsertColumn(hwndListView, 7, &lvc);
- /* Subclass the ListView */
- // orgListViewWndProc = SubclassWindow(hwndListView, ListViewWndProc);
- orgListViewWndProc = (WNDPROC)(LONG_PTR)GetWindowLongPtrW(hwndListView,
GWLP_WNDPROC);
- SetWindowLongPtrW(hwndListView, GWLP_WNDPROC, (LONG_PTR)ListViewWndProc);
-
/* Initialize the save Dialog */
ZeroMemory(&sfn, sizeof(sfn));
ZeroMemory(szSaveFilter, sizeof(szSaveFilter));
@@ -2771,15 +2640,6 @@
UpdateWindow(hwndMainWindow);
return TRUE;
-}
-
-VOID
-ExitInstance(HINSTANCE hInstance)
-{
- /* Restore the original ListView WndProc */
- // SubclassWindow(hwndListView, orgListViewWndProc);
- SetWindowLongPtrW(hwndListView, GWLP_WNDPROC, (LONG_PTR)orgListViewWndProc);
- orgListViewWndProc = NULL;
}
VOID ResizeWnd(INT cx, INT cy)