1 /*
2  *  ReactOS Win32 Applications
3  *  Copyright (C) 2007 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT : See COPYING in the top level directory
21  * PROJECT   : Event Log Viewer
22  * FILE      : eventvwr.c
23  * PROGRAMMER: Marc Piulachs (marc.piulachs at codexchange [dot] net)
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <windef.h>
29 #include <winbase.h>
30 #include <winuser.h>
31 #include <wingdi.h>
32 #include <winnls.h>
33 #include <winreg.h>
34 #include <commctrl.h>
35 #include <commdlg.h>
36 #include <strsafe.h>
37 
38 #include "resource.h"
39 
40 #if _MSC_VER
41     #pragma warning(disable: 4996)   /* 'strdup' was declared deprecated */
42     #define _CRT_SECURE_NO_DEPRECATE /* all deprecated unsafe string functions */
43 #endif
44 
45 static const WCHAR szWindowClass[]           = L"EVENTVWR"; /* the main window class name*/
46 static const WCHAR EVENTLOG_BASE_KEY[]       = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\";
47 
48 // MessageFile message buffer size
49 #define EVENT_MESSAGE_EVENTTEXT_BUFFER  1024*10
50 #define EVENT_MESSAGE_FILE_BUFFER       1024*10
51 #define EVENT_DLL_SEPARATOR             L";"
52 #define EVENT_MESSAGE_FILE              L"EventMessageFile"
53 #define EVENT_CATEGORY_MESSAGE_FILE     L"CategoryMessageFile"
54 #define EVENT_PARAMETER_MESSAGE_FILE    L"ParameterMessageFile"
55 
56 #define MAX_LOADSTRING 255
57 #define ENTRY_SIZE 2056
58 
59 /* Globals */
60 HINSTANCE hInst;                            /* current instance */
61 WCHAR szTitle[MAX_LOADSTRING];              /* The title bar text */
62 WCHAR szTitleTemplate[MAX_LOADSTRING];      /* The logged-on title bar text */
63 WCHAR szSaveFilter[MAX_LOADSTRING];         /* Filter Mask for the save Dialog */
64 HWND hwndMainWindow;                        /* Main window */
65 HWND hwndListView;                          /* ListView control */
66 HWND hwndStatus;                            /* Status bar */
67 HMENU hMainMenu;                            /* The application's main menu */
68 WCHAR szStatusBarTemplate[MAX_LOADSTRING];  /* The status bar text */
69 PEVENTLOGRECORD *g_RecordPtrs = NULL;
70 DWORD g_TotalRecords = 0;
71 OPENFILENAMEW sfn;
72 
73 LPWSTR lpSourceLogName = NULL;
74 LPWSTR lpComputerName  = NULL;
75 
76 DWORD dwNumLogs = 0;
77 WCHAR **LogNames;
78 
79 /* Forward declarations of functions included in this code module: */
80 ATOM MyRegisterClass(HINSTANCE hInstance);
81 BOOL InitInstance(HINSTANCE, int);
82 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
83 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
84 INT_PTR CALLBACK EventDetails(HWND, UINT, WPARAM, LPARAM);
85 static INT_PTR CALLBACK StatusMessageWindowProc (HWND, UINT, WPARAM, LPARAM);
86 
87 
88 int APIENTRY
89 wWinMain(HINSTANCE hInstance,
90           HINSTANCE hPrevInstance,
91           LPWSTR    lpCmdLine,
92           int       nCmdShow)
93 {
94     MSG msg;
95     HACCEL hAccelTable;
96     INITCOMMONCONTROLSEX iccx;
97 
98     UNREFERENCED_PARAMETER(hPrevInstance);
99     UNREFERENCED_PARAMETER(lpCmdLine);
100 
101     /* Whenever any of the common controls are used in your app,
102      * you must call InitCommonControlsEx() to register the classes
103      * for those controls. */
104     iccx.dwSize = sizeof(INITCOMMONCONTROLSEX);
105     iccx.dwICC = ICC_LISTVIEW_CLASSES;
106     InitCommonControlsEx(&iccx);
107 
108     /* Initialize global strings */
109     LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
110     LoadStringW(hInstance, IDS_APP_TITLE_EX, szTitleTemplate, MAX_LOADSTRING);
111     LoadStringW(hInstance, IDS_STATUS_MSG, szStatusBarTemplate, MAX_LOADSTRING);
112     MyRegisterClass(hInstance);
113 
114     /* Perform application initialization: */
115     if (!InitInstance(hInstance, nCmdShow))
116     {
117         return FALSE;
118     }
119 
120     hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDA_EVENTVWR));
121 
122     /* Main message loop: */
123     while (GetMessageW(&msg, NULL, 0, 0))
124     {
125         if (!TranslateAcceleratorW(msg.hwnd, hAccelTable, &msg))
126         {
127             TranslateMessage(&msg);
128             DispatchMessage(&msg);
129         }
130     }
131 
132     return (int)msg.wParam;
133 }
134 
135 static void FreeRecords(void)
136 {
137     DWORD iIndex;
138 
139     if (!g_RecordPtrs)
140         return;
141 
142     for (iIndex = 0; iIndex < g_TotalRecords; iIndex++)
143         HeapFree(GetProcessHeap(), 0, g_RecordPtrs[iIndex]);
144     HeapFree(GetProcessHeap(), 0, g_RecordPtrs);
145     g_RecordPtrs = NULL;
146 }
147 
148 VOID
149 ShowLastWin32Error(VOID)
150 {
151     DWORD dwError;
152     LPWSTR lpMessageBuffer;
153 
154     dwError = GetLastError();
155     FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
156                    NULL,
157                    dwError,
158                    0,
159                    (LPWSTR)&lpMessageBuffer,
160                    0,
161                    NULL);
162 
163     MessageBoxW(hwndMainWindow, lpMessageBuffer, szTitle, MB_OK | MB_ICONERROR);
164     LocalFree(lpMessageBuffer);
165 }
166 
167 VOID
168 EventTimeToSystemTime(DWORD EventTime,
169                       SYSTEMTIME *pSystemTime)
170 {
171     SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
172     FILETIME ftLocal;
173     union
174     {
175         FILETIME ft;
176         ULONGLONG ll;
177     } u1970, uUCT;
178 
179     uUCT.ft.dwHighDateTime = 0;
180     uUCT.ft.dwLowDateTime = EventTime;
181     SystemTimeToFileTime(&st1970, &u1970.ft);
182     uUCT.ll = uUCT.ll * 10000000 + u1970.ll;
183     FileTimeToLocalFileTime(&uUCT.ft, &ftLocal);
184     FileTimeToSystemTime(&ftLocal, pSystemTime);
185 }
186 
187 
188 void
189 TrimNulls(LPWSTR s)
190 {
191     WCHAR *c;
192 
193     if (s != NULL)
194     {
195         c = s + wcslen(s) - 1;
196         while (c >= s && iswspace(*c))
197             --c;
198         *++c = L'\0';
199     }
200 }
201 
202 
203 BOOL
204 GetEventMessageFileDLL(IN LPCWSTR lpLogName,
205                        IN LPCWSTR SourceName,
206                        IN LPCWSTR EntryName,
207                        OUT PWCHAR ExpandedName)
208 {
209     DWORD dwSize;
210     BYTE szModuleName[MAX_PATH];
211     WCHAR szKeyName[MAX_PATH];
212     HKEY hAppKey = NULL;
213     HKEY hSourceKey = NULL;
214     BOOL bReturn = FALSE;
215 
216     StringCbCopyW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\");
217     StringCbCatW(szKeyName, sizeof(szKeyName), lpLogName);
218 
219     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
220                      szKeyName,
221                      0,
222                      KEY_READ,
223                      &hAppKey) == ERROR_SUCCESS)
224     {
225         if (RegOpenKeyExW(hAppKey,
226                          SourceName,
227                          0,
228                          KEY_READ,
229                          &hSourceKey) == ERROR_SUCCESS)
230         {
231             dwSize = MAX_PATH;
232             if (RegQueryValueExW(hSourceKey,
233                                 EntryName,
234                                 NULL,
235                                 NULL,
236                                 (LPBYTE)szModuleName,
237                                 &dwSize) == ERROR_SUCCESS)
238             {
239                 /* Returns a string containing the requested substituted environment variable. */
240                 ExpandEnvironmentStringsW((LPCWSTR)szModuleName, ExpandedName, MAX_PATH);
241 
242                 /* Successful */
243                 bReturn = TRUE;
244             }
245         }
246     }
247     else
248     {
249         ShowLastWin32Error();
250     }
251 
252     if (hSourceKey != NULL)
253         RegCloseKey(hSourceKey);
254 
255     if (hAppKey != NULL)
256         RegCloseKey(hAppKey);
257 
258     return bReturn;
259 }
260 
261 
262 BOOL
263 GetEventCategory(IN LPCWSTR KeyName,
264                  IN LPCWSTR SourceName,
265                  IN EVENTLOGRECORD *pevlr,
266                  OUT PWCHAR CategoryName)
267 {
268     HANDLE hLibrary = NULL;
269     WCHAR szMessageDLL[MAX_PATH];
270     LPVOID lpMsgBuf = NULL;
271 
272     if (GetEventMessageFileDLL (KeyName, SourceName, EVENT_CATEGORY_MESSAGE_FILE , szMessageDLL))
273     {
274         hLibrary = LoadLibraryExW(szMessageDLL,
275                                  NULL,
276                                  DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
277         if (hLibrary != NULL)
278         {
279             /* Retrieve the message string. */
280             if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
281                               hLibrary,
282                               pevlr->EventCategory,
283                               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
284                               (LPWSTR)&lpMsgBuf,
285                               EVENT_MESSAGE_FILE_BUFFER,
286                               NULL) != 0)
287             {
288                 /* Trim the string */
289                 TrimNulls(lpMsgBuf);
290 
291                 /* Copy the category name */
292                 StringCchCopyW(CategoryName, MAX_PATH, lpMsgBuf);
293             }
294             else
295             {
296                 LoadStringW(hInst, IDS_NONE, CategoryName, MAX_PATH);
297             }
298 
299             if (hLibrary != NULL)
300                 FreeLibrary(hLibrary);
301 
302             /* Free the buffer allocated by FormatMessage */
303             if (lpMsgBuf)
304                 LocalFree(lpMsgBuf);
305 
306             return TRUE;
307         }
308     }
309 
310     LoadStringW(hInst, IDS_NONE, CategoryName, MAX_PATH);
311 
312     return FALSE;
313 }
314 
315 
316 BOOL
317 GetEventMessage(IN LPCWSTR KeyName,
318                 IN LPCWSTR SourceName,
319                 IN EVENTLOGRECORD *pevlr,
320                 OUT PWCHAR EventText)
321 {
322     DWORD i;
323     HANDLE hLibrary = NULL;
324     WCHAR SourceModuleName[1000];
325     WCHAR ParameterModuleName[1000];
326     LPWSTR lpMsgBuf = NULL;
327     WCHAR szStringIDNotFound[MAX_LOADSTRING];
328     LPWSTR szDll;
329     LPWSTR szMessage;
330     LPWSTR *szArguments;
331     BOOL bDone = FALSE;
332 
333     /* TODO : GetEventMessageFileDLL can return a comma separated list of DLLs */
334     if (GetEventMessageFileDLL (KeyName, SourceName, EVENT_MESSAGE_FILE, SourceModuleName))
335     {
336         /* Get the event message */
337         szMessage = (LPWSTR)((LPBYTE)pevlr + pevlr->StringOffset);
338 
339         /* Allocate space for parameters */
340         szArguments = malloc(sizeof(LPVOID) * pevlr->NumStrings);
341         if (!szArguments)
342         {
343             return FALSE;
344         }
345 
346         for (i = 0; i < pevlr->NumStrings ; i++)
347         {
348             if (wcsstr(szMessage , L"%%"))
349             {
350                 if (GetEventMessageFileDLL(KeyName, SourceName, EVENT_PARAMETER_MESSAGE_FILE, ParameterModuleName))
351                 {
352                     /* Not yet support for reading messages from parameter message DLL */
353                 }
354             }
355 
356             szArguments[i] = szMessage;
357             szMessage += wcslen(szMessage) + 1;
358         }
359 
360         szDll = wcstok(SourceModuleName, EVENT_DLL_SEPARATOR);
361         while ((szDll != NULL) && (!bDone))
362         {
363             hLibrary = LoadLibraryExW(szDll,
364                                      NULL,
365                                      DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
366             if (hLibrary == NULL)
367             {
368                 /* The DLL could not be loaded try the next one (if any) */
369                 szDll = wcstok(NULL, EVENT_DLL_SEPARATOR);
370             }
371             else
372             {
373                 /* Retrieve the message string. */
374                 if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
375                                   FORMAT_MESSAGE_ALLOCATE_BUFFER |
376                                   FORMAT_MESSAGE_FROM_HMODULE |
377                                   FORMAT_MESSAGE_ARGUMENT_ARRAY,
378                                   hLibrary,
379                                   pevlr->EventID,
380                                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
381                                   (LPWSTR)&lpMsgBuf,
382                                   0,
383                                   (va_list*)szArguments) == 0)
384                 {
385                     /* We haven't found the string , get next DLL (if any) */
386                     szDll = wcstok(NULL, EVENT_DLL_SEPARATOR);
387                 }
388                 else
389                 {
390                     if (lpMsgBuf)
391                     {
392                         /* The ID was found and the message was formated */
393                         bDone = TRUE;
394 
395                         /* Trim the string */
396                         TrimNulls((LPWSTR)lpMsgBuf);
397 
398                         /* Copy the event text */
399                         StringCchCopyW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, lpMsgBuf);
400                     }
401                 }
402 
403                 FreeLibrary(hLibrary);
404             }
405         }
406 
407         if (!bDone)
408         {
409             LoadStringW(hInst, IDS_EVENTSTRINGIDNOTFOUND, szStringIDNotFound, MAX_LOADSTRING);
410             StringCchPrintfW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, szStringIDNotFound, (pevlr->EventID & 0xFFFF), SourceName);
411         }
412 
413         free(szArguments);
414 
415         /* No more dlls to try, return result */
416         return bDone;
417     }
418 
419     LoadStringW(hInst, IDS_EVENTSTRINGIDNOTFOUND, szStringIDNotFound, MAX_LOADSTRING);
420     StringCchPrintfW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, szStringIDNotFound, (pevlr->EventID & 0xFFFF), SourceName);
421 
422     return FALSE;
423 }
424 
425 
426 VOID
427 GetEventType(IN WORD dwEventType,
428              OUT PWCHAR eventTypeText)
429 {
430     switch (dwEventType)
431     {
432         case EVENTLOG_ERROR_TYPE:
433             LoadStringW(hInst, IDS_EVENTLOG_ERROR_TYPE, eventTypeText, MAX_LOADSTRING);
434             break;
435         case EVENTLOG_WARNING_TYPE:
436             LoadStringW(hInst, IDS_EVENTLOG_WARNING_TYPE, eventTypeText, MAX_LOADSTRING);
437             break;
438         case EVENTLOG_INFORMATION_TYPE:
439             LoadStringW(hInst, IDS_EVENTLOG_INFORMATION_TYPE, eventTypeText, MAX_LOADSTRING);
440             break;
441         case EVENTLOG_AUDIT_SUCCESS:
442             LoadStringW(hInst, IDS_EVENTLOG_AUDIT_SUCCESS, eventTypeText, MAX_LOADSTRING);
443             break;
444         case EVENTLOG_AUDIT_FAILURE:
445             LoadStringW(hInst, IDS_EVENTLOG_AUDIT_FAILURE, eventTypeText, MAX_LOADSTRING);
446             break;
447         case EVENTLOG_SUCCESS:
448             LoadStringW(hInst, IDS_EVENTLOG_SUCCESS, eventTypeText, MAX_LOADSTRING);
449             break;
450         default:
451             LoadStringW(hInst, IDS_EVENTLOG_UNKNOWN_TYPE, eventTypeText, MAX_LOADSTRING);
452             break;
453     }
454 }
455 
456 BOOL
457 GetEventUserName(EVENTLOGRECORD *pelr,
458                  OUT PWCHAR pszUser)
459 {
460     PSID lpSid;
461     WCHAR szName[1024];
462     WCHAR szDomain[1024];
463     SID_NAME_USE peUse;
464     DWORD cbName = 1024;
465     DWORD cbDomain = 1024;
466 
467     /* Point to the SID. */
468     lpSid = (PSID)((LPBYTE)pelr + pelr->UserSidOffset);
469 
470     /* User SID */
471     if (pelr->UserSidLength > 0)
472     {
473         if (LookupAccountSidW(NULL,
474                              lpSid,
475                              szName,
476                              &cbName,
477                              szDomain,
478                              &cbDomain,
479                              &peUse))
480         {
481             StringCchCopyW(pszUser, MAX_PATH, szName);
482             return TRUE;
483         }
484     }
485 
486     return FALSE;
487 }
488 
489 
490 static DWORD WINAPI
491 ShowStatusMessageThread(IN LPVOID lpParameter)
492 {
493     HWND *phWnd = (HWND *)lpParameter;
494     HWND hWnd;
495     MSG Msg;
496 
497     hWnd = CreateDialogParam(hInst,
498                              MAKEINTRESOURCE(IDD_PROGRESSBOX),
499                              GetDesktopWindow(),
500                              StatusMessageWindowProc,
501                              (LPARAM)NULL);
502     if (!hWnd)
503         return 0;
504 
505     *phWnd = hWnd;
506 
507     ShowWindow(hWnd, SW_SHOW);
508 
509     /* Message loop for the Status window */
510     while (GetMessage(&Msg, NULL, 0, 0))
511     {
512         TranslateMessage(&Msg);
513         DispatchMessage(&Msg);
514     }
515 
516     return 0;
517 }
518 
519 
520 BOOL
521 QueryEventMessages(LPWSTR lpMachineName,
522                    LPWSTR lpLogName)
523 {
524     HWND hwndDlg = NULL;
525     HANDLE hEventLog;
526     EVENTLOGRECORD *pevlr;
527     DWORD dwRead, dwNeeded, dwThisRecord, dwTotalRecords = 0, dwCurrentRecord = 0, dwRecordsToRead = 0, dwFlags, dwMaxLength;
528     size_t cchRemaining;
529     LPWSTR lpSourceName;
530     LPWSTR lpComputerName;
531     LPSTR lpData;
532     BOOL bResult = TRUE; /* Read succeeded. */
533 
534     WCHAR szWindowTitle[MAX_PATH];
535     WCHAR szStatusText[MAX_PATH];
536     WCHAR szLocalDate[MAX_PATH];
537     WCHAR szLocalTime[MAX_PATH];
538     WCHAR szEventID[MAX_PATH];
539     WCHAR szEventTypeText[MAX_LOADSTRING];
540     WCHAR szCategoryID[MAX_PATH];
541     WCHAR szUsername[MAX_PATH];
542     WCHAR szEventText[EVENT_MESSAGE_FILE_BUFFER];
543     WCHAR szCategory[MAX_PATH];
544     WCHAR szData[MAX_PATH];
545     PWCHAR lpTitleTemplateEnd;
546 
547     SYSTEMTIME time;
548     LVITEMW lviEventItem;
549 
550     dwFlags = EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ;
551 
552     /* Open the event log. */
553     hEventLog = OpenEventLogW(lpMachineName,
554                              lpLogName);
555     if (hEventLog == NULL)
556     {
557         ShowLastWin32Error();
558         return FALSE;
559     }
560 
561     lpSourceLogName = lpLogName;
562     lpComputerName = lpMachineName;
563 
564     /* Disable listview redraw */
565     SendMessage(hwndListView, WM_SETREDRAW, FALSE, 0);
566 
567     /* Clear the list view */
568     (void)ListView_DeleteAllItems (hwndListView);
569     FreeRecords();
570 
571     GetOldestEventLogRecord(hEventLog, &dwThisRecord);
572 
573     /* Get the total number of event log records. */
574     GetNumberOfEventLogRecords (hEventLog , &dwTotalRecords);
575     g_TotalRecords = dwTotalRecords;
576 
577     if (dwTotalRecords > 0)
578     {
579         EnableMenuItem(hMainMenu, IDM_CLEAR_EVENTS, MF_BYCOMMAND | MF_ENABLED);
580         EnableMenuItem(hMainMenu, IDM_SAVE_PROTOCOL, MF_BYCOMMAND | MF_ENABLED);
581     }
582     else
583     {
584         EnableMenuItem(hMainMenu, IDM_CLEAR_EVENTS, MF_BYCOMMAND | MF_GRAYED);
585         EnableMenuItem(hMainMenu, IDM_SAVE_PROTOCOL, MF_BYCOMMAND | MF_GRAYED);
586     }
587 
588     g_RecordPtrs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwTotalRecords * sizeof(PVOID));
589 
590     /* If we have at least 1000 records show the waiting dialog */
591     if (dwTotalRecords > 1000)
592     {
593         CloseHandle(CreateThread(NULL,
594                                  0,
595                                  ShowStatusMessageThread,
596                                  (LPVOID)&hwndDlg,
597                                  0,
598                                  NULL));
599     }
600 
601     while (dwCurrentRecord < dwTotalRecords)
602     {
603         pevlr = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
604         g_RecordPtrs[dwCurrentRecord] = pevlr;
605 
606         bResult = ReadEventLog(hEventLog,  // Event log handle
607                                dwFlags,    // Sequential read
608                                0,          // Ignored for sequential read
609                                pevlr,      // Pointer to buffer
610                                sizeof(EVENTLOGRECORD),   // Size of buffer
611                                &dwRead,    // Number of bytes read
612                                &dwNeeded); // Bytes in the next record
613         if((!bResult) && (GetLastError () == ERROR_INSUFFICIENT_BUFFER))
614         {
615             HeapFree(GetProcessHeap(), 0, pevlr);
616             pevlr = HeapAlloc(GetProcessHeap(), 0, dwNeeded);
617             g_RecordPtrs[dwCurrentRecord] = pevlr;
618 
619             ReadEventLogW(hEventLog,  // event log handle
620                          dwFlags,    // read flags
621                          0,          // offset; default is 0
622                          pevlr,      // pointer to buffer
623                          dwNeeded,   // size of buffer
624                          &dwRead,    // number of bytes read
625                          &dwNeeded); // bytes in next record
626         }
627 
628         while (dwRead > 0)
629         {
630             LoadStringW(hInst, IDS_NOT_AVAILABLE, szUsername, MAX_PATH);
631             LoadStringW(hInst, IDS_NOT_AVAILABLE, szEventText, MAX_PATH);
632             LoadStringW(hInst, IDS_NONE, szCategory, MAX_PATH);
633 
634             // Get the event source name.
635             lpSourceName = (LPWSTR)((LPBYTE)pevlr + sizeof(EVENTLOGRECORD));
636 
637             // Get the computer name
638             lpComputerName = (LPWSTR)((LPBYTE)pevlr + sizeof(EVENTLOGRECORD) + (wcslen(lpSourceName) + 1) * sizeof(WCHAR));
639 
640             // This ist the data section of the current event
641             lpData = (LPSTR)((LPBYTE)pevlr + pevlr->DataOffset);
642 
643             // Compute the event type
644             EventTimeToSystemTime(pevlr->TimeWritten, &time);
645 
646             // Get the username that generated the event
647             GetEventUserName(pevlr, szUsername);
648 
649             GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, szLocalDate, MAX_PATH);
650             GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &time, NULL, szLocalTime, MAX_PATH);
651 
652             GetEventType(pevlr->EventType, szEventTypeText);
653             GetEventCategory(lpLogName, lpSourceName, pevlr, szCategory);
654 
655             StringCbPrintfW(szEventID, sizeof(szEventID), L"%u", (pevlr->EventID & 0xFFFF));
656             StringCbPrintfW(szCategoryID, sizeof(szCategoryID), L"%u", pevlr->EventCategory);
657 
658             lviEventItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
659             lviEventItem.iItem = 0;
660             lviEventItem.iSubItem = 0;
661             lviEventItem.lParam = (LPARAM)pevlr;
662             lviEventItem.pszText = szEventTypeText;
663 
664             switch (pevlr->EventType)
665             {
666                 case EVENTLOG_ERROR_TYPE:
667                     lviEventItem.iImage = 2;
668                     break;
669 
670                 case EVENTLOG_AUDIT_FAILURE:
671                     lviEventItem.iImage = 2;
672                     break;
673 
674                 case EVENTLOG_WARNING_TYPE:
675                     lviEventItem.iImage = 1;
676                     break;
677 
678                 case EVENTLOG_INFORMATION_TYPE:
679                     lviEventItem.iImage = 0;
680                     break;
681 
682                 case EVENTLOG_AUDIT_SUCCESS:
683                     lviEventItem.iImage = 0;
684                     break;
685 
686                 case EVENTLOG_SUCCESS:
687                     lviEventItem.iImage = 0;
688                     break;
689             }
690 
691             lviEventItem.iItem = ListView_InsertItem(hwndListView, &lviEventItem);
692 
693             ListView_SetItemText(hwndListView, lviEventItem.iItem, 1, szLocalDate);
694             ListView_SetItemText(hwndListView, lviEventItem.iItem, 2, szLocalTime);
695             ListView_SetItemText(hwndListView, lviEventItem.iItem, 3, lpSourceName);
696             ListView_SetItemText(hwndListView, lviEventItem.iItem, 4, szCategory);
697             ListView_SetItemText(hwndListView, lviEventItem.iItem, 5, szEventID);
698             ListView_SetItemText(hwndListView, lviEventItem.iItem, 6, szUsername); //User
699             ListView_SetItemText(hwndListView, lviEventItem.iItem, 7, lpComputerName); //Computer
700             MultiByteToWideChar(CP_ACP,
701                                 0,
702                                 lpData,
703                                 pevlr->DataLength,
704                                 szData,
705                                 MAX_PATH);
706             ListView_SetItemText(hwndListView, lviEventItem.iItem, 8, szData); //Event Text
707 
708             dwRead -= pevlr->Length;
709             pevlr = (EVENTLOGRECORD *)((LPBYTE) pevlr + pevlr->Length);
710         }
711 
712         dwRecordsToRead--;
713         dwCurrentRecord++;
714     }
715 
716     // All events loaded
717     if(hwndDlg)
718         EndDialog(hwndDlg, 0);
719 
720     StringCchPrintfExW(szWindowTitle,
721                        sizeof(szWindowTitle) / sizeof(WCHAR),
722                        &lpTitleTemplateEnd,
723                        &cchRemaining,
724                        0,
725                        szTitleTemplate, szTitle, lpLogName); /* i = number of characters written */
726     /* lpComputerName can be NULL here if no records was read */
727     dwMaxLength = (DWORD)cchRemaining;
728     if (!lpComputerName)
729         GetComputerNameW(lpTitleTemplateEnd, &dwMaxLength);
730     else
731         StringCchCopyW(lpTitleTemplateEnd, dwMaxLength, lpComputerName);
732 
733     StringCbPrintfW(szStatusText, sizeof(szStatusText), szStatusBarTemplate, lpLogName, dwTotalRecords);
734 
735     // Update the status bar
736     SendMessageW(hwndStatus, SB_SETTEXT, (WPARAM)0, (LPARAM)szStatusText);
737 
738     // Set the window title
739     SetWindowTextW(hwndMainWindow, szWindowTitle);
740 
741     // Resume list view redraw
742     SendMessageW(hwndListView, WM_SETREDRAW, TRUE, 0);
743 
744     // Close the event log.
745     CloseEventLog(hEventLog);
746 
747     return TRUE;
748 }
749 
750 
751 VOID
752 SaveProtocol(VOID)
753 {
754     HANDLE hEventLog;
755     WCHAR szFileName[MAX_PATH];
756 
757     ZeroMemory(szFileName, sizeof(szFileName));
758 
759     sfn.lpstrFile = szFileName;
760     sfn.nMaxFile  = MAX_PATH;
761 
762     if (!GetSaveFileNameW(&sfn))
763     {
764         return;
765     }
766 
767     hEventLog = OpenEventLogW(lpComputerName, lpSourceLogName);
768     if (!hEventLog)
769     {
770         ShowLastWin32Error();
771         return;
772     }
773 
774     if (!BackupEventLogW(hEventLog, szFileName))
775     {
776         ShowLastWin32Error();
777     }
778 
779     CloseEventLog(hEventLog);
780 }
781 
782 
783 BOOL
784 ClearEvents(VOID)
785 {
786     HANDLE hEventLog;
787     WCHAR szFileName[MAX_PATH];
788     WCHAR szMessage[MAX_LOADSTRING];
789 
790     ZeroMemory(szFileName, sizeof(szFileName));
791     ZeroMemory(szMessage, sizeof(szMessage));
792 
793     LoadStringW(hInst, IDS_CLEAREVENTS_MSG, szMessage, MAX_LOADSTRING);
794 
795     sfn.lpstrFile = szFileName;
796     sfn.nMaxFile  = MAX_PATH;
797 
798     switch (MessageBoxW(hwndMainWindow, szMessage, szTitle, MB_YESNOCANCEL | MB_ICONINFORMATION))
799     {
800         case IDCANCEL:
801         {
802             return FALSE;
803         }
804 
805         case IDNO:
806         {
807             sfn.lpstrFile = NULL;
808             break;
809         }
810 
811         case IDYES:
812         {
813             if (!GetSaveFileNameW(&sfn))
814             {
815                 return FALSE;
816             }
817             break;
818         }
819     }
820 
821     hEventLog = OpenEventLogW(lpComputerName, lpSourceLogName);
822     if (!hEventLog)
823     {
824         ShowLastWin32Error();
825         return FALSE;
826     }
827 
828     if (!ClearEventLogW(hEventLog, sfn.lpstrFile))
829     {
830         ShowLastWin32Error();
831         CloseEventLog(hEventLog);
832         return FALSE;
833     }
834 
835     CloseEventLog(hEventLog);
836 
837     return TRUE;
838 }
839 
840 
841 VOID
842 Refresh(VOID)
843 {
844     QueryEventMessages(lpComputerName,
845                        lpSourceLogName);
846 }
847 
848 
849 ATOM
850 MyRegisterClass(HINSTANCE hInstance)
851 {
852     WNDCLASSEXW wcex;
853 
854     wcex.cbSize = sizeof(WNDCLASSEX);
855     wcex.style = 0;
856     wcex.lpfnWndProc = WndProc;
857     wcex.cbClsExtra = 0;
858     wcex.cbWndExtra = 0;
859     wcex.hInstance = hInstance;
860     wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_EVENTVWR));
861     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
862     wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
863     wcex.lpszMenuName = MAKEINTRESOURCE(IDM_EVENTVWR);
864     wcex.lpszClassName = szWindowClass;
865     wcex.hIconSm = (HICON)LoadImage(hInstance,
866                                     MAKEINTRESOURCE(IDI_EVENTVWR),
867                                     IMAGE_ICON,
868                                     16,
869                                     16,
870                                     LR_SHARED);
871 
872     return RegisterClassExW(&wcex);
873 }
874 
875 
876 VOID
877 GetDisplayNameFile(IN LPCWSTR lpLogName,
878                    OUT PWCHAR lpModuleName)
879 {
880     HKEY hKey;
881     WCHAR *KeyPath;
882     WCHAR szModuleName[MAX_PATH];
883     DWORD cbData;
884     SIZE_T cbKeyPath;
885 
886     cbKeyPath = (wcslen(EVENTLOG_BASE_KEY) + wcslen(lpLogName) + 1) * sizeof(WCHAR);
887     KeyPath = HeapAlloc(GetProcessHeap(), 0, cbKeyPath);
888     if (!KeyPath)
889     {
890         return;
891     }
892 
893     StringCbCopyW(KeyPath, cbKeyPath, EVENTLOG_BASE_KEY);
894     StringCbCatW(KeyPath, cbKeyPath, lpLogName);
895 
896     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, KeyPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
897     {
898         HeapFree(GetProcessHeap(), 0, KeyPath);
899         return;
900     }
901 
902     cbData = sizeof(szModuleName);
903     if (RegQueryValueExW(hKey, L"DisplayNameFile", NULL, NULL, (LPBYTE)szModuleName, &cbData) == ERROR_SUCCESS)
904     {
905         ExpandEnvironmentStringsW(szModuleName, lpModuleName, MAX_PATH);
906     }
907 
908     RegCloseKey(hKey);
909     HeapFree(GetProcessHeap(), 0, KeyPath);
910 }
911 
912 
913 DWORD
914 GetDisplayNameID(IN LPCWSTR lpLogName)
915 {
916     HKEY hKey;
917     WCHAR *KeyPath;
918     DWORD dwMessageID = 0;
919     DWORD cbData;
920     SIZE_T cbKeyPath;
921 
922     cbKeyPath = (wcslen(EVENTLOG_BASE_KEY) + wcslen(lpLogName) + 1) * sizeof(WCHAR);
923     KeyPath = HeapAlloc(GetProcessHeap(), 0, cbKeyPath);
924     if (!KeyPath)
925     {
926         return 0;
927     }
928 
929     StringCbCopyW(KeyPath, cbKeyPath, EVENTLOG_BASE_KEY);
930     StringCbCatW(KeyPath, cbKeyPath, lpLogName);
931 
932     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, KeyPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
933     {
934         HeapFree(GetProcessHeap(), 0, KeyPath);
935         return 0;
936     }
937 
938     cbData = sizeof(dwMessageID);
939     RegQueryValueExW(hKey, L"DisplayNameID", NULL, NULL, (LPBYTE)&dwMessageID, &cbData);
940 
941     RegCloseKey(hKey);
942     HeapFree(GetProcessHeap(), 0, KeyPath);
943 
944     return dwMessageID;
945 }
946 
947 
948 VOID
949 BuildLogList(void)
950 {
951     HKEY hKey;
952     DWORD lpcName;
953     DWORD dwIndex;
954     DWORD dwMessageID;
955     DWORD dwMaxKeyLength;
956     WCHAR szModuleName[MAX_PATH];
957     LPWSTR lpDisplayName;
958     HANDLE hLibrary = NULL;
959 
960     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, EVENTLOG_BASE_KEY, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
961     {
962         return;
963     }
964 
965     if (RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwNumLogs, &dwMaxKeyLength, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
966     {
967         RegCloseKey(hKey);
968         return;
969     }
970 
971     if (!dwNumLogs)
972     {
973         RegCloseKey(hKey);
974         return;
975     }
976 
977     LogNames = HeapAlloc(GetProcessHeap(), 0, (dwNumLogs + 1) * sizeof(WCHAR*));
978 
979     if (!LogNames)
980     {
981         RegCloseKey(hKey);
982         return;
983     }
984 
985     for (dwIndex = 0; dwIndex < dwNumLogs; dwIndex++)
986     {
987         LogNames[dwIndex] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((dwMaxKeyLength + 1) * sizeof(WCHAR)));
988 
989         if (LogNames[dwIndex] != NULL)
990         {
991             lpcName = dwMaxKeyLength + 1;
992 
993             if (RegEnumKeyExW(hKey, dwIndex, LogNames[dwIndex], &lpcName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
994             {
995                 lpDisplayName = NULL;
996 
997                 ZeroMemory(szModuleName, sizeof(szModuleName));
998                 GetDisplayNameFile(LogNames[dwIndex], szModuleName);
999                 dwMessageID = GetDisplayNameID(LogNames[dwIndex]);
1000 
1001                 hLibrary = LoadLibraryExW(szModuleName, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
1002                 if (hLibrary != NULL)
1003                 {
1004                     FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE, hLibrary, dwMessageID, 0, (LPWSTR)&lpDisplayName, 0, NULL);
1005                     FreeLibrary(hLibrary);
1006                 }
1007 
1008                 if (lpDisplayName)
1009                 {
1010                     InsertMenuW(hMainMenu, IDM_SAVE_PROTOCOL, MF_BYCOMMAND | MF_STRING, ID_FIRST_LOG + dwIndex, lpDisplayName);
1011                 }
1012                 else
1013                 {
1014                     InsertMenuW(hMainMenu, IDM_SAVE_PROTOCOL, MF_BYCOMMAND | MF_STRING, ID_FIRST_LOG + dwIndex, LogNames[dwIndex]);
1015                 }
1016 
1017                 LocalFree(lpDisplayName);
1018             }
1019         }
1020     }
1021 
1022     InsertMenuW(hMainMenu, IDM_SAVE_PROTOCOL, MF_BYCOMMAND | MF_SEPARATOR, ID_FIRST_LOG + dwIndex + 1, NULL);
1023 
1024     RegCloseKey(hKey);
1025 
1026     return;
1027 }
1028 
1029 
1030 VOID
1031 FreeLogList(void)
1032 {
1033     DWORD dwIndex;
1034 
1035     if (!LogNames)
1036     {
1037         return;
1038     }
1039 
1040     for (dwIndex = 0; dwIndex < dwNumLogs; dwIndex++)
1041     {
1042         if (LogNames[dwIndex])
1043         {
1044             HeapFree(GetProcessHeap(), 0, LogNames[dwIndex]);
1045         }
1046 
1047         DeleteMenu(hMainMenu, ID_FIRST_LOG + dwIndex, MF_BYCOMMAND);
1048     }
1049 
1050     DeleteMenu(hMainMenu, ID_FIRST_LOG + dwIndex + 1, MF_BYCOMMAND);
1051 
1052     HeapFree(GetProcessHeap(), 0, LogNames);
1053 
1054     dwNumLogs = 0;
1055 
1056     return;
1057 }
1058 
1059 
1060 BOOL
1061 InitInstance(HINSTANCE hInstance,
1062              int nCmdShow)
1063 {
1064     HIMAGELIST hSmall;
1065     LVCOLUMNW lvc = {0};
1066     WCHAR szTemp[256];
1067 
1068     hInst = hInstance; // Store instance handle in our global variable
1069 
1070     hwndMainWindow = CreateWindowW(szWindowClass,
1071                                   szTitle,
1072                                   WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
1073                                   CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
1074                                   NULL,
1075                                   NULL,
1076                                   hInstance,
1077                                   NULL);
1078     if (!hwndMainWindow)
1079     {
1080         return FALSE;
1081     }
1082 
1083     hwndStatus = CreateWindowExW(0,                                  // no extended styles
1084                                 STATUSCLASSNAMEW,                    // status bar
1085                                 L"Done.",                     // no text
1086                                 WS_CHILD | WS_BORDER | WS_VISIBLE,  // styles
1087                                 0, 0, 0, 0,                         // x, y, cx, cy
1088                                 hwndMainWindow,                     // parent window
1089                                 (HMENU)100,                         // window ID
1090                                 hInstance,                          // instance
1091                                 NULL);                              // window data
1092 
1093     // Create our listview child window.  Note that I use WS_EX_CLIENTEDGE
1094     // and WS_BORDER to create the normal "sunken" look.  Also note that
1095     // LVS_EX_ styles cannot be set in CreateWindowEx().
1096     hwndListView = CreateWindowExW(WS_EX_CLIENTEDGE,
1097                                   WC_LISTVIEWW,
1098                                   L"",
1099                                   LVS_SHOWSELALWAYS | WS_CHILD | WS_VISIBLE | LVS_REPORT,
1100                                   0,
1101                                   0,
1102                                   243,
1103                                   200,
1104                                   hwndMainWindow,
1105                                   NULL,
1106                                   hInstance,
1107                                   NULL);
1108 
1109     // After the ListView is created, we can add extended list view styles.
1110     (void)ListView_SetExtendedListViewStyle (hwndListView, LVS_EX_FULLROWSELECT);
1111 
1112     // Create the ImageList
1113     hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
1114                               GetSystemMetrics(SM_CYSMICON),
1115                               ILC_COLOR32,
1116                               1,
1117                               1);
1118 
1119     // Add event type icons to ImageList
1120     ImageList_AddIcon (hSmall, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_INFORMATIONICON)));
1121     ImageList_AddIcon (hSmall, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WARNINGICON)));
1122     ImageList_AddIcon (hSmall, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ERRORICON)));
1123 
1124     // Assign ImageList to List View
1125     (void)ListView_SetImageList (hwndListView, hSmall, LVSIL_SMALL);
1126 
1127     // Now set up the listview with its columns.
1128     lvc.mask = LVCF_TEXT | LVCF_WIDTH;
1129     lvc.cx = 90;
1130     LoadStringW(hInstance,
1131                 IDS_COLUMNTYPE,
1132                 szTemp,
1133                 sizeof(szTemp) / sizeof(WCHAR));
1134     lvc.pszText = szTemp;
1135     (void)ListView_InsertColumn(hwndListView, 0, &lvc);
1136 
1137     lvc.cx = 70;
1138     LoadStringW(hInstance,
1139                 IDS_COLUMNDATE,
1140                 szTemp,
1141                 sizeof(szTemp) / sizeof(WCHAR));
1142     lvc.pszText = szTemp;
1143     (void)ListView_InsertColumn(hwndListView, 1, &lvc);
1144 
1145     lvc.cx = 70;
1146     LoadStringW(hInstance,
1147                 IDS_COLUMNTIME,
1148                 szTemp,
1149                 sizeof(szTemp) / sizeof(WCHAR));
1150     lvc.pszText = szTemp;
1151     (void)ListView_InsertColumn(hwndListView, 2, &lvc);
1152 
1153     lvc.cx = 150;
1154     LoadStringW(hInstance,
1155                 IDS_COLUMNSOURCE,
1156                 szTemp,
1157                 sizeof(szTemp) / sizeof(WCHAR));
1158     lvc.pszText = szTemp;
1159     (void)ListView_InsertColumn(hwndListView, 3, &lvc);
1160 
1161     lvc.cx = 100;
1162     LoadStringW(hInstance,
1163                 IDS_COLUMNCATEGORY,
1164                 szTemp,
1165                 sizeof(szTemp) / sizeof(WCHAR));
1166     lvc.pszText = szTemp;
1167     (void)ListView_InsertColumn(hwndListView, 4, &lvc);
1168 
1169     lvc.cx = 60;
1170     LoadStringW(hInstance,
1171                 IDS_COLUMNEVENT,
1172                 szTemp,
1173                 sizeof(szTemp) / sizeof(WCHAR));
1174     lvc.pszText = szTemp;
1175     (void)ListView_InsertColumn(hwndListView, 5, &lvc);
1176 
1177     lvc.cx = 120;
1178     LoadStringW(hInstance,
1179                 IDS_COLUMNUSER,
1180                 szTemp,
1181                 sizeof(szTemp) / sizeof(WCHAR));
1182     lvc.pszText = szTemp;
1183     (void)ListView_InsertColumn(hwndListView, 6, &lvc);
1184 
1185     lvc.cx = 100;
1186     LoadStringW(hInstance,
1187                 IDS_COLUMNCOMPUTER,
1188                 szTemp,
1189                 sizeof(szTemp) / sizeof(WCHAR));
1190     lvc.pszText = szTemp;
1191     (void)ListView_InsertColumn(hwndListView, 7, &lvc);
1192 
1193     lvc.cx = 0;
1194     LoadStringW(hInstance,
1195                 IDS_COLUMNEVENTDATA,
1196                 szTemp,
1197                 sizeof(szTemp) / sizeof(WCHAR));
1198     lvc.pszText = szTemp;
1199     (void)ListView_InsertColumn(hwndListView, 8, &lvc);
1200 
1201     // Initialize the save Dialog
1202     ZeroMemory(&sfn, sizeof(sfn));
1203     ZeroMemory(szSaveFilter, sizeof(szSaveFilter));
1204 
1205     LoadStringW(hInst, IDS_SAVE_FILTER, szSaveFilter, MAX_LOADSTRING);
1206 
1207     sfn.lStructSize     = sizeof(sfn);
1208     sfn.hwndOwner       = hwndMainWindow;
1209     sfn.hInstance       = hInstance;
1210     sfn.lpstrFilter     = szSaveFilter;
1211     sfn.lpstrInitialDir = NULL;
1212     sfn.Flags           = OFN_HIDEREADONLY | OFN_SHAREAWARE;
1213     sfn.lpstrDefExt     = NULL;
1214 
1215     ShowWindow(hwndMainWindow, nCmdShow);
1216     UpdateWindow(hwndMainWindow);
1217 
1218     BuildLogList();
1219 
1220     QueryEventMessages(lpComputerName, LogNames[0]);
1221 
1222     CheckMenuRadioItem(GetMenu(hwndMainWindow), ID_FIRST_LOG, ID_FIRST_LOG + dwNumLogs, ID_FIRST_LOG, MF_BYCOMMAND);
1223 
1224     return TRUE;
1225 }
1226 
1227 
1228 LRESULT CALLBACK
1229 WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1230 {
1231     RECT rect;
1232     NMHDR *hdr;
1233 
1234     switch (message)
1235     {
1236         case WM_CREATE:
1237             hMainMenu = GetMenu(hWnd);
1238             break;
1239 
1240         case WM_NOTIFY:
1241             switch (((LPNMHDR)lParam)->code)
1242             {
1243                 case NM_DBLCLK :
1244                     hdr = (NMHDR FAR*)lParam;
1245                     if (hdr->hwndFrom == hwndListView)
1246                     {
1247                         LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE)lParam;
1248 
1249                         if (lpnmitem->iItem != -1)
1250                         {
1251                             DialogBox(hInst,
1252                                       MAKEINTRESOURCE(IDD_EVENTPROPERTIES),
1253                                       hWnd,
1254                                       EventDetails);
1255                         }
1256                     }
1257                     break;
1258             }
1259             break;
1260 
1261         case WM_COMMAND:
1262             // Parse the menu selections:
1263 
1264             if ((LOWORD(wParam) >= ID_FIRST_LOG) && (LOWORD(wParam) <= ID_FIRST_LOG + dwNumLogs))
1265             {
1266                 if (LogNames[LOWORD(wParam) - ID_FIRST_LOG])
1267                 {
1268                     if (QueryEventMessages(lpComputerName, LogNames[LOWORD(wParam) - ID_FIRST_LOG]))
1269                     {
1270                         CheckMenuRadioItem(GetMenu(hWnd), ID_FIRST_LOG, ID_FIRST_LOG + dwNumLogs, LOWORD(wParam), MF_BYCOMMAND);
1271                     }
1272                 }
1273             }
1274             else
1275 
1276             switch (LOWORD(wParam))
1277             {
1278                 case IDM_SAVE_PROTOCOL:
1279                     SaveProtocol();
1280                     break;
1281 
1282                 case IDM_CLEAR_EVENTS:
1283                     if (ClearEvents())
1284                     {
1285                         Refresh();
1286                     }
1287                     break;
1288 
1289                 case IDM_REFRESH:
1290                     Refresh();
1291                     break;
1292 
1293                 case IDM_ABOUT:
1294                     DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
1295                     break;
1296 
1297                 case IDM_HELP:
1298                     MessageBoxW(hwndMainWindow,
1299                                L"Help not implemented yet!",
1300                                L"Event Log",
1301                                MB_OK | MB_ICONINFORMATION);
1302                                break;
1303 
1304                 case IDM_EXIT:
1305                     DestroyWindow(hWnd);
1306                     break;
1307 
1308                 default:
1309                     return DefWindowProc(hWnd, message, wParam, lParam);
1310             }
1311             break;
1312 
1313         case WM_SIZE:
1314             // Gets the window rectangle
1315             GetClientRect(hWnd, &rect);
1316 
1317             // Relocate the listview
1318             MoveWindow(hwndListView,
1319                        0,
1320                        0,
1321                        rect.right,
1322                        rect.bottom - 20,
1323                        1);
1324 
1325             // Resize the statusbar;
1326             SendMessage(hwndStatus, message, wParam, lParam);
1327             break;
1328 
1329         case WM_DESTROY:
1330             FreeRecords();
1331             FreeLogList();
1332             PostQuitMessage(0);
1333             break;
1334 
1335         default:
1336             return DefWindowProc(hWnd, message, wParam, lParam);
1337     }
1338 
1339     return 0;
1340 }
1341 
1342 
1343 // Message handler for about box.
1344 INT_PTR CALLBACK
1345 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1346 {
1347     UNREFERENCED_PARAMETER(lParam);
1348     switch (message)
1349     {
1350         case WM_INITDIALOG:
1351             {
1352                 return (INT_PTR)TRUE;
1353             }
1354 
1355         case WM_COMMAND:
1356             if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
1357             {
1358                 EndDialog(hDlg, LOWORD(wParam));
1359                 return (INT_PTR)TRUE;
1360             }
1361             break;
1362     }
1363 
1364     return (INT_PTR)FALSE;
1365 }
1366 
1367 VOID
1368 DisplayEvent(HWND hDlg)
1369 {
1370     WCHAR szEventType[MAX_PATH];
1371     WCHAR szTime[MAX_PATH];
1372     WCHAR szDate[MAX_PATH];
1373     WCHAR szUser[MAX_PATH];
1374     WCHAR szComputer[MAX_PATH];
1375     WCHAR szSource[MAX_PATH];
1376     WCHAR szCategory[MAX_PATH];
1377     WCHAR szEventID[MAX_PATH];
1378     WCHAR szEventText[EVENT_MESSAGE_EVENTTEXT_BUFFER];
1379     WCHAR szEventData[MAX_PATH];
1380     BOOL bEventData = FALSE;
1381     LVITEMW li;
1382     EVENTLOGRECORD* pevlr;
1383     int iIndex;
1384 
1385     // Get index of selected item
1386     iIndex = (int)SendMessage (hwndListView, LVM_GETNEXTITEM, -1, LVNI_SELECTED | LVNI_FOCUSED);
1387 
1388     li.mask = LVIF_PARAM;
1389     li.iItem = iIndex;
1390     li.iSubItem = 0;
1391 
1392     (void)ListView_GetItem(hwndListView, &li);
1393 
1394     pevlr = (EVENTLOGRECORD*)li.lParam;
1395 
1396     if (iIndex != -1)
1397     {
1398         ListView_GetItemText(hwndListView, iIndex, 0, szEventType, sizeof(szEventType) / sizeof(WCHAR));
1399         ListView_GetItemText(hwndListView, iIndex, 1, szDate, sizeof(szDate) / sizeof(WCHAR));
1400         ListView_GetItemText(hwndListView, iIndex, 2, szTime, sizeof(szTime) / sizeof(WCHAR));
1401         ListView_GetItemText(hwndListView, iIndex, 3, szSource, sizeof(szSource) / sizeof(WCHAR));
1402         ListView_GetItemText(hwndListView, iIndex, 4, szCategory, sizeof(szCategory) / sizeof(WCHAR));
1403         ListView_GetItemText(hwndListView, iIndex, 5, szEventID, sizeof(szEventID) / sizeof(WCHAR));
1404         ListView_GetItemText(hwndListView, iIndex, 6, szUser, sizeof(szUser) / sizeof(WCHAR));
1405         ListView_GetItemText(hwndListView, iIndex, 7, szComputer, sizeof(szComputer) / sizeof(WCHAR));
1406 
1407         bEventData = !(pevlr->DataLength == 0);
1408 
1409         if (pevlr->DataLength > 0)
1410         {
1411             MultiByteToWideChar(CP_ACP,
1412                                 0,
1413                                 (LPCSTR)((LPBYTE)pevlr + pevlr->DataOffset),
1414                                 pevlr->DataLength,
1415                                 szEventData,
1416                                 MAX_PATH);
1417         }
1418 
1419         GetEventMessage(lpSourceLogName, szSource, pevlr, szEventText);
1420 
1421         EnableWindow(GetDlgItem(hDlg, IDC_BYTESRADIO), bEventData);
1422         EnableWindow(GetDlgItem(hDlg, IDC_WORDRADIO), bEventData);
1423 
1424         SetDlgItemTextW(hDlg, IDC_EVENTDATESTATIC, szDate);
1425         SetDlgItemTextW(hDlg, IDC_EVENTTIMESTATIC, szTime);
1426 
1427         SetDlgItemTextW(hDlg, IDC_EVENTUSERSTATIC, szUser);
1428         SetDlgItemTextW(hDlg, IDC_EVENTSOURCESTATIC, szSource);
1429         SetDlgItemTextW(hDlg, IDC_EVENTCOMPUTERSTATIC, szComputer);
1430         SetDlgItemTextW(hDlg, IDC_EVENTCATEGORYSTATIC, szCategory);
1431         SetDlgItemTextW(hDlg, IDC_EVENTIDSTATIC, szEventID);
1432         SetDlgItemTextW(hDlg, IDC_EVENTTYPESTATIC, szEventType);
1433         SetDlgItemTextW(hDlg, IDC_EVENTTEXTEDIT, szEventText);
1434         SetDlgItemTextW(hDlg, IDC_EVENTDATAEDIT, szEventData);
1435     }
1436     else
1437     {
1438         MessageBoxW(NULL,
1439                    L"No Items in ListView",
1440                    L"Error",
1441                    MB_OK | MB_ICONINFORMATION);
1442     }
1443 }
1444 
1445 VOID
1446 CopyEventEntry(HWND hWnd)
1447 {
1448     WCHAR output[4130], tmpHeader[512];
1449     WCHAR szEventType[MAX_PATH];
1450     WCHAR szSource[MAX_PATH];
1451     WCHAR szCategory[MAX_PATH];
1452     WCHAR szEventID[MAX_PATH];
1453     WCHAR szDate[MAX_PATH];
1454     WCHAR szTime[MAX_PATH];
1455     WCHAR szUser[MAX_PATH];
1456     WCHAR szComputer[MAX_PATH];
1457     WCHAR evtDesc[ENTRY_SIZE];
1458     HGLOBAL hMem;
1459 
1460     if (!OpenClipboard(hWnd))
1461         return;
1462 
1463     /* First, empty the clipboard before we begin to use it */
1464     EmptyClipboard();
1465 
1466     /* Get the formatted text needed to place the content into */
1467     LoadStringW(hInst, IDS_COPY, tmpHeader, sizeof(tmpHeader) / sizeof(WCHAR));
1468 
1469     /* Grabs all the information and get it ready for the clipboard */
1470     GetDlgItemText(hWnd, IDC_EVENTTYPESTATIC, szEventType, MAX_PATH);
1471     GetDlgItemText(hWnd, IDC_EVENTSOURCESTATIC, szSource, MAX_PATH);
1472     GetDlgItemText(hWnd, IDC_EVENTCATEGORYSTATIC, szCategory, MAX_PATH);
1473     GetDlgItemText(hWnd, IDC_EVENTIDSTATIC, szEventID, MAX_PATH);
1474     GetDlgItemText(hWnd, IDC_EVENTDATESTATIC, szDate, MAX_PATH);
1475     GetDlgItemText(hWnd, IDC_EVENTTIMESTATIC, szTime, MAX_PATH);
1476     GetDlgItemText(hWnd, IDC_EVENTUSERSTATIC, szUser, MAX_PATH);
1477     GetDlgItemText(hWnd, IDC_EVENTCOMPUTERSTATIC, szComputer, MAX_PATH);
1478     GetDlgItemText(hWnd, IDC_EVENTTEXTEDIT, evtDesc, ENTRY_SIZE);
1479 
1480     /* Consolidate the information into on big piece */
1481     wsprintfW(output, tmpHeader, szEventType, szSource, szCategory, szEventID, szDate, szTime, szUser, szComputer, evtDesc);
1482 
1483     /* Sort out the memory needed to write to the clipboard */
1484     hMem = GlobalAlloc(GMEM_MOVEABLE, ENTRY_SIZE);
1485     memcpy(GlobalLock(hMem), output, ENTRY_SIZE);
1486     GlobalUnlock(hMem);
1487 
1488     /* Write the final content to the clipboard */
1489     SetClipboardData(CF_UNICODETEXT, hMem);
1490 
1491     /* Close the clipboard once we're done with it */
1492     CloseClipboard();
1493 }
1494 
1495 static
1496 INT_PTR CALLBACK
1497 StatusMessageWindowProc(IN HWND hwndDlg,
1498                         IN UINT uMsg,
1499                         IN WPARAM wParam,
1500                         IN LPARAM lParam)
1501 {
1502     UNREFERENCED_PARAMETER(wParam);
1503 
1504     switch (uMsg)
1505     {
1506         case WM_INITDIALOG:
1507         {
1508             return TRUE;
1509         }
1510     }
1511     return FALSE;
1512 }
1513 
1514 static
1515 VOID
1516 InitDetailsDlg(HWND hDlg)
1517 {
1518     HANDLE nextIcon = LoadImage(hInst, MAKEINTRESOURCE(IDI_NEXT), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1519     HANDLE prevIcon = LoadImage(hInst, MAKEINTRESOURCE(IDI_PREV), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1520     HANDLE copyIcon = LoadImage(hInst, MAKEINTRESOURCE(IDI_COPY), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1521 
1522     SendMessage(GetDlgItem(hDlg, IDC_NEXT), BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)nextIcon);
1523     SendMessage(GetDlgItem(hDlg, IDC_PREVIOUS), BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)prevIcon);
1524     SendMessage(GetDlgItem(hDlg, IDC_COPY), BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)copyIcon);
1525 }
1526 
1527 // Message handler for event details box.
1528 INT_PTR CALLBACK
1529 EventDetails(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1530 {
1531     UNREFERENCED_PARAMETER(lParam);
1532 
1533     switch (message)
1534     {
1535         case WM_INITDIALOG:
1536             InitDetailsDlg(hDlg);
1537 
1538             // Show event info on dialog box
1539             DisplayEvent(hDlg);
1540             return (INT_PTR)TRUE;
1541 
1542         case WM_COMMAND:
1543             switch (LOWORD(wParam))
1544             {
1545                 case IDOK:
1546                 case IDCANCEL:
1547                     EndDialog(hDlg, LOWORD(wParam));
1548                     return (INT_PTR)TRUE;
1549 
1550                 case IDC_PREVIOUS:
1551                     SendMessage(hwndListView, WM_KEYDOWN, VK_UP, 0);
1552 
1553                     // Show event info on dialog box
1554                     DisplayEvent(hDlg);
1555                     return (INT_PTR)TRUE;
1556 
1557                 case IDC_NEXT:
1558                     SendMessage(hwndListView, WM_KEYDOWN, VK_DOWN, 0);
1559 
1560                     // Show event info on dialog box
1561                     DisplayEvent(hDlg);
1562                     return (INT_PTR)TRUE;
1563 
1564                 case IDC_COPY:
1565                     CopyEventEntry(hDlg);
1566                     return (INT_PTR)TRUE;
1567 
1568                 case IDC_BYTESRADIO:
1569                     return (INT_PTR)TRUE;
1570 
1571                 case IDC_WORDRADIO:
1572                     return (INT_PTR)TRUE;
1573 
1574                 case IDHELP:
1575                     MessageBoxW(hDlg,
1576                                L"Help not implemented yet!",
1577                                L"Event Log",
1578                                MB_OK | MB_ICONINFORMATION);
1579                     return (INT_PTR)TRUE;
1580 
1581                 default:
1582                     break;
1583             }
1584             break;
1585     }
1586 
1587     return (INT_PTR)FALSE;
1588 }
1589