* Sync with trunk r64401.
[reactos.git] / base / applications / mscutils / eventvwr / eventvwr.c
index 86b7666..ab71fb9 100644 (file)
@@ -33,6 +33,7 @@
 #include <winreg.h>
 #include <commctrl.h>
 #include <commdlg.h>
+#include <strsafe.h>
 
 #include "resource.h"
 
     #define _CRT_SECURE_NO_DEPRECATE /* all deprecated unsafe string functions */
 #endif
 
-static const LPWSTR EVENT_SOURCE_APPLICATION = L"Application";
-static const LPWSTR EVENT_SOURCE_SECURITY    = L"Security";
-static const LPWSTR EVENT_SOURCE_SYSTEM      = L"System";
 static const WCHAR szWindowClass[]           = L"EVENTVWR"; /* the main window class name*/
+static const WCHAR EVENTLOG_BASE_KEY[]       = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\";
 
-//MessageFile message buffer size
+// MessageFile message buffer size
 #define EVENT_MESSAGE_EVENTTEXT_BUFFER  1024*10
 #define EVENT_MESSAGE_FILE_BUFFER       1024*10
 #define EVENT_DLL_SEPARATOR             L";"
@@ -73,6 +72,9 @@ OPENFILENAMEW sfn;
 LPWSTR lpSourceLogName = NULL;
 LPWSTR lpComputerName  = NULL;
 
+DWORD dwNumLogs = 0;
+WCHAR **LogNames;
+
 /* Forward declarations of functions included in this code module: */
 ATOM MyRegisterClass(HINSTANCE hInstance);
 BOOL InitInstance(HINSTANCE, int);
@@ -201,7 +203,7 @@ BOOL
 GetEventMessageFileDLL(IN LPCWSTR lpLogName,
                        IN LPCWSTR SourceName,
                        IN LPCWSTR EntryName,
-                       OUT LPWSTR ExpandedName)
+                       OUT PWCHAR ExpandedName)
 {
     DWORD dwSize;
     BYTE szModuleName[MAX_PATH];
@@ -210,8 +212,8 @@ GetEventMessageFileDLL(IN LPCWSTR lpLogName,
     HKEY hSourceKey = NULL;
     BOOL bReturn = FALSE;
 
-    wcscpy(szKeyName, L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\");
-    wcscat(szKeyName, lpLogName);
+    StringCbCopyW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\");
+    StringCbCatW(szKeyName, sizeof(szKeyName), lpLogName);
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
                      szKeyName,
@@ -260,7 +262,7 @@ BOOL
 GetEventCategory(IN LPCWSTR KeyName,
                  IN LPCWSTR SourceName,
                  IN EVENTLOGRECORD *pevlr,
-                 OUT LPWSTR CategoryName)
+                 OUT PWCHAR CategoryName)
 {
     HANDLE hLibrary = NULL;
     WCHAR szMessageDLL[MAX_PATH];
@@ -286,7 +288,7 @@ GetEventCategory(IN LPCWSTR KeyName,
                 TrimNulls(lpMsgBuf);
 
                 /* Copy the category name */
-                wcscpy(CategoryName, lpMsgBuf);
+                StringCchCopyW(CategoryName, MAX_PATH, lpMsgBuf);
             }
             else
             {
@@ -314,7 +316,7 @@ BOOL
 GetEventMessage(IN LPCWSTR KeyName,
                 IN LPCWSTR SourceName,
                 IN EVENTLOGRECORD *pevlr,
-                OUT LPWSTR EventText)
+                OUT PWCHAR EventText)
 {
     DWORD i;
     HANDLE hLibrary = NULL;
@@ -393,7 +395,7 @@ GetEventMessage(IN LPCWSTR KeyName,
                         TrimNulls((LPWSTR)lpMsgBuf);
 
                         /* Copy the event text */
-                        wcscpy(EventText ,lpMsgBuf);
+                        StringCchCopyW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, lpMsgBuf);
                     }
                 }
 
@@ -404,7 +406,7 @@ GetEventMessage(IN LPCWSTR KeyName,
         if (!bDone)
         {
             LoadStringW(hInst, IDS_EVENTSTRINGIDNOTFOUND, szStringIDNotFound, MAX_LOADSTRING);
-            swprintf(EventText, szStringIDNotFound, (pevlr->EventID & 0xFFFF), SourceName);
+            StringCchPrintfW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, szStringIDNotFound, (pevlr->EventID & 0xFFFF), SourceName);
         }
 
         free(szArguments);
@@ -414,7 +416,7 @@ GetEventMessage(IN LPCWSTR KeyName,
     }
 
     LoadStringW(hInst, IDS_EVENTSTRINGIDNOTFOUND, szStringIDNotFound, MAX_LOADSTRING);
-    swprintf(EventText, szStringIDNotFound, (pevlr->EventID & 0xFFFF), SourceName);
+    StringCchPrintfW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, szStringIDNotFound, (pevlr->EventID & 0xFFFF), SourceName);
 
     return FALSE;
 }
@@ -422,7 +424,7 @@ GetEventMessage(IN LPCWSTR KeyName,
 
 VOID
 GetEventType(IN WORD dwEventType,
-             OUT LPWSTR eventTypeText)
+             OUT PWCHAR eventTypeText)
 {
     switch (dwEventType)
     {
@@ -452,7 +454,7 @@ GetEventType(IN WORD dwEventType,
 
 BOOL
 GetEventUserName(EVENTLOGRECORD *pelr,
-                 OUT LPWSTR pszUser)
+                 OUT PWCHAR pszUser)
 {
     PSID lpSid;
     WCHAR szName[1024];
@@ -475,7 +477,7 @@ GetEventUserName(EVENTLOGRECORD *pelr,
                              &cbDomain,
                              &peUse))
         {
-            wcscpy(pszUser, szName);
+            StringCchCopyW(pszUser, MAX_PATH, szName);
             return TRUE;
         }
     }
@@ -522,23 +524,24 @@ QueryEventMessages(LPWSTR lpMachineName,
     HANDLE hEventLog;
     EVENTLOGRECORD *pevlr;
     DWORD dwRead, dwNeeded, dwThisRecord, dwTotalRecords = 0, dwCurrentRecord = 0, dwRecordsToRead = 0, dwFlags, dwMaxLength;
+    size_t cchRemaining;
     LPWSTR lpSourceName;
     LPWSTR lpComputerName;
     LPSTR lpData;
     BOOL bResult = TRUE; /* Read succeeded. */
-    int i;
 
     WCHAR szWindowTitle[MAX_PATH];
     WCHAR szStatusText[MAX_PATH];
     WCHAR szLocalDate[MAX_PATH];
     WCHAR szLocalTime[MAX_PATH];
     WCHAR szEventID[MAX_PATH];
-    WCHAR szEventTypeText[MAX_PATH];
+    WCHAR szEventTypeText[MAX_LOADSTRING];
     WCHAR szCategoryID[MAX_PATH];
     WCHAR szUsername[MAX_PATH];
     WCHAR szEventText[EVENT_MESSAGE_FILE_BUFFER];
     WCHAR szCategory[MAX_PATH];
     WCHAR szData[MAX_PATH];
+    PWCHAR lpTitleTemplateEnd;
 
     SYSTEMTIME time;
     LVITEMW lviEventItem;
@@ -648,8 +651,8 @@ QueryEventMessages(LPWSTR lpMachineName,
             GetEventType(pevlr->EventType, szEventTypeText);
             GetEventCategory(lpLogName, lpSourceName, pevlr, szCategory);
 
-            swprintf(szEventID, L"%u", (pevlr->EventID & 0xFFFF));
-            swprintf(szCategoryID, L"%u", pevlr->EventCategory);
+            StringCbPrintfW(szEventID, sizeof(szEventID), L"%u", (pevlr->EventID & 0xFFFF));
+            StringCbPrintfW(szCategoryID, sizeof(szCategoryID), L"%u", pevlr->EventCategory);
 
             lviEventItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
             lviEventItem.iItem = 0;
@@ -712,16 +715,20 @@ QueryEventMessages(LPWSTR lpMachineName,
     // All events loaded
     EndDialog(hwndDlg, 0);
 
-
-    i = swprintf(szWindowTitle, szTitleTemplate, szTitle, lpLogName); /* i = number of characters written */
+    StringCchPrintfExW(szWindowTitle,
+                       sizeof(szWindowTitle) / sizeof(WCHAR),
+                       &lpTitleTemplateEnd,
+                       &cchRemaining,
+                       0,
+                       szTitleTemplate, szTitle, lpLogName); /* i = number of characters written */
     /* lpComputerName can be NULL here if no records was read */
-    dwMaxLength = sizeof(szWindowTitle) / sizeof(WCHAR) - i;
-    if(!lpComputerName)
-        GetComputerNameW(szWindowTitle+i, &dwMaxLength);
+    dwMaxLength = cchRemaining;
+    if (!lpComputerName)
+        GetComputerNameW(lpTitleTemplateEnd, &dwMaxLength);
     else
-        _snwprintf(szWindowTitle+i, dwMaxLength, L"%s", lpComputerName);
+        StringCchCopyW(lpTitleTemplateEnd, dwMaxLength, lpComputerName);
 
-    swprintf(szStatusText, szStatusBarTemplate, lpLogName, dwTotalRecords);
+    StringCbPrintfW(szStatusText, sizeof(szStatusText), szStatusBarTemplate, lpLogName, dwTotalRecords);
 
     // Update the status bar
     SendMessageW(hwndStatus, SB_SETTEXT, (WPARAM)0, (LPARAM)szStatusText);
@@ -791,7 +798,6 @@ ClearEvents(VOID)
         case IDCANCEL:
         {
             return FALSE;
-            break;
         }
 
         case IDNO:
@@ -838,19 +844,6 @@ Refresh(VOID)
 }
 
 
-//
-//  FUNCTION: MyRegisterClass()
-//
-//  PURPOSE: Registers the window class.
-//
-//  COMMENTS:
-//
-//    This function and its usage are only necessary if you want this code
-//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
-//    function that was added to Windows 95. It is important to call this function
-//    so that the application will get 'well formed' small icons associated
-//    with it.
-//
 ATOM
 MyRegisterClass(HINSTANCE hInstance)
 {
@@ -874,16 +867,190 @@ MyRegisterClass(HINSTANCE hInstance)
 }
 
 
-//
-//   FUNCTION: InitInstance(HINSTANCE, int)
-//
-//   PURPOSE: Saves instance handle and creates main window
-//
-//   COMMENTS:
-//
-//        In this function, we save the instance handle in a global variable and
-//        create and display the main program window.
-//
+VOID
+GetDisplayNameFile(IN LPCWSTR lpLogName,
+                   OUT PWCHAR lpModuleName)
+{
+    HKEY hKey;
+    WCHAR *KeyPath;
+    WCHAR szModuleName[MAX_PATH];
+    DWORD cbData;
+    DWORD cbKeyPath;
+
+    cbKeyPath = (wcslen(EVENTLOG_BASE_KEY) + wcslen(lpLogName) + 1) * sizeof(WCHAR);
+    KeyPath = HeapAlloc(GetProcessHeap(), 0, cbKeyPath);
+    if (!KeyPath)
+    {
+        return;
+    }
+
+    StringCbCopyW(KeyPath, cbKeyPath, EVENTLOG_BASE_KEY);
+    StringCbCatW(KeyPath, cbKeyPath, lpLogName);
+
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, KeyPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
+    {
+        HeapFree(GetProcessHeap(), 0, KeyPath);
+        return;
+    }
+
+    cbData = sizeof(szModuleName);
+    if (RegQueryValueExW(hKey, L"DisplayNameFile", NULL, NULL, (LPBYTE)szModuleName, &cbData) == ERROR_SUCCESS)
+    {
+        ExpandEnvironmentStringsW(szModuleName, lpModuleName, MAX_PATH);
+    }
+
+    RegCloseKey(hKey);
+    HeapFree(GetProcessHeap(), 0, KeyPath);
+}
+
+
+DWORD
+GetDisplayNameID(IN LPCWSTR lpLogName)
+{
+    HKEY hKey;
+    WCHAR *KeyPath;
+    DWORD dwMessageID = 0;
+    DWORD cbData;
+    DWORD cbKeyPath;
+
+    cbKeyPath = (wcslen(EVENTLOG_BASE_KEY) + wcslen(lpLogName) + 1) * sizeof(WCHAR);
+    KeyPath = HeapAlloc(GetProcessHeap(), 0, cbKeyPath);
+    if (!KeyPath)
+    {
+        return 0;
+    }
+
+    StringCbCopyW(KeyPath, cbKeyPath, EVENTLOG_BASE_KEY);
+    StringCbCatW(KeyPath, cbKeyPath, lpLogName);
+
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, KeyPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
+    {
+        HeapFree(GetProcessHeap(), 0, KeyPath);
+        return 0;
+    }
+
+    cbData = sizeof(dwMessageID);
+    RegQueryValueExW(hKey, L"DisplayNameID", NULL, NULL, (LPBYTE)&dwMessageID, &cbData);
+
+    RegCloseKey(hKey);
+    HeapFree(GetProcessHeap(), 0, KeyPath);
+
+    return dwMessageID;
+}
+
+
+VOID
+BuildLogList(void)
+{
+    HKEY hKey;
+    DWORD lpcName;
+    DWORD dwIndex;
+    DWORD dwMessageID;
+    DWORD dwMaxKeyLength;
+    WCHAR szModuleName[MAX_PATH];
+    LPWSTR lpDisplayName;
+    HANDLE hLibrary = NULL;
+
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, EVENTLOG_BASE_KEY, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
+    {
+        return;
+    }
+
+    if (RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwNumLogs, &dwMaxKeyLength, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+    {
+        RegCloseKey(hKey);
+        return;
+    }
+
+    if (!dwNumLogs)
+    {
+        RegCloseKey(hKey);
+        return;
+    }
+
+    LogNames = HeapAlloc(GetProcessHeap(), 0, (dwNumLogs + 1) * sizeof(WCHAR*));
+
+    if (!LogNames)
+    {
+        RegCloseKey(hKey);
+        return;
+    }
+
+    for (dwIndex = 0; dwIndex < dwNumLogs; dwIndex++)
+    {
+        LogNames[dwIndex] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((dwMaxKeyLength + 1) * sizeof(WCHAR)));
+
+        if (LogNames[dwIndex] != NULL)
+        {
+            lpcName = dwMaxKeyLength + 1;
+
+            if (RegEnumKeyExW(hKey, dwIndex, LogNames[dwIndex], &lpcName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
+            {
+                lpDisplayName = NULL;
+
+                ZeroMemory(szModuleName, sizeof(szModuleName));
+                GetDisplayNameFile(LogNames[dwIndex], szModuleName);
+                dwMessageID = GetDisplayNameID(LogNames[dwIndex]);
+
+                hLibrary = LoadLibraryExW(szModuleName, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
+                if (hLibrary != NULL)
+                {
+                    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE, hLibrary, dwMessageID, 0, (LPWSTR)&lpDisplayName, 0, NULL);
+                    FreeLibrary(hLibrary);
+                }
+
+                if (lpDisplayName)
+                {
+                    InsertMenuW(hMainMenu, ID_SAVE_PROTOCOL, MF_BYCOMMAND | MF_STRING, ID_FIRST_LOG + dwIndex, lpDisplayName);
+                }
+                else
+                {
+                    InsertMenuW(hMainMenu, ID_SAVE_PROTOCOL, MF_BYCOMMAND | MF_STRING, ID_FIRST_LOG + dwIndex, LogNames[dwIndex]);
+                }
+
+                LocalFree(lpDisplayName);
+            }
+        }
+    }
+
+    InsertMenuW(hMainMenu, ID_SAVE_PROTOCOL, MF_BYCOMMAND | MF_SEPARATOR, ID_FIRST_LOG + dwIndex + 1, NULL);
+
+    RegCloseKey(hKey);
+
+    return;
+}
+
+
+VOID
+FreeLogList(void)
+{
+    DWORD dwIndex;
+
+    if (!LogNames)
+    {
+        return;
+    }
+
+    for (dwIndex = 0; dwIndex < dwNumLogs; dwIndex++)
+    {
+        if (LogNames[dwIndex])
+        {
+            HeapFree(GetProcessHeap(), 0, LogNames[dwIndex]);
+        }
+
+        DeleteMenu(hMainMenu, ID_FIRST_LOG + dwIndex, MF_BYCOMMAND);
+    }
+
+    DeleteMenu(hMainMenu, ID_FIRST_LOG + dwIndex + 1, MF_BYCOMMAND);
+
+    HeapFree(GetProcessHeap(), 0, LogNames);
+
+    dwNumLogs = 0;
+
+    return;
+}
+
+
 BOOL
 InitInstance(HINSTANCE hInstance,
              int nCmdShow)
@@ -1042,23 +1209,16 @@ InitInstance(HINSTANCE hInstance,
     ShowWindow(hwndMainWindow, nCmdShow);
     UpdateWindow(hwndMainWindow);
 
-    QueryEventMessages(lpComputerName,            // Use the local computer.
-                       EVENT_SOURCE_APPLICATION); // The event log category
+    BuildLogList();
+
+    QueryEventMessages(lpComputerName, LogNames[0]);
+
+    CheckMenuRadioItem(GetMenu(hwndMainWindow), ID_FIRST_LOG, ID_FIRST_LOG + dwNumLogs, ID_FIRST_LOG, MF_BYCOMMAND);
 
     return TRUE;
 }
 
 
-//
-//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
-//
-//  PURPOSE:  Processes messages for the main window.
-//
-//  WM_COMMAND - process the application menu
-//  WM_PAINT   - Paint the main window
-//  WM_DESTROY - post a quit message and return
-//
-//
 LRESULT CALLBACK
 WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
@@ -1069,11 +1229,6 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
     {
         case WM_CREATE:
             hMainMenu = GetMenu(hWnd);
-            CheckMenuRadioItem(GetMenu(hWnd),
-                               ID_LOG_APPLICATION,
-                               ID_LOG_SYSTEM,
-                               ID_LOG_APPLICATION,
-                               MF_BYCOMMAND);
             break;
 
         case WM_NOTIFY:
@@ -1099,44 +1254,21 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 
         case WM_COMMAND:
             // Parse the menu selections:
-            switch (LOWORD(wParam))
-            {
-                case ID_LOG_APPLICATION:
-                    if (QueryEventMessages(lpComputerName,            // Use the local computer.
-                                           EVENT_SOURCE_APPLICATION)) // The event log category
-                    {
-                        CheckMenuRadioItem(GetMenu(hWnd),
-                                           ID_LOG_APPLICATION,
-                                           ID_LOG_SYSTEM,
-                                           ID_LOG_APPLICATION,
-                                           MF_BYCOMMAND);
-                    }
-                    break;
 
-                case ID_LOG_SECURITY:
-                    if (QueryEventMessages(lpComputerName,         // Use the local computer.
-                                           EVENT_SOURCE_SECURITY)) // The event log category
-                    {
-                        CheckMenuRadioItem(GetMenu(hWnd),
-                                           ID_LOG_APPLICATION,
-                                           ID_LOG_SYSTEM,
-                                           ID_LOG_SECURITY,
-                                           MF_BYCOMMAND);
-                    }
-                    break;
-
-                case ID_LOG_SYSTEM:
-                    if (QueryEventMessages(lpComputerName,       // Use the local computer.
-                                           EVENT_SOURCE_SYSTEM)) // The event log category
+            if ((LOWORD(wParam) >= ID_FIRST_LOG) && (LOWORD(wParam) <= ID_FIRST_LOG + dwNumLogs))
+            {
+                if (LogNames[LOWORD(wParam) - ID_FIRST_LOG])
+                {
+                    if (QueryEventMessages(lpComputerName, LogNames[LOWORD(wParam) - ID_FIRST_LOG]))
                     {
-                        CheckMenuRadioItem(GetMenu(hWnd),
-                                           ID_LOG_APPLICATION,
-                                           ID_LOG_SYSTEM,
-                                           ID_LOG_SYSTEM,
-                                           MF_BYCOMMAND);
+                        CheckMenuRadioItem(GetMenu(hWnd), ID_FIRST_LOG, ID_FIRST_LOG + dwNumLogs, LOWORD(wParam), MF_BYCOMMAND);
                     }
-                    break;
+                }
+            }
+            else
 
+            switch (LOWORD(wParam))
+            {
                 case ID_SAVE_PROTOCOL:
                     SaveProtocol();
                     break;
@@ -1191,6 +1323,7 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
             break;
         case WM_DESTROY:
             FreeRecords();
+            FreeLogList();
             PostQuitMessage(0);
             break;