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/eventvwr/eventvwr.c?rev=73749&r1=73748&r2=73749&view=diff
==============================================================================
--- 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)


Reply via email to