ReactOS  0.4.14-dev-50-g13bb5e2
eventvwr.c
Go to the documentation of this file.
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  * PROJECT: ReactOS Event Log Viewer
21  * LICENSE: GPL - See COPYING in the top level directory
22  * FILE: base/applications/mscutils/eventvwr/eventvwr.c
23  * PURPOSE: Event Log Viewer main file
24  * PROGRAMMERS: Marc Piulachs (marc.piulachs at codexchange [dot] net)
25  * Eric Kohl
26  * Hermes Belusca-Maito
27  */
28 
29 #include "eventvwr.h"
30 #include "evtdetctl.h"
31 
32 #include <sddl.h> // For ConvertSidToStringSidW
33 #include <shellapi.h>
34 #include <shlwapi.h>
35 
36 // #include "resource.h"
37 
38 #define LVM_PROGRESS (WM_APP + 1) // Used by the subclassed ListView
39 
40 static const LPCWSTR EVENTVWR_WNDCLASS = L"EVENTVWR"; /* The main window class name */
41 static const LPCWSTR EVENTLOG_BASE_KEY = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\";
42 static const LPCWSTR EVNTVWR_PARAM_KEY = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Event Viewer";
43 
44 /* The 3 system logs that should always exist in the user's system */
45 static const LPCWSTR SystemLogs[] =
46 {
47  L"Application",
48  L"Security",
49  L"System"
50 };
51 
52 /* MessageFile message buffer size */
53 #define EVENT_MESSAGE_EVENTTEXT_BUFFER 1024*10 // NOTE: Used by evtdetctl.c
54 #define EVENT_MESSAGE_FILE_BUFFER 1024*10
55 #define EVENT_DLL_SEPARATOR L";"
56 #define EVENT_CATEGORY_MESSAGE_FILE L"CategoryMessageFile"
57 #define EVENT_MESSAGE_FILE L"EventMessageFile"
58 #define EVENT_PARAMETER_MESSAGE_FILE L"ParameterMessageFile"
59 
60 #define MAX_LOADSTRING 255
61 
62 #define SPLIT_WIDTH 4
63 
64 /* Globals */
65 HINSTANCE hInst; /* Current instance */
66 WCHAR szTitle[MAX_LOADSTRING]; /* The title bar text */
67 WCHAR szTitleTemplate[MAX_LOADSTRING]; /* The logged-on title bar text */
68 WCHAR szStatusBarTemplate[MAX_LOADSTRING]; /* The status bar text */
69 WCHAR szLoadingWait[MAX_LOADSTRING]; /* The "Loading, please wait..." text */
70 WCHAR szEmptyList[MAX_LOADSTRING]; /* The "There are no items to show in this view" text */
71 WCHAR szSaveFilter[MAX_LOADSTRING]; /* Filter Mask for the save Dialog */
72 
73 INT nVSplitPos; /* Vertical splitter (1) position */
74 INT nHSplitPos; /* Horizontal splitter (2) position */
75 BYTE bSplit = 0; /* Splitter state:
76  * 0: No splitting;
77  * 1: Vertical splitting;
78  * 2: Horizontal splitting.
79  */
80 
81 HWND hwndMainWindow = NULL; /* Main window */
82 HWND hwndTreeView; /* TreeView control */
83 HWND hwndListView; /* ListView control */ // NOTE: Used by evtdetctl.c
84 HWND hwndEventDetails; /* Event details pane */
85 HWND hwndStatus; /* Status bar */
86 HWND hwndStatusProgress; /* Progress bar in the status bar */
87 HMENU hMainMenu; /* The application's main menu */
88 
90 
91 LPWSTR lpComputerName = NULL; /* NULL: local user computer (default) */
92 LPWSTR lpszzUserLogsToLoad = NULL; /* The list of user logs to load at startup (multi-string) */
94 
95 HKEY hkMachine = NULL; // Registry handle to the HKEY_LOCAL_MACHINE key of the remote computer registry.
96 
97 /* Global event records cache for the current active event log filter */
100 
101 /* Lists of event logs and event log filters */
105 
108 
109 /*
110  * Setting EnumFilter to a valid pointer and raising the hStartEnumEvent event
111  * triggers the event-enumerator thread to perform a new enumeration.
112  */
114 HANDLE hStartStopEnumEvent = NULL; // End-of-application event
115 HANDLE hStartEnumEvent = NULL; // Command event
116 
117 /* Default Open/Save-As dialog box */
119 
120 
121 /* Event Viewer Application Settings */
122 typedef struct _SETTINGS
123 {
124  BOOL bShowDetailsPane; /* Show (TRUE) or Hide (FALSE) the events details pane */
125  BOOL bShowGrid; /* Show (TRUE) or Hide (FALSE) the events view grid */
126  BOOL bSaveSettings; /* Save (TRUE) or do not save (FALSE) current settings on exit */
127  BOOL bNewestEventsFirst; /* Sort the displayed events the newest ones first (TRUE) or last (FALSE) */
128  INT nVSplitPos; /* Vertical splitter position */
129  INT nHSplitPos; /* Horizontal splitter position */
131 } SETTINGS, *PSETTINGS;
132 
134 
135 
136 /* Forward declarations of functions included in this code module */
137 
138 static DWORD WINAPI
140 
141 VOID OpenUserEventLogFile(IN LPCWSTR lpszFileName);
142 
146 
152 
153 
154 /* MAIN FUNCTIONS *************************************************************/
155 
156 VOID
158 {
159  LPWSTR lpMessageBuffer;
160 
161  if (dwError == ERROR_SUCCESS)
162  return;
163 
167  NULL,
168  dwError,
170  (LPWSTR)&lpMessageBuffer,
171  0, NULL))
172  {
173  return;
174  }
175 
176  MessageBoxW(hwndMainWindow, lpMessageBuffer, szTitle, MB_OK | MB_ICONERROR);
177  LocalFree(lpMessageBuffer);
178 }
179 
180 VOID
182 {
184  LPCWSTR lpUsage;
185  INT iUsageLen = LoadStringW(hInst, IDS_USAGE, (LPWSTR)&lpUsage, 0);
186 
187  if (iUsageLen == 0)
188  return;
189 
190  lpBuffer = HeapAlloc(GetProcessHeap(), 0, (iUsageLen + 1) * sizeof(WCHAR));
191  if (!lpBuffer)
192  return;
193 
194  StringCchCopyNW(lpBuffer, iUsageLen + 1, lpUsage, iUsageLen);
196 
198 }
199 
200 BOOL
202 {
203  BOOL Success = FALSE;
204  INT i, argc;
205  LPWSTR* argv;
206 
207  /* Skip any leading whitespace */
208  if (lpCmdLine)
209  {
210  while (iswspace(*lpCmdLine))
211  ++lpCmdLine;
212  }
213 
214  /* No command line means no processing needed */
215  if (!lpCmdLine || !*lpCmdLine)
216  return TRUE;
217 
218  /* Build the arguments vector */
219  argv = CommandLineToArgvW(lpCmdLine, &argc);
220  if (!argv)
221  return FALSE;
222 
223  /* Parse the command line for options (skip the program name) */
224  for (i = 1; i < argc; ++i)
225  {
226  /* Check for new options */
227  if (argv[i][0] == L'-' || argv[i][0] == L'/')
228  {
229  if (argv[i][1] == L'?' && argv[i][2] == 0)
230  {
231  /* Display help */
232  DisplayUsage();
233  goto Quit;
234  }
235  else
236  if (argv[i][2] == L':')
237  {
238  switch (towupper(argv[i][1]))
239  {
240  case L'L':
241  {
242  LPWSTR lpNewBuffer;
243  LPWSTR lpFileName = argv[i] + 3;
244  SIZE_T cbFileName;
245 
246  /* Check for a quoted file name */
247  if (*lpFileName == L'\"')
248  {
249  /* Skip this quote, and the last one too if any */
250  ++lpFileName;
251  cbFileName = wcslen(lpFileName);
252  if (cbFileName > 0 && lpFileName[cbFileName - 1] == L'\"')
253  lpFileName[cbFileName - 1] = UNICODE_NULL;
254  }
255 
256  /* Skip this one if we do not actually have a file name */
257  if (!*lpFileName)
258  continue;
259 
260  cbFileName = (wcslen(lpFileName) + 1) * sizeof(WCHAR);
261 
262  /* Reallocate the list of user logs to load */
264  {
265  lpNewBuffer = HeapReAlloc(GetProcessHeap(),
268  /* Count the multi-string NULL-terminator */
269  cbUserLogsSize + cbFileName + sizeof(WCHAR));
270  }
271  else
272  {
273  cbUserLogsSize = 0;
274  lpNewBuffer = HeapAlloc(GetProcessHeap(),
276  /* Count the multi-string NULL-terminator */
277  cbUserLogsSize + cbFileName + sizeof(WCHAR));
278  }
279 
280  if (!lpNewBuffer)
281  {
283  goto Quit;
284  }
285 
286  lpszzUserLogsToLoad = lpNewBuffer;
287  lpNewBuffer = (LPWSTR)((ULONG_PTR)lpNewBuffer + cbUserLogsSize);
288  cbUserLogsSize += cbFileName;
289 
290  /* Save the file name */
291  StringCbCopyW(lpNewBuffer, cbFileName, lpFileName);
292 
293  continue;
294  }
295 
296  default:
297  break;
298  }
299  }
300 
301  /* Unknown argument: display help and bail out */
302  DisplayUsage();
303  goto Quit;
304  }
305  else
306  {
307  /*
308  * An argument that does not start with the switch character.
309  * If this is the first argument then this corresponds to the
310  * optional computer name. Otherwise this is a wrong argument.
311  */
312  if (i == 1)
313  {
314  /* Store the computer name */
315  LPWSTR lpTemp = argv[i];
316  SIZE_T cbLength;
317 
318  /* Strip any leading backslashes */
319  while (*lpTemp == L'\\')
320  ++lpTemp;
321 
322  cbLength = (wcslen(lpTemp) + 1) * sizeof(WCHAR);
324  if (lpComputerName)
325  {
326  StringCbCopyW(lpComputerName, cbLength, lpTemp);
327  }
328  /* else, fall back to local computer */
329  }
330  else
331  {
332  /* Invalid syntax: display help and bail out */
333  DisplayUsage();
334  goto Quit;
335  }
336  }
337  }
338 
339  Success = TRUE;
340 
341 Quit:
342  /* In case of failure, free anything we have allocated */
343  if (!Success)
344  {
346  {
347  cbUserLogsSize = 0;
350  }
351  if (lpComputerName)
352  {
355  }
356  }
357 
358  /* Free the arguments vector and exit */
359  LocalFree(argv);
360  return Success;
361 }
362 
363 BOOL
364 LoadSettings(int nDefCmdShow)
365 {
366  HKEY hKeyEventVwr;
367  LONG Result;
368  DWORD dwSize;
369  DWORD dwType;
370  DWORD Value;
371  UNICODE_STRING ValueU;
372  WCHAR buffer[100];
373 
374  /* Load the default values */
375  Settings.bShowDetailsPane = TRUE;
376  Settings.bShowGrid = FALSE;
377  Settings.bSaveSettings = TRUE;
378  Settings.bNewestEventsFirst = TRUE;
379  Settings.nVSplitPos = 250; /* Splitter default positions */
380  Settings.nHSplitPos = 250;
381  ZeroMemory(&Settings.wpPos, sizeof(Settings.wpPos));
382  Settings.wpPos.length = sizeof(Settings.wpPos);
383  Settings.wpPos.rcNormalPosition.left = CW_USEDEFAULT;
384  Settings.wpPos.rcNormalPosition.top = CW_USEDEFAULT;
385  Settings.wpPos.rcNormalPosition.right = CW_USEDEFAULT;
386  Settings.wpPos.rcNormalPosition.bottom = CW_USEDEFAULT;
387 
388  /* Try to create/open the Event Viewer user key */
391  0,
392  NULL,
395  NULL,
396  &hKeyEventVwr,
397  NULL) != ERROR_SUCCESS)
398  {
399  return FALSE;
400  }
401 
402  // Result = RegQueryValueExW(hKeyEventVwr, L"Filter", NULL, &dwType, (LPBYTE)&szFilter, &dwSize); // REG_SZ
403  // Result = RegQueryValueExW(hKeyEventVwr, L"Find", NULL, &dwType, (LPBYTE)&szFind, &dwSize); // REG_SZ
404  // Result = RegQueryValueExW(hKeyEventVwr, L"Module", NULL, &dwType, (LPBYTE)&szModule, &dwSize); // REG_SZ
405 
406  dwSize = sizeof(Value);
407  Result = RegQueryValueExW(hKeyEventVwr, L"DetailsPane", NULL, &dwType, (LPBYTE)&Value, &dwSize);
408  if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
409  {
410  if (dwType == REG_SZ)
411  {
412  ValueU.Buffer = (PWSTR)&Value;
413  ValueU.Length = ValueU.MaximumLength = dwSize;
414  RtlUnicodeStringToInteger(&ValueU, 10, &Value);
415  }
416  Settings.bShowDetailsPane = !!Value;
417  }
418 
419  dwSize = sizeof(Value);
420  Result = RegQueryValueExW(hKeyEventVwr, L"ShowGrid", NULL, &dwType, (LPBYTE)&Value, &dwSize);
421  if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
422  {
423  if (dwType == REG_SZ)
424  {
425  ValueU.Buffer = (PWSTR)&Value;
426  ValueU.Length = ValueU.MaximumLength = dwSize;
427  RtlUnicodeStringToInteger(&ValueU, 10, &Value);
428  }
429  Settings.bShowGrid = !!Value;
430  }
431 
432  dwSize = sizeof(Value);
433  Result = RegQueryValueExW(hKeyEventVwr, L"SortOrder", NULL, &dwType, (LPBYTE)&Value, &dwSize);
434  if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
435  {
436  if (dwType == REG_SZ)
437  {
438  ValueU.Buffer = (PWSTR)&Value;
439  ValueU.Length = ValueU.MaximumLength = dwSize;
440  RtlUnicodeStringToInteger(&ValueU, 10, &Value);
441  }
442  Settings.bNewestEventsFirst = !!Value;
443  }
444 
445  /* Retrieve the splitter positions */
446  dwSize = sizeof(Value);
447  Result = RegQueryValueExW(hKeyEventVwr, L"VSplitPos", NULL, &dwType, (LPBYTE)&Value, &dwSize);
448  if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
449  {
450  if (dwType == REG_SZ)
451  {
452  ValueU.Buffer = (PWSTR)&Value;
453  ValueU.Length = ValueU.MaximumLength = dwSize;
454  RtlUnicodeStringToInteger(&ValueU, 10, &Value);
455  }
456  Settings.nVSplitPos = Value;
457  }
458 
459  dwSize = sizeof(Value);
460  Result = RegQueryValueExW(hKeyEventVwr, L"HSplitPos", NULL, &dwType, (LPBYTE)&Value, &dwSize);
461  if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
462  {
463  if (dwType == REG_SZ)
464  {
465  ValueU.Buffer = (PWSTR)&Value;
466  ValueU.Length = ValueU.MaximumLength = dwSize;
467  RtlUnicodeStringToInteger(&ValueU, 10, &Value);
468  }
469  Settings.nHSplitPos = Value;
470  }
471 
472  /* Retrieve the geometry of the main window */
473  dwSize = sizeof(buffer);
474  Result = RegQueryValueExW(hKeyEventVwr, L"Window", NULL, &dwType, (LPBYTE)buffer, &dwSize);
475  if ((Result != ERROR_SUCCESS) || (dwType != REG_SZ))
476  buffer[0] = UNICODE_NULL;
477 
478  if (swscanf(buffer, L"%d %d %d %d %d",
479  &Settings.wpPos.rcNormalPosition.left,
480  &Settings.wpPos.rcNormalPosition.top,
481  &Settings.wpPos.rcNormalPosition.right,
482  &Settings.wpPos.rcNormalPosition.bottom,
483  &Settings.wpPos.showCmd) != 5)
484  {
485  /* Parsing failed, use defaults */
486  Settings.wpPos.rcNormalPosition.left = CW_USEDEFAULT;
487  Settings.wpPos.rcNormalPosition.top = CW_USEDEFAULT;
488  Settings.wpPos.rcNormalPosition.right = CW_USEDEFAULT;
489  Settings.wpPos.rcNormalPosition.bottom = CW_USEDEFAULT;
490  Settings.wpPos.showCmd = nDefCmdShow; // SW_SHOWNORMAL;
491  }
492 
493  dwSize = sizeof(Value);
494  Result = RegQueryValueExW(hKeyEventVwr, L"SaveSettings", NULL, &dwType, (LPBYTE)&Value, &dwSize);
495  if ((Result == ERROR_SUCCESS) && (dwType == REG_SZ || dwType == REG_DWORD))
496  {
497  if (dwType == REG_SZ)
498  {
499  ValueU.Buffer = (PWSTR)&Value;
500  ValueU.Length = ValueU.MaximumLength = dwSize;
501  RtlUnicodeStringToInteger(&ValueU, 10, &Value);
502  }
503  Settings.bSaveSettings = !!Value;
504  }
505 
506  RegCloseKey(hKeyEventVwr);
507  return TRUE;
508 }
509 
510 BOOL
512 {
513  HKEY hKeyEventVwr;
514  DWORD dwSize;
515  WCHAR buffer[100];
516 
517  /* Try to create/open the Event Viewer user key */
520  0,
521  NULL,
524  NULL,
525  &hKeyEventVwr,
526  NULL) != ERROR_SUCCESS)
527  {
528  return FALSE;
529  }
530 
531  dwSize = sizeof(Settings.bSaveSettings);
532  RegSetValueExW(hKeyEventVwr, L"SaveSettings", 0, REG_DWORD, (LPBYTE)&Settings.bSaveSettings, dwSize);
533 
534  /* Do not save more settings if we are not asked to do so */
535  if (!Settings.bSaveSettings)
536  goto Quit;
537 
538  dwSize = sizeof(Settings.bShowDetailsPane);
539  RegSetValueExW(hKeyEventVwr, L"DetailsPane", 0, REG_DWORD, (LPBYTE)&Settings.bShowDetailsPane, dwSize);
540 
541  dwSize = sizeof(Settings.bShowGrid);
542  RegSetValueExW(hKeyEventVwr, L"ShowGrid", 0, REG_DWORD, (LPBYTE)&Settings.bShowGrid, dwSize);
543 
544  dwSize = sizeof(Settings.bNewestEventsFirst);
545  RegSetValueExW(hKeyEventVwr, L"SortOrder", 0, REG_DWORD, (LPBYTE)&Settings.bNewestEventsFirst, dwSize);
546 
547  Settings.nVSplitPos = nVSplitPos;
548  dwSize = sizeof(Settings.nVSplitPos);
549  RegSetValueExW(hKeyEventVwr, L"VSplitPos", 0, REG_DWORD, (LPBYTE)&Settings.nVSplitPos, dwSize);
550 
551  Settings.nHSplitPos = nHSplitPos;
552  dwSize = sizeof(Settings.nHSplitPos);
553  RegSetValueExW(hKeyEventVwr, L"HSplitPos", 0, REG_DWORD, (LPBYTE)&Settings.nHSplitPos, dwSize);
554 
555  StringCbPrintfW(buffer, sizeof(buffer),
556  L"%d %d %d %d %d",
557  Settings.wpPos.rcNormalPosition.left,
558  Settings.wpPos.rcNormalPosition.top,
559  Settings.wpPos.rcNormalPosition.right,
560  Settings.wpPos.rcNormalPosition.bottom,
561  Settings.wpPos.showCmd);
562 
563  dwSize = (DWORD)(wcslen(buffer) * sizeof(WCHAR));
564  RegSetValueExW(hKeyEventVwr, L"Window", 0, REG_SZ, (LPBYTE)buffer, dwSize);
565 
566 Quit:
567  RegCloseKey(hKeyEventVwr);
568  return TRUE;
569 }
570 
571 int APIENTRY
573  HINSTANCE hPrevInstance,
574  LPWSTR lpCmdLine,
575  int nCmdShow)
576 {
577  HANDLE hThread;
579  HMODULE hRichEdit;
580  HACCEL hAccelTable;
581  MSG msg;
582 
583  UNREFERENCED_PARAMETER(hPrevInstance);
584  UNREFERENCED_PARAMETER(lpCmdLine);
585 
586  /* Whenever any of the common controls are used in your app,
587  * you must call InitCommonControlsEx() to register the classes
588  * for those controls. */
589  iccx.dwSize = sizeof(iccx);
591  InitCommonControlsEx(&iccx);
592 
593  /* Load the RichEdit DLL to add support for RichEdit controls */
594  hRichEdit = LoadLibraryW(L"riched20.dll");
595  if (!hRichEdit)
596  return -1;
597 
598  msg.wParam = (WPARAM)-1;
599 
600  /* Store the instance handle in the global variable */
601  hInst = hInstance;
602 
603  /* Initialize global strings */
609 
610  /*
611  * Process the command-line arguments. Note that we need the full
612  * command-line, with the program file included, and not just what
613  * WinMain() provides in its lpCmdLine parameter.
614  */
616  goto Quit;
617 
619  goto Quit;
620 
621  /* Load the settings */
622  LoadSettings(nCmdShow);
623 
624  /* Perform application initialization */
625  if (!InitInstance(hInstance))
626  goto Quit;
627 
629 
630  /* Create the Start/Stop enumerator thread */
631  // Manual-reset event
633  if (!hStartStopEnumEvent)
634  goto Cleanup;
635 
636  // Auto-reset event
638  if (!hStartEnumEvent)
639  goto Cleanup;
640 
643  NULL, 0, NULL);
644  if (!hThread)
645  goto Cleanup;
646 
647  /* Retrieve the available event logs on this computer and create filters for them */
651 
652  /* Open the user-specified logs if any are present on the command-line */
654  {
655  LPWSTR lpUserLog;
656  for (lpUserLog = lpszzUserLogsToLoad; *lpUserLog; lpUserLog += wcslen(lpUserLog) + 1)
657  {
658  OpenUserEventLogFile(lpUserLog);
659  }
660 
661  /* Now cleanup the list of user logs */
662  cbUserLogsSize = 0;
665  }
666 
667  /* Main message loop */
668  while (GetMessageW(&msg, NULL, 0, 0))
669  {
670  if (!TranslateAcceleratorW(hwndMainWindow, hAccelTable, &msg))
671  {
674  }
675  }
676 
677  /* Save the settings */
678  SaveSettings();
679 
680  /* Disconnect from computer */
682  {
683  /* We are connected to some other computer, close the old connection */
685  hkMachine = NULL;
686  }
687 
688  /* Stop the enumerator thread */
692 
693  /* Free the filters list and the event logs list */
695  FreeLogList();
696 
697 Cleanup:
698  /* Handle cleanup */
699  if (hStartEnumEvent)
703 
704 Quit:
705  /* Final cleanup */
707  {
708  cbUserLogsSize = 0;
711  }
712  if (lpComputerName)
713  {
716  }
717  FreeLibrary(hRichEdit);
718 
719  return (int)msg.wParam;
720 }
721 
722 
723 /* GENERIC HELPER FUNCTIONS ***************************************************/
724 
725 VOID
727  OUT PSYSTEMTIME pSystemTime)
728 {
729  SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
730  FILETIME ftLocal;
731  union
732  {
733  FILETIME ft;
734  ULONGLONG ll;
735  } u1970, uUCT;
736 
737  uUCT.ft.dwHighDateTime = 0;
738  uUCT.ft.dwLowDateTime = EventTime;
739  SystemTimeToFileTime(&st1970, &u1970.ft);
740  uUCT.ll = uUCT.ll * 10000000 + u1970.ll;
741  FileTimeToLocalFileTime(&uUCT.ft, &ftLocal);
742  FileTimeToSystemTime(&ftLocal, pSystemTime);
743 }
744 
745 /*
746  * This function takes in entry a path to a single DLL, in which
747  * the message string of ID dwMessageId has to be searched.
748  * The other parameters are similar to those of the FormatMessageW API.
749  */
750 LPWSTR
752  IN LPCWSTR lpMessageDll,
753  IN DWORD dwFlags, // If we always use the same flags, just remove this param...
754  IN DWORD dwMessageId,
755  IN DWORD nSize,
756  IN va_list* Arguments OPTIONAL)
757 {
759  DWORD dwLength;
760  LPWSTR lpMsgBuf = NULL;
761 
762  hLibrary = LoadLibraryExW(lpMessageDll, NULL,
763  /* LOAD_LIBRARY_AS_IMAGE_RESOURCE | */ LOAD_LIBRARY_AS_DATAFILE);
764  if (hLibrary == NULL)
765  return NULL;
766 
767  /* Sanitize dwFlags */
770 
771  _SEH2_TRY
772  {
773  /*
774  * Retrieve the message string without appending extra newlines.
775  * Wrap in SEH to protect from invalid string parameters.
776  */
777  _SEH2_TRY
778  {
780  /* FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE |
781  FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, */
782  hLibrary,
783  dwMessageId,
785  (LPWSTR)&lpMsgBuf,
786  nSize,
787  Arguments);
788  }
790  {
791  dwLength = 0;
792 
793  /*
794  * An exception occurred while calling FormatMessage, this is usually
795  * the sign that a parameter was invalid, either 'lpMsgBuf' was NULL
796  * but we did not pass the flag FORMAT_MESSAGE_ALLOCATE_BUFFER, or the
797  * array pointer 'Arguments' was NULL or did not contain enough elements,
798  * and we did not pass the flag FORMAT_MESSAGE_IGNORE_INSERTS, and the
799  * message string expected too many inserts.
800  * In this last case only, we can call again FormatMessage but ignore
801  * explicitly the inserts. The string that we will return to the user
802  * will not be pre-formatted.
803  */
804  if (((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) || lpMsgBuf) &&
806  {
807  /* Remove any possible harmful flags and always ignore inserts */
810 
811  /* If this call also throws an exception, we are really dead */
813  hLibrary,
814  dwMessageId,
816  (LPWSTR)&lpMsgBuf,
817  nSize,
818  NULL /* Arguments */);
819  }
820  }
821  _SEH2_END;
822  }
824  {
826  }
827  _SEH2_END;
828 
829  if (dwLength == 0)
830  {
831  ASSERT(lpMsgBuf == NULL);
832  lpMsgBuf = NULL;
833  }
834  else
835  {
836  LPWSTR ptr;
837 
838  ASSERT(lpMsgBuf);
839 
840  /* Trim any trailing whitespace */
841  ptr = lpMsgBuf + dwLength - 1;
842  while (iswspace(*ptr))
843  *ptr-- = UNICODE_NULL;
844  }
845 
846  return lpMsgBuf;
847 }
848 
849 /*
850  * This function takes in entry a comma-separated list of DLLs, in which
851  * the message string of ID dwMessageId has to be searched.
852  * The other parameters are similar to those of the FormatMessageW API.
853  */
854 LPWSTR
856  IN LPCWSTR lpMessageDllList,
857  IN DWORD dwFlags, // If we always use the same flags, just remove this param...
858  IN DWORD dwMessageId,
859  IN DWORD nSize,
860  IN va_list* Arguments OPTIONAL)
861 {
862  BOOL Success = FALSE;
863  SIZE_T cbLength;
864  LPWSTR szMessageDllList;
865  LPWSTR szDll;
866  LPWSTR lpMsgBuf = NULL;
867 
868  /* Allocate a local buffer for the DLL list that can be tokenized */
869  // TODO: Optimize that!! Maybe we can cleverly use lpMessageDllList in read/write mode
870  // and cleverly temporarily replace the ';' by UNICODE_NULL, do our job, then reverse the change.
871  cbLength = (wcslen(lpMessageDllList) + 1) * sizeof(WCHAR);
872  szMessageDllList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbLength);
873  if (!szMessageDllList)
874  return NULL;
875  RtlCopyMemory(szMessageDllList, lpMessageDllList, cbLength);
876 
877  /* Loop through the list of message DLLs */
878  szDll = wcstok(szMessageDllList, EVENT_DLL_SEPARATOR);
879  while ((szDll != NULL) && !Success)
880  {
881  // Uses LANG_USER_DEFAULT
882  lpMsgBuf = GetMessageStringFromDll(szDll,
883  dwFlags,
884  dwMessageId,
885  nSize,
886  Arguments);
887  if (lpMsgBuf)
888  {
889  /* The ID was found and the message was formatted */
890  Success = TRUE;
891  break;
892  }
893 
894  /*
895  * The DLL could not be loaded, or the message could not be found,
896  * try the next DLL, if any.
897  */
898  szDll = wcstok(NULL, EVENT_DLL_SEPARATOR);
899  }
900 
901  HeapFree(GetProcessHeap(), 0, szMessageDllList);
902 
903  return lpMsgBuf;
904 }
905 
906 
907 typedef struct
908 {
909  LPWSTR pStartingAddress; // Pointer to the beginning of a parameter string in pMessage
910  LPWSTR pEndingAddress; // Pointer to the end of a parameter string in pMessage
911  DWORD pParameterID; // Parameter identifier found in pMessage
912  LPWSTR pParameter; // Actual parameter string
914 
915 DWORD
917  IN LPCWSTR lpMessageDllList,
918  IN BOOL bMessagePreFormatted,
919  IN CONST LPCWSTR pMessage,
920  OUT LPWSTR* pFinalMessage)
921 {
922  /*
923  * This code is heavily adapted from the MSDN example:
924  * https://msdn.microsoft.com/en-us/library/windows/desktop/bb427356.aspx
925  * with bugs removed.
926  */
927 
929  DWORD dwParamCount = 0; // Number of insertion strings found in pMessage
930  size_t cchBuffer = 0; // Size of the buffer in characters
931  size_t cchParams = 0; // Number of characters in all the parameter strings
932  size_t cch = 0;
933  DWORD i = 0;
934  param_strings_format_data* pParamData = NULL; // Array of pointers holding information about each parameter string in pMessage
935  LPWSTR pTempMessage = (LPWSTR)pMessage;
936  LPWSTR pTempFinalMessage = NULL;
937 
938  *pFinalMessage = NULL;
939 
940  /* Determine the number of parameter insertion strings in pMessage */
941  if (bMessagePreFormatted)
942  {
943  while ((pTempMessage = wcschr(pTempMessage, L'%')))
944  {
945  pTempMessage++;
946  if (iswdigit(*pTempMessage))
947  {
948  dwParamCount++;
949  while (iswdigit(*++pTempMessage)) ;
950  }
951  }
952  }
953  else
954  {
955  while ((pTempMessage = wcsstr(pTempMessage, L"%%")))
956  {
957  pTempMessage += 2;
958  if (iswdigit(*pTempMessage))
959  {
960  dwParamCount++;
961  while (iswdigit(*++pTempMessage)) ;
962  }
963  }
964  }
965 
966  /* If there are no parameter insertion strings in pMessage, just return */
967  if (dwParamCount == 0)
968  {
969  // *pFinalMessage = NULL;
970  goto Cleanup;
971  }
972 
973  /* Allocate the array of parameter string format data */
974  pParamData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwParamCount * sizeof(param_strings_format_data));
975  if (!pParamData)
976  {
978  goto Cleanup;
979  }
980 
981  /*
982  * Retrieve each parameter in pMessage and the beginning and end of the
983  * insertion string, as well as the message identifier of the parameter.
984  */
985  pTempMessage = (LPWSTR)pMessage;
986  if (bMessagePreFormatted)
987  {
988  while ((pTempMessage = wcschr(pTempMessage, L'%')) && (i < dwParamCount))
989  {
990  pTempMessage++;
991  if (iswdigit(*pTempMessage))
992  {
993  pParamData[i].pStartingAddress = pTempMessage-1;
994  pParamData[i].pParameterID = (DWORD)_wtol(pTempMessage);
995 
996  while (iswdigit(*++pTempMessage)) ;
997 
998  pParamData[i].pEndingAddress = pTempMessage;
999  i++;
1000  }
1001  }
1002  }
1003  else
1004  {
1005  while ((pTempMessage = wcsstr(pTempMessage, L"%%")) && (i < dwParamCount))
1006  {
1007  pTempMessage += 2;
1008  if (iswdigit(*pTempMessage))
1009  {
1010  pParamData[i].pStartingAddress = pTempMessage-2;
1011  pParamData[i].pParameterID = (DWORD)_wtol(pTempMessage);
1012 
1013  while (iswdigit(*++pTempMessage)) ;
1014 
1015  pParamData[i].pEndingAddress = pTempMessage;
1016  i++;
1017  }
1018  }
1019  }
1020 
1021  /* Retrieve each parameter string */
1022  for (i = 0; i < dwParamCount; i++)
1023  {
1024  // pParamData[i].pParameter = GetMessageString(pParamData[i].pParameterID, 0, NULL);
1025  pParamData[i].pParameter =
1026  GetMessageStringFromDllList(lpMessageDllList,
1029  pParamData[i].pParameterID,
1030  0, NULL);
1031  if (!pParamData[i].pParameter)
1032  {
1033  /* Skip the insertion string */
1034  continue;
1035  }
1036 
1037  cchParams += wcslen(pParamData[i].pParameter);
1038  }
1039 
1040  /*
1041  * Allocate the final message buffer, the size of which is based on the
1042  * length of the original message and the length of each parameter string.
1043  */
1044  cchBuffer = wcslen(pMessage) + cchParams + 1;
1045  *pFinalMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cchBuffer * sizeof(WCHAR));
1046  if (!*pFinalMessage)
1047  {
1049  goto Cleanup;
1050  }
1051 
1052  pTempFinalMessage = *pFinalMessage;
1053 
1054  /* Build the final message string */
1055  pTempMessage = (LPWSTR)pMessage;
1056  for (i = 0; i < dwParamCount; i++)
1057  {
1058  /* Append the segment from pMessage */
1059  cch = pParamData[i].pStartingAddress - pTempMessage;
1060  StringCchCopyNW(pTempFinalMessage, cchBuffer, pTempMessage, cch);
1061  pTempMessage = pParamData[i].pEndingAddress;
1062  cchBuffer -= cch;
1063  pTempFinalMessage += cch;
1064 
1065  /* Append the parameter string */
1066  if (pParamData[i].pParameter)
1067  {
1068  StringCchCopyW(pTempFinalMessage, cchBuffer, pParamData[i].pParameter);
1069  cch = wcslen(pParamData[i].pParameter); // pTempFinalMessage
1070  }
1071  else
1072  {
1073  /*
1074  * We failed to retrieve the parameter string before, so just
1075  * place back the original string placeholder.
1076  */
1077  cch = pParamData[i].pEndingAddress /* == pTempMessage */ - pParamData[i].pStartingAddress;
1078  StringCchCopyNW(pTempFinalMessage, cchBuffer, pParamData[i].pStartingAddress, cch);
1079  // cch = wcslen(pTempFinalMessage);
1080  }
1081  cchBuffer -= cch;
1082  pTempFinalMessage += cch;
1083  }
1084 
1085  /* Append the last segment from pMessage */
1086  StringCchCopyW(pTempFinalMessage, cchBuffer, pTempMessage);
1087 
1088 Cleanup:
1089 
1090  // if (Status != ERROR_SUCCESS)
1091  // *pFinalMessage = NULL;
1092 
1093  if (pParamData)
1094  {
1095  for (i = 0; i < dwParamCount; i++)
1096  {
1097  if (pParamData[i].pParameter)
1098  LocalFree(pParamData[i].pParameter);
1099  }
1100 
1101  HeapFree(GetProcessHeap(), 0, pParamData);
1102  }
1103 
1104  return Status;
1105 }
1106 
1107 
1108 /*
1109  * The following functions were adapted from
1110  * shell32!dialogs/filedefext.cpp:``SH_...'' functions.
1111  */
1112 
1113 UINT
1114 FormatInteger(LONGLONG Num, LPWSTR pwszResult, UINT cchResultMax)
1115 {
1116  WCHAR wszNumber[24];
1117  WCHAR wszDecimalSep[8], wszThousandSep[8];
1118  NUMBERFMTW nf;
1119  WCHAR wszGrouping[12];
1120  INT cchGrouping;
1121  INT cchResult;
1122  INT i;
1123 
1124  // Print the number in uniform mode
1125  swprintf(wszNumber, L"%I64u", Num);
1126 
1127  // Get system strings for decimal and thousand separators.
1128  GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, wszDecimalSep, _countof(wszDecimalSep));
1129  GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, wszThousandSep, _countof(wszThousandSep));
1130 
1131  // Initialize format for printing the number in bytes
1132  ZeroMemory(&nf, sizeof(nf));
1133  nf.lpDecimalSep = wszDecimalSep;
1134  nf.lpThousandSep = wszThousandSep;
1135 
1136  // Get system string for groups separator
1137  cchGrouping = GetLocaleInfoW(LOCALE_USER_DEFAULT,
1139  wszGrouping,
1140  _countof(wszGrouping));
1141 
1142  // Convert grouping specs from string to integer
1143  for (i = 0; i < cchGrouping; i++)
1144  {
1145  WCHAR wch = wszGrouping[i];
1146 
1147  if (wch >= L'0' && wch <= L'9')
1148  nf.Grouping = nf.Grouping * 10 + (wch - L'0');
1149  else if (wch != L';')
1150  break;
1151  }
1152 
1153  if ((nf.Grouping % 10) == 0)
1154  nf.Grouping /= 10;
1155  else
1156  nf.Grouping *= 10;
1157 
1158  // Format the number
1160  0,
1161  wszNumber,
1162  &nf,
1163  pwszResult,
1164  cchResultMax);
1165 
1166  if (!cchResult)
1167  return 0;
1168 
1169  // GetNumberFormatW returns number of characters including UNICODE_NULL
1170  return cchResult - 1;
1171 }
1172 
1173 UINT
1174 FormatByteSize(LONGLONG cbSize, LPWSTR pwszResult, UINT cchResultMax)
1175 {
1176  UINT cchWritten, cchRemaining;
1177  LPWSTR pwszEnd;
1178  size_t cchStringRemaining;
1179 
1180  /* Write formated bytes count */
1181  cchWritten = FormatInteger(cbSize, pwszResult, cchResultMax);
1182  if (!cchWritten)
1183  return 0;
1184 
1185  /* Copy " bytes" to buffer */
1186  pwszEnd = pwszResult + cchWritten;
1187  cchRemaining = cchResultMax - cchWritten;
1188  StringCchCopyExW(pwszEnd, cchRemaining, L" ", &pwszEnd, &cchStringRemaining, 0);
1189  cchRemaining = (UINT)cchStringRemaining;
1190  cchWritten = LoadStringW(hInst, IDS_BYTES_FORMAT, pwszEnd, cchRemaining);
1191  cchRemaining -= cchWritten;
1192 
1193  return cchResultMax - cchRemaining;
1194 }
1195 
1196 LPWSTR
1197 FormatFileSizeWithBytes(const PULARGE_INTEGER lpQwSize, LPWSTR pwszResult, UINT cchResultMax)
1198 {
1199  UINT cchWritten, cchRemaining;
1200  LPWSTR pwszEnd;
1201  size_t cchCopyRemaining;
1202 
1203  /* Format bytes in KBs, MBs etc */
1204  if (StrFormatByteSizeW(lpQwSize->QuadPart, pwszResult, cchResultMax) == NULL)
1205  return NULL;
1206 
1207  /* If there is less bytes than 1KB, we have nothing to do */
1208  if (lpQwSize->QuadPart < 1024)
1209  return pwszResult;
1210 
1211  /* Concatenate " (" */
1212  cchWritten = (UINT)wcslen(pwszResult);
1213  pwszEnd = pwszResult + cchWritten;
1214  cchRemaining = cchResultMax - cchWritten;
1215  StringCchCopyExW(pwszEnd, cchRemaining, L" (", &pwszEnd, &cchCopyRemaining, 0);
1216  cchRemaining = (UINT)cchCopyRemaining;
1217 
1218  /* Write formated bytes count */
1219  cchWritten = FormatByteSize(lpQwSize->QuadPart, pwszEnd, cchRemaining);
1220  pwszEnd += cchWritten;
1221  cchRemaining -= cchWritten;
1222 
1223  /* Copy ")" to the buffer */
1224  StringCchCopyW(pwszEnd, cchRemaining, L")");
1225 
1226  return pwszResult;
1227 }
1228 
1229 /* Adapted from shell32!dialogs/filedefext.cpp:``CFileDefExt::GetFileTimeString'' */
1230 BOOL
1231 GetFileTimeString(LPFILETIME lpFileTime, LPWSTR pwszResult, UINT cchResult)
1232 {
1233  FILETIME ft;
1234  SYSTEMTIME st;
1235  int cchWritten;
1236  UINT cchRemaining = cchResult;
1237  size_t cchCopyRemaining;
1238  LPWSTR pwszEnd = pwszResult;
1239 
1240  if (!FileTimeToLocalFileTime(lpFileTime, &ft) || !FileTimeToSystemTime(&ft, &st))
1241  return FALSE;
1242 
1243  cchWritten = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, pwszEnd, cchRemaining);
1244  if (cchWritten)
1245  --cchWritten; // GetDateFormatW returns count with terminating zero
1246  // else
1247  // ERR("GetDateFormatW failed\n");
1248 
1249  cchRemaining -= cchWritten;
1250  pwszEnd += cchWritten;
1251 
1252  StringCchCopyExW(pwszEnd, cchRemaining, L", ", &pwszEnd, &cchCopyRemaining, 0);
1253  cchRemaining = (UINT)cchCopyRemaining;
1254 
1255  cchWritten = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, pwszEnd, cchRemaining);
1256  if (cchWritten)
1257  --cchWritten; // GetTimeFormatW returns count with terminating zero
1258  // else
1259  // ERR("GetTimeFormatW failed\n");
1260 
1261  return TRUE;
1262 }
1263 
1264 
1265 HTREEITEM
1268  IN LPWSTR lpText,
1269  IN INT Image,
1270  IN INT SelectedImage,
1271  IN LPARAM lParam)
1272 {
1273  TV_INSERTSTRUCTW Insert;
1274 
1275  ZeroMemory(&Insert, sizeof(Insert));
1276 
1277  Insert.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1278  Insert.hInsertAfter = TVI_LAST;
1279  Insert.hParent = hParent;
1280  Insert.item.pszText = lpText;
1281  Insert.item.iImage = Image;
1282  Insert.item.iSelectedImage = SelectedImage;
1283  Insert.item.lParam = lParam;
1284 
1285  Insert.item.mask |= TVIF_STATE;
1286  Insert.item.stateMask = TVIS_OVERLAYMASK;
1287  Insert.item.state = INDEXTOOVERLAYMASK(1);
1288 
1289  return TreeView_InsertItem(hTreeView, &Insert);
1290 }
1291 
1292 
1293 /* LOG HELPER FUNCTIONS *******************************************************/
1294 
1295 PEVENTLOG
1297  IN PCWSTR LogName,
1298  IN BOOL Permanent)
1299 {
1300  PEVENTLOG EventLog;
1301  SIZE_T cchName;
1302 
1303  /* Allocate a new event log entry */
1304  EventLog = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*EventLog));
1305  if (!EventLog)
1306  return NULL;
1307 
1308  /* Allocate the computer name string (optional) and copy it */
1309  if (ComputerName)
1310  {
1311  cchName = wcslen(ComputerName) + 1;
1312  EventLog->ComputerName = HeapAlloc(GetProcessHeap(), 0, cchName * sizeof(WCHAR));
1313  if (EventLog->ComputerName)
1314  StringCchCopyW(EventLog->ComputerName, cchName, ComputerName);
1315  }
1316 
1317  /* Allocate the event log name string and copy it */
1318  cchName = wcslen(LogName) + 1;
1319  EventLog->LogName = HeapAlloc(GetProcessHeap(), 0, cchName * sizeof(WCHAR));
1320  if (!EventLog->LogName)
1321  {
1322  if (EventLog->ComputerName)
1323  HeapFree(GetProcessHeap(), 0, EventLog->ComputerName);
1324  HeapFree(GetProcessHeap(), 0, EventLog);
1325  return NULL;
1326  }
1327  StringCchCopyW(EventLog->LogName, cchName, LogName);
1328 
1329  EventLog->Permanent = Permanent;
1330 
1331  return EventLog;
1332 }
1333 
1334 VOID
1336 {
1337  if (EventLog->LogName)
1338  HeapFree(GetProcessHeap(), 0, EventLog->LogName);
1339 
1340  if (EventLog->ComputerName)
1341  HeapFree(GetProcessHeap(), 0, EventLog->ComputerName);
1342 
1343  if (EventLog->FileName)
1344  HeapFree(GetProcessHeap(), 0, EventLog->FileName);
1345 
1346  HeapFree(GetProcessHeap(), 0, EventLog);
1347 }
1348 
1349 
1350 PWSTR
1352 {
1353  PWSTR pStr;
1354  ULONG Length;
1355 
1356  if (!MultiStr)
1357  return NULL;
1358 
1359  pStr = (PWSTR)MultiStr;
1360  while (*pStr) pStr += (wcslen(pStr) + 1);
1361  Length = MultiStr - pStr + 2;
1362 
1363  pStr = HeapAlloc(GetProcessHeap(), 0, Length * sizeof(WCHAR));
1364  // NOTE: If we failed allocating the string, then fall back into no filter!
1365  if (pStr)
1366  RtlCopyMemory(pStr, MultiStr, Length * sizeof(WCHAR));
1367 
1368  return pStr;
1369 }
1370 
1372 AllocEventLogFilter(// IN PCWSTR FilterName,
1374  IN BOOL Warning,
1375  IN BOOL Error,
1376  IN BOOL AuditSuccess,
1377  IN BOOL AuditFailure,
1378  IN PCWSTR Sources OPTIONAL,
1379  IN PCWSTR Users OPTIONAL,
1380  IN PCWSTR ComputerNames OPTIONAL,
1381  IN ULONG NumOfEventLogs,
1382  IN PEVENTLOG* EventLogs)
1383 {
1384  PEVENTLOGFILTER EventLogFilter;
1385 
1386  /* Allocate a new event log filter entry, big enough to accommodate the list of logs */
1387  EventLogFilter = HeapAlloc(GetProcessHeap(),
1389  FIELD_OFFSET(EVENTLOGFILTER, EventLogs[NumOfEventLogs]));
1390  if (!EventLogFilter)
1391  return NULL;
1392 
1393  EventLogFilter->Information = Information;
1394  EventLogFilter->Warning = Warning;
1395  EventLogFilter->Error = Error;
1396  EventLogFilter->AuditSuccess = AuditSuccess;
1397  EventLogFilter->AuditFailure = AuditFailure;
1398 
1399  /* Allocate and copy the sources, users, and computers multi-strings */
1400  EventLogFilter->Sources = AllocAndCopyMultiStr(Sources);
1401  EventLogFilter->Users = AllocAndCopyMultiStr(Users);
1402  EventLogFilter->ComputerNames = AllocAndCopyMultiStr(ComputerNames);
1403 
1404  /* Copy the list of event logs */
1405  EventLogFilter->NumOfEventLogs = NumOfEventLogs;
1406  RtlCopyMemory(EventLogFilter->EventLogs, EventLogs, NumOfEventLogs * sizeof(PEVENTLOG));
1407 
1408  /* Initialize the filter reference count */
1409  EventLogFilter->ReferenceCount = 1;
1410 
1411  return EventLogFilter;
1412 }
1413 
1414 VOID
1416 {
1417  if (EventLogFilter->Sources)
1418  HeapFree(GetProcessHeap(), 0, EventLogFilter->Sources);
1419 
1420  if (EventLogFilter->Users)
1421  HeapFree(GetProcessHeap(), 0, EventLogFilter->Users);
1422 
1423  if (EventLogFilter->ComputerNames)
1424  HeapFree(GetProcessHeap(), 0, EventLogFilter->ComputerNames);
1425 
1426  HeapFree(GetProcessHeap(), 0, EventLogFilter);
1427 }
1428 
1430 {
1431  ASSERT(EventLogFilter);
1432  return InterlockedIncrement(&EventLogFilter->ReferenceCount);
1433 }
1434 
1436 {
1437  LONG RefCount;
1438 
1439  ASSERT(EventLogFilter);
1440 
1441  /* When the reference count reaches zero, delete the filter */
1442  RefCount = InterlockedDecrement(&EventLogFilter->ReferenceCount);
1443  if (RefCount <= 0)
1444  {
1445  /* Remove the filter from the list */
1447  EventLogFilter_Free(EventLogFilter);
1448  }
1449 
1450  return RefCount;
1451 }
1452 
1453 void
1455 {
1456  WCHAR *c;
1457 
1458  if (s != NULL)
1459  {
1460  c = s + wcslen(s) - 1;
1461  while (c >= s && iswspace(*c))
1462  --c;
1463  *++c = L'\0';
1464  }
1465 }
1466 
1467 DWORD
1469  IN LPCWSTR ComputerName OPTIONAL,
1471  OUT LPWSTR lpFullFileName OPTIONAL,
1472  IN DWORD nSize)
1473 {
1474  SIZE_T dwLength;
1475 
1476  /* Determine the needed size after expansion of any environment strings */
1478  if (dwLength == 0)
1479  {
1480  /* We failed, bail out */
1481  return 0;
1482  }
1483 
1484  /* If the file path is on a remote computer, estimate its length */
1485  // FIXME: Use WNetGetUniversalName instead?
1486  if (ComputerName && *ComputerName)
1487  {
1488  /* Skip any leading backslashes */
1489  while (*ComputerName == L'\\')
1490  ++ComputerName;
1491 
1492  if (*ComputerName)
1493  {
1494  /* Count 2 backslashes plus the computer name and one backslash separator */
1495  dwLength += 2 + wcslen(ComputerName) + 1;
1496  }
1497  }
1498 
1499  /* Check whether we have enough space */
1500  if (dwLength > nSize)
1501  {
1502  /* No, return the needed size in characters (includes NULL-terminator) */
1503  return dwLength;
1504  }
1505 
1506 
1507  /* Now expand the file path */
1508  ASSERT(dwLength <= nSize);
1509 
1510  /* Expand any existing environment strings */
1511  if (ExpandEnvironmentStringsW(lpFileName, lpFullFileName, dwLength) == 0)
1512  {
1513  /* We failed, bail out */
1514  return 0;
1515  }
1516 
1517  /* If the file path is on a remote computer, retrieve the network share form of the file name */
1518  // FIXME: Use WNetGetUniversalName instead?
1519  if (ComputerName && *ComputerName)
1520  {
1521  /* Note that we previously skipped any potential leading backslashes */
1522 
1523  /* Replace ':' by '$' in the drive letter */
1524  if (*lpFullFileName && lpFullFileName[1] == L':')
1525  lpFullFileName[1] = L'$';
1526 
1527  /* Prepend the computer name */
1528  RtlMoveMemory(lpFullFileName + 2 + wcslen(ComputerName) + 1,
1529  lpFullFileName, dwLength * sizeof(WCHAR) - (2 + wcslen(ComputerName) + 1) * sizeof(WCHAR));
1530  lpFullFileName[0] = L'\\';
1531  lpFullFileName[1] = L'\\';
1532  wcsncpy(lpFullFileName + 2, ComputerName, wcslen(ComputerName));
1533  lpFullFileName[2 + wcslen(ComputerName)] = L'\\';
1534  }
1535 
1536  /* Return the number of stored characters (includes NULL-terminator) */
1537  return dwLength;
1538 }
1539 
1540 BOOL
1543  IN LPCWSTR EntryName,
1544  OUT PWCHAR lpModuleName) // TODO: Add IN DWORD BufLen
1545 {
1546  BOOL Success = FALSE;
1547  LONG Result;
1548  DWORD dwType, dwSize;
1550  WCHAR szKeyName[MAX_PATH];
1551  HKEY hLogKey = NULL;
1552  HKEY hSourceKey = NULL;
1553 
1554  StringCbCopyW(szKeyName, sizeof(szKeyName), EVENTLOG_BASE_KEY);
1555  StringCbCatW(szKeyName, sizeof(szKeyName), lpLogName);
1556 
1558  szKeyName,
1559  0,
1560  KEY_READ,
1561  &hLogKey);
1562  if (Result != ERROR_SUCCESS)
1563  return FALSE;
1564 
1565  Result = RegOpenKeyExW(hLogKey,
1566  SourceName,
1567  0,
1569  &hSourceKey);
1570  if (Result != ERROR_SUCCESS)
1571  {
1572  RegCloseKey(hLogKey);
1573  return FALSE;
1574  }
1575 
1576  dwSize = sizeof(szModuleName);
1577  Result = RegQueryValueExW(hSourceKey,
1578  EntryName,
1579  NULL,
1580  &dwType,
1582  &dwSize);
1583  if ((Result != ERROR_SUCCESS) || (dwType != REG_EXPAND_SZ && dwType != REG_SZ))
1584  {
1586  }
1587  else
1588  {
1589  /* NULL-terminate the string and expand it */
1590  szModuleName[dwSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
1592  Success = TRUE;
1593  }
1594 
1595  RegCloseKey(hSourceKey);
1596  RegCloseKey(hLogKey);
1597 
1598  return Success;
1599 }
1600 
1601 BOOL
1604  IN PEVENTLOGRECORD pevlr,
1605  OUT PWCHAR CategoryName) // TODO: Add IN DWORD BufLen
1606 {
1607  BOOL Success = FALSE;
1608  WCHAR szMessageDLL[MAX_PATH];
1609  LPWSTR lpMsgBuf = NULL;
1610 
1612  goto Quit;
1613 
1614  /* Retrieve the message string without appending extra newlines */
1615  lpMsgBuf =
1616  GetMessageStringFromDllList(szMessageDLL,
1619  pevlr->EventCategory,
1621  NULL);
1622  if (lpMsgBuf)
1623  {
1624  /* Trim the string */
1625  TrimNulls(lpMsgBuf);
1626 
1627  /* Copy the category name */
1628  StringCchCopyW(CategoryName, MAX_PATH, lpMsgBuf);
1629 
1630  /* Free the buffer allocated by FormatMessage */
1631  LocalFree(lpMsgBuf);
1632 
1633  /* The ID was found and the message was formatted */
1634  Success = TRUE;
1635  }
1636 
1637 Quit:
1638  if (!Success)
1639  {
1640  if (pevlr->EventCategory != 0)
1641  {
1642  StringCchPrintfW(CategoryName, MAX_PATH, L"(%lu)", pevlr->EventCategory);
1643  Success = TRUE;
1644  }
1645  }
1646 
1647  return Success;
1648 }
1649 
1650 
1651 BOOL // NOTE: Used by evtdetctl.c
1654  IN PEVENTLOGRECORD pevlr,
1655  OUT PWCHAR EventText) // TODO: Add IN DWORD BufLen
1656 {
1657  BOOL Success = FALSE;
1658  DWORD i;
1659  size_t cch;
1660  WCHAR SourceModuleName[1024];
1661  WCHAR ParameterModuleName[1024];
1662  BOOL IsParamModNameCached = FALSE;
1663  LPWSTR lpMsgBuf = NULL;
1664  LPWSTR szStringArray, szMessage;
1665  LPWSTR *szArguments;
1666 
1667  /* Get the event string array */
1668  szStringArray = (LPWSTR)((LPBYTE)pevlr + pevlr->StringOffset);
1669 
1670  /* NOTE: GetEventMessageFileDLL can return a comma-separated list of DLLs */
1671  if (!GetEventMessageFileDLL(KeyName, SourceName, EVENT_MESSAGE_FILE, SourceModuleName))
1672  goto Quit;
1673 
1674  /* Allocate space for insertion strings */
1675  szArguments = HeapAlloc(GetProcessHeap(), 0, pevlr->NumStrings * sizeof(LPVOID));
1676  if (!szArguments)
1677  goto Quit;
1678 
1679  if (!IsParamModNameCached)
1680  {
1681  /* Now that the parameter file list is loaded, no need to reload it at the next run! */
1682  IsParamModNameCached = GetEventMessageFileDLL(KeyName, SourceName, EVENT_PARAMETER_MESSAGE_FILE, ParameterModuleName);
1683  // FIXME: If the string loading failed the first time, no need to retry it just after???
1684  }
1685 
1686  if (IsParamModNameCached)
1687  {
1688  /* Not yet support for reading messages from parameter message DLL */
1689  }
1690 
1691  szMessage = szStringArray;
1692  /*
1693  * HACK:
1694  * We do some hackish preformatting of the cached event strings...
1695  * That's because after we pass the string to FormatMessage
1696  * (via GetMessageStringFromDllList) with the FORMAT_MESSAGE_ARGUMENT_ARRAY
1697  * flag, instead of ignoring the insertion parameters and do the formatting
1698  * by ourselves. Therefore, the resulting string should have the parameter
1699  * string placeholders starting with a single '%' instead of a mix of one
1700  * and two '%'.
1701  */
1702  /* HACK part 1: Compute the full length of the string array */
1703  cch = 0;
1704  for (i = 0; i < pevlr->NumStrings; i++)
1705  {
1706  szMessage += wcslen(szMessage) + 1;
1707  }
1708  cch = szMessage - szStringArray;
1709 
1710  /* HACK part 2: Now do the HACK proper! */
1711  szMessage = szStringArray;
1712  for (i = 0; i < pevlr->NumStrings; i++)
1713  {
1714  lpMsgBuf = szMessage;
1715  while ((lpMsgBuf = wcsstr(lpMsgBuf, L"%%")))
1716  {
1717  if (iswdigit(lpMsgBuf[2]))
1718  {
1719  RtlMoveMemory(lpMsgBuf, lpMsgBuf+1, ((szStringArray + cch) - lpMsgBuf - 1) * sizeof(WCHAR));
1720  }
1721  }
1722 
1723  szArguments[i] = szMessage;
1724  szMessage += wcslen(szMessage) + 1;
1725  }
1726 
1727  /* Retrieve the message string without appending extra newlines */
1728  lpMsgBuf =
1729  GetMessageStringFromDllList(SourceModuleName,
1732  pevlr->EventID,
1733  0,
1734  (va_list*)szArguments);
1735  if (lpMsgBuf)
1736  {
1737  /* Trim the string */
1738  TrimNulls(lpMsgBuf);
1739 
1740  szMessage = NULL;
1741  Success = (ApplyParameterStringsToMessage(ParameterModuleName,
1742  TRUE,
1743  lpMsgBuf,
1744  &szMessage) == ERROR_SUCCESS);
1745  if (Success && szMessage)
1746  {
1747  /* Free the buffer allocated by FormatMessage */
1748  LocalFree(lpMsgBuf);
1749  lpMsgBuf = szMessage;
1750  }
1751 
1752  /* Copy the event text */
1753  StringCchCopyW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, lpMsgBuf);
1754 
1755  /* Free the buffer allocated by FormatMessage */
1756  LocalFree(lpMsgBuf);
1757  }
1758 
1759  HeapFree(GetProcessHeap(), 0, szArguments);
1760 
1761 Quit:
1762  if (!Success)
1763  {
1764  /* Get a read-only pointer to the "event-not-found" string */
1765  lpMsgBuf = HeapAlloc(GetProcessHeap(), 0, EVENT_MESSAGE_EVENTTEXT_BUFFER * sizeof(WCHAR));
1767  StringCchPrintfW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, lpMsgBuf, (pevlr->EventID & 0xFFFF), SourceName);
1768 
1769  /* Append the strings */
1770  szMessage = szStringArray;
1771  for (i = 0; i < pevlr->NumStrings; i++)
1772  {
1773  StringCchCatW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, szMessage);
1775  szMessage += wcslen(szMessage) + 1;
1776  }
1777  }
1778 
1779  return Success;
1780 }
1781 
1782 VOID
1783 GetEventType(IN WORD dwEventType,
1784  OUT PWCHAR eventTypeText) // TODO: Add IN DWORD BufLen
1785 {
1786  switch (dwEventType)
1787  {
1788  case EVENTLOG_ERROR_TYPE:
1790  break;
1791  case EVENTLOG_WARNING_TYPE:
1793  break;
1796  break;
1797  case EVENTLOG_SUCCESS:
1799  break;
1802  break;
1805  break;
1806  default:
1808  break;
1809  }
1810 }
1811 
1812 BOOL
1814  IN OUT PSID *pLastSid,
1815  OUT PWCHAR pszUser) // TODO: Add IN DWORD BufLen
1816 {
1817  PSID pCurrentSid;
1818  PWSTR StringSid;
1819  WCHAR szName[1024];
1820  WCHAR szDomain[1024];
1823  DWORD cchDomain = ARRAYSIZE(szDomain);
1824  BOOL Success = FALSE;
1825 
1826  /* Point to the SID */
1827  pCurrentSid = (PSID)((LPBYTE)pelr + pelr->UserSidOffset);
1828 
1829  if (!IsValidSid(pCurrentSid))
1830  {
1831  *pLastSid = NULL;
1832  return FALSE;
1833  }
1834  else if (*pLastSid && EqualSid(*pLastSid, pCurrentSid))
1835  {
1836  return TRUE;
1837  }
1838 
1839  /* User SID */
1840  if (pelr->UserSidLength > 0)
1841  {
1842  /*
1843  * Try to retrieve the user account name and domain name corresponding
1844  * to the SID. If it cannot be retrieved, try to convert the SID to a
1845  * string-form. It should not be bigger than the user-provided buffer
1846  * 'pszUser', otherwise we return an error.
1847  */
1849  pCurrentSid,
1850  szName,
1851  &cchName,
1852  szDomain,
1853  &cchDomain,
1854  &peUse))
1855  {
1856  StringCchCopyW(pszUser, MAX_PATH, szName);
1857  Success = TRUE;
1858  }
1859  else if (ConvertSidToStringSidW(pCurrentSid, &StringSid))
1860  {
1861  /* Copy the string only if the user-provided buffer is big enough */
1862  if (wcslen(StringSid) + 1 <= MAX_PATH) // + 1 for NULL-terminator
1863  {
1864  StringCchCopyW(pszUser, MAX_PATH, StringSid);
1865  Success = TRUE;
1866  }
1867  else
1868  {
1870  Success = FALSE;
1871  }
1872 
1873  /* Free the allocated buffer */
1874  LocalFree(StringSid);
1875  }
1876  }
1877 
1878  *pLastSid = Success ? pCurrentSid : NULL;
1879 
1880  return Success;
1881 }
1882 
1883 
1885 {
1886  DWORD iIndex;
1887 
1888  if (!g_RecordPtrs)
1889  return;
1890 
1891  for (iIndex = 0; iIndex < g_TotalRecords; iIndex++)
1892  {
1893  if (g_RecordPtrs[iIndex])
1894  HeapFree(GetProcessHeap(), 0, g_RecordPtrs[iIndex]);
1895  }
1897  g_RecordPtrs = NULL;
1898  g_TotalRecords = 0;
1899 }
1900 
1901 BOOL
1903  IN PEVENTLOGRECORD pevlr)
1904 {
1905  if ((pevlr->EventType == EVENTLOG_SUCCESS && !EventLogFilter->Information ) ||
1906  (pevlr->EventType == EVENTLOG_INFORMATION_TYPE && !EventLogFilter->Information ) ||
1907  (pevlr->EventType == EVENTLOG_WARNING_TYPE && !EventLogFilter->Warning ) ||
1908  (pevlr->EventType == EVENTLOG_ERROR_TYPE && !EventLogFilter->Error ) ||
1909  (pevlr->EventType == EVENTLOG_AUDIT_SUCCESS && !EventLogFilter->AuditSuccess) ||
1910  (pevlr->EventType == EVENTLOG_AUDIT_FAILURE && !EventLogFilter->AuditFailure))
1911  {
1912  return FALSE;
1913  }
1914  return TRUE;
1915 }
1916 
1917 BOOL
1918 FilterByString(IN PCWSTR FilterString, // This is a multi-string
1919  IN PWSTR String)
1920 {
1921  PCWSTR pStr;
1922 
1923  /* The filter string is NULL so it does not filter anything */
1924  if (!FilterString)
1925  return TRUE;
1926 
1927  /*
1928  * If the filter string filters for an empty string AND the source string
1929  * is an empty string, we have a match (particular case of the last one).
1930  */
1931  if (!*FilterString && !*String)
1932  return TRUE;
1933 
1934  // if (*FilterString || *String)
1935 
1936  /*
1937  * If the filter string is empty BUT the source string is not empty,
1938  * OR vice-versa, we cannot have a match.
1939  */
1940  if ( (!*FilterString && *String) || (*FilterString && !*String) )
1941  return FALSE;
1942 
1943  /*
1944  * If the filter string filters for at least a non-empty string,
1945  * browse it and search for a string that matches the source string.
1946  */
1947  // else if (*FilterString && *String)
1948  {
1949  pStr = FilterString;
1950  while (*pStr)
1951  {
1952  if (wcsicmp(pStr, String) == 0)
1953  {
1954  /* We have a match, break the loop */
1955  break;
1956  }
1957 
1958  pStr += (wcslen(pStr) + 1);
1959  }
1960  if (!*pStr) // && *String
1961  {
1962  /* We do not have a match */
1963  return FALSE;
1964  }
1965  }
1966 
1967  /* We have a match */
1968  return TRUE;
1969 }
1970 
1971 /*
1972  * The events enumerator thread.
1973  */
1974 static DWORD WINAPI
1976 {
1977  PEVENTLOGFILTER EventLogFilter = (PEVENTLOGFILTER)lpParameter;
1978  PEVENTLOG EventLog;
1979 
1980  ULONG LogIndex;
1981  HANDLE hEventLog;
1982  PEVENTLOGRECORD pEvlr = NULL;
1983  PBYTE pEvlrEnd;
1984  PBYTE pEvlrBuffer;
1985  DWORD dwWanted, dwRead, dwNeeded, dwStatus = ERROR_SUCCESS;
1986  DWORD dwTotalRecords = 0, dwCurrentRecord = 0;
1987  DWORD dwFlags, dwMaxLength;
1988  size_t cchRemaining;
1989  LPWSTR lpszSourceName;
1990  LPWSTR lpszComputerName;
1991  BOOL bResult = TRUE; /* Read succeeded */
1993  PSID pLastSid = NULL;
1994 
1995  UINT uStep = 0, uStepAt = 0, uPos = 0;
1996 
1997  WCHAR szWindowTitle[MAX_PATH];
1998  WCHAR szStatusText[MAX_PATH];
1999  WCHAR szLocalDate[MAX_PATH];
2000  WCHAR szLocalTime[MAX_PATH];
2001  WCHAR szEventID[MAX_PATH];
2002  WCHAR szEventTypeText[MAX_LOADSTRING];
2003  WCHAR szCategoryID[MAX_PATH];
2004  WCHAR szUsername[MAX_PATH];
2005  WCHAR szNoUsername[MAX_PATH];
2006  WCHAR szCategory[MAX_PATH];
2007  WCHAR szNoCategory[MAX_PATH];
2008  PWCHAR lpTitleTemplateEnd;
2009 
2010  SYSTEMTIME time;
2011  LVITEMW lviEventItem;
2012 
2013  /* Save the current event log filter globally */
2014  EventLogFilter_AddRef(EventLogFilter);
2015  ActiveFilter = EventLogFilter;
2016 
2017 
2019  EventLog = EventLogFilter->EventLogs[0];
2020 
2021  // FIXME: Use something else instead of EventLog->LogName !!
2022 
2023  /*
2024  * Use a different formatting, whether the event log filter holds
2025  * only one log, or many logs (the latter case is WIP TODO!)
2026  */
2027  if (EventLogFilter->NumOfEventLogs <= 1)
2028  {
2029  StringCchPrintfExW(szWindowTitle,
2030  ARRAYSIZE(szWindowTitle),
2031  &lpTitleTemplateEnd,
2032  &cchRemaining,
2033  0,
2034  szTitleTemplate, szTitle, EventLog->LogName); /* i = number of characters written */
2035  dwMaxLength = (DWORD)cchRemaining;
2036  if (!EventLog->ComputerName)
2037  GetComputerNameW(lpTitleTemplateEnd, &dwMaxLength);
2038  else
2039  StringCchCopyW(lpTitleTemplateEnd, dwMaxLength, EventLog->ComputerName);
2040 
2041  StringCbPrintfW(szStatusText,
2042  sizeof(szStatusText),
2044  EventLog->LogName,
2045  0,
2046  0);
2047  }
2048  else
2049  {
2050  // TODO: Use a different title & implement filtering for multi-log filters !!
2051  // (EventLogFilter->NumOfEventLogs > 1)
2053  L"Many-logs filtering is not implemented yet!!",
2054  L"Event Log",
2056  }
2057 
2058  /* Set the window title */
2059  SetWindowTextW(hwndMainWindow, szWindowTitle);
2060 
2061  /* Update the status bar */
2062  StatusBar_SetText(hwndStatus, 0, szStatusText);
2063 
2064 
2065  /* Disable list view redraw */
2067 
2068  /* Clear the list view and free the cached records */
2070  FreeRecords();
2071 
2076 
2077  /* Do a loop over the logs enumerated in the filter */
2078  // FIXME: For now we only support 1 event log per filter!
2079  LogIndex = 0;
2080  // for (LogIndex = 0; LogIndex < EventLogFilter->NumOfEventLogs; ++LogIndex)
2081  {
2082 
2083  EventLog = EventLogFilter->EventLogs[LogIndex];
2084 
2085  /* Open the event log */
2086  if (EventLog->Permanent)
2087  hEventLog = OpenEventLogW(EventLog->ComputerName, EventLog->LogName);
2088  else
2089  hEventLog = OpenBackupEventLogW(EventLog->ComputerName, EventLog->LogName); // FileName
2090 
2091  if (hEventLog == NULL)
2092  {
2094  goto Cleanup;
2095  }
2096 
2097  // GetOldestEventLogRecord(hEventLog, &dwThisRecord);
2098 
2099  /* Get the total number of event log records */
2100  GetNumberOfEventLogRecords(hEventLog, &dwTotalRecords);
2101 
2102  if (dwTotalRecords > 0)
2103  {
2106  }
2107  else
2108  {
2111  }
2112 
2113  /* Set up the event records cache */
2114  g_RecordPtrs = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwTotalRecords * sizeof(*g_RecordPtrs));
2115  if (!g_RecordPtrs)
2116  {
2117  // ShowWin32Error(GetLastError());
2118  goto Quit;
2119  }
2120  g_TotalRecords = dwTotalRecords;
2121 
2123  goto Quit;
2124 
2125  LoadStringW(hInst, IDS_NOT_AVAILABLE, szNoUsername, ARRAYSIZE(szNoUsername));
2126  LoadStringW(hInst, IDS_NONE, szNoCategory, ARRAYSIZE(szNoCategory));
2127 
2129  uStepAt = (dwTotalRecords / 100) + 1;
2130 
2132 
2133  /* 0x7ffff is the maximum buffer size ReadEventLog will accept */
2134  dwWanted = 0x7ffff;
2135  pEvlr = HeapAlloc(hProcessHeap, 0, dwWanted);
2136 
2137  if (!pEvlr)
2138  goto Quit;
2139 
2140  while (dwStatus == ERROR_SUCCESS)
2141  {
2142  bResult = ReadEventLogW(hEventLog, dwFlags, 0, pEvlr, dwWanted, &dwRead, &dwNeeded);
2143  dwStatus = GetLastError();
2144 
2145  if (!bResult && dwStatus == ERROR_INSUFFICIENT_BUFFER)
2146  {
2147  pEvlr = HeapReAlloc(hProcessHeap, 0, pEvlr, dwNeeded);
2148  dwWanted = dwNeeded;
2149 
2150  if (!pEvlr)
2151  break;
2152 
2153  bResult = ReadEventLogW(hEventLog, dwFlags, 0, pEvlr, dwNeeded, &dwRead, &dwNeeded);
2154 
2155  if (!bResult)
2156  break;
2157  }
2158  else if (!bResult)
2159  {
2160  /* Exit on other errors (ERROR_HANDLE_EOF) */
2161  break;
2162  }
2163 
2164  pEvlrBuffer = (LPBYTE)pEvlr;
2165  pEvlrEnd = pEvlrBuffer + dwRead;
2166 
2167  while (pEvlrBuffer < pEvlrEnd)
2168  {
2169  PEVENTLOGRECORD pEvlrTmp = (PEVENTLOGRECORD)pEvlrBuffer;
2170  PWSTR lpszUsername, lpszCategoryName;
2171  g_RecordPtrs[dwCurrentRecord] = NULL;
2172 
2173  // ProgressBar_StepIt(hwndStatusProgress);
2174  uStep++;
2175  if (uStep % uStepAt == 0)
2176  {
2177  ++uPos;
2179  }
2180 
2182  goto Quit;
2183 
2184  /* Filter by event type */
2185  if (!FilterByType(EventLogFilter, pEvlrTmp))
2186  goto SkipEvent;
2187 
2188  /* Get the event source name and filter it */
2189  lpszSourceName = (LPWSTR)(pEvlrBuffer + sizeof(EVENTLOGRECORD));
2190  if (!FilterByString(EventLogFilter->Sources, lpszSourceName))
2191  goto SkipEvent;
2192 
2193  /* Get the computer name and filter it */
2194  lpszComputerName = (LPWSTR)(pEvlrBuffer + sizeof(EVENTLOGRECORD) + (wcslen(lpszSourceName) + 1) * sizeof(WCHAR));
2195  if (!FilterByString(EventLogFilter->ComputerNames, lpszComputerName))
2196  goto SkipEvent;
2197 
2198  /* Compute the event time */
2199  EventTimeToSystemTime(pEvlrTmp->TimeWritten, &time);
2200  GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, szLocalDate, ARRAYSIZE(szLocalDate));
2201  GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &time, NULL, szLocalTime, ARRAYSIZE(szLocalTime));
2202 
2203  /* Get the username that generated the event, and filter it */
2204  lpszUsername = GetEventUserName(pEvlrTmp, &pLastSid, szUsername) ? szUsername : szNoUsername;
2205 
2206  if (!FilterByString(EventLogFilter->Users, lpszUsername))
2207  goto SkipEvent;
2208 
2209  // TODO: Filter by event ID and category
2210  GetEventType(pEvlrTmp->EventType, szEventTypeText);
2211 
2212  lpszCategoryName = GetEventCategory(EventLog->LogName, lpszSourceName, pEvlrTmp, szCategory) ? szCategory : szNoCategory;
2213 
2214  StringCbPrintfW(szEventID, sizeof(szEventID), L"%u", (pEvlrTmp->EventID & 0xFFFF));
2215  StringCbPrintfW(szCategoryID, sizeof(szCategoryID), L"%u", pEvlrTmp->EventCategory);
2216 
2217  g_RecordPtrs[dwCurrentRecord] = HeapAlloc(hProcessHeap, 0, pEvlrTmp->Length);
2218  RtlCopyMemory(g_RecordPtrs[dwCurrentRecord], pEvlrTmp, pEvlrTmp->Length);
2219 
2220  lviEventItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
2221  lviEventItem.iItem = 0;
2222  lviEventItem.iSubItem = 0;
2223  lviEventItem.lParam = (LPARAM)g_RecordPtrs[dwCurrentRecord];
2224  lviEventItem.pszText = szEventTypeText;
2225 
2226  switch (pEvlrTmp->EventType)
2227  {
2228  case EVENTLOG_SUCCESS:
2230  lviEventItem.iImage = 0;
2231  break;
2232 
2233  case EVENTLOG_WARNING_TYPE:
2234  lviEventItem.iImage = 1;
2235  break;
2236 
2237  case EVENTLOG_ERROR_TYPE:
2238  lviEventItem.iImage = 2;
2239  break;
2240 
2242  lviEventItem.iImage = 3;
2243  break;
2244 
2246  lviEventItem.iImage = 4;
2247  break;
2248  }
2249 
2250  lviEventItem.iItem = ListView_InsertItem(hwndListView, &lviEventItem);
2251 
2252  ListView_SetItemText(hwndListView, lviEventItem.iItem, 1, szLocalDate);
2253  ListView_SetItemText(hwndListView, lviEventItem.iItem, 2, szLocalTime);
2254  ListView_SetItemText(hwndListView, lviEventItem.iItem, 3, lpszSourceName);
2255  ListView_SetItemText(hwndListView, lviEventItem.iItem, 4, lpszCategoryName);
2256  ListView_SetItemText(hwndListView, lviEventItem.iItem, 5, szEventID);
2257  ListView_SetItemText(hwndListView, lviEventItem.iItem, 6, lpszUsername);
2258  ListView_SetItemText(hwndListView, lviEventItem.iItem, 7, lpszComputerName);
2259 
2260 SkipEvent:
2261  pEvlrBuffer += pEvlrTmp->Length;
2262  dwCurrentRecord++;
2263  }
2264  }
2265 
2266 Quit:
2267 
2268  if (pEvlr)
2269  HeapFree(hProcessHeap, 0, pEvlr);
2270 
2271  /* Close the event log */
2272  CloseEventLog(hEventLog);
2273 
2274  } // end-for (LogIndex)
2275 
2276  /* All events loaded */
2277 
2278 Cleanup:
2279 
2282 
2283  // FIXME: Use something else instead of EventLog->LogName !!
2284 
2285  /*
2286  * Use a different formatting, whether the event log filter holds
2287  * only one log, or many logs (the latter case is WIP TODO!)
2288  */
2289  if (EventLogFilter->NumOfEventLogs <= 1)
2290  {
2291  StringCbPrintfW(szStatusText,
2292  sizeof(szStatusText),
2294  EventLog->LogName,
2295  dwTotalRecords,
2297  }
2298  else
2299  {
2300  // TODO: Use a different title & implement filtering for multi-log filters !!
2301  // (EventLogFilter->NumOfEventLogs > 1)
2302  }
2303 
2304  /* Update the status bar */
2305  StatusBar_SetText(hwndStatus, 0, szStatusText);
2306 
2307  /* Resume list view redraw */
2309 
2310  EventLogFilter_Release(EventLogFilter);
2311 
2314 
2315  return 0;
2316 }
2317 
2318 /*
2319  * The purpose of this thread is to serialize the creation of the events
2320  * enumeration thread, since the Event Log Viewer currently only supports
2321  * one view, one event list, one enumeration.
2322  */
2323 static DWORD WINAPI
2325 {
2326  HANDLE WaitHandles[2];
2327  DWORD WaitResult;
2328 
2329  WaitHandles[0] = hStartStopEnumEvent; // End-of-application event
2330  WaitHandles[1] = hStartEnumEvent; // Command event
2331 
2332  while (TRUE)
2333  {
2334  WaitResult = WaitForMultipleObjects(ARRAYSIZE(WaitHandles),
2335  WaitHandles,
2336  FALSE, // WaitAny
2337  INFINITE);
2338  switch (WaitResult)
2339  {
2340  case WAIT_OBJECT_0 + 0:
2341  {
2342  /* End-of-application event signaled, quit this thread */
2343 
2344  /* Stop the previous enumeration */
2345  if (hEnumEventsThread)
2346  {
2347  if (hStopEnumEvent)
2348  {
2351  // NOTE: The following is done by the enumeration thread just before terminating.
2352  // hStopEnumEvent = NULL;
2353  }
2354 
2357  }
2358 
2359  /* Clear the list view and free the cached records */
2361  FreeRecords();
2362 
2363  /* Reset the active filter */
2364  ActiveFilter = NULL;
2365 
2366  return 0;
2367  }
2368 
2369  case WAIT_OBJECT_0 + 1:
2370  {
2371  /* Restart a new enumeration if needed */
2372  PEVENTLOGFILTER EventLogFilter;
2373 
2374  /* Stop the previous enumeration */
2375  if (hEnumEventsThread)
2376  {
2377  if (hStopEnumEvent)
2378  {
2381  // NOTE: The following is done by the enumeration thread just before terminating.
2382  // hStopEnumEvent = NULL;
2383  }
2384 
2387  }
2388 
2389  /* Clear the list view and free the cached records */
2391  FreeRecords();
2392 
2393  /* Reset the active filter */
2394  ActiveFilter = NULL;
2395 
2396  EventLogFilter = InterlockedExchangePointer((PVOID*)&EnumFilter, NULL);
2397  if (!EventLogFilter)
2398  break;
2399 
2400  // Manual-reset event
2402  if (!hStopEnumEvent)
2403  break;
2404 
2406  0,
2408  (LPVOID)EventLogFilter,
2410  NULL);
2411  if (!hEnumEventsThread)
2412  {
2414  hStopEnumEvent = NULL;
2415  break;
2416  }
2417  // CloseHandle(hEnumEventsThread);
2419 
2420  break;
2421  }
2422 
2423  default:
2424  {
2425  /* Unknown command, must never go there! */
2426  return GetLastError();
2427  }
2428  }
2429  }
2430 
2431  return 0;
2432 }
2433 
2434 VOID
2436 {
2437  /* Signal the enumerator thread we want to enumerate events */
2438  InterlockedExchangePointer((PVOID*)&EnumFilter, EventLogFilter);
2440  return;
2441 }
2442 
2443 
2446 {
2447  TVITEMEXW tvItemEx;
2448  HTREEITEM hti;
2449 
2450  if (phti)
2451  *phti = NULL;
2452 
2453  /* Get index of selected item */
2455  if (hti == NULL)
2456  return NULL; // No filter
2457 
2458  tvItemEx.mask = TVIF_PARAM;
2459  tvItemEx.hItem = hti;
2460 
2461  TreeView_GetItem(hwndTreeView, &tvItemEx);
2462 
2463  if (phti)
2464  *phti = tvItemEx.hItem;
2465 
2466  return (PEVENTLOGFILTER)tvItemEx.lParam;
2467 }
2468 
2469 
2470 VOID
2472 {
2473  WIN32_FIND_DATAW FindData;
2474  HANDLE hFind;
2475  PEVENTLOG EventLog;
2476  PEVENTLOGFILTER EventLogFilter;
2477  SIZE_T cchFileName;
2478  HTREEITEM hItem = NULL;
2479 
2480  /* Check whether the file actually exists */
2481  hFind = FindFirstFileW(lpszFileName, &FindData);
2482  if (hFind == INVALID_HANDLE_VALUE)
2483  {
2485  return;
2486  }
2487  FindClose(hFind);
2488 
2489  /* Allocate a new event log entry */
2490  EventLog = AllocEventLog(NULL, lpszFileName, FALSE);
2491  if (EventLog == NULL)
2492  {
2494  return;
2495  }
2496 
2497  /* Allocate a new event log filter entry for this event log */
2498  EventLogFilter = AllocEventLogFilter(// LogName,
2499  TRUE, TRUE, TRUE, TRUE, TRUE,
2500  NULL, NULL, NULL,
2501  1, &EventLog);
2502  if (EventLogFilter == NULL)
2503  {
2505  EventLog_Free(EventLog);
2506  return;
2507  }
2508 
2509  /* Add the event log and the filter into their lists */
2510  InsertTailList(&EventLogList, &EventLog->ListEntry);
2511  InsertTailList(&EventLogFilterList, &EventLogFilter->ListEntry);
2512 
2513  /* Retrieve and cache the event log file */
2514  cchFileName = wcslen(lpszFileName) + 1;
2515  EventLog->FileName = HeapAlloc(GetProcessHeap(), 0, cchFileName * sizeof(WCHAR));
2516  if (EventLog->FileName)
2517  StringCchCopyW(EventLog->FileName, cchFileName, lpszFileName);
2518 
2520  (LPWSTR)lpszFileName,
2521  2, 3, (LPARAM)EventLogFilter);
2522 
2523  /* Select the event log */
2524  if (hItem)
2525  {
2526  // TreeView_Expand(hwndTreeView, htiUserLogs, TVE_EXPAND);
2529  }
2532 }
2533 
2534 VOID
2536 {
2537  WCHAR szFileName[MAX_PATH];
2538 
2539  ZeroMemory(szFileName, sizeof(szFileName));
2540 
2541  sfn.lpstrFile = szFileName;
2542  sfn.nMaxFile = ARRAYSIZE(szFileName);
2543 
2544  if (!GetOpenFileNameW(&sfn))
2545  return;
2547 
2549 }
2550 
2551 VOID
2553 {
2554  PEVENTLOG EventLog;
2555  HANDLE hEventLog;
2556  WCHAR szFileName[MAX_PATH];
2557 
2558  /* Bail out if there is no available filter */
2559  if (!EventLogFilter)
2560  return;
2561 
2562  ZeroMemory(szFileName, sizeof(szFileName));
2563 
2564  sfn.lpstrFile = szFileName;
2565  sfn.nMaxFile = ARRAYSIZE(szFileName);
2566 
2567  if (!GetSaveFileNameW(&sfn))
2568  return;
2569 
2570  EventLogFilter_AddRef(EventLogFilter);
2571 
2572  EventLog = EventLogFilter->EventLogs[0];
2573  hEventLog = OpenEventLogW(EventLog->ComputerName, EventLog->LogName);
2574 
2575  EventLogFilter_Release(EventLogFilter);
2576 
2577  if (!hEventLog)
2578  {
2580  return;
2581  }
2582 
2583  if (!BackupEventLogW(hEventLog, szFileName))
2585 
2586  CloseEventLog(hEventLog);
2587 }
2588 
2589 VOID
2591 {
2592  /* Bail out if there is no available filter */
2593  if (!EventLogFilter)
2594  return;
2595 
2596  if (InterlockedCompareExchangePointer((PVOID*)&ActiveFilter, NULL, NULL) == EventLogFilter)
2597  {
2598  /* Signal the enumerator thread we want to stop enumerating events */
2599  // EnumEvents(NULL);
2602  }
2603 
2604  /*
2605  * The deletion of the item automatically triggers a TVN_SELCHANGED
2606  * notification, that will reset the ActiveFilter (in case the item
2607  * selected is a filter). Otherwise we reset it there.
2608  */
2610 
2611  /* Remove the filter from the list */
2612  RemoveEntryList(&EventLogFilter->ListEntry);
2613  EventLogFilter_Release(EventLogFilter);
2614 
2615  // /* Select the default event log */
2616  // // TreeView_Expand(hwndTreeView, htiUserLogs, TVE_EXPAND);
2617  // TreeView_SelectItem(hwndTreeView, hItem);
2618  // TreeView_EnsureVisible(hwndTreeView, hItem);
2621 }
2622 
2623 
2624 BOOL
2626 {
2627  BOOL Success;
2628  PEVENTLOG EventLog;
2629  HANDLE hEventLog;
2630  WCHAR szFileName[MAX_PATH];
2631  WCHAR szMessage[MAX_LOADSTRING];
2632 
2633  /* Bail out if there is no available filter */
2634  if (!EventLogFilter)
2635  return FALSE;
2636 
2637  ZeroMemory(szFileName, sizeof(szFileName));
2638  ZeroMemory(szMessage, sizeof(szMessage));
2639 
2640  LoadStringW(hInst, IDS_CLEAREVENTS_MSG, szMessage, ARRAYSIZE(szMessage));
2641 
2642  sfn.lpstrFile = szFileName;
2643  sfn.nMaxFile = ARRAYSIZE(szFileName);
2644 
2646  {
2647  case IDCANCEL:
2648  return FALSE;
2649 
2650  case IDNO:
2651  sfn.lpstrFile = NULL;
2652  break;
2653 
2654  case IDYES:
2655  if (!GetSaveFileNameW(&sfn))
2656  return FALSE;
2657  break;
2658  }
2659 
2660  EventLogFilter_AddRef(EventLogFilter);
2661 
2662  EventLog = EventLogFilter->EventLogs[0];
2663  hEventLog = OpenEventLogW(EventLog->ComputerName, EventLog->LogName);
2664 
2665  EventLogFilter_Release(EventLogFilter);
2666 
2667  if (!hEventLog)
2668  {
2670  return FALSE;
2671  }
2672 
2673  Success = ClearEventLogW(hEventLog, sfn.lpstrFile);
2674  if (!Success)
2676 
2677  CloseEventLog(hEventLog);
2678  return Success;
2679 }
2680 
2681 
2682 VOID
2683 Refresh(IN PEVENTLOGFILTER EventLogFilter)
2684 {
2685  /* Bail out if there is no available filter */
2686  if (!EventLogFilter)
2687  return;
2688 
2689  /* Reenumerate the events through the filter */
2690  EnumEvents(EventLogFilter);
2691 }
2692 
2693 
2694 ATOM
2696 {
2697  WNDCLASSEXW wcex;
2698 
2699  wcex.cbSize = sizeof(wcex);
2700  wcex.style = 0;
2701  wcex.lpfnWndProc = WndProc;
2702  wcex.cbClsExtra = 0;
2703  wcex.cbWndExtra = 0;
2704  wcex.hInstance = hInstance;
2707  wcex.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); // COLOR_WINDOW + 1
2712  IMAGE_ICON,
2713  16,
2714  16,
2715  LR_SHARED);
2716 
2717  return RegisterClassExW(&wcex);
2718 }
2719 
2720 
2721 BOOL
2723  OUT PWCHAR lpModuleName, // TODO: Add IN DWORD BufLen
2724  OUT PDWORD pdwMessageID)
2725 {
2726  BOOL Success = FALSE;
2727  LONG Result;
2728  HKEY hLogKey;
2729  WCHAR *KeyPath;
2730  SIZE_T cbKeyPath;
2731  DWORD dwType, cbData;
2732  DWORD dwMessageID = 0;
2734 
2735  /* Use a default value for the message ID */
2736  *pdwMessageID = 0;
2737 
2738  cbKeyPath = (wcslen(EVENTLOG_BASE_KEY) + wcslen(lpLogName) + 1) * sizeof(WCHAR);
2739  KeyPath = HeapAlloc(GetProcessHeap(), 0, cbKeyPath);
2740  if (!KeyPath)
2741  return FALSE;
2742 
2743  StringCbCopyW(KeyPath, cbKeyPath, EVENTLOG_BASE_KEY);
2744  StringCbCatW(KeyPath, cbKeyPath, lpLogName);
2745 
2746  Result = RegOpenKeyExW(hkMachine, KeyPath, 0, KEY_QUERY_VALUE, &hLogKey);
2747  HeapFree(GetProcessHeap(), 0, KeyPath);
2748  if (Result != ERROR_SUCCESS)
2749  return FALSE;
2750 
2751  cbData = sizeof(szModuleName);
2752  Result = RegQueryValueExW(hLogKey,
2753  L"DisplayNameFile",
2754  NULL,
2755  &dwType,
2757  &cbData);
2758  if ((Result != ERROR_SUCCESS) || (dwType != REG_EXPAND_SZ && dwType != REG_SZ))
2759  {
2761  }
2762  else
2763  {
2764  /* NULL-terminate the string and expand it */
2765  szModuleName[cbData / sizeof(WCHAR) - 1] = UNICODE_NULL;
2767  Success = TRUE;
2768  }
2769 
2770  /*
2771  * If we have a 'DisplayNameFile', query for 'DisplayNameID';
2772  * otherwise it's not really useful. 'DisplayNameID' is optional.
2773  */
2774  if (Success)
2775  {
2776  cbData = sizeof(dwMessageID);
2777  Result = RegQueryValueExW(hLogKey,
2778  L"DisplayNameID",
2779  NULL,
2780  &dwType,
2781  (LPBYTE)&dwMessageID,
2782  &cbData);
2783  if ((Result != ERROR_SUCCESS) || (dwType != REG_DWORD))
2784  dwMessageID = 0;
2785 
2786  *pdwMessageID = dwMessageID;
2787  }
2788 
2789  RegCloseKey(hLogKey);
2790 
2791  return Success;
2792 }
2793 
2794 
2795 VOID
2797 {
2798  LONG Result;
2799  HKEY hEventLogKey, hLogKey;
2800  DWORD dwNumLogs = 0;
2801  DWORD dwIndex, dwMaxKeyLength;
2802  DWORD dwType;
2803  PEVENTLOG EventLog;
2804  PEVENTLOGFILTER EventLogFilter;
2805  LPWSTR LogName = NULL;
2807  DWORD lpcName;
2808  DWORD dwMessageID;
2810  HTREEITEM hRootNode = NULL, hItem = NULL, hItemDefault = NULL;
2811 
2813  {
2814  /* We are connected to some other computer, close the old connection */
2816  hkMachine = NULL;
2817  }
2818  if (!lpComputerName || !*lpComputerName)
2819  {
2820  /* Use the local computer registry */
2822  }
2823  else
2824  {
2825  /* Connect to the remote computer registry */
2827  if (Result != ERROR_SUCCESS)
2828  {
2829  /* Connection failed, display a message and bail out */
2830  hkMachine = NULL;
2832  return;
2833  }
2834  }
2835 
2836  /* Open the EventLog key */
2837  Result = RegOpenKeyExW(hkMachine, EVENTLOG_BASE_KEY, 0, KEY_READ, &hEventLogKey);
2838  if (Result != ERROR_SUCCESS)
2839  {
2840  return;
2841  }
2842 
2843  /* Retrieve the number of event logs enumerated as registry keys */
2844  Result = RegQueryInfoKeyW(hEventLogKey, NULL, NULL, NULL, &dwNumLogs, &dwMaxKeyLength,
2845  NULL, NULL, NULL, NULL, NULL, NULL);
2846  if (Result != ERROR_SUCCESS)
2847  {
2848  goto Quit;
2849  }
2850  if (!dwNumLogs)
2851  goto Quit;
2852 
2853  /* Take the NULL terminator into account */
2854  ++dwMaxKeyLength;
2855 
2856  /* Allocate the temporary buffer */
2857  LogName = HeapAlloc(GetProcessHeap(), 0, dwMaxKeyLength * sizeof(WCHAR));
2858  if (!LogName)
2859  goto Quit;
2860 
2861  /* Enumerate and retrieve each event log name */
2862  for (dwIndex = 0; dwIndex < dwNumLogs; dwIndex++)
2863  {
2864  lpcName = dwMaxKeyLength;
2865  Result = RegEnumKeyExW(hEventLogKey, dwIndex, LogName, &lpcName, NULL, NULL, NULL, NULL);
2866  if (Result != ERROR_SUCCESS)
2867  continue;
2868 
2869  /* Take the NULL terminator into account */
2870  ++lpcName;
2871 
2872  /* Allocate a new event log entry */
2873  EventLog = AllocEventLog(lpComputerName, LogName, TRUE);
2874  if (EventLog == NULL)
2875  continue;
2876 
2877  /* Allocate a new event log filter entry for this event log */
2878  EventLogFilter = AllocEventLogFilter(// LogName,
2879  TRUE, TRUE, TRUE, TRUE, TRUE,
2880  NULL, NULL, NULL,
2881  1, &EventLog);
2882  if (EventLogFilter == NULL)
2883  {
2884  EventLog_Free(EventLog);
2885  continue;
2886  }
2887 
2888  /* Add the event log and the filter into their lists */
2889  InsertTailList(&EventLogList, &EventLog->ListEntry);
2890  InsertTailList(&EventLogFilterList, &EventLogFilter->ListEntry);
2891 
2892  EventLog->FileName = NULL;
2893 
2894  /* Retrieve and cache the event log file */
2895  Result = RegOpenKeyExW(hEventLogKey,
2896  LogName,
2897  0,
2899  &hLogKey);
2900  if (Result == ERROR_SUCCESS)
2901  {
2902  lpcName = 0;
2903  Result = RegQueryValueExW(hLogKey,
2904  L"File",
2905  NULL,
2906  &dwType,
2907  NULL,
2908  &lpcName);
2909  if ((Result != ERROR_SUCCESS) || (dwType != REG_EXPAND_SZ && dwType != REG_SZ))
2910  {
2911  // Windows' EventLog uses some kind of default value, we do not.
2912  EventLog->FileName = NULL;
2913  }
2914  else
2915  {
2916  lpcName = ROUND_DOWN(lpcName, sizeof(WCHAR));
2917  EventLog->FileName = HeapAlloc(GetProcessHeap(), 0, lpcName);
2918  if (EventLog->FileName)
2919  {
2920  Result = RegQueryValueExW(hLogKey,
2921  L"File",
2922  NULL,
2923  &dwType,
2924  (LPBYTE)EventLog->FileName,
2925  &lpcName);
2926  if (Result != ERROR_SUCCESS)
2927  {
2928  HeapFree(GetProcessHeap(), 0, EventLog->FileName);
2929  EventLog->FileName = NULL;
2930  }
2931  else
2932  {
2933  EventLog->FileName[lpcName / sizeof(WCHAR) - 1] = UNICODE_NULL;
2934  }
2935  }
2936  }
2937 
2938  RegCloseKey(hLogKey);
2939  }
2940 
2941  /* Get the display name for the event log */
2942  lpDisplayName = NULL;
2943 
2945  if (GetDisplayNameFileAndID(LogName, szModuleName, &dwMessageID))
2946  {
2947  /* Retrieve the message string without appending extra newlines */
2948  lpDisplayName =
2952  dwMessageID,
2953  0,
2954  NULL);
2955  }
2956 
2957  /*
2958  * Select the correct tree root node, whether the log is a System
2959  * or an Application log. Default to Application log otherwise.
2960  */
2961  hRootNode = htiAppLogs;
2962  for (lpcName = 0; lpcName < ARRAYSIZE(SystemLogs); ++lpcName)
2963  {
2964  /* Check whether the log name is part of the system logs */
2965  if (wcsicmp(LogName, SystemLogs[lpcName]) == 0)
2966  {
2967  hRootNode = htiSystemLogs;
2968  break;
2969  }
2970  }
2971 
2972  hItem = TreeViewAddItem(hwndTreeView, hRootNode,
2973  (lpDisplayName ? lpDisplayName : LogName),
2974  2, 3, (LPARAM)EventLogFilter);
2975 
2976  /* Try to get the default event log: "Application" */
2977  if ((hItemDefault == NULL) && (wcsicmp(LogName, SystemLogs[0]) == 0))
2978  {
2979  hItemDefault = hItem;
2980  }
2981 
2982  /* Free the buffer allocated by FormatMessage */
2983  if (lpDisplayName)
2985  }
2986 
2987  HeapFree(GetProcessHeap(), 0, LogName);
2988 
2989 Quit:
2990  RegCloseKey(hEventLogKey);
2991 
2992  /* Select the default event log */
2993  if (hItemDefault)
2994  {
2995  // TreeView_Expand(hwndTreeView, hRootNode, TVE_EXPAND);
2996  TreeView_SelectItem(hwndTreeView, hItemDefault);
2997  TreeView_EnsureVisible(hwndTreeView, hItemDefault);
2998  }
3001 
3002  return;
3003 }
3004 
3005 VOID
3007 {
3009  PEVENTLOG EventLog;
3010 
3011  while (!IsListEmpty(&EventLogList))
3012  {
3014  EventLog = (PEVENTLOG)CONTAINING_RECORD(Entry, EVENTLOG, ListEntry);
3015  EventLog_Free(EventLog);
3016  }
3017 
3018  return;
3019 }
3020 
3021 VOID
3023 {
3025  PEVENTLOGFILTER EventLogFilter;
3026 
3027  while (!IsListEmpty(&EventLogFilterList))
3028  {
3030  EventLogFilter = (PEVENTLOGFILTER)CONTAINING_RECORD(Entry, EVENTLOGFILTER, ListEntry);
3031  EventLogFilter_Free(EventLogFilter);
3032  }
3033 
3034  ActiveFilter = NULL;
3035 
3036  return;
3037 }
3038 
3039 BOOL
3041 {
3042  RECT rcClient, rs;
3043  LONG StatusHeight;
3044  HIMAGELIST hSmall;
3045  LVCOLUMNW lvc = {0};
3046  WCHAR szTemp[256];
3047 
3048  /* Create the main window */
3049  rs = Settings.wpPos.rcNormalPosition;
3051  szTitle,
3053  rs.left, rs.top,
3054  (rs.right != CW_USEDEFAULT && rs.left != CW_USEDEFAULT) ? rs.right - rs.left : CW_USEDEFAULT,
3055  (rs.bottom != CW_USEDEFAULT && rs.top != CW_USEDEFAULT) ? rs.bottom - rs.top : CW_USEDEFAULT,
3056  NULL,
3057  NULL,
3058  hInstance,
3059  NULL);
3060  if (!hwndMainWindow)
3061  return FALSE;
3062 
3063  /* Create the status bar */
3064  hwndStatus = CreateWindowExW(0, // no extended styles
3065  STATUSCLASSNAMEW, // status bar
3066  L"", // no text
3067  WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, // styles
3068  0, 0, 0, 0, // x, y, cx, cy
3069  hwndMainWindow, // parent window
3070  (HMENU)100, // window ID
3071  hInstance, // instance
3072  NULL); // window data
3073 
3074  GetClientRect(hwndMainWindow, &rcClient);
3075  GetWindowRect(hwndStatus, &rs);
3076  StatusHeight = rs.bottom - rs.top;
3077 
3078  /* Create a progress bar in the status bar (hidden by default) */
3080  hwndStatusProgress = CreateWindowExW(0, // no extended styles
3081  PROGRESS_CLASSW, // status bar
3082  NULL, // no text
3083  WS_CHILD | PBS_SMOOTH, // styles
3084  rs.left, rs.top, // x, y
3085  rs.right - rs.left, rs.bottom - rs.top, // cx, cy
3086  hwndStatus, // parent window
3087  NULL, // window ID
3088  hInstance, // instance
3089  NULL); // window data
3090  /* Remove its static edge */
3094 
3095  /* Initialize the splitter default positions */
3096  nVSplitPos = Settings.nVSplitPos;
3097  nHSplitPos = Settings.nHSplitPos;
3098 
3099  /* Create the TreeView */
3101  WC_TREEVIEWW,
3102  NULL,
3103  // WS_CHILD | WS_VISIBLE | TVS_HASLINES | TVS_SHOWSELALWAYS,
3105  0, 0,
3106  nVSplitPos - SPLIT_WIDTH/2,
3107  (rcClient.bottom - rcClient.top) - StatusHeight,
3109  NULL,
3110  hInstance,
3111  NULL);
3112 
3113  /* Create the ImageList */
3116  ILC_COLOR32 | ILC_MASK, // ILC_COLOR24
3117  1, 1);
3118 
3119  /* Add event type icons to the ImageList: closed/opened folder, event log (normal/viewed) */
3124 
3125  /* Assign the ImageList to the Tree View */
3127 
3128  /* Add the event logs nodes */
3129  // "System Logs"
3132  // "Application Logs"
3133  LoadStringW(hInstance, IDS_EVENTLOG_APP, szTemp, ARRAYSIZE(szTemp));
3134  htiAppLogs = TreeViewAddItem(hwndTreeView, NULL, szTemp, 0, 1, (LPARAM)NULL);
3135  // "User Logs"
3136  LoadStringW(hInstance, IDS_EVENTLOG_USER, szTemp, ARRAYSIZE(szTemp));
3138 
3139  /* Create the Event details pane (optional) */
3141  if (hwndEventDetails)
3142  {
3146  nVSplitPos + SPLIT_WIDTH/2,
3147  nHSplitPos + SPLIT_WIDTH/2,
3148  (rcClient.right - rcClient.left) - nVSplitPos - SPLIT_WIDTH/2,
3149  (rcClient.bottom - rcClient.top) - nHSplitPos - SPLIT_WIDTH/2 - StatusHeight,
3151  }
3152 
3153  /* Create the ListView */
3155  WC_LISTVIEWW,
3156  NULL,
3158  nVSplitPos + SPLIT_WIDTH/2,
3159  0,
3160  (rcClient.right - rcClient.left) - nVSplitPos - SPLIT_WIDTH/2,
3161  hwndEventDetails && Settings.bShowDetailsPane
3162  ? nHSplitPos - SPLIT_WIDTH/2
3163  : (rcClient.bottom - rcClient.top) - StatusHeight,
3165  NULL,
3166  hInstance,
3167  NULL);
3168 
3169  /* Add the extended ListView styles */
3171 
3172  /* Create the ImageList */
3175  ILC_COLOR32 | ILC_MASK, // ILC_COLOR24
3176  1, 1);
3177 
3178  /* Add event type icons to the ImageList */
3184 
3185  /* Assign the ImageList to the List View */
3187 
3188  /* Now set up the listview with its columns */
3189  lvc.mask = LVCF_TEXT | LVCF_WIDTH;
3190  lvc.cx = 90;
3193  szTemp,
3194  ARRAYSIZE(szTemp));
3195  lvc.pszText = szTemp;
3197 
3198  lvc.cx = 70;
3201  szTemp,
3202  ARRAYSIZE(szTemp));
3203  lvc.pszText = szTemp;
3205 
3206  lvc.cx = 70;
3209  szTemp,
3210  ARRAYSIZE(szTemp));
3211  lvc.pszText = szTemp;
3213 
3214  lvc.cx = 150;
3217  szTemp,
3218  ARRAYSIZE(szTemp));
3219  lvc.pszText = szTemp;
3221 
3222  lvc.cx = 100;
3225  szTemp,
3226  ARRAYSIZE(szTemp));
3227  lvc.pszText = szTemp;
3229 
3230  lvc.cx = 60;
3233  szTemp,
3234  ARRAYSIZE(szTemp));
3235  lvc.pszText = szTemp;
3237 
3238  lvc.cx = 120;
3241  szTemp,
3242  ARRAYSIZE(szTemp));
3243  lvc.pszText = szTemp;
3245 
3246  lvc.cx = 100;
3249  szTemp,
3250  ARRAYSIZE(szTemp));
3251  lvc.pszText = szTemp;
3253 
3254  /* Initialize the save Dialog */
3255  ZeroMemory(&sfn, sizeof(sfn));
3257 
3259 
3260  sfn.lStructSize = sizeof(sfn);
3266  sfn.lpstrDefExt = NULL;
3267 
3268  ShowWindow(hwndMainWindow, Settings.wpPos.showCmd);
3270 
3271  return TRUE;
3272 }
3273 
3275 {
3276  RECT rs;
3277  LONG StatusHeight;
3278  LONG_PTR dwExStyle;
3279  HDWP hdwp;
3280 
3281  /* Resize the status bar -- now done in WM_SIZE */
3282  // SendMessageW(hwndStatus, WM_SIZE, 0, 0);
3283  GetWindowRect(hwndStatus, &rs);
3284  StatusHeight = rs.bottom - rs.top;
3285 
3286  /*
3287  * Move the progress bar -- Take into account for extra size due to the static edge
3288  * (AdjustWindowRectEx() does not seem to work for the progress bar).
3289  */
3294  rs.left, rs.top, rs.right - rs.left, rs.bottom - rs.top,
3297 
3298  /*
3299  * TODO: Adjust the splitter positions:
3300  * - Vertical splitter (1) : fixed position from the left window side.
3301  * - Horizontal splitter (2): fixed position from the bottom window side.
3302  */
3304  nHSplitPos = min(max(nHSplitPos, SPLIT_WIDTH/2), cy - SPLIT_WIDTH/2 - StatusHeight); // FIXME!
3305 
3306  hdwp = BeginDeferWindowPos(3);
3307 
3308  if (hdwp)
3309  hdwp = DeferWindowPos(hdwp,
3310  hwndTreeView,
3311  HWND_TOP,
3312  0, 0,
3313  nVSplitPos - SPLIT_WIDTH/2,
3314  cy - StatusHeight,
3316 
3317  if (hdwp)
3318  hdwp = DeferWindowPos(hdwp,
3319  hwndListView,
3320  HWND_TOP,
3321  nVSplitPos + SPLIT_WIDTH/2, 0,
3322  cx - nVSplitPos - SPLIT_WIDTH/2,
3323  hwndEventDetails && Settings.bShowDetailsPane
3324  ? nHSplitPos - SPLIT_WIDTH/2
3325  : cy - StatusHeight,
3327 
3328  if (hwndEventDetails && Settings.bShowDetailsPane && hdwp)
3329  hdwp = DeferWindowPos(hdwp,
3331  HWND_TOP,
3332  nVSplitPos + SPLIT_WIDTH/2,
3333  nHSplitPos + SPLIT_WIDTH/2,
3334  cx - nVSplitPos - SPLIT_WIDTH/2,
3335  cy - nHSplitPos - SPLIT_WIDTH/2 - StatusHeight,
3337 
3338  if (hdwp)
3339  EndDeferWindowPos(hdwp);
3340 }
3341 
3342 
3345 {
3346  RECT rect;
3347 
3348  switch (uMsg)
3349  {
3350  case WM_CREATE:
3351  hMainMenu = GetMenu(hWnd);
3352  break;
3353 
3354  case WM_DESTROY:
3355  {
3357  PostQuitMessage(0);
3358  break;
3359  }
3360 
3361  case WM_NOTIFY:
3362  {
3364 
3365  if (hdr->hwndFrom == hwndListView)
3366  {
3367  switch (hdr->code)
3368  {
3369  case LVN_ITEMCHANGED:
3370  {
3372 
3373  if ( (pnmv->uChanged & LVIF_STATE) && /* The state has changed */
3374  (pnmv->uNewState & LVIS_SELECTED) /* The item has been (de)selected */ )
3375  {
3376  if (hwndEventDetails)
3378  }
3379  break;
3380  }
3381 
3382  case NM_DBLCLK:
3383  case NM_RETURN:
3385  break;
3386  }
3387  }
3388  else if (hdr->hwndFrom == hwndTreeView)
3389  {
3390  switch (hdr->code)
3391  {
3392  case TVN_BEGINLABELEDIT:
3393  {
3394  HTREEITEM hItem = ((LPNMTVDISPINFO)lParam)->item.hItem;
3395 
3396  /* Disable label editing for root nodes */
3397  return ((hItem == htiSystemLogs) ||
3398  (hItem == htiAppLogs) ||
3399  (hItem == htiUserLogs));
3400  }
3401 
3402  case TVN_ENDLABELEDIT:
3403  {
3404  TVITEMW item = ((LPNMTVDISPINFO)lParam)->item;
3405  HTREEITEM hItem = item.hItem;
3406 
3407  /* Disable label editing for root nodes */
3408  if ((hItem == htiSystemLogs) ||
3409  (hItem == htiAppLogs) ||
3410  (hItem == htiUserLogs))
3411  {
3412  return FALSE;
3413  }
3414 
3415  if (item.pszText)
3416  {
3417  LPWSTR pszText = item.pszText;
3418 
3419  /* Trim leading whitespace */
3420  while (*pszText && iswspace(*pszText))
3421  ++pszText;
3422 
3423  if (!*pszText)
3424  return FALSE;
3425 
3426  return TRUE;
3427  }
3428  else
3429  {
3430  return FALSE;
3431  }
3432  }
3433 
3434  case TVN_SELCHANGED:
3435  {
3436  PEVENTLOGFILTER EventLogFilter =
3437  (PEVENTLOGFILTER)((LPNMTREEVIEW)lParam)->itemNew.lParam;
3438 
3439  // FIXME: It might be nice to reference here the filter,
3440  // so that we don't have to reference/dereference it many times
3441  // in the other functions???
3442 
3443  // FIXME: This is a hack!!
3444  if (hwndEventDetails && EventLogFilter)
3445  {
3446  SendMessageW(hwndEventDetails, EVT_SETFILTER, 0, (LPARAM)EventLogFilter);
3447  }
3448 
3449  if (EventLogFilter)
3450  {
3451  /*
3452  * If we have selected a filter, enable the menu commands;
3453  * they will possibly be updated after events enumeration.
3454  */
3460  }
3461  else
3462  {
3468  }
3469 
3470  /*
3471  * The enumeration thread that is triggered by EnumEvents
3472  * will set a new value for the 'ActiveFilter'.
3473  */
3474  if (EventLogFilter)
3475  EnumEvents(EventLogFilter);
3476 
3477  break;
3478  }
3479  }
3480  }
3481  break;
3482  }
3483 
3484  case WM_COMMAND:
3485  {
3486  /* Parse the menu selections */
3487  switch (LOWORD(wParam))
3488  {
3489  case IDM_OPEN_EVENTLOG:
3490  OpenUserEventLog();
3491  break;
3492 
3493  case IDM_SAVE_EVENTLOG:
3495  break;
3496 
3497  case IDM_CLOSE_EVENTLOG:
3498  {
3499  HTREEITEM hti;
3500  PEVENTLOGFILTER EventLogFilter = GetSelectedFilter(&hti);
3501  CloseUserEventLog(EventLogFilter, hti);
3502  break;
3503  }
3504 
3505  case IDM_CLEAR_EVENTS:
3506  {
3507  PEVENTLOGFILTER EventLogFilter = GetSelectedFilter(NULL);
3508  if (EventLogFilter && ClearEvents(EventLogFilter))
3509  Refresh(EventLogFilter);
3510  break;
3511  }
3512 
3513  case IDM_RENAME_EVENTLOG:
3514  if (GetFocus() == hwndTreeView)
3516  break;
3517 
3518  case IDM_EVENTLOG_SETTINGS:
3519  {
3520  PEVENTLOGFILTER EventLogFilter = GetSelectedFilter(NULL);
3521  // TODO: Check the returned value?
3522  if (EventLogFilter)
3523  EventLogProperties(hInst, hWnd, EventLogFilter);
3524  break;
3525  }
3526 
3527  case IDM_LIST_NEWEST:
3528  {
3530  if (!Settings.bNewestEventsFirst)
3531  {
3532  Settings.bNewestEventsFirst = TRUE;
3534  }
3535  break;
3536  }
3537 
3538  case IDM_LIST_OLDEST:
3539  {
3541  if (Settings.bNewestEventsFirst)
3542  {
3543  Settings.bNewestEventsFirst = FALSE;
3545  }
3546  break;
3547  }
3548 
3549  case IDM_EVENT_DETAILS:
3550  {
3551  // LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE)lParam;
3552  PEVENTLOGFILTER EventLogFilter = GetSelectedFilter(NULL);
3553  if (/*lpnmitem->iItem != -1 &&*/ EventLogFilter)
3554  {
3555  EventLogFilter_AddRef(EventLogFilter);
3558  hWnd,
3559  EventDetails,
3560  (LPARAM)EventLogFilter);
3561  EventLogFilter_Release(EventLogFilter);
3562  }
3563  break;
3564  }
3565 
3566  case IDM_REFRESH:
3568  break;
3569 
3571  {
3572  Settings.bShowDetailsPane = !Settings.bShowDetailsPane;
3574  MF_BYCOMMAND | (Settings.bShowDetailsPane ? MF_CHECKED : MF_UNCHECKED));
3575 
3576  GetClientRect(hWnd, &rect);
3577  if (Settings.bShowDetailsPane)
3578  {
3579  ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
3581  }
3582  else
3583  {
3585  ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
3586  }
3587 
3588  break;
3589  }
3590 
3591  case IDM_LIST_GRID_LINES:
3592  {
3593  Settings.bShowGrid = !Settings.bShowGrid;
3595  MF_BYCOMMAND | (Settings.bShowGrid ? MF_CHECKED : MF_UNCHECKED));
3596 
3598  break;
3599  }
3600 
3601  case IDM_SAVE_SETTINGS:
3602  {
3603  Settings.bSaveSettings = !Settings.bSaveSettings;
3605  MF_BYCOMMAND | (Settings.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
3606  break;
3607  }
3608 
3609  case IDM_ABOUT:
3610  {
3611  HICON hIcon;
3612  WCHAR szCopyright[MAX_LOADSTRING];
3613 
3615  LoadStringW(hInst, IDS_COPYRIGHT, szCopyright, ARRAYSIZE(szCopyright));
3616  ShellAboutW(hWnd, szTitle, szCopyright, hIcon);
3618  break;
3619  }
3620 
3621  case IDM_HELP:
3623  L"Help not implemented yet!",
3624  L"Event Log",
3626  break;
3627 
3628  case IDM_EXIT:
3630  break;
3631 
3632  default:
3633  return DefWindowProcW(hWnd, uMsg, wParam, lParam);
3634  }
3635  break;
3636  }
3637 
3638  case WM_INITMENU:
3639  {
3640  if ((HMENU)wParam != hMainMenu)
3641  break;
3642 
3644  Settings.bNewestEventsFirst ? IDM_LIST_NEWEST : IDM_LIST_OLDEST,
3645  MF_BYCOMMAND);
3646 
3647  if (!hwndEventDetails)
3648  {
3651  }
3653  MF_BYCOMMAND | (Settings.bShowDetailsPane ? MF_CHECKED : MF_UNCHECKED));
3654 
3656  MF_BYCOMMAND | (Settings.bShowGrid ? MF_CHECKED : MF_UNCHECKED));
3657 
3659  MF_BYCOMMAND | (Settings.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
3660 
3661  break;
3662  }
3663 
3664 #if 0
3665  case WM_INITMENUPOPUP:
3666  lParam = lParam;
3667  break;
3668 
3669  case WM_CONTEXTMENU:
3670  lParam = lParam;
3671  break;
3672 #endif
3673 
3674  case WM_SETCURSOR:
3675  {
3676  POINT pt;
3677 
3678  if (LOWORD(lParam) != HTCLIENT)
3679  goto Default;
3680 
3681  GetCursorPos(&pt);
3682  ScreenToClient(hWnd, &pt);
3683 
3684  /* Set the cursor for the vertical splitter */
3685  if (pt.x >= nVSplitPos - SPLIT_WIDTH/2 && pt.x < nVSplitPos + SPLIT_WIDTH/2 + 1)
3686  {
3687  RECT rs;
3688  GetClientRect(hWnd, &rect);
3689  GetWindowRect(hwndStatus, &rs);
3690  if (pt.y >= rect.top && pt.y < rect.bottom - (rs.bottom - rs.top))
3691  {
3693  return TRUE;
3694  }
3695  }
3696  else
3697  /* Set the cursor for the horizontal splitter, if the Event details pane is displayed */
3698  if (hwndEventDetails && Settings.bShowDetailsPane &&
3699  (pt.y >= nHSplitPos - SPLIT_WIDTH/2 && pt.y < nHSplitPos + SPLIT_WIDTH/2 + 1))
3700  {
3701  // RECT rs;
3702  GetClientRect(hWnd, &rect);
3703  // GetWindowRect(hwndStatus, &rs);
3704  if (pt.x >= nVSplitPos + SPLIT_WIDTH/2 + 1 /* rect.left + (rs.bottom - rs.top) */ &&
3705  pt.x < rect.right)
3706  {
3708  return TRUE;
3709  }
3710  }
3711  goto Default;
3712  }
3713 
3714  case WM_LBUTTONDOWN:
3715  {
3716  INT x = GET_X_LPARAM(lParam);
3717  INT y = GET_Y_LPARAM(lParam);
3718 
3719  /* Reset the splitter state */
3720  bSplit = 0;
3721 
3722  /* Capture the cursor for the vertical splitter */
3723  if (x >= nVSplitPos - SPLIT_WIDTH/2 && x < nVSplitPos + SPLIT_WIDTH/2 + 1)
3724  {
3725  bSplit = 1;
3726  SetCapture(hWnd);
3727  }
3728  else
3729  /* Capture the cursor for the horizontal splitter, if the Event details pane is displayed */
3730  if (hwndEventDetails && Settings.bShowDetailsPane &&
3731  (y >= nHSplitPos - SPLIT_WIDTH/2 && y < nHSplitPos + SPLIT_WIDTH/2 + 1))
3732  {
3733  bSplit = 2;
3734  SetCapture(hWnd);
3735  }
3736  break;
3737  }
3738 
3739  case WM_LBUTTONUP:
3740  case WM_RBUTTONDOWN:
3741  {
3742  if (GetCapture() != hWnd)
3743  break;
3744 
3745  /* Adjust the correct splitter position */
3746  if (bSplit == 1)
3748  else if (bSplit == 2)
3750 
3751  /* If we are splitting, resize the windows */
3752  if (bSplit != 0)
3753  {
3754  GetClientRect(hWnd, &rect);
3755  ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
3756  }
3757 
3758  /* Reset the splitter state */
3759  bSplit = 0;
3760 
3761  ReleaseCapture();
3762  break;
3763  }
3764 
3765  case WM_MOUSEMOVE:
3766  {
3767  if (GetCapture() != hWnd)
3768  break;
3769 
3770  /* Move the correct splitter */
3771  if (bSplit == 1)
3772  {
3773  INT x = GET_X_LPARAM(lParam);
3774 
3775  GetClientRect(hWnd, &rect);
3776 
3777  x = min(max(x, SPLIT_WIDTH/2), rect.right - rect.left - SPLIT_WIDTH/2);
3778  if (nVSplitPos != x)
3779  {
3780  nVSplitPos = x;
3781  ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
3782  }
3783  }
3784  else if (bSplit == 2)
3785  {
3786  RECT rs;
3787  INT y = GET_Y_LPARAM(lParam);
3788 
3789  GetClientRect(hWnd, &rect);
3790  GetWindowRect(hwndStatus, &rs);
3791 
3792  y = min(max(y, SPLIT_WIDTH/2), rect.bottom - rect.top - SPLIT_WIDTH/2 - (rs.bottom - rs.top));
3793  if (nHSplitPos != y)
3794  {
3795  nHSplitPos = y;
3796  ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
3797  }
3798  }
3799  break;
3800  }
3801 
3802  case WM_SIZE:
3803  {
3804  if (wParam != SIZE_MINIMIZED)
3805  {
3808  break;
3809  }
3810  /* Fall through the default case */
3811  }
3812 
3813  default: Default:
3814  return DefWindowProcW(hWnd, uMsg, wParam, lParam);
3815  }
3816 
3817  return 0;
3818 }
3819 
3820 
3821 static
3822 VOID
3824 {
3825  LPWSTR lpLogName = EventLog->LogName;
3826 
3827  DWORD Result, dwType;
3828  DWORD dwMaxSize = 0, dwRetention = 0;
3829  BOOL Success;
3830  WIN32_FIND_DATAW FileInfo; // WIN32_FILE_ATTRIBUTE_DATA
3832  WCHAR wszBuf[MAX_PATH];
3833  WCHAR szTemp[MAX_LOADSTRING];
3834  LPWSTR FileName;
3835 
3836  HKEY hLogKey;
3837  WCHAR *KeyPath;
3838  DWORD cbData;
3839  SIZE_T cbKeyPath;
3840 
3841  if (EventLog->Permanent)
3842  {
3843 
3844  cbKeyPath = (wcslen(EVENTLOG_BASE_KEY) + wcslen(lpLogName) + 1) * sizeof(WCHAR);
3845  KeyPath = HeapAlloc(GetProcessHeap(), 0, cbKeyPath);
3846  if (!KeyPath)
3847  {
3848  goto Quit;
3849  }
3850 
3851  StringCbCopyW(KeyPath, cbKeyPath, EVENTLOG_BASE_KEY);
3852  StringCbCatW(KeyPath, cbKeyPath, lpLogName);
3853 
3854  if (RegOpenKeyExW(hkMachine, KeyPath, 0, KEY_QUERY_VALUE, &hLogKey) != ERROR_SUCCESS)
3855  {
3856  HeapFree(GetProcessHeap(), 0, KeyPath);
3857  goto Quit;
3858  }
3859  HeapFree(GetProcessHeap(), 0, KeyPath);
3860 
3861 
3862  cbData = sizeof(dwMaxSize);
3863  Result = RegQueryValueExW(hLogKey,
3864  L"MaxSize",
3865  NULL,
3866  &dwType,
3867  (LPBYTE)&dwMaxSize,
3868  &cbData);
3869  if ((Result != ERROR_SUCCESS) || (dwType != REG_DWORD))
3870  {
3871  // dwMaxSize = 512 * 1024; /* 512 kBytes */
3872  dwMaxSize = 0;
3873  }
3874  /* Convert in KB */
3875  dwMaxSize /= 1024;
3876 
3877  cbData = sizeof(dwRetention);
3878  Result = RegQueryValueExW(hLogKey,
3879  L"Retention",
3880  NULL,
3881  &dwType,
3882  (LPBYTE)&dwRetention,
3883  &cbData);
3884  if ((Result != ERROR_SUCCESS) || (dwType != REG_DWORD))
3885  {
3886  /* On Windows 2003 it is 604800 (secs) == 7 days */
3887  dwRetention = 0;
3888  }
3889  /* Convert in days, rounded up */ // ROUND_UP
3890  // dwRetention = ROUND_UP(dwRetention, 24*3600) / (24*3600);
3891  dwRetention = (dwRetention + 24*3600 - 1) / (24*3600);
3892 
3893 
3894  RegCloseKey(hLogKey);
3895 
3896  }
3897 
3898 
3899 Quit:
3900 
3901  SetDlgItemTextW(hDlg, IDC_DISPLAYNAME, lpLogName); // FIXME!
3902  SetDlgItemTextW(hDlg, IDC_LOGNAME, lpLogName);
3903 
3904  FileName = EventLog->FileName;
3905  if (FileName && *FileName)
3906  {
3907  /* Expand the file name. If the log file is on a remote computer, retrieve the network share form of the file name. */
3908  GetExpandedFilePathName(EventLog->ComputerName, FileName, wszBuf, ARRAYSIZE(wszBuf));
3909  FileName = wszBuf;
3910  }
3911  else
3912  {
3913  FileName = L"";
3914  }
3916 
3917  if (FileName && *FileName)
3918  {
3919  /*
3920  * The general problem here (and in the shell as well) is that
3921  * GetFileAttributesEx fails for files that are opened without
3922  * shared access. To retrieve file information for those we need
3923  * to use something else: FindFirstFile, on the full file name.
3924  */
3928  if (!Success)
3929  {
3931  Success = (hFind != INVALID_HANDLE_VALUE);
3932  if (Success)
3933  FindClose(hFind);
3934  }
3935  }
3936  else
3937  {
3938  Success = FALSE;
3939  }
3940 
3941  /* Starting there, FileName becomes invalid because we are reusing wszBuf */
3942 
3943  if (Success)
3944  {
3945  FileSize.u.LowPart = FileInfo.nFileSizeLow;
3946  FileSize.u.HighPart = FileInfo.nFileSizeHigh;
3947  if (FormatFileSizeWithBytes(&FileSize, wszBuf, ARRAYSIZE(wszBuf)))
3948  SetDlgItemTextW(hDlg, IDC_SIZE_LABEL, wszBuf);
3949 
3950  LoadStringW(hInst, IDS_NOT_AVAILABLE, szTemp, ARRAYSIZE(szTemp));
3951 
3952  if (GetFileTimeString(&FileInfo.ftCreationTime, wszBuf, ARRAYSIZE(wszBuf)))
3953  SetDlgItemTextW(hDlg, IDC_CREATED_LABEL, wszBuf);
3954  else
3955  SetDlgItemTextW(hDlg, IDC_CREATED_LABEL, szTemp);
3956 
3957  if (GetFileTimeString(&FileInfo.ftLastWriteTime, wszBuf, ARRAYSIZE(wszBuf)))
3958  SetDlgItemTextW(hDlg, IDC_MODIFIED_LABEL, wszBuf);
3959  else
3960  SetDlgItemTextW(hDlg, IDC_MODIFIED_LABEL, szTemp);
3961 
3962  if (GetFileTimeString(&FileInfo.ftLastAccessTime, wszBuf, ARRAYSIZE(wszBuf)))
3963  SetDlgItemTextW(hDlg, IDC_ACCESSED_LABEL, wszBuf);
3964  else
3965  SetDlgItemTextW(hDlg, IDC_MODIFIED_LABEL, szTemp);
3966  }
3967  else
3968  {
3969  LoadStringW(hInst, IDS_NOT_AVAILABLE, szTemp, ARRAYSIZE(szTemp));
3970 
3971  SetDlgItemTextW(hDlg, IDC_SIZE_LABEL, szTemp);
3972  SetDlgItemTextW(hDlg, IDC_CREATED_LABEL, szTemp);
3973  SetDlgItemTextW(hDlg, IDC_MODIFIED_LABEL, szTemp);
3974  SetDlgItemTextW(hDlg, IDC_ACCESSED_LABEL, szTemp);
3975  }
3976 
3977  if (EventLog->Permanent)
3978  {
3981 
3982  SetDlgItemInt(hDlg, IDC_EDIT_MAXLOGSIZE, dwMaxSize, FALSE);
3983  SetDlgItemInt(hDlg, IDC_EDIT_EVENTS_AGE, dwRetention, FALSE);
3984 
3985  if (dwRetention == 0)
3986  {
3990  }
3991  else if (dwRetention == INFINITE)
3992  {
3996  }
3997  else
3998  {
4002  }
4003  }
4004  else
4005  {
4006  // TODO: Hide the unused controls! Or, just use another type of property sheet!
4007  }
4008 }
4009 
4010 /* Message handler for EventLog Properties dialog */
4013 {
4014  PEVENTLOG EventLog;
4015 
4016  EventLog = (PEVENTLOG)GetWindowLongPtrW(hDlg, DWLP_USER);
4017 
4018  switch (uMsg)
4019  {
4020  case WM_INITDIALOG:
4021  {
4022  EventLog = (PEVENTLOG)((LPPROPSHEETPAGE)lParam)->lParam;
4023  SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)EventLog);
4024 
4025  InitPropertiesDlg(hDlg, EventLog);
4026 
4027  PropSheet_UnChanged(GetParent(hDlg), hDlg);
4028  return (INT_PTR)TRUE;
4029  }
4030 
4031  case WM_DESTROY:
4032  return (INT_PTR)TRUE;
4033 
4034  case WM_COMMAND:
4035  switch (LOWORD(wParam))
4036  {
4037  case IDOK:
4038  case IDCANCEL:
4039  EndDialog(hDlg, LOWORD(wParam));
4040  return (INT_PTR)TRUE;
4041 
4043  {
4047  break;
4048  }
4049 
4051  {
4055  break;
4056  }
4057 
4058  case IDC_NO_OVERWRITE:
4059  {
4063  break;
4064  }
4065 
4066  case IDHELP:
4067  MessageBoxW(hDlg,
4068  L"Help not implemented yet!",
4069  L"Event Log",
4071  return (INT_PTR)TRUE;
4072 
4073  default:
4074  break;
4075  }
4076  break;
4077  }
4078 
4079  return (INT_PTR)FALSE;
4080 }
4081 
4082 INT_PTR
4084 {
4085  INT_PTR ret = 0;
4086  PROPSHEETHEADERW psh;
4087  PROPSHEETPAGEW psp[1]; // 2
4088 
4089  /*
4090  * Bail out if there is no available filter, or if the filter
4091  * contains more than one log.
4092  */
4093  if (!EventLogFilter)
4094  return 0;
4095 
4096  EventLogFilter_AddRef(EventLogFilter);
4097 
4098  if (EventLogFilter->NumOfEventLogs > 1 ||
4099  EventLogFilter->EventLogs[0] == NULL)
4100  {
4101  goto Quit;
4102  }
4103 
4104  /* Header */
4105  psh.dwSize = sizeof(psh);
4106  psh.dwFlags = PSH_PROPSHEETPAGE /*| PSH_USEICONID */ | PSH_PROPTITLE | PSH_HASHELP /*| PSH_NOCONTEXTHELP */ /*| PSH_USECALLBACK */;
4107  psh.hInstance = hInstance;
4108  psh.hwndParent = hWndParent;
4109  // psh.pszIcon = MAKEINTRESOURCEW(IDI_APPICON); // Disabled because it only sets the small icon; the big icon is a stretched version of the small one.
4110  psh.pszCaption = EventLogFilter->EventLogs[0]->LogName;
4111  psh.nStartPage = 0;
4112  psh.ppsp = psp;
4113  psh.nPages = ARRAYSIZE(psp);
4114  // psh.pfnCallback = PropSheetCallback;
4115 
4116  /* Log properties page */
4117  psp[0].dwSize = sizeof(psp[0]);
4118  psp[0].dwFlags = PSP_HASHELP;
4119  psp[0].hInstance = hInstance;
4121  psp[0].pfnDlgProc = EventLogPropProc;
4122  psp[0].lParam = (LPARAM)EventLogFilter->EventLogs[0];
4123 
4124 #if 0
4125  /* TODO: Log sources page */
4126  psp[1].dwSize = sizeof(psp[1]);
4127  psp[1].dwFlags = PSP_HASHELP;
4128  psp[1].hInstance = hInstance;
4130  psp[1].pfnDlgProc = GeneralPageWndProc;
4131  psp[0].lParam = (LPARAM)EventLogFilter->EventLogs[0];
4132 #endif
4133 
4134  /* Create the property sheet */
4135  ret = PropertySheetW(&psh);
4136 
4137 Quit:
4138  EventLogFilter_Release(EventLogFilter);
4139  return ret;
4140 }
4141 
4142 /* Message handler for Event Details dialog */
4143 static HWND hWndDetailsCtrl = NULL; // May go into the DWLP_USER
4144 static HWND hWndGrip = NULL;
4145 static INT cxMin, cyMin; // In window coordinates
4146 static INT cxOld, cyOld; // In client coordinates
4147 
4150 {
4151  switch (uMsg)
4152  {
4153  case WM_INITDIALOG:
4154  {
4155  LONG_PTR dwStyle;
4156  INT sbVXSize, sbHYSize;
4157  RECT rcWnd, rect;
4158 
4160  if (!hWndDetailsCtrl)
4161  {
4162  EndDialog(hDlg, 0);
4163  return (INT_PTR)TRUE;
4164  }
4165 
4166  /* Create a size grip if the dialog has a sizing border */
4167  GetClientRect(hDlg, &rcWnd);
4168  dwStyle = GetWindowLongPtrW(hDlg, GWL_STYLE);
4169  sbVXSize = GetSystemMetrics(SM_CXVSCROLL);
4170  sbHYSize = GetSystemMetrics(SM_CYHSCROLL);
4171  if (dwStyle & WS_THICKFRAME /* == WS_SIZEBOX */)
4172  {
4174  NULL,
4176  rcWnd.right - sbVXSize,
4177  rcWnd.bottom - sbHYSize,
4178  sbVXSize, sbHYSize,
4179  hDlg,
4180  NULL,
4181  hInst,
4182  NULL);
4183  }
4184 
4185  // SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)hWndDetailsCtrl);
4186 
4187  /*
4188  * Compute the minimum window size (in window coordinates) by
4189  * adding the widths/heights of the "Help" and "Close" buttons,
4190  * together with the margins, and add some minimal spacing
4191  * between the buttons.
4192  */
4193  GetWindowRect(hDlg, &rcWnd);
4194  cxMin = cyMin = 0;
4195 
4196  GetWindowRect(GetDlgItem(hDlg, IDHELP), &rect);
4197  cxMin += (rect.right - rect.left) + (rect.left - rcWnd.left); // == (rect.right - rcWnd.left);
4198  cyMin += (rect.bottom - rect.top) + (rcWnd.bottom - rect.bottom); // == (rcWnd.bottom - rect.top);
4199 
4200  GetWindowRect(GetDlgItem(hDlg, IDOK), &rect);
4201  cxMin += (rect.right - rect.left) + (rcWnd.right - rect.right); // == (rcWnd.right - rect.left);
4202  cyMin += (rect.bottom - rect.top) + (rcWnd.bottom - rect.bottom); // == (rcWnd.bottom - rect.top);
4203 
4204  /*
4205  * Convert the window rect from window to client coordinates
4206  * in order to retrieve the sizes of the left and top margins,
4207  * and add some extra space.
4208  */
4209  MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rcWnd, sizeof(RECT)/sizeof(POINT));
4210 
4211  cxMin += -2*rcWnd.left; // Minimal spacing between the buttons == 2 * left margin
4212  cyMin += -rcWnd.top + 12; // Add some space on top
4213 
4214  GetClientRect(hDlg, &rcWnd);
4215  cxOld = rcWnd.right - rcWnd.left;
4216  cyOld = rcWnd.bottom - rcWnd.top;
4217 
4218  /* Show event info on dialog control */
4220 
4221  // SetWindowPos(hWndDetailsCtrl, NULL,
4222  // 0, 0,
4223  // (rcWnd.right - rcWnd.left),
4224  // (rcWnd.bottom - rcWnd.top),
4225  // SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
4226 
4227  /*
4228  * Hide the placeholder static control and show the event details
4229  * control instead. Note that the placeholder is here so far just
4230  * to get the dimensions right in the dialog resource editor.
4231  * I plan to remove it and use a custom control with a suitable
4232  * window class for it, that would create the event details control
4233  * instead.
4234  */
4237  return (INT_PTR)TRUE;
4238  }
4239 
4240  case WM_DESTROY:
4244  return (INT_PTR)TRUE;
4245 
4246  case WM_COMMAND:
4247  switch (LOWORD(wParam))
4248  {
4249  case IDOK:
4250  case IDCANCEL:
4251  EndDialog(hDlg, LOWORD(wParam));
4252  return (INT_PTR)TRUE;
4253 
4254  case IDHELP:
4255  MessageBoxW(hDlg,
4256  L"Help not implemented yet!",
4257  L"Event Log",
4259  return (INT_PTR)TRUE;
4260 
4261  default:
4262  break;
4263  }
4264  break;
4265 
4266  case WM_SETCURSOR:
4267  if (((HWND)wParam == hWndGrip) && (LOWORD(lParam) == HTCLIENT))
4268  {
4271  return (INT_PTR)TRUE;
4272  }
4273  break;
4274 
4275  case WM_SIZING:
4276  {
4277  /* Forbid resizing the dialog smaller than its minimal size */
4278  PRECT dragRect = (PRECT)lParam;
4279 
4280  if ((wParam == WMSZ_LEFT) || (wParam == WMSZ_TOPLEFT) || (wParam == WMSZ_BOTTOMLEFT))
4281  {
4282  if (dragRect->right - dragRect->left < cxMin)
4283  dragRect->left = dragRect->right - cxMin;
4284  }
4285 
4286  if ((wParam == WMSZ_RIGHT) || (wParam == WMSZ_TOPRIGHT) || (wParam == WMSZ_BOTTOMRIGHT))
4287  {
4288  if (dragRect->right - dragRect->left < cxMin)
4289  dragRect->right = dragRect->left + cxMin;
4290  }
4291 
4292  if ((wParam == WMSZ_TOP) || (wParam == WMSZ_TOPLEFT) || (wParam == WMSZ_TOPRIGHT))
4293  {
4294  if (dragRect->bottom - dragRect->top < cyMin)
4295  dragRect->top = dragRect->bottom - cyMin;
4296  }
4297 
4299  {
4300  if (dragRect->bottom - dragRect->top < cyMin)
4301  dragRect->bottom = dragRect->top + cyMin;
4302  }
4303 
4305  return (INT_PTR)TRUE;
4306  }
4307 
4308  case WM_SIZE:
4309  {
4310  INT cx = LOWORD(lParam);
4311  INT cy = HIWORD(lParam);
4312 
4313  HDWP hdwp;
4314  HWND hItemWnd;
4315  RECT rect;
4316 
4317  hdwp = BeginDeferWindowPos(4);
4318 
4319  /* Resize the event details control window */
4320 
4321  hItemWnd = hWndDetailsCtrl;
4322  GetWindowRect(hItemWnd, &rect);
4323  MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
4324 
4325  if (hdwp)
4326  hdwp = DeferWindowPos(hdwp,
4327  hItemWnd,
4328  HWND_TOP,
4329  0, 0,
4330  (rect.right - rect.left) + (cx - cxOld),
4331  (rect.bottom - rect.top) + (cy - cyOld),
4333 
4334  /* Move the buttons */
4335 
4336  hItemWnd = GetDlgItem(hDlg, IDHELP);
4337  GetWindowRect(hItemWnd, &rect);
4338  MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
4339 
4340  if (hdwp)
4341  hdwp = DeferWindowPos(hdwp,
4342  hItemWnd,
4343  HWND_TOP,
4344  rect.left,
4345  rect.top + (cy - cyOld),
4346  0, 0,
4348 
4349  hItemWnd = GetDlgItem(hDlg, IDOK);
4350  GetWindowRect(hItemWnd, &rect);
4351  MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
4352 
4353  if (hdwp)
4354  hdwp = DeferWindowPos(hdwp,
4355  hItemWnd,
4356  HWND_TOP,
4357  rect.left + (cx - cxOld),
4358  rect.top + (cy - cyOld),
4359  0, 0,
4361 
4362  /* Move the size grip */
4363  if (hWndGrip && hdwp)
4364  {
4366  MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
4367 
4368  hdwp = DeferWindowPos(hdwp,
4369  hWndGrip,
4370  HWND_TOP,
4371  rect.left + (cx - cxOld),
4372  rect.top + (cy - cyOld),
4373  0, 0,
4375  }
4376 
4377  if (hdwp)
4378  EndDeferWindowPos(hdwp);
4379 
4380  /* Hide the size grip if we are in maximized mode */
4381  if (hWndGrip)
4383 
4384  cxOld = cx;
4385  cyOld = cy;
4386 
4388  return (INT_PTR)TRUE;
4389  }
4390  }
4391 
4392  return (INT_PTR)FALSE;
4393 }
#define IDC_SIZEWE
Definition: winuser.h:689
#define WS_CLIPSIBLINGS
Definition: pedump.c:618
LPWSTR lpThousandSep
Definition: winnls.h:643
#define STATUSCLASSNAMEW
Definition: commctrl.h:1908
_In_opt_ ULONG _Out_ PULONG Value
Definition: rtlfuncs.h:2343
HANDLE WINAPI OpenEventLogW(IN LPCWSTR lpUNCServerName, IN LPCWSTR lpSourceName)
Definition: eventlog.c:985
#define LOCALE_SGROUPING
Definition: winnls.h:44
HINSTANCE hInstance
Definition: commdlg.h:362
_In_ LPCSTR _Out_writes_bytes_to_opt_ cbSid PSID _Inout_ LPDWORD _Out_writes_to_opt_ cchReferencedDomainName LPSTR _Inout_ LPDWORD _Out_ PSID_NAME_USE peUse
Definition: winbase.h:2684
HWND hwndParent
Definition: prsht.h:277
#define WS_THICKFRAME
Definition: pedump.c:630
LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
Definition: string.c:2376
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4711
void TrimNulls(LPWSTR s)
Definition: eventvwr.c:1454
static int argc
Definition: ServiceArgs.c:12
const uint16_t * PCWSTR
Definition: typedefs.h:55
#define WMSZ_BOTTOMRIGHT
Definition: winuser.h:2446
#define IN
Definition: typedefs.h:38
DWORD Flags
Definition: commdlg.h:373
INT_PTR EventLogProperties(HINSTANCE, HWND, PEVENTLOGFILTER)
Definition: eventvwr.c:4083
#define max(a, b)
Definition: svc.c:63
BOOL AuditSuccess
Definition: eventvwr.h:117
STRSAFEAPI StringCchCopyNW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc, size_t cchToCopy)
Definition: strsafe.h:236
#define MAX_LOADSTRING
Definition: eventvwr.c:60
BOOL WINAPI TranslateMessage(_In_ const MSG *)
static HICON
Definition: imagelist.c:84
BOOL bNewestEventsFirst
Definition: eventvwr.c:127
int iImage
Definition: commctrl.h:2339
#define IDM_EVENT_DETAILS
Definition: resource.h:75
HDWP WINAPI BeginDeferWindowPos(_In_ int)
#define SM_CYHSCROLL
Definition: winuser.h:952
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define WC_TREEVIEWW
Definition: commctrl.h:3215
BOOL bShowDetailsPane
Definition: eventvwr.c:124
#define IDOK
Definition: winuser.h:824
#define IDS_EVENTLOG_ERROR_TYPE
Definition: resource.h:101
#define CloseHandle
Definition: compat.h:398
#define PBS_SMOOTH
Definition: commctrl.h:2152
#define LR_SHARED
Definition: winuser.h:1090
char hdr[14]
Definition: iptest.cpp:33
LPCWSTR lpstrFilter
Definition: commdlg.h:363
#define IMAGE_ICON
Definition: winuser.h:212
#define FORMAT_MESSAGE_MAX_WIDTH_MASK
Definition: winbase.h:406
PEVENTLOGRECORD * g_RecordPtrs
Definition: eventvwr.c:99
PEVENTLOG EventLogs[ANYSIZE_ARRAY]
Definition: eventvwr.h:135
LPARAM lParam
Definition: commctrl.h:3327
LPCPROPSHEETPAGEW ppsp
Definition: prsht.h:290
BYTE bSplit
Definition: eventvwr.c:75
#define LVCF_WIDTH
Definition: commctrl.h:2559
INT_PTR WINAPI DialogBoxParamW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_opt_ HWND, _In_opt_ DLGPROC, _In_ LPARAM)
#define MF_BYCOMMAND
Definition: winuser.h:202
#define LVSIL_SMALL
Definition: commctrl.h:2271
enum _SID_NAME_USE SID_NAME_USE
LPCWSTR pszTemplate
Definition: prsht.h:209
int cbWndExtra
Definition: winuser.h:3194
#define ERROR_SUCCESS
Definition: deptool.c:10
static INT cyMin
Definition: eventvwr.c:4145
#define WM_CONTEXTMENU
Definition: richedit.h:64
int WINAPI MapWindowPoints(_In_opt_ HWND hWndFrom, _In_opt_ HWND hWndTo, _Inout_updates_(cPoints) LPPOINT lpPoints, _In_ UINT cPoints)
#define WM_LBUTTONDOWN
Definition: winuser.h:1758
UINT uNewState
Definition: commctrl.h:3008
LIST_ENTRY ListEntry
Definition: eventvwr.h:104
LPWSTR lpDecimalSep
Definition: winnls.h:642
#define IDM_ABOUT
Definition: resource.h:29
VOID BuildLogListAndFilterList(IN LPCWSTR lpComputerName)
Definition: eventvwr.c:2796
struct _Entry Entry
Definition: kefuncs.h:640
#define IDYES
Definition: winuser.h:829
#define IDS_CLEAREVENTS_MSG
Definition: resource.h:95
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
PWSTR LogName
Definition: eventvwr.h:90
BOOL WINAPI IsWindow(_In_opt_ HWND)
BOOL ProcessCmdLine(IN LPWSTR lpCmdLine)
Definition: eventvwr.c:201
#define LVCF_TEXT
Definition: commctrl.h:2560
USHORT MaximumLength
Definition: env_spec_w32.h:370
LPCWSTR lpstrInitialDir
Definition: commdlg.h:371
BOOL Information
Definition: eventvwr.h:114
INT nHSplitPos
Definition: eventvwr.c:74
#define LVS_SHOWSELALWAYS
Definition: commctrl.h:2239
#define IDI_EVENTVWR
Definition: resource.h:4
static const LPCWSTR EVENTVWR_WNDCLASS
Definition: eventvwr.c:40
BOOL GetEventCategory(IN LPCWSTR KeyName, IN LPCWSTR SourceName, IN PEVENTLOGRECORD pevlr, OUT PWCHAR CategoryName)
Definition: eventvwr.c:1602
WORD ATOM
Definition: dimm.idl:113
#define IDM_SAVE_SETTINGS
Definition: resource.h:79
#define SIZE_MAXIMIZED
Definition: winuser.h:2482
#define KEY_READ
Definition: nt_native.h:1023
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
#define pt(x, y)
Definition: drawing.c:79
#define WM_INITMENUPOPUP
Definition: winuser.h:1728
#define SW_HIDE
Definition: winuser.h:762
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
INT nHSplitPos
Definition: eventvwr.c:129
VOID GetEventType(IN WORD dwEventType, OUT PWCHAR eventTypeText)
Definition: eventvwr.c:1783
WINDOWPLACEMENT wpPos
Definition: eventvwr.c:130
VOID DisplayUsage(VOID)
Definition: eventvwr.c:181
uint16_t * PWSTR
Definition: typedefs.h:54
BOOL WINAPI BackupEventLogW(IN HANDLE hEventLog, IN LPCWSTR lpBackupFileName)
Definition: eventlog.c:245
#define LVS_REPORT
Definition: commctrl.h:2234
#define IDD_EVENTDETAILS_DLG
Definition: resource.h:23
static const LPCWSTR EVNTVWR_PARAM_KEY
Definition: eventvwr.c:42
BOOL WINAPI CheckMenuRadioItem(_In_ HMENU, _In_ UINT, _In_ UINT, _In_ UINT, _In_ UINT)
BOOL WINAPI EqualSid(PSID pSid1, PSID pSid2)
Definition: security.c:708
#define _countof(array)
Definition: fontsub.cpp:30
#define LOCALE_USER_DEFAULT
#define IDC_MODIFIED_LABEL
Definition: resource.h:51
#define TreeView_EditLabel(hwnd, hitem)
Definition: commctrl.h:3476
#define IDM_LIST_OLDEST
Definition: resource.h:74