* Sync with trunk r64401.
[reactos.git] / base / applications / mscutils / eventvwr / eventvwr.c
index 4bf6442..ab71fb9 100644 (file)
 #include <windef.h>
 #include <winbase.h>
 #include <winuser.h>
+#include <wingdi.h>
 #include <winnls.h>
 #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 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";"
@@ -58,16 +59,22 @@ static const WCHAR szWindowClass[]          = L"EVENTVWR"; /* the main window cl
 HINSTANCE hInst;                            /* current instance */
 WCHAR szTitle[MAX_LOADSTRING];              /* The title bar text */
 WCHAR szTitleTemplate[MAX_LOADSTRING];      /* The logged-on title bar text */
+WCHAR szSaveFilter[MAX_LOADSTRING];         /* Filter Mask for the save Dialog */
 HWND hwndMainWindow;                        /* Main window */
 HWND hwndListView;                          /* ListView control */
 HWND hwndStatus;                            /* Status bar */
+HMENU hMainMenu;                            /* The application's main menu */
 WCHAR szStatusBarTemplate[MAX_LOADSTRING];  /* The status bar text */
 PEVENTLOGRECORD *g_RecordPtrs = NULL;
 DWORD g_TotalRecords = 0;
+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);
@@ -137,6 +144,25 @@ static void FreeRecords(void)
     g_RecordPtrs = NULL;
 }
 
+VOID
+ShowLastWin32Error(VOID)
+{
+    DWORD dwError;
+    LPWSTR lpMessageBuffer;
+
+    dwError = GetLastError();
+    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                   NULL,
+                   dwError,
+                   0,
+                   (LPWSTR)&lpMessageBuffer,
+                   0,
+                   NULL);
+
+    MessageBoxW(hwndMainWindow, lpMessageBuffer, szTitle, MB_OK | MB_ICONERROR);
+    LocalFree(lpMessageBuffer);
+}
+
 VOID
 EventTimeToSystemTime(DWORD EventTime,
                       SYSTEMTIME *pSystemTime)
@@ -177,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];
@@ -186,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,
@@ -219,10 +245,7 @@ GetEventMessageFileDLL(IN LPCWSTR lpLogName,
     }
     else
     {
-        MessageBoxW(NULL,
-                   L"Registry access failed!",
-                   L"Event Log",
-                   MB_OK | MB_ICONINFORMATION);
+        ShowLastWin32Error();
     }
 
     if (hSourceKey != NULL)
@@ -239,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];
@@ -261,18 +284,11 @@ GetEventCategory(IN LPCWSTR KeyName,
                               EVENT_MESSAGE_FILE_BUFFER,
                               NULL) != 0)
             {
-                if (lpMsgBuf)
-                {
-                    /* Trim the string */
-                    TrimNulls((LPWSTR)lpMsgBuf);
+                /* Trim the string */
+                TrimNulls(lpMsgBuf);
 
-                    /* Copy the category name */
-                    wcscpy(CategoryName, (LPCWSTR)lpMsgBuf);
-                }
-                else
-                {
-                    wcscpy(CategoryName, (LPCWSTR)lpMsgBuf);
-                }
+                /* Copy the category name */
+                StringCchCopyW(CategoryName, MAX_PATH, lpMsgBuf);
             }
             else
             {
@@ -300,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;
@@ -379,7 +395,7 @@ GetEventMessage(IN LPCWSTR KeyName,
                         TrimNulls((LPWSTR)lpMsgBuf);
 
                         /* Copy the event text */
-                        wcscpy(EventText ,lpMsgBuf);
+                        StringCchCopyW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, lpMsgBuf);
                     }
                 }
 
@@ -390,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);
@@ -400,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;
 }
@@ -408,7 +424,7 @@ GetEventMessage(IN LPCWSTR KeyName,
 
 VOID
 GetEventType(IN WORD dwEventType,
-             OUT LPWSTR eventTypeText)
+             OUT PWCHAR eventTypeText)
 {
     switch (dwEventType)
     {
@@ -438,7 +454,7 @@ GetEventType(IN WORD dwEventType,
 
 BOOL
 GetEventUserName(EVENTLOGRECORD *pelr,
-                 OUT LPWSTR pszUser)
+                 OUT PWCHAR pszUser)
 {
     PSID lpSid;
     WCHAR szName[1024];
@@ -461,7 +477,7 @@ GetEventUserName(EVENTLOGRECORD *pelr,
                              &cbDomain,
                              &peUse))
         {
-            wcscpy(pszUser, szName);
+            StringCchCopyW(pszUser, MAX_PATH, szName);
             return TRUE;
         }
     }
@@ -508,44 +524,42 @@ 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;
 
     dwFlags = EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ;
 
-    lpSourceLogName = lpLogName;
-    lpComputerName = lpMachineName;
-
     /* Open the event log. */
     hEventLog = OpenEventLogW(lpMachineName,
                              lpLogName);
     if (hEventLog == NULL)
     {
-        MessageBoxW(NULL,
-                   L"Could not open the event log.",
-                   L"Event Log",
-                   MB_OK | MB_ICONINFORMATION);
+        ShowLastWin32Error();
         return FALSE;
     }
 
+    lpSourceLogName = lpLogName;
+    lpComputerName = lpMachineName;
+
     /* Disable listview redraw */
     SendMessage(hwndListView, WM_SETREDRAW, FALSE, 0);
 
@@ -559,6 +573,17 @@ QueryEventMessages(LPWSTR lpMachineName,
     GetNumberOfEventLogRecords (hEventLog , &dwTotalRecords);
     g_TotalRecords = dwTotalRecords;
 
+    if (dwTotalRecords > 0)
+    {
+        EnableMenuItem(hMainMenu, ID_CLEAR_EVENTS, MF_BYCOMMAND | MF_ENABLED);
+        EnableMenuItem(hMainMenu, ID_SAVE_PROTOCOL, MF_BYCOMMAND | MF_ENABLED);
+    }
+    else
+    {
+        EnableMenuItem(hMainMenu, ID_CLEAR_EVENTS, MF_BYCOMMAND | MF_GRAYED);
+        EnableMenuItem(hMainMenu, ID_SAVE_PROTOCOL, MF_BYCOMMAND | MF_GRAYED);
+    }
+
     g_RecordPtrs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwTotalRecords * sizeof(PVOID));
 
     /* If we have at least 1000 records show the waiting dialog */
@@ -626,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;
@@ -690,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);
@@ -717,6 +746,96 @@ QueryEventMessages(LPWSTR lpMachineName,
 }
 
 
+VOID
+SaveProtocol(VOID)
+{
+    HANDLE hEventLog;
+    WCHAR szFileName[MAX_PATH];
+
+    ZeroMemory(szFileName, sizeof(szFileName));
+
+    sfn.lpstrFile = szFileName;
+    sfn.nMaxFile  = MAX_PATH;
+
+    if (!GetSaveFileNameW(&sfn))
+    {
+        return;
+    }
+
+    hEventLog = OpenEventLogW(lpComputerName, lpSourceLogName);
+    if (!hEventLog)
+    {
+        ShowLastWin32Error();
+        return;
+    }
+
+    if (!BackupEventLogW(hEventLog, szFileName))
+    {
+        ShowLastWin32Error();
+    }
+
+    CloseEventLog(hEventLog);
+}
+
+
+BOOL
+ClearEvents(VOID)
+{
+    HANDLE hEventLog;
+    WCHAR szFileName[MAX_PATH];
+    WCHAR szMessage[MAX_LOADSTRING];
+
+    ZeroMemory(szFileName, sizeof(szFileName));
+    ZeroMemory(szMessage, sizeof(szMessage));
+
+    LoadStringW(hInst, IDS_CLEAREVENTS_MSG, szMessage, MAX_LOADSTRING);
+
+    sfn.lpstrFile = szFileName;
+    sfn.nMaxFile  = MAX_PATH;
+
+    switch (MessageBoxW(hwndMainWindow, szMessage, szTitle, MB_YESNOCANCEL | MB_ICONINFORMATION))
+    {
+        case IDCANCEL:
+        {
+            return FALSE;
+        }
+
+        case IDNO:
+        {
+            sfn.lpstrFile = NULL;
+            break;
+        }
+
+        case IDYES:
+        {
+            if (!GetSaveFileNameW(&sfn))
+            {
+                return FALSE;
+            }
+            break;
+        }
+    }
+
+    hEventLog = OpenEventLogW(lpComputerName, lpSourceLogName);
+    if (!hEventLog)
+    {
+        ShowLastWin32Error();
+        return FALSE;
+    }
+
+    if (!ClearEventLogW(hEventLog, sfn.lpstrFile))
+    {
+        ShowLastWin32Error();
+        CloseEventLog(hEventLog);
+        return FALSE;
+    }
+
+    CloseEventLog(hEventLog);
+
+    return TRUE;
+}
+
+
 VOID
 Refresh(VOID)
 {
@@ -725,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)
 {
@@ -761,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)
@@ -912,26 +1192,33 @@ InitInstance(HINSTANCE hInstance,
     lvc.pszText = szTemp;
     (void)ListView_InsertColumn(hwndListView, 8, &lvc);
 
+    // Initialize the save Dialog
+    ZeroMemory(&sfn, sizeof(sfn));
+    ZeroMemory(szSaveFilter, sizeof(szSaveFilter));
+
+    LoadStringW(hInst, IDS_SAVE_FILTER, szSaveFilter, MAX_LOADSTRING);
+
+    sfn.lStructSize     = sizeof(sfn);
+    sfn.hwndOwner       = hwndMainWindow;
+    sfn.hInstance       = hInstance;
+    sfn.lpstrFilter     = szSaveFilter;
+    sfn.lpstrInitialDir = NULL;
+    sfn.Flags           = OFN_HIDEREADONLY | OFN_SHAREAWARE;
+    sfn.lpstrDefExt     = NULL;
+
     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)
 {
@@ -941,11 +1228,7 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
     switch (message)
     {
         case WM_CREATE:
-            CheckMenuRadioItem(GetMenu(hWnd),
-                               ID_LOG_APPLICATION,
-                               ID_LOG_SYSTEM,
-                               ID_LOG_APPLICATION,
-                               MF_BYCOMMAND);
+            hMainMenu = GetMenu(hWnd);
             break;
 
         case WM_NOTIFY:
@@ -971,41 +1254,29 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 
         case WM_COMMAND:
             // Parse the menu selections:
-            switch (LOWORD(wParam))
+
+            if ((LOWORD(wParam) >= ID_FIRST_LOG) && (LOWORD(wParam) <= ID_FIRST_LOG + dwNumLogs))
             {
-                case ID_LOG_APPLICATION:
-                    if (QueryEventMessages(lpComputerName,            // Use the local computer.
-                                           EVENT_SOURCE_APPLICATION)) // The event log category
+                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_APPLICATION,
-                                           MF_BYCOMMAND);
+                        CheckMenuRadioItem(GetMenu(hWnd), ID_FIRST_LOG, ID_FIRST_LOG + dwNumLogs, LOWORD(wParam), MF_BYCOMMAND);
                     }
-                    break;
+                }
+            }
+            else
 
-                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);
-                    }
+            switch (LOWORD(wParam))
+            {
+                case ID_SAVE_PROTOCOL:
+                    SaveProtocol();
                     break;
 
-                case ID_LOG_SYSTEM:
-                    if (QueryEventMessages(lpComputerName,       // Use the local computer.
-                                           EVENT_SOURCE_SYSTEM)) // The event log category
+                case ID_CLEAR_EVENTS:
+                    if (ClearEvents())
                     {
-                        CheckMenuRadioItem(GetMenu(hWnd),
-                                           ID_LOG_APPLICATION,
-                                           ID_LOG_SYSTEM,
-                                           ID_LOG_SYSTEM,
-                                           MF_BYCOMMAND);
+                        Refresh();
                     }
                     break;
 
@@ -1018,7 +1289,7 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                     break;
 
                 case IDM_HELP:
-                    MessageBoxW(NULL,
+                    MessageBoxW(hwndMainWindow,
                                L"Help not implemented yet!",
                                L"Event Log",
                                MB_OK | MB_ICONINFORMATION);
@@ -1052,6 +1323,7 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
             break;
         case WM_DESTROY:
             FreeRecords();
+            FreeLogList();
             PostQuitMessage(0);
             break;
 
@@ -1118,14 +1390,14 @@ DisplayEvent(HWND hDlg)
 
     if (iIndex != -1)
     {
-        ListView_GetItemText(hwndListView, iIndex, 0, szEventType, sizeof(szEventType) * sizeof(WCHAR));
-        ListView_GetItemText(hwndListView, iIndex, 1, szDate, sizeof(szDate) * sizeof(WCHAR));
-        ListView_GetItemText(hwndListView, iIndex, 2, szTime, sizeof(szTime) * sizeof(WCHAR));
-        ListView_GetItemText(hwndListView, iIndex, 3, szSource, sizeof(szSource) * sizeof(WCHAR));
-        ListView_GetItemText(hwndListView, iIndex, 4, szCategory, sizeof(szCategory) * sizeof(WCHAR));
-        ListView_GetItemText(hwndListView, iIndex, 5, szEventID, sizeof(szEventID) * sizeof(WCHAR));
-        ListView_GetItemText(hwndListView, iIndex, 6, szUser, sizeof(szUser) * sizeof(WCHAR));
-        ListView_GetItemText(hwndListView, iIndex, 7, szComputer, sizeof(szComputer) * sizeof(WCHAR));
+        ListView_GetItemText(hwndListView, iIndex, 0, szEventType, sizeof(szEventType) / sizeof(WCHAR));
+        ListView_GetItemText(hwndListView, iIndex, 1, szDate, sizeof(szDate) / sizeof(WCHAR));
+        ListView_GetItemText(hwndListView, iIndex, 2, szTime, sizeof(szTime) / sizeof(WCHAR));
+        ListView_GetItemText(hwndListView, iIndex, 3, szSource, sizeof(szSource) / sizeof(WCHAR));
+        ListView_GetItemText(hwndListView, iIndex, 4, szCategory, sizeof(szCategory) / sizeof(WCHAR));
+        ListView_GetItemText(hwndListView, iIndex, 5, szEventID, sizeof(szEventID) / sizeof(WCHAR));
+        ListView_GetItemText(hwndListView, iIndex, 6, szUser, sizeof(szUser) / sizeof(WCHAR));
+        ListView_GetItemText(hwndListView, iIndex, 7, szComputer, sizeof(szComputer) / sizeof(WCHAR));
 
         bEventData = !(pevlr->DataLength == 0);
 
@@ -1228,7 +1500,7 @@ EventDetails(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
                     return (INT_PTR)TRUE;
 
                 case IDHELP:
-                    MessageBoxW(NULL,
+                    MessageBoxW(hDlg,
                                L"Help not implemented yet!",
                                L"Event Log",
                                MB_OK | MB_ICONINFORMATION);