[EVENTVWR] Additions for the Event Viewer.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 17 Apr 2018 21:01:45 +0000 (23:01 +0200)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 17 Apr 2018 21:17:48 +0000 (23:17 +0200)
CORE-11637, CORE-12269

- Implement support for remote connections to NT computers to view their
  event logs (and the event logs settings). For the moment the remote
  computer name specification is is only available via the command-line.
  Note that the paths to the event log files need also to be translated
  to network-share format.
- Implement loading and saving the settings of the event viewer.
- Implement showing/hiding the events description pane, the ListView
  grid, and whether or not to save the EventViewer settings.
- Handle hypertext link click handling for the RichEdit edit box of the
  events description dialog.

26 files changed:
base/applications/mscutils/eventvwr/eventvwr.c
base/applications/mscutils/eventvwr/evtdetctl.c
base/applications/mscutils/eventvwr/lang/bg-BG.rc
base/applications/mscutils/eventvwr/lang/cs-CZ.rc
base/applications/mscutils/eventvwr/lang/de-DE.rc
base/applications/mscutils/eventvwr/lang/el-GR.rc
base/applications/mscutils/eventvwr/lang/en-US.rc
base/applications/mscutils/eventvwr/lang/es-ES.rc
base/applications/mscutils/eventvwr/lang/fr-FR.rc
base/applications/mscutils/eventvwr/lang/he-IL.rc
base/applications/mscutils/eventvwr/lang/it-IT.rc
base/applications/mscutils/eventvwr/lang/ja-JP.rc
base/applications/mscutils/eventvwr/lang/ko-KR.rc
base/applications/mscutils/eventvwr/lang/no-NO.rc
base/applications/mscutils/eventvwr/lang/pl-PL.rc
base/applications/mscutils/eventvwr/lang/pt-BR.rc
base/applications/mscutils/eventvwr/lang/ro-RO.rc
base/applications/mscutils/eventvwr/lang/ru-RU.rc
base/applications/mscutils/eventvwr/lang/sk-SK.rc
base/applications/mscutils/eventvwr/lang/sq-AL.rc
base/applications/mscutils/eventvwr/lang/sv-SE.rc
base/applications/mscutils/eventvwr/lang/tr-TR.rc
base/applications/mscutils/eventvwr/lang/uk-UA.rc
base/applications/mscutils/eventvwr/lang/zh-CN.rc
base/applications/mscutils/eventvwr/lang/zh-TW.rc
base/applications/mscutils/eventvwr/resource.h

index 318e5de..01c416e 100644 (file)
@@ -39,6 +39,7 @@
 
 static const LPCWSTR EVENTVWR_WNDCLASS = L"EVENTVWR"; /* The main window class name */
 static const LPCWSTR EVENTLOG_BASE_KEY = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\";
+static const LPCWSTR EVNTVWR_PARAM_KEY = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Event Viewer";
 
 /* The 3 system logs that should always exist in the user's system */
 static const LPCWSTR SystemLogs[] =
@@ -91,6 +92,7 @@ LPWSTR lpComputerName = NULL;       /* NULL: local user computer (default) */
 LPWSTR lpszzUserLogsToLoad = NULL;  /* The list of user logs to load at startup (multi-string) */
 SIZE_T cbUserLogsSize = 0;
 
+HKEY hkMachine = NULL; // Registry handle to the HKEY_LOCAL_MACHINE key of the remote computer registry.
 
 /* Global event records cache for the current active event log filter */
 DWORD g_TotalRecords = 0;
@@ -100,7 +102,6 @@ PEVENTLOGRECORD* g_RecordPtrs = NULL;
 LIST_ENTRY EventLogList;
 LIST_ENTRY EventLogFilterList;
 PEVENTLOGFILTER ActiveFilter = NULL;
-BOOL NewestEventsFirst = TRUE;
 
 HANDLE hEnumEventsThread = NULL;
 HANDLE hStopEnumEvent    = NULL;
@@ -117,6 +118,21 @@ HANDLE hStartEnumEvent     = NULL;  // Command event
 OPENFILENAMEW sfn;
 
 
+/* Event Viewer Application Settings */
+typedef struct _SETTINGS
+{
+    BOOL bShowDetailsPane;      /* Show (TRUE) or Hide (FALSE) the events details pane */
+    BOOL bShowGrid;             /* Show (TRUE) or Hide (FALSE) the events view grid */
+    BOOL bSaveSettings;         /* Save (TRUE) or do not save (FALSE) current settings on exit */
+    BOOL bNewestEventsFirst;    /* Sort the displayed events the newest ones first (TRUE) or last (FALSE) */
+    INT  nVSplitPos;            /* Vertical splitter position */
+    INT  nHSplitPos;            /* Horizontal splitter position */
+    WINDOWPLACEMENT wpPos;
+} SETTINGS, *PSETTINGS;
+
+SETTINGS Settings;
+
+
 /* Forward declarations of functions included in this code module */
 
 static DWORD WINAPI
@@ -129,7 +145,7 @@ VOID FreeLogList(VOID);
 VOID FreeLogFilterList(VOID);
 
 ATOM MyRegisterClass(HINSTANCE);
-BOOL InitInstance(HINSTANCE, int);
+BOOL InitInstance(HINSTANCE);
 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 INT_PTR EventLogProperties(HINSTANCE, HWND, PEVENTLOGFILTER);
 INT_PTR CALLBACK EventDetails(HWND, UINT, WPARAM, LPARAM);
@@ -296,13 +312,18 @@ ProcessCmdLine(IN LPWSTR lpCmdLine)
             if (i == 1)
             {
                 /* Store the computer name */
+                LPWSTR lpTemp = argv[i];
                 SIZE_T cbLength;
 
-                cbLength = (wcslen(argv[i]) + 1) * sizeof(WCHAR);
+                /* Strip any leading backslashes */
+                while (*lpTemp == L'\\')
+                    ++lpTemp;
+
+                cbLength = (wcslen(lpTemp) + 1) * sizeof(WCHAR);
                 lpComputerName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbLength);
                 if (lpComputerName)
                 {
-                    StringCbCopyW(lpComputerName, cbLength, argv[i]);
+                    StringCbCopyW(lpComputerName, cbLength, lpTemp);
                 }
                 /* else, fall back to local computer */
             }
@@ -339,6 +360,214 @@ Quit:
     return Success;
 }
 
+BOOL
+LoadSettings(int nDefCmdShow)
+{
+    HKEY hKeyEventVwr;
+    LONG Result;
+    DWORD dwSize;
+    DWORD dwType;
+    DWORD Value;
+    UNICODE_STRING ValueU;
+    WCHAR buffer[100];
+
+    /* Load the default values */
+    Settings.bShowDetailsPane = TRUE;
+    Settings.bShowGrid = FALSE;
+    Settings.bSaveSettings = TRUE;
+    Settings.bNewestEventsFirst = TRUE;
+    Settings.nVSplitPos = 250; /* Splitter default positions */
+    Settings.nHSplitPos = 250;
+    ZeroMemory(&Settings.wpPos, sizeof(Settings.wpPos));
+    Settings.wpPos.length = sizeof(Settings.wpPos);
+    Settings.wpPos.rcNormalPosition.left = CW_USEDEFAULT;
+    Settings.wpPos.rcNormalPosition.top  = CW_USEDEFAULT;
+    Settings.wpPos.rcNormalPosition.right  = CW_USEDEFAULT;
+    Settings.wpPos.rcNormalPosition.bottom = CW_USEDEFAULT;
+
+    /* Try to create/open the Event Viewer user key */
+    if (RegCreateKeyExW(HKEY_CURRENT_USER,
+                        EVNTVWR_PARAM_KEY,
+                        0,
+                        NULL,
+                        REG_OPTION_NON_VOLATILE,
+                        KEY_READ | KEY_WRITE,
+                        NULL,
+                        &hKeyEventVwr,
+                        NULL) != ERROR_SUCCESS)
+    {
+        return FALSE;
+    }
+
+    // Result = RegQueryValueExW(hKeyEventVwr, L"Filter", NULL, &dwType, (LPBYTE)&szFilter, &dwSize); // REG_SZ
+    // Result = RegQueryValueExW(hKeyEventVwr, L"Find", NULL, &dwType, (LPBYTE)&szFind, &dwSize); // REG_SZ
+    // Result = RegQueryValueExW(hKeyEventVwr, L"Module", NULL, &dwType, (LPBYTE)&szModule, &dwSize); // REG_SZ
+
+    dwSize = sizeof(Value);
+    Result = RegQueryValueExW(hKeyEventVwr, L"DetailsPane", NULL, &dwType, (LPBYTE)&Value, &dwSize);
+    if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
+    {
+        if (dwType == REG_SZ)
+        {
+            ValueU.Buffer = (PWSTR)&Value;
+            ValueU.Length = ValueU.MaximumLength = dwSize;
+            RtlUnicodeStringToInteger(&ValueU, 10, &Value);
+        }
+        Settings.bShowDetailsPane = !!Value;
+    }
+
+    dwSize = sizeof(Value);
+    Result = RegQueryValueExW(hKeyEventVwr, L"ShowGrid", NULL, &dwType, (LPBYTE)&Value, &dwSize);
+    if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
+    {
+        if (dwType == REG_SZ)
+        {
+            ValueU.Buffer = (PWSTR)&Value;
+            ValueU.Length = ValueU.MaximumLength = dwSize;
+            RtlUnicodeStringToInteger(&ValueU, 10, &Value);
+        }
+        Settings.bShowGrid = !!Value;
+    }
+
+    dwSize = sizeof(Value);
+    Result = RegQueryValueExW(hKeyEventVwr, L"SortOrder", NULL, &dwType, (LPBYTE)&Value, &dwSize);
+    if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
+    {
+        if (dwType == REG_SZ)
+        {
+            ValueU.Buffer = (PWSTR)&Value;
+            ValueU.Length = ValueU.MaximumLength = dwSize;
+            RtlUnicodeStringToInteger(&ValueU, 10, &Value);
+        }
+        Settings.bNewestEventsFirst = !!Value;
+    }
+
+    /* Retrieve the splitter positions */
+    dwSize = sizeof(Value);
+    Result = RegQueryValueExW(hKeyEventVwr, L"VSplitPos", NULL, &dwType, (LPBYTE)&Value, &dwSize);
+    if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
+    {
+        if (dwType == REG_SZ)
+        {
+            ValueU.Buffer = (PWSTR)&Value;
+            ValueU.Length = ValueU.MaximumLength = dwSize;
+            RtlUnicodeStringToInteger(&ValueU, 10, &Value);
+        }
+        Settings.nVSplitPos = Value;
+    }
+
+    dwSize = sizeof(Value);
+    Result = RegQueryValueExW(hKeyEventVwr, L"HSplitPos", NULL, &dwType, (LPBYTE)&Value, &dwSize);
+    if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
+    {
+        if (dwType == REG_SZ)
+        {
+            ValueU.Buffer = (PWSTR)&Value;
+            ValueU.Length = ValueU.MaximumLength = dwSize;
+            RtlUnicodeStringToInteger(&ValueU, 10, &Value);
+        }
+        Settings.nHSplitPos = Value;
+    }
+
+    /* Retrieve the geometry of the main window */
+    dwSize = sizeof(buffer);
+    Result = RegQueryValueExW(hKeyEventVwr, L"Window", NULL, &dwType, (LPBYTE)buffer, &dwSize);
+    if ((Result != ERROR_SUCCESS) || (dwType != REG_SZ))
+        buffer[0] = UNICODE_NULL;
+
+    if (swscanf(buffer, L"%d %d %d %d %d",
+                &Settings.wpPos.rcNormalPosition.left,
+                &Settings.wpPos.rcNormalPosition.top,
+                &Settings.wpPos.rcNormalPosition.right,
+                &Settings.wpPos.rcNormalPosition.bottom,
+                &Settings.wpPos.showCmd) != 5)
+    {
+        /* Parsing failed, use defaults */
+        Settings.wpPos.rcNormalPosition.left = CW_USEDEFAULT;
+        Settings.wpPos.rcNormalPosition.top  = CW_USEDEFAULT;
+        Settings.wpPos.rcNormalPosition.right  = CW_USEDEFAULT;
+        Settings.wpPos.rcNormalPosition.bottom = CW_USEDEFAULT;
+        Settings.wpPos.showCmd = nDefCmdShow; // SW_SHOWNORMAL;
+    }
+
+    dwSize = sizeof(Value);
+    Result = RegQueryValueExW(hKeyEventVwr, L"SaveSettings", NULL, &dwType, (LPBYTE)&Value, &dwSize);
+    if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
+    {
+        if (dwType == REG_SZ)
+        {
+            ValueU.Buffer = (PWSTR)&Value;
+            ValueU.Length = ValueU.MaximumLength = dwSize;
+            RtlUnicodeStringToInteger(&ValueU, 10, &Value);
+        }
+        Settings.bSaveSettings = !!Value;
+    }
+
+    RegCloseKey(hKeyEventVwr);
+    return TRUE;
+}
+
+BOOL
+SaveSettings(VOID)
+{
+    HKEY hKeyEventVwr;
+    DWORD dwSize;
+    WCHAR buffer[100];
+
+    /* Try to create/open the Event Viewer user key */
+    if (RegCreateKeyExW(HKEY_CURRENT_USER,
+                        EVNTVWR_PARAM_KEY,
+                        0,
+                        NULL,
+                        REG_OPTION_NON_VOLATILE,
+                        KEY_READ | KEY_WRITE,
+                        NULL,
+                        &hKeyEventVwr,
+                        NULL) != ERROR_SUCCESS)
+    {
+        return FALSE;
+    }
+
+    dwSize = sizeof(Settings.bSaveSettings);
+    RegSetValueExW(hKeyEventVwr, L"SaveSettings", 0, REG_DWORD, (LPBYTE)&Settings.bSaveSettings, dwSize);
+
+    /* Do not save more settings if we are not asked to do so */
+    if (!Settings.bSaveSettings)
+        goto Quit;
+
+    dwSize = sizeof(Settings.bShowDetailsPane);
+    RegSetValueExW(hKeyEventVwr, L"DetailsPane", 0, REG_DWORD, (LPBYTE)&Settings.bShowDetailsPane, dwSize);
+
+    dwSize = sizeof(Settings.bShowGrid);
+    RegSetValueExW(hKeyEventVwr, L"ShowGrid", 0, REG_DWORD, (LPBYTE)&Settings.bShowGrid, dwSize);
+
+    dwSize = sizeof(Settings.bNewestEventsFirst);
+    RegSetValueExW(hKeyEventVwr, L"SortOrder", 0, REG_DWORD, (LPBYTE)&Settings.bNewestEventsFirst, dwSize);
+
+    Settings.nVSplitPos = nVSplitPos;
+    dwSize = sizeof(Settings.nVSplitPos);
+    RegSetValueExW(hKeyEventVwr, L"VSplitPos", 0, REG_DWORD, (LPBYTE)&Settings.nVSplitPos, dwSize);
+
+    Settings.nHSplitPos = nHSplitPos;
+    dwSize = sizeof(Settings.nHSplitPos);
+    RegSetValueExW(hKeyEventVwr, L"HSplitPos", 0, REG_DWORD, (LPBYTE)&Settings.nHSplitPos, dwSize);
+
+    StringCbPrintfW(buffer, sizeof(buffer),
+                    L"%d %d %d %d %d",
+                    Settings.wpPos.rcNormalPosition.left,
+                    Settings.wpPos.rcNormalPosition.top,
+                    Settings.wpPos.rcNormalPosition.right,
+                    Settings.wpPos.rcNormalPosition.bottom,
+                    Settings.wpPos.showCmd);
+
+    dwSize = wcslen(buffer) * sizeof(WCHAR);
+    RegSetValueExW(hKeyEventVwr, L"Window", 0, REG_SZ, (LPBYTE)buffer, dwSize);
+
+Quit:
+    RegCloseKey(hKeyEventVwr);
+    return TRUE;
+}
+
 int APIENTRY
 wWinMain(HINSTANCE hInstance,
          HINSTANCE hPrevInstance,
@@ -389,8 +618,11 @@ wWinMain(HINSTANCE hInstance,
     if (!MyRegisterClass(hInstance))
         goto Quit;
 
+    /* Load the settings */
+    LoadSettings(nCmdShow);
+
     /* Perform application initialization */
-    if (!InitInstance(hInstance, nCmdShow))
+    if (!InitInstance(hInstance))
         goto Quit;
 
     hAccelTable = LoadAcceleratorsW(hInstance, MAKEINTRESOURCEW(IDA_EVENTVWR));
@@ -442,6 +674,17 @@ wWinMain(HINSTANCE hInstance,
         }
     }
 
+    /* Save the settings */
+    SaveSettings();
+
+    /* Disconnect from computer */
+    if (hkMachine && hkMachine != HKEY_LOCAL_MACHINE)
+    {
+        /* We are connected to some other computer, close the old connection */
+        RegCloseKey(hkMachine);
+        hkMachine = NULL;
+    }
+
     /* Stop the enumerator thread */
     SetEvent(hStartStopEnumEvent);
     WaitForSingleObject(hThread, INFINITE);
@@ -590,7 +833,14 @@ GetMessageStringFromDll(
     }
     else
     {
+        LPWSTR ptr;
+
         ASSERT(lpMsgBuf);
+
+        /* Trim any trailing whitespace */
+        ptr = lpMsgBuf + dwLength - 1;
+        while (iswspace(*ptr))
+            *ptr-- = UNICODE_NULL;
     }
 
     return lpMsgBuf;
@@ -1210,6 +1460,79 @@ TrimNulls(LPWSTR s)
     }
 }
 
+DWORD
+GetExpandedFilePathName(
+    IN LPCWSTR ComputerName OPTIONAL,
+    IN LPCWSTR lpFileName,
+    OUT LPWSTR lpFullFileName OPTIONAL,
+    IN DWORD nSize)
+{
+    DWORD dwLength;
+
+    /* Determine the needed size after expansion of any environment strings */
+    dwLength = ExpandEnvironmentStringsW(lpFileName, NULL, 0);
+    if (dwLength == 0)
+    {
+        /* We failed, bail out */
+        return 0;
+    }
+
+    /* If the file path is on a remote computer, estimate its length */
+    // FIXME: Use WNetGetUniversalName instead?
+    if (ComputerName && *ComputerName)
+    {
+        /* Skip any leading backslashes */
+        while (*ComputerName == L'\\')
+            ++ComputerName;
+
+        if (*ComputerName)
+        {
+            /* Count 2 backslashes plus the computer name and one backslash separator */
+            dwLength += 2 + wcslen(ComputerName) + 1;
+        }
+    }
+
+    /* Check whether we have enough space */
+    if (dwLength > nSize)
+    {
+        /* No, return the needed size in characters (includes NULL-terminator) */
+        return dwLength;
+    }
+
+
+    /* Now expand the file path */
+    ASSERT(dwLength <= nSize);
+
+    /* Expand any existing environment strings */
+    if (ExpandEnvironmentStringsW(lpFileName, lpFullFileName, dwLength) == 0)
+    {
+        /* We failed, bail out */
+        return 0;
+    }
+
+    /* If the file path is on a remote computer, retrieve the network share form of the file name */
+    // FIXME: Use WNetGetUniversalName instead?
+    if (ComputerName && *ComputerName)
+    {
+        /* Note that we previously skipped any potential leading backslashes */
+
+        /* Replace ':' by '$' in the drive letter */
+        if (*lpFullFileName && lpFullFileName[1] == L':')
+            lpFullFileName[1] = L'$';
+
+        /* Prepend the computer name */
+        RtlMoveMemory(lpFullFileName + 2 + wcslen(ComputerName) + 1,
+                      lpFullFileName, dwLength * sizeof(WCHAR) - (2 + wcslen(ComputerName) + 1) * sizeof(WCHAR));
+        lpFullFileName[0] = L'\\';
+        lpFullFileName[1] = L'\\';
+        wcsncpy(lpFullFileName + 2, ComputerName, wcslen(ComputerName));
+        lpFullFileName[2 + wcslen(ComputerName)] = L'\\';
+    }
+
+    /* Return the number of stored characters (includes NULL-terminator) */
+    return dwLength;
+}
+
 BOOL
 GetEventMessageFileDLL(IN LPCWSTR lpLogName,
                        IN LPCWSTR SourceName,
@@ -1227,7 +1550,7 @@ GetEventMessageFileDLL(IN LPCWSTR lpLogName,
     StringCbCopyW(szKeyName, sizeof(szKeyName), EVENTLOG_BASE_KEY);
     StringCbCatW(szKeyName, sizeof(szKeyName), lpLogName);
 
-    Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+    Result = RegOpenKeyExW(hkMachine,
                            szKeyName,
                            0,
                            KEY_READ,
@@ -1261,7 +1584,7 @@ GetEventMessageFileDLL(IN LPCWSTR lpLogName,
     {
         /* NULL-terminate the string and expand it */
         szModuleName[dwSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
-        ExpandEnvironmentStringsW(szModuleName, lpModuleName, ARRAYSIZE(szModuleName));
+        GetExpandedFilePathName(lpComputerName, szModuleName, lpModuleName, ARRAYSIZE(szModuleName));
         Success = TRUE;
     }
 
@@ -1518,7 +1841,7 @@ GetEventUserName(IN PEVENTLOGRECORD pelr,
          * string-form. It should not be bigger than the user-provided buffer
          * 'pszUser', otherwise we return an error.
          */
-        if (LookupAccountSidW(NULL, // FIXME: Use computer name? From the particular event?
+        if (LookupAccountSidW(lpComputerName,
                               pCurrentSid,
                               szName,
                               &cchName,
@@ -1801,7 +2124,7 @@ EnumEventsThread(IN LPVOID lpParameter)
     ProgressBar_SetRange(hwndStatusProgress, MAKELPARAM(0, 100));
     uStepAt = (dwTotalRecords / 100) + 1;
 
-    dwFlags = EVENTLOG_SEQUENTIAL_READ | (NewestEventsFirst ? EVENTLOG_FORWARDS_READ : EVENTLOG_BACKWARDS_READ);
+    dwFlags = EVENTLOG_SEQUENTIAL_READ | (Settings.bNewestEventsFirst ? EVENTLOG_FORWARDS_READ : EVENTLOG_BACKWARDS_READ);
 
     /* 0x7ffff is the maximum buffer size ReadEventLog will accept */
     dwWanted = 0x7ffff;
@@ -2416,7 +2739,7 @@ GetDisplayNameFileAndID(IN LPCWSTR lpLogName,
     StringCbCopyW(KeyPath, cbKeyPath, EVENTLOG_BASE_KEY);
     StringCbCatW(KeyPath, cbKeyPath, lpLogName);
 
-    Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, KeyPath, 0, KEY_QUERY_VALUE, &hLogKey);
+    Result = RegOpenKeyExW(hkMachine, KeyPath, 0, KEY_QUERY_VALUE, &hLogKey);
     HeapFree(GetProcessHeap(), 0, KeyPath);
     if (Result != ERROR_SUCCESS)
         return FALSE;
@@ -2436,7 +2759,7 @@ GetDisplayNameFileAndID(IN LPCWSTR lpLogName,
     {
         /* NULL-terminate the string and expand it */
         szModuleName[cbData / sizeof(WCHAR) - 1] = UNICODE_NULL;
-        ExpandEnvironmentStringsW(szModuleName, lpModuleName, ARRAYSIZE(szModuleName));
+        GetExpandedFilePathName(lpComputerName, szModuleName, lpModuleName, ARRAYSIZE(szModuleName));
         Success = TRUE;
     }
 
@@ -2482,11 +2805,32 @@ BuildLogListAndFilterList(IN LPCWSTR lpComputerName)
     LPWSTR lpDisplayName;
     HTREEITEM hRootNode = NULL, hItem = NULL, hItemDefault = NULL;
 
+    if (hkMachine && hkMachine != HKEY_LOCAL_MACHINE)
+    {
+        /* We are connected to some other computer, close the old connection */
+        RegCloseKey(hkMachine);
+        hkMachine = NULL;
+    }
+    if (!lpComputerName || !*lpComputerName)
+    {
+        /* Use the local computer registry */
+        hkMachine = HKEY_LOCAL_MACHINE;
+    }
+    else
+    {
+        /* Connect to the remote computer registry */
+        Result = RegConnectRegistry(lpComputerName, HKEY_LOCAL_MACHINE, &hkMachine);
+        if (Result != ERROR_SUCCESS)
+        {
+            /* Connection failed, display a message and bail out */
+            hkMachine = NULL;
+            ShowWin32Error(GetLastError());
+            return;
+        }
+    }
+
     /* Open the EventLog key */
-    // TODO: Implement connection to remote computer...
-    // At the moment we only support the user local computer.
-    // FIXME: Use local or remote computer
-    Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, EVENTLOG_BASE_KEY, 0, KEY_READ, &hEventLogKey);
+    Result = RegOpenKeyExW(hkMachine, EVENTLOG_BASE_KEY, 0, KEY_READ, &hEventLogKey);
     if (Result != ERROR_SUCCESS)
     {
         return;
@@ -2689,8 +3033,7 @@ FreeLogFilterList(VOID)
 }
 
 BOOL
-InitInstance(HINSTANCE hInstance,
-             int nCmdShow)
+InitInstance(HINSTANCE hInstance)
 {
     RECT rcClient, rs;
     LONG StatusHeight;
@@ -2699,10 +3042,13 @@ InitInstance(HINSTANCE hInstance,
     WCHAR szTemp[256];
 
     /* Create the main window */
+    rs = Settings.wpPos.rcNormalPosition;
     hwndMainWindow = CreateWindowW(EVENTVWR_WNDCLASS,
                                    szTitle,
                                    WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
-                                   CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+                                   rs.left, rs.top,
+                                   (rs.right  != CW_USEDEFAULT && rs.left != CW_USEDEFAULT) ? rs.right - rs.left : CW_USEDEFAULT,
+                                   (rs.bottom != CW_USEDEFAULT && rs.top  != CW_USEDEFAULT) ? rs.bottom - rs.top : CW_USEDEFAULT,
                                    NULL,
                                    NULL,
                                    hInstance,
@@ -2737,11 +3083,14 @@ InitInstance(HINSTANCE hInstance,
                                          NULL,                       // window ID
                                          hInstance,                  // instance
                                          NULL);                      // window data
+    /* Remove its static edge */
+    SetWindowLongPtrW(hwndStatusProgress, GWL_EXSTYLE,
+                      GetWindowLongPtrW(hwndStatusProgress, GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
     ProgressBar_SetStep(hwndStatusProgress, 1);
 
     /* Initialize the splitter default positions */
-    nVSplitPos = 250;
-    nHSplitPos = 250;
+    nVSplitPos = Settings.nVSplitPos;
+    nHSplitPos = Settings.nHSplitPos;
 
     /* Create the TreeView */
     hwndTreeView = CreateWindowExW(WS_EX_CLIENTEDGE,
@@ -2785,11 +3134,8 @@ InitInstance(HINSTANCE hInstance,
 
     /* Create the Event details pane (optional) */
     hwndEventDetails = CreateEventDetailsCtrl(hInst, hwndMainWindow, (LPARAM)NULL);
-    // hwndEventDetails = NULL;
     if (hwndEventDetails)
     {
-    // SetWindowLongPtrW(hwndEventDetails, GWL_STYLE,
-                      // GetWindowLongPtrW(hwndEventDetails, GWL_STYLE) | WS_BORDER);
     SetWindowLongPtrW(hwndEventDetails, GWL_EXSTYLE,
                       GetWindowLongPtrW(hwndEventDetails, GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
     SetWindowPos(hwndEventDetails, NULL,
@@ -2797,7 +3143,7 @@ InitInstance(HINSTANCE hInstance,
                  nHSplitPos + SPLIT_WIDTH/2,
                  (rcClient.right - rcClient.left) - nVSplitPos - SPLIT_WIDTH/2,
                  (rcClient.bottom - rcClient.top) - nHSplitPos - SPLIT_WIDTH/2 - StatusHeight,
-                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
+                 SWP_NOZORDER | SWP_NOACTIVATE | (Settings.bShowDetailsPane ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
     }
 
     /* Create the ListView */
@@ -2808,15 +3154,16 @@ InitInstance(HINSTANCE hInstance,
                                    nVSplitPos + SPLIT_WIDTH/2,
                                    0,
                                    (rcClient.right - rcClient.left) - nVSplitPos - SPLIT_WIDTH/2,
-                                   hwndEventDetails ? nHSplitPos - SPLIT_WIDTH/2
-                                                    : (rcClient.bottom - rcClient.top) - StatusHeight,
+                                   hwndEventDetails && Settings.bShowDetailsPane
+                                       ? nHSplitPos - SPLIT_WIDTH/2
+                                       : (rcClient.bottom - rcClient.top) - StatusHeight,
                                    hwndMainWindow,
                                    NULL,
                                    hInstance,
                                    NULL);
 
     /* Add the extended ListView styles */
-    ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_HEADERDRAGDROP | LVS_EX_FULLROWSELECT |LVS_EX_LABELTIP);
+    ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_HEADERDRAGDROP | LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP | (Settings.bShowGrid ? LVS_EX_GRIDLINES : 0));
 
     /* Create the ImageList */
     hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
@@ -2914,7 +3261,7 @@ InitInstance(HINSTANCE hInstance,
     sfn.Flags           = OFN_HIDEREADONLY | OFN_SHAREAWARE;
     sfn.lpstrDefExt     = NULL;
 
-    ShowWindow(hwndMainWindow, nCmdShow);
+    ShowWindow(hwndMainWindow, Settings.wpPos.showCmd);
     UpdateWindow(hwndMainWindow);
 
     return TRUE;
@@ -2922,20 +3269,27 @@ InitInstance(HINSTANCE hInstance,
 
 VOID ResizeWnd(INT cx, INT cy)
 {
-    HDWP hdwp;
     RECT rs;
     LONG StatusHeight;
+    LONG_PTR dwExStyle;
+    HDWP hdwp;
 
     /* Resize the status bar -- now done in WM_SIZE */
     // SendMessageW(hwndStatus, WM_SIZE, 0, 0);
     GetWindowRect(hwndStatus, &rs);
     StatusHeight = rs.bottom - rs.top;
 
-    /* Move the progress bar */
+    /*
+     * Move the progress bar -- Take into account for extra size due to the static edge
+     * (AdjustWindowRectEx() does not seem to work for the progress bar).
+     */
     StatusBar_GetItemRect(hwndStatus, 0, &rs);
+    dwExStyle = GetWindowLongPtrW(hwndStatusProgress, GWL_EXSTYLE);
+    SetWindowLongPtrW(hwndStatusProgress, GWL_EXSTYLE, dwExStyle | WS_EX_STATICEDGE);
     MoveWindow(hwndStatusProgress,
-               rs.left, rs.top, rs.right-rs.left, rs.bottom-rs.top,
+               rs.left, rs.top, rs.right - rs.left, rs.bottom - rs.top,
                IsWindowVisible(hwndStatusProgress) ? TRUE : FALSE);
+    SetWindowLongPtrW(hwndStatusProgress, GWL_EXSTYLE, dwExStyle);
 
     /*
      * TODO: Adjust the splitter positions:
@@ -2962,11 +3316,12 @@ VOID ResizeWnd(INT cx, INT cy)
                               HWND_TOP,
                               nVSplitPos + SPLIT_WIDTH/2, 0,
                               cx - nVSplitPos - SPLIT_WIDTH/2,
-                              hwndEventDetails ? nHSplitPos - SPLIT_WIDTH/2
-                                               : cy - StatusHeight,
+                              hwndEventDetails && Settings.bShowDetailsPane
+                                  ? nHSplitPos - SPLIT_WIDTH/2
+                                  : cy - StatusHeight,
                               SWP_NOZORDER | SWP_NOACTIVATE);
 
-    if (hwndEventDetails && hdwp)
+    if (hwndEventDetails && Settings.bShowDetailsPane && hdwp)
         hdwp = DeferWindowPos(hdwp,
                               hwndEventDetails,
                               HWND_TOP,
@@ -2993,8 +3348,11 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             break;
 
         case WM_DESTROY:
+        {
+            GetWindowPlacement(hwndMainWindow, &Settings.wpPos);
             PostQuitMessage(0);
             break;
+        }
 
         case WM_NOTIFY:
         {
@@ -3165,9 +3523,9 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
                 case IDM_LIST_NEWEST:
                 {
                     CheckMenuRadioItem(hMainMenu, IDM_LIST_NEWEST, IDM_LIST_OLDEST, IDM_LIST_NEWEST, MF_BYCOMMAND);
-                    if (!NewestEventsFirst)
+                    if (!Settings.bNewestEventsFirst)
                     {
-                        NewestEventsFirst = TRUE;
+                        Settings.bNewestEventsFirst = TRUE;
                         Refresh(GetSelectedFilter(NULL));
                     }
                     break;
@@ -3176,9 +3534,9 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
                 case IDM_LIST_OLDEST:
                 {
                     CheckMenuRadioItem(hMainMenu, IDM_LIST_NEWEST, IDM_LIST_OLDEST, IDM_LIST_OLDEST, MF_BYCOMMAND);
-                    if (NewestEventsFirst)
+                    if (Settings.bNewestEventsFirst)
                     {
-                        NewestEventsFirst = FALSE;
+                        Settings.bNewestEventsFirst = FALSE;
                         Refresh(GetSelectedFilter(NULL));
                     }
                     break;
@@ -3205,6 +3563,45 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
                     Refresh(GetSelectedFilter(NULL));
                     break;
 
+                case IDM_EVENT_DETAILS_VIEW:
+                {
+                    Settings.bShowDetailsPane = !Settings.bShowDetailsPane;
+                    CheckMenuItem(hMainMenu, IDM_EVENT_DETAILS_VIEW,
+                                  MF_BYCOMMAND | (Settings.bShowDetailsPane ? MF_CHECKED : MF_UNCHECKED));
+
+                    GetClientRect(hWnd, &rect);
+                    if (Settings.bShowDetailsPane)
+                    {
+                        ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
+                        ShowWindow(hwndEventDetails, SW_SHOW);
+                    }
+                    else
+                    {
+                        ShowWindow(hwndEventDetails, SW_HIDE);
+                        ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
+                    }
+
+                    break;
+                }
+
+                case IDM_LIST_GRID_LINES:
+                {
+                    Settings.bShowGrid = !Settings.bShowGrid;
+                    CheckMenuItem(hMainMenu, IDM_LIST_GRID_LINES,
+                                  MF_BYCOMMAND | (Settings.bShowGrid ? MF_CHECKED : MF_UNCHECKED));
+
+                    ListView_SetExtendedListViewStyleEx(hwndListView, LVS_EX_GRIDLINES, (Settings.bShowGrid ? LVS_EX_GRIDLINES : 0));
+                    break;
+                }
+
+                case IDM_SAVE_SETTINGS:
+                {
+                    Settings.bSaveSettings = !Settings.bSaveSettings;
+                    CheckMenuItem(hMainMenu, IDM_SAVE_SETTINGS,
+                                  MF_BYCOMMAND | (Settings.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
+                    break;
+                }
+
                 case IDM_ABOUT:
                 {
                     HICON hIcon;
@@ -3234,6 +3631,42 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             break;
         }
 
+        case WM_INITMENU:
+        {
+            if ((HMENU)wParam != hMainMenu)
+                break;
+
+            CheckMenuRadioItem(hMainMenu, IDM_LIST_NEWEST, IDM_LIST_OLDEST,
+                               Settings.bNewestEventsFirst ? IDM_LIST_NEWEST : IDM_LIST_OLDEST,
+                               MF_BYCOMMAND);
+
+            if (!hwndEventDetails)
+            {
+                EnableMenuItem(hMainMenu, IDM_EVENT_DETAILS_VIEW,
+                               MF_BYCOMMAND | MF_GRAYED);
+            }
+            CheckMenuItem(hMainMenu, IDM_EVENT_DETAILS_VIEW,
+                          MF_BYCOMMAND | (Settings.bShowDetailsPane ? MF_CHECKED : MF_UNCHECKED));
+
+            CheckMenuItem(hMainMenu, IDM_LIST_GRID_LINES,
+                          MF_BYCOMMAND | (Settings.bShowGrid ? MF_CHECKED : MF_UNCHECKED));
+
+            CheckMenuItem(hMainMenu, IDM_SAVE_SETTINGS,
+                          MF_BYCOMMAND | (Settings.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
+
+            break;
+        }
+
+#if 0
+        case WM_INITMENUPOPUP:
+            lParam = lParam;
+            break;
+
+        case WM_CONTEXTMENU:
+            lParam = lParam;
+            break;
+#endif
+
         case WM_SETCURSOR:
         {
             POINT pt;
@@ -3258,7 +3691,7 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             }
             else
             /* Set the cursor for the horizontal splitter, if the Event details pane is displayed */
-            if (hwndEventDetails &&
+            if (hwndEventDetails && Settings.bShowDetailsPane &&
                 (pt.y >= nHSplitPos - SPLIT_WIDTH/2 && pt.y < nHSplitPos + SPLIT_WIDTH/2 + 1))
             {
                 // RECT rs;
@@ -3290,7 +3723,7 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             }
             else
             /* Capture the cursor for the horizontal splitter, if the Event details pane is displayed */
-            if (hwndEventDetails &&
+            if (hwndEventDetails && Settings.bShowDetailsPane &&
                 (y >= nHSplitPos - SPLIT_WIDTH/2 && y < nHSplitPos + SPLIT_WIDTH/2 + 1))
             {
                 bSplit = 2;
@@ -3414,7 +3847,7 @@ InitPropertiesDlg(HWND hDlg, PEVENTLOG EventLog)
     StringCbCopyW(KeyPath, cbKeyPath, EVENTLOG_BASE_KEY);
     StringCbCatW(KeyPath, cbKeyPath, lpLogName);
 
-    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, KeyPath, 0, KEY_QUERY_VALUE, &hLogKey) != ERROR_SUCCESS)
+    if (RegOpenKeyExW(hkMachine, KeyPath, 0, KEY_QUERY_VALUE, &hLogKey) != ERROR_SUCCESS)
     {
         HeapFree(GetProcessHeap(), 0, KeyPath);
         goto Quit;
@@ -3467,7 +3900,8 @@ Quit:
     FileName = EventLog->FileName;
     if (FileName && *FileName)
     {
-        ExpandEnvironmentStringsW(FileName, wszBuf, ARRAYSIZE(wszBuf));
+        /* Expand the file name. If the log file is on a remote computer, retrieve the network share form of the file name. */
+        GetExpandedFilePathName(EventLog->ComputerName, FileName, wszBuf, ARRAYSIZE(wszBuf));
         FileName = wszBuf;
     }
     else
index 5a68585..d767fe7 100644 (file)
@@ -11,6 +11,8 @@
 #include "eventvwr.h"
 #include "evtdetctl.h"
 
+#include <shellapi.h>
+
 // FIXME:
 #define EVENT_MESSAGE_EVENTTEXT_BUFFER  1024*10
 extern HWND hwndListView;
@@ -343,7 +345,46 @@ Quit:
     CloseClipboard();
 }
 
-static VOID
+static
+VOID
+OnLink(HWND hDlg, ENLINK* penLink)
+{
+    LPWSTR pLink;
+    TEXTRANGE txtRange;
+
+    ASSERT(penLink->nmhdr.idFrom == IDC_EVENTTEXTEDIT);
+
+    /* Only act on left button up events */
+    if (penLink->msg != WM_LBUTTONUP)
+        return;
+
+    /* If the range is empty, do nothing */
+    if (penLink->chrg.cpMin == penLink->chrg.cpMax)
+        return;
+
+    /* Allocate memory for the text link */
+    pLink = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                      (max(penLink->chrg.cpMin, penLink->chrg.cpMax) -
+                       min(penLink->chrg.cpMin, penLink->chrg.cpMax) + 1) * sizeof(WCHAR));
+    if (!pLink)
+    {
+        /* Not enough memory, bail out */
+        return;
+    }
+
+    txtRange.chrg = penLink->chrg;
+    txtRange.lpstrText = pLink;
+    SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_GETTEXTRANGE, 0, (LPARAM)&txtRange);
+
+    /* Open the link */
+    ShellExecuteW(hDlg, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
+
+    /* Free the buffer */
+    HeapFree(GetProcessHeap(), 0, pLink);
+}
+
+static
+VOID
 OnScroll(HWND hDlg, PDETAILDATA pData, INT nBar, WORD sbCode)
 {
     RECT rect;
@@ -858,13 +899,20 @@ EventDetailsCtrl(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
             break;
 
         case WM_NOTIFY:
-            switch (((LPNMHDR)lParam)->code)
+        {
+            LPNMHDR hdr = (LPNMHDR)lParam;
+
+            if (hdr->idFrom == IDC_EVENTTEXTEDIT)
             {
-                case EN_LINK:
-                    // TODO: Act on the activated RichEdit link!
-                    break;
+                switch (hdr->code)
+                {
+                    case EN_LINK:
+                        OnLink(hDlg, (ENLINK*)lParam);
+                        break;
+                }
             }
             break;
+        }
 
         case WM_HSCROLL:
             OnScroll(hDlg, pData, SB_HORZ, LOWORD(wParam));
index 9399ff1..2a874b1 100644 (file)
@@ -25,7 +25,10 @@ BEGIN
     END
     POPUP "На&стройки"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "Помо&щ"
     BEGIN
index ea4f7db..0a347f7 100644 (file)
@@ -25,7 +25,10 @@ BEGIN
     END
     POPUP "&Možnosti"
     BEGIN
-        MENUITEM "&Zobrazit podrobnosti", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Nápověda"
     BEGIN
index c80fde7..b73f20c 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "&Optionen"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Hilfe"
     BEGIN
index ba92148..eea6b9d 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "&Επιλογές"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Βοήθεια"
     BEGIN
index 9990028..4dcd143 100644 (file)
@@ -33,7 +33,10 @@ BEGIN
     END
     POPUP "&Options"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Help"
     BEGIN
index b279a01..a89bef6 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "&Opciones"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "Ay&uda"
     BEGIN
index 9600746..81dbc99 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "&Options"
     BEGIN
-        MENUITEM "&Montrer la vue des détails d'événements", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "&Vue des détails d'événements", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grille", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Enregistrer la configuration en quittant", IDM_SAVE_SETTINGS
     END
     POPUP "Aide"
     BEGIN
index 0ad6a42..c53929f 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "אפשרויות"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "עזרה"
     BEGIN
index ffa965c..a8b4fe8 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "&Opzioni"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Aiuto"
     BEGIN
index 749d3a2..023a714 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "オプション(&O)"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "ヘルプ(&H)"
     BEGIN
index 257d78e..1b0fdf5 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "옵션(&O)"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "도움말(&H)"
     BEGIN
index 76d95e1..d2f1ee5 100644 (file)
@@ -25,7 +25,10 @@ BEGIN
     END
     POPUP "&Handling"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Hjelp"
     BEGIN
index ca16e64..3c125fd 100644 (file)
@@ -29,7 +29,10 @@ BEGIN
     END
     POPUP "Op&cje"
     BEGIN
-        MENUITEM "&Pokaż szczegóły zdarzenia ", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "Po&moc"
     BEGIN
index c67973d..56c3568 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "&Opções"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Ajuda"
     BEGIN
index 319fb4a..f545812 100644 (file)
@@ -30,7 +30,10 @@ BEGIN
     END
     POPUP "&Opțiuni"
     BEGIN
-        MENUITEM "&Afișează detalii de eveniment", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "Aj&utor"
     BEGIN
index c1eeffb..fda9dd8 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "&Настройки"
     BEGIN
-        MENUITEM "&Область сведений событий", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Справка"
     BEGIN
index 2e5b291..36160cf 100644 (file)
@@ -30,7 +30,10 @@ BEGIN
     END
     POPUP "&Možnosti"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Pomocník"
     BEGIN
index 70bedaf..a469dc4 100644 (file)
@@ -33,7 +33,10 @@ BEGIN
     END
     POPUP "&Opsione"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "Ndihmë"
     BEGIN
index d591cd4..b5b922c 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "&Åtgärd"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Hjälp"
     BEGIN
index 9a37929..e9d174b 100644 (file)
@@ -33,7 +33,10 @@ BEGIN
     END
     POPUP "&Seçenekler"
     BEGIN
-        MENUITEM "&Olay Ayrıntıları Görünümüyle Göster", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Yardım"
     BEGIN
index a79d9cf..d5a6dc1 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "&Властивості"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "&Допомога"
     BEGIN
index f250d05..58945d9 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "选项(&O)"
     BEGIN
-        MENUITEM "显示日志详情视图(&S)", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "帮助(&H)"
     BEGIN
index 94afc5c..db57f03 100644 (file)
@@ -27,7 +27,10 @@ BEGIN
     END
     POPUP "選項(&O)"
     BEGIN
-        MENUITEM "&Show event details view", IDM_SHOW_EVENT_DETAILS_VIEW
+        MENUITEM "Event details &view", IDM_EVENT_DETAILS_VIEW
+        MENUITEM "&Grid lines", IDM_LIST_GRID_LINES
+        MENUITEM SEPARATOR
+        MENUITEM "&Save settings on exit", IDM_SAVE_SETTINGS
     END
     POPUP "説明(&H)"
     BEGIN
index 6917955..b4a0777 100644 (file)
 #define IDM_LIST_OLDEST         32779
 #define IDM_EVENT_DETAILS       32780
 #define IDM_REFRESH             32781
-#define IDM_SHOW_EVENT_DETAILS_VIEW 32782
-#define IDM_HELP                32783
-#define IDM_ABOUT               32784
+#define IDM_EVENT_DETAILS_VIEW  32782
+#define IDM_LIST_GRID_LINES     32783
+#define IDM_SAVE_SETTINGS       32784
+#define IDM_HELP                32785
+#define IDM_ABOUT               32786
 
 
 /* String IDs */