ReactOS  0.4.11-dev-195-gef016bf
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 
197  HeapFree(GetProcessHeap(), 0, lpBuffer);
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 = 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 
618  if (!MyRegisterClass(hInstance))
619  goto Quit;
620 
621  /* Load the settings */
622  LoadSettings(nCmdShow);
623 
624  /* Perform application initialization */
625  if (!InitInstance(hInstance))
626  goto Quit;
627 
628  hAccelTable = LoadAcceleratorsW(hInstance, MAKEINTRESOURCEW(IDA_EVENTVWR));
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 
641  hThread = CreateThread(NULL, 0,
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 */
648  InitializeListHead(&EventLogList);
649  InitializeListHead(&EventLogFilterList);
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  {
672  TranslateMessage(&msg);
673  DispatchMessageW(&msg);
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 */
690  WaitForSingleObject(hThread, INFINITE);
691  CloseHandle(hThread);
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 */
768  dwFlags &= ~FORMAT_MESSAGE_FROM_STRING;
769  dwFlags |= FORMAT_MESSAGE_FROM_HMODULE;
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  {
779  dwLength = FormatMessageW(dwFlags,
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) &&
805  !(dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS))
806  {
807  /* Remove any possible harmful flags and always ignore inserts */
808  dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
810 
811  /* If this call also throws an exception, we are really dead */
812  dwLength = FormatMessageW(dwFlags,
813  hLibrary,
814  dwMessageId,
816  (LPWSTR)&lpMsgBuf,
817  nSize,
818  NULL /* Arguments */);
819  }
820  }
821  _SEH2_END;
822  }
824  {
825  FreeLibrary(hLibrary);
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  {
977  Status = ERROR_OUTOFMEMORY;
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  {
1048  Status = ERROR_OUTOFMEMORY;
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  INT cchWritten;
1177  LPWSTR pwszEnd;
1178  size_t cchRemaining;
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, &cchRemaining, 0);
1189  cchWritten = LoadStringW(hInst, IDS_BYTES_FORMAT, pwszEnd, cchRemaining);
1190  cchRemaining -= cchWritten;
1191 
1192  return cchResultMax - cchRemaining;
1193 }
1194 
1195 LPWSTR
1196 FormatFileSizeWithBytes(const PULARGE_INTEGER lpQwSize, LPWSTR pwszResult, UINT cchResultMax)
1197 {
1198  UINT cchWritten;
1199  LPWSTR pwszEnd;
1200  size_t cchRemaining;
1201 
1202  /* Format bytes in KBs, MBs etc */
1203  if (StrFormatByteSizeW(lpQwSize->QuadPart, pwszResult, cchResultMax) == NULL)
1204  return NULL;
1205 
1206  /* If there is less bytes than 1KB, we have nothing to do */
1207  if (lpQwSize->QuadPart < 1024)
1208  return pwszResult;
1209 
1210  /* Concatenate " (" */
1211  cchWritten = wcslen(pwszResult);
1212  pwszEnd = pwszResult + cchWritten;
1213  cchRemaining = cchResultMax - cchWritten;
1214  StringCchCopyExW(pwszEnd, cchRemaining, L" (", &pwszEnd, &cchRemaining, 0);
1215 
1216  /* Write formated bytes count */
1217  cchWritten = FormatByteSize(lpQwSize->QuadPart, pwszEnd, cchRemaining);
1218  pwszEnd += cchWritten;
1219  cchRemaining -= cchWritten;
1220 
1221  /* Copy ")" to the buffer */
1222  StringCchCopyW(pwszEnd, cchRemaining, L")");
1223 
1224  return pwszResult;
1225 }
1226 
1227 /* Adapted from shell32!dialogs/filedefext.cpp:``CFileDefExt::GetFileTimeString'' */
1228 BOOL
1229 GetFileTimeString(LPFILETIME lpFileTime, LPWSTR pwszResult, UINT cchResult)
1230 {
1231  FILETIME ft;
1232  SYSTEMTIME st;
1233  int cchWritten;
1234  size_t cchRemaining = cchResult;
1235  LPWSTR pwszEnd = pwszResult;
1236 
1237  if (!FileTimeToLocalFileTime(lpFileTime, &ft) || !FileTimeToSystemTime(&ft, &st))
1238  return FALSE;
1239 
1240  cchWritten = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, pwszEnd, cchRemaining);
1241  if (cchWritten)
1242  --cchWritten; // GetDateFormatW returns count with terminating zero
1243  // else
1244  // ERR("GetDateFormatW failed\n");
1245 
1246  cchRemaining -= cchWritten;
1247  pwszEnd += cchWritten;
1248 
1249  StringCchCopyExW(pwszEnd, cchRemaining, L", ", &pwszEnd, &cchRemaining, 0);
1250 
1251  cchWritten = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, pwszEnd, cchRemaining);
1252  if (cchWritten)
1253  --cchWritten; // GetTimeFormatW returns count with terminating zero
1254  // else
1255  // ERR("GetTimeFormatW failed\n");
1256 
1257  return TRUE;
1258 }
1259 
1260 
1261 HTREEITEM
1264  IN LPWSTR lpText,
1265  IN INT Image,
1266  IN INT SelectedImage,
1267  IN LPARAM lParam)
1268 {
1269  TV_INSERTSTRUCTW Insert;
1270 
1271  ZeroMemory(&Insert, sizeof(Insert));
1272 
1273  Insert.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1274  Insert.hInsertAfter = TVI_LAST;
1275  Insert.hParent = hParent;
1276  Insert.item.pszText = lpText;
1277  Insert.item.iImage = Image;
1278  Insert.item.iSelectedImage = SelectedImage;
1279  Insert.item.lParam = lParam;
1280 
1281  Insert.item.mask |= TVIF_STATE;
1282  Insert.item.stateMask = TVIS_OVERLAYMASK;
1283  Insert.item.state = INDEXTOOVERLAYMASK(1);
1284 
1285  return TreeView_InsertItem(hTreeView, &Insert);
1286 }
1287 
1288 
1289 /* LOG HELPER FUNCTIONS *******************************************************/
1290 
1291 PEVENTLOG
1293  IN PCWSTR LogName,
1294  IN BOOL Permanent)
1295 {
1296  PEVENTLOG EventLog;
1297  UINT cchName;
1298 
1299  /* Allocate a new event log entry */
1300  EventLog = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*EventLog));
1301  if (!EventLog)
1302  return NULL;
1303 
1304  /* Allocate the computer name string (optional) and copy it */
1305  if (ComputerName)
1306  {
1307  cchName = wcslen(ComputerName) + 1;
1308  EventLog->ComputerName = HeapAlloc(GetProcessHeap(), 0, cchName * sizeof(WCHAR));
1309  if (EventLog->ComputerName)
1310  StringCchCopyW(EventLog->ComputerName, cchName, ComputerName);
1311  }
1312 
1313  /* Allocate the event log name string and copy it */
1314  cchName = wcslen(LogName) + 1;
1315  EventLog->LogName = HeapAlloc(GetProcessHeap(), 0, cchName * sizeof(WCHAR));
1316  if (!EventLog->LogName)
1317  {
1318  if (EventLog->ComputerName)
1319  HeapFree(GetProcessHeap(), 0, EventLog->ComputerName);
1320  HeapFree(GetProcessHeap(), 0, EventLog);
1321  return NULL;
1322  }
1323  StringCchCopyW(EventLog->LogName, cchName, LogName);
1324 
1325  EventLog->Permanent = Permanent;
1326 
1327  return EventLog;
1328 }
1329 
1330 VOID
1332 {
1333  if (EventLog->LogName)
1334  HeapFree(GetProcessHeap(), 0, EventLog->LogName);
1335 
1336  if (EventLog->ComputerName)
1337  HeapFree(GetProcessHeap(), 0, EventLog->ComputerName);
1338 
1339  if (EventLog->FileName)
1340  HeapFree(GetProcessHeap(), 0, EventLog->FileName);
1341 
1342  HeapFree(GetProcessHeap(), 0, EventLog);
1343 }
1344 
1345 
1346 PWSTR
1348 {
1349  PWSTR pStr;
1350  ULONG Length;
1351 
1352  if (!MultiStr)
1353  return NULL;
1354 
1355  pStr = (PWSTR)MultiStr;
1356  while (*pStr) pStr += (wcslen(pStr) + 1);
1357  Length = MultiStr - pStr + 2;
1358 
1359  pStr = HeapAlloc(GetProcessHeap(), 0, Length * sizeof(WCHAR));
1360  // NOTE: If we failed allocating the string, then fall back into no filter!
1361  if (pStr)
1362  RtlCopyMemory(pStr, MultiStr, Length * sizeof(WCHAR));
1363 
1364  return pStr;
1365 }
1366 
1368 AllocEventLogFilter(// IN PCWSTR FilterName,
1370  IN BOOL Warning,
1371  IN BOOL Error,
1372  IN BOOL AuditSuccess,
1373  IN BOOL AuditFailure,
1374  IN PCWSTR Sources OPTIONAL,
1375  IN PCWSTR Users OPTIONAL,
1376  IN PCWSTR ComputerNames OPTIONAL,
1377  IN ULONG NumOfEventLogs,
1378  IN PEVENTLOG* EventLogs)
1379 {
1380  PEVENTLOGFILTER EventLogFilter;
1381 
1382  /* Allocate a new event log filter entry, big enough to accommodate the list of logs */
1383  EventLogFilter = HeapAlloc(GetProcessHeap(),
1385  FIELD_OFFSET(EVENTLOGFILTER, EventLogs[NumOfEventLogs]));
1386  if (!EventLogFilter)
1387  return NULL;
1388 
1389  EventLogFilter->Information = Information;
1390  EventLogFilter->Warning = Warning;
1391  EventLogFilter->Error = Error;
1392  EventLogFilter->AuditSuccess = AuditSuccess;
1393  EventLogFilter->AuditFailure = AuditFailure;
1394 
1395  /* Allocate and copy the sources, users, and computers multi-strings */
1396  EventLogFilter->Sources = AllocAndCopyMultiStr(Sources);
1397  EventLogFilter->Users = AllocAndCopyMultiStr(Users);
1398  EventLogFilter->ComputerNames = AllocAndCopyMultiStr(ComputerNames);
1399 
1400  /* Copy the list of event logs */
1401  EventLogFilter->NumOfEventLogs = NumOfEventLogs;
1402  RtlCopyMemory(EventLogFilter->EventLogs, EventLogs, NumOfEventLogs * sizeof(PEVENTLOG));
1403 
1404  /* Initialize the filter reference count */
1405  EventLogFilter->ReferenceCount = 1;
1406 
1407  return EventLogFilter;
1408 }
1409 
1410 VOID
1412 {
1413  if (EventLogFilter->Sources)
1414  HeapFree(GetProcessHeap(), 0, EventLogFilter->Sources);
1415 
1416  if (EventLogFilter->Users)
1417  HeapFree(GetProcessHeap(), 0, EventLogFilter->Users);
1418 
1419  if (EventLogFilter->ComputerNames)
1420  HeapFree(GetProcessHeap(), 0, EventLogFilter->ComputerNames);
1421 
1422  HeapFree(GetProcessHeap(), 0, EventLogFilter);
1423 }
1424 
1426 {
1427  ASSERT(EventLogFilter);
1428  return InterlockedIncrement(&EventLogFilter->ReferenceCount);
1429 }
1430 
1432 {
1433  LONG RefCount;
1434 
1435  ASSERT(EventLogFilter);
1436 
1437  /* When the reference count reaches zero, delete the filter */
1438  RefCount = InterlockedDecrement(&EventLogFilter->ReferenceCount);
1439  if (RefCount <= 0)
1440  {
1441  /* Remove the filter from the list */
1443  EventLogFilter_Free(EventLogFilter);
1444  }
1445 
1446  return RefCount;
1447 }
1448 
1449 void
1451 {
1452  WCHAR *c;
1453 
1454  if (s != NULL)
1455  {
1456  c = s + wcslen(s) - 1;
1457  while (c >= s && iswspace(*c))
1458  --c;
1459  *++c = L'\0';
1460  }
1461 }
1462 
1463 DWORD
1465  IN LPCWSTR ComputerName OPTIONAL,
1467  OUT LPWSTR lpFullFileName OPTIONAL,
1468  IN DWORD nSize)
1469 {
1470  DWORD dwLength;
1471 
1472  /* Determine the needed size after expansion of any environment strings */
1473  dwLength = ExpandEnvironmentStringsW(lpFileName, NULL, 0);
1474  if (dwLength == 0)
1475  {
1476  /* We failed, bail out */
1477  return 0;
1478  }
1479 
1480  /* If the file path is on a remote computer, estimate its length */
1481  // FIXME: Use WNetGetUniversalName instead?
1482  if (ComputerName && *ComputerName)
1483  {
1484  /* Skip any leading backslashes */
1485  while (*ComputerName == L'\\')
1486  ++ComputerName;
1487 
1488  if (*ComputerName)
1489  {
1490  /* Count 2 backslashes plus the computer name and one backslash separator */
1491  dwLength += 2 + wcslen(ComputerName) + 1;
1492  }
1493  }
1494 
1495  /* Check whether we have enough space */
1496  if (dwLength > nSize)
1497  {
1498  /* No, return the needed size in characters (includes NULL-terminator) */
1499  return dwLength;
1500  }
1501 
1502 
1503  /* Now expand the file path */
1504  ASSERT(dwLength <= nSize);
1505 
1506  /* Expand any existing environment strings */
1507  if (ExpandEnvironmentStringsW(lpFileName, lpFullFileName, dwLength) == 0)
1508  {
1509  /* We failed, bail out */
1510  return 0;
1511  }
1512 
1513  /* If the file path is on a remote computer, retrieve the network share form of the file name */
1514  // FIXME: Use WNetGetUniversalName instead?
1515  if (ComputerName && *ComputerName)
1516  {
1517  /* Note that we previously skipped any potential leading backslashes */
1518 
1519  /* Replace ':' by '$' in the drive letter */
1520  if (*lpFullFileName && lpFullFileName[1] == L':')
1521  lpFullFileName[1] = L'$';
1522 
1523  /* Prepend the computer name */
1524  RtlMoveMemory(lpFullFileName + 2 + wcslen(ComputerName) + 1,
1525  lpFullFileName, dwLength * sizeof(WCHAR) - (2 + wcslen(ComputerName) + 1) * sizeof(WCHAR));
1526  lpFullFileName[0] = L'\\';
1527  lpFullFileName[1] = L'\\';
1528  wcsncpy(lpFullFileName + 2, ComputerName, wcslen(ComputerName));
1529  lpFullFileName[2 + wcslen(ComputerName)] = L'\\';
1530  }
1531 
1532  /* Return the number of stored characters (includes NULL-terminator) */
1533  return dwLength;
1534 }
1535 
1536 BOOL
1539  IN LPCWSTR EntryName,
1540  OUT PWCHAR lpModuleName) // TODO: Add IN DWORD BufLen
1541 {
1542  BOOL Success = FALSE;
1543  LONG Result;
1544  DWORD dwType, dwSize;
1546  WCHAR szKeyName[MAX_PATH];
1547  HKEY hLogKey = NULL;
1548  HKEY hSourceKey = NULL;
1549 
1550  StringCbCopyW(szKeyName, sizeof(szKeyName), EVENTLOG_BASE_KEY);
1551  StringCbCatW(szKeyName, sizeof(szKeyName), lpLogName);
1552 
1553  Result = RegOpenKeyExW(hkMachine,
1554  szKeyName,
1555  0,
1556  KEY_READ,
1557  &hLogKey);
1558  if (Result != ERROR_SUCCESS)
1559  return FALSE;
1560 
1561  Result = RegOpenKeyExW(hLogKey,
1562  SourceName,
1563  0,
1565  &hSourceKey);
1566  if (Result != ERROR_SUCCESS)
1567  {
1568  RegCloseKey(hLogKey);
1569  return FALSE;
1570  }
1571 
1572  dwSize = sizeof(szModuleName);
1573  Result = RegQueryValueExW(hSourceKey,
1574  EntryName,
1575  NULL,
1576  &dwType,
1577  (LPBYTE)szModuleName,
1578  &dwSize);
1579  if ((Result != ERROR_SUCCESS) || (dwType != REG_EXPAND_SZ && dwType != REG_SZ))
1580  {
1581  szModuleName[0] = UNICODE_NULL;
1582  }
1583  else
1584  {
1585  /* NULL-terminate the string and expand it */
1586  szModuleName[dwSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
1587  GetExpandedFilePathName(lpComputerName, szModuleName, lpModuleName, ARRAYSIZE(szModuleName));
1588  Success = TRUE;
1589  }
1590 
1591  RegCloseKey(hSourceKey);
1592  RegCloseKey(hLogKey);
1593 
1594  return Success;
1595 }
1596 
1597 BOOL
1600  IN PEVENTLOGRECORD pevlr,
1601  OUT PWCHAR CategoryName) // TODO: Add IN DWORD BufLen
1602 {
1603  BOOL Success = FALSE;
1604  WCHAR szMessageDLL[MAX_PATH];
1605  LPWSTR lpMsgBuf = NULL;
1606 
1607  if (!GetEventMessageFileDLL(KeyName, SourceName, EVENT_CATEGORY_MESSAGE_FILE, szMessageDLL))
1608  goto Quit;
1609 
1610  /* Retrieve the message string without appending extra newlines */
1611  lpMsgBuf =
1612  GetMessageStringFromDllList(szMessageDLL,
1615  pevlr->EventCategory,
1617  NULL);
1618  if (lpMsgBuf)
1619  {
1620  /* Trim the string */
1621  TrimNulls(lpMsgBuf);
1622 
1623  /* Copy the category name */
1624  StringCchCopyW(CategoryName, MAX_PATH, lpMsgBuf);
1625 
1626  /* Free the buffer allocated by FormatMessage */
1627  LocalFree(lpMsgBuf);
1628 
1629  /* The ID was found and the message was formatted */
1630  Success = TRUE;
1631  }
1632 
1633 Quit:
1634  if (!Success)
1635  {
1636  if (pevlr->EventCategory != 0)
1637  {
1638  StringCchPrintfW(CategoryName, MAX_PATH, L"(%lu)", pevlr->EventCategory);
1639  Success = TRUE;
1640  }
1641  }
1642 
1643  return Success;
1644 }
1645 
1646 
1647 BOOL // NOTE: Used by evtdetctl.c
1650  IN PEVENTLOGRECORD pevlr,
1651  OUT PWCHAR EventText) // TODO: Add IN DWORD BufLen
1652 {
1653  BOOL Success = FALSE;
1654  DWORD i;
1655  size_t cch;
1656  WCHAR SourceModuleName[1024];
1657  WCHAR ParameterModuleName[1024];
1658  BOOL IsParamModNameCached = FALSE;
1659  LPWSTR lpMsgBuf = NULL;
1660  LPWSTR szStringArray, szMessage;
1661  LPWSTR *szArguments;
1662 
1663  /* Get the event string array */
1664  szStringArray = (LPWSTR)((LPBYTE)pevlr + pevlr->StringOffset);
1665 
1666  /* NOTE: GetEventMessageFileDLL can return a comma-separated list of DLLs */
1667  if (!GetEventMessageFileDLL(KeyName, SourceName, EVENT_MESSAGE_FILE, SourceModuleName))
1668  goto Quit;
1669 
1670  /* Allocate space for insertion strings */
1671  szArguments = HeapAlloc(GetProcessHeap(), 0, pevlr->NumStrings * sizeof(LPVOID));
1672  if (!szArguments)
1673  goto Quit;
1674 
1675  if (!IsParamModNameCached)
1676  {
1677  /* Now that the parameter file list is loaded, no need to reload it at the next run! */
1678  IsParamModNameCached = GetEventMessageFileDLL(KeyName, SourceName, EVENT_PARAMETER_MESSAGE_FILE, ParameterModuleName);
1679  // FIXME: If the string loading failed the first time, no need to retry it just after???
1680  }
1681 
1682  if (IsParamModNameCached)
1683  {
1684  /* Not yet support for reading messages from parameter message DLL */
1685  }
1686 
1687  szMessage = szStringArray;
1688  /*
1689  * HACK:
1690  * We do some hackish preformatting of the cached event strings...
1691  * That's because after we pass the string to FormatMessage
1692  * (via GetMessageStringFromDllList) with the FORMAT_MESSAGE_ARGUMENT_ARRAY
1693  * flag, instead of ignoring the insertion parameters and do the formatting
1694  * by ourselves. Therefore, the resulting string should have the parameter
1695  * string placeholders starting with a single '%' instead of a mix of one
1696  * and two '%'.
1697  */
1698  /* HACK part 1: Compute the full length of the string array */
1699  cch = 0;
1700  for (i = 0; i < pevlr->NumStrings; i++)
1701  {
1702  szMessage += wcslen(szMessage) + 1;
1703  }
1704  cch = szMessage - szStringArray;
1705 
1706  /* HACK part 2: Now do the HACK proper! */
1707  szMessage = szStringArray;
1708  for (i = 0; i < pevlr->NumStrings; i++)
1709  {
1710  lpMsgBuf = szMessage;
1711  while ((lpMsgBuf = wcsstr(lpMsgBuf, L"%%")))
1712  {
1713  if (iswdigit(lpMsgBuf[2]))
1714  {
1715  RtlMoveMemory(lpMsgBuf, lpMsgBuf+1, ((szStringArray + cch) - lpMsgBuf - 1) * sizeof(WCHAR));
1716  }
1717  }
1718 
1719  szArguments[i] = szMessage;
1720  szMessage += wcslen(szMessage) + 1;
1721  }
1722 
1723  /* Retrieve the message string without appending extra newlines */
1724  lpMsgBuf =
1725  GetMessageStringFromDllList(SourceModuleName,
1728  pevlr->EventID,
1729  0,
1730  (va_list*)szArguments);
1731  if (lpMsgBuf)
1732  {
1733  /* Trim the string */
1734  TrimNulls(lpMsgBuf);
1735 
1736  szMessage = NULL;
1737  Success = (ApplyParameterStringsToMessage(ParameterModuleName,
1738  TRUE,
1739  lpMsgBuf,
1740  &szMessage) == ERROR_SUCCESS);
1741  if (Success && szMessage)
1742  {
1743  /* Free the buffer allocated by FormatMessage */
1744  LocalFree(lpMsgBuf);
1745  lpMsgBuf = szMessage;
1746  }
1747 
1748  /* Copy the event text */
1749  StringCchCopyW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, lpMsgBuf);
1750 
1751  /* Free the buffer allocated by FormatMessage */
1752  LocalFree(lpMsgBuf);
1753  }
1754 
1755  HeapFree(GetProcessHeap(), 0, szArguments);
1756 
1757 Quit:
1758  if (!Success)
1759  {
1760  /* Get a read-only pointer to the "event-not-found" string */
1761  lpMsgBuf = HeapAlloc(GetProcessHeap(), 0, EVENT_MESSAGE_EVENTTEXT_BUFFER * sizeof(WCHAR));
1763  StringCchPrintfW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, lpMsgBuf, (pevlr->EventID & 0xFFFF), SourceName);
1764 
1765  /* Append the strings */
1766  szMessage = szStringArray;
1767  for (i = 0; i < pevlr->NumStrings; i++)
1768  {
1769  StringCchCatW(EventText, EVENT_MESSAGE_EVENTTEXT_BUFFER, szMessage);
1771  szMessage += wcslen(szMessage) + 1;
1772  }
1773  }
1774 
1775  return Success;
1776 }
1777 
1778 VOID
1779 GetEventType(IN WORD dwEventType,
1780  OUT PWCHAR eventTypeText) // TODO: Add IN DWORD BufLen
1781 {
1782  switch (dwEventType)
1783  {
1784  case EVENTLOG_ERROR_TYPE:
1786  break;
1787  case EVENTLOG_WARNING_TYPE:
1789  break;
1792  break;
1793  case EVENTLOG_SUCCESS:
1795  break;
1798  break;
1801  break;
1802  default:
1804  break;
1805  }
1806 }
1807 
1808 BOOL
1810  IN OUT PSID *pLastSid,
1811  OUT PWCHAR pszUser) // TODO: Add IN DWORD BufLen
1812 {
1813  PSID pCurrentSid;
1814  PWSTR StringSid;
1815  WCHAR szName[1024];
1816  WCHAR szDomain[1024];
1818  DWORD cchName = ARRAYSIZE(szName);
1819  DWORD cchDomain = ARRAYSIZE(szDomain);
1820  BOOL Success = FALSE;
1821 
1822  /* Point to the SID */
1823  pCurrentSid = (PSID)((LPBYTE)pelr + pelr->UserSidOffset);
1824 
1825  if (!IsValidSid(pCurrentSid))
1826  {
1827  *pLastSid = NULL;
1828  return FALSE;
1829  }
1830  else if (*pLastSid && EqualSid(*pLastSid, pCurrentSid))
1831  {
1832  return TRUE;
1833  }
1834 
1835  /* User SID */
1836  if (pelr->UserSidLength > 0)
1837  {
1838  /*
1839  * Try to retrieve the user account name and domain name corresponding
1840  * to the SID. If it cannot be retrieved, try to convert the SID to a
1841  * string-form. It should not be bigger than the user-provided buffer
1842  * 'pszUser', otherwise we return an error.
1843  */
1845  pCurrentSid,
1846  szName,
1847  &cchName,
1848  szDomain,
1849  &cchDomain,
1850  &peUse))
1851  {
1852  StringCchCopyW(pszUser, MAX_PATH, szName);
1853  Success = TRUE;
1854  }
1855  else if (ConvertSidToStringSidW(pCurrentSid, &StringSid))
1856  {
1857  /* Copy the string only if the user-provided buffer is big enough */
1858  if (wcslen(StringSid) + 1 <= MAX_PATH) // + 1 for NULL-terminator
1859  {
1860  StringCchCopyW(pszUser, MAX_PATH, StringSid);
1861  Success = TRUE;
1862  }
1863  else
1864  {
1866  Success = FALSE;
1867  }
1868 
1869  /* Free the allocated buffer */
1870  LocalFree(StringSid);
1871  }
1872  }
1873 
1874  *pLastSid = Success ? pCurrentSid : NULL;
1875 
1876  return Success;
1877 }
1878 
1879 
1881 {
1882  DWORD iIndex;
1883 
1884  if (!g_RecordPtrs)
1885  return;
1886 
1887  for (iIndex = 0; iIndex < g_TotalRecords; iIndex++)
1888  {
1889  if (g_RecordPtrs[iIndex])
1890  HeapFree(GetProcessHeap(), 0, g_RecordPtrs[iIndex]);
1891  }
1892  HeapFree(GetProcessHeap(), 0, g_RecordPtrs);
1893  g_RecordPtrs = NULL;
1894  g_TotalRecords = 0;
1895 }
1896 
1897 BOOL
1899  IN PEVENTLOGRECORD pevlr)
1900 {
1901  if ((pevlr->EventType == EVENTLOG_SUCCESS && !EventLogFilter->Information ) ||
1902  (pevlr->EventType == EVENTLOG_INFORMATION_TYPE && !EventLogFilter->Information ) ||
1903  (pevlr->EventType == EVENTLOG_WARNING_TYPE && !EventLogFilter->Warning ) ||
1904  (pevlr->EventType == EVENTLOG_ERROR_TYPE && !EventLogFilter->Error ) ||
1905  (pevlr->EventType == EVENTLOG_AUDIT_SUCCESS && !EventLogFilter->AuditSuccess) ||
1906  (pevlr->EventType == EVENTLOG_AUDIT_FAILURE && !EventLogFilter->AuditFailure))
1907  {
1908  return FALSE;
1909  }
1910  return TRUE;
1911 }
1912 
1913 BOOL
1914 FilterByString(IN PCWSTR FilterString, // This is a multi-string
1915  IN PWSTR String)
1916 {
1917  PCWSTR pStr;
1918 
1919  /* The filter string is NULL so it does not filter anything */
1920  if (!FilterString)
1921  return TRUE;
1922 
1923  /*
1924  * If the filter string filters for an empty string AND the source string
1925  * is an empty string, we have a match (particular case of the last one).
1926  */
1927  if (!*FilterString && !*String)
1928  return TRUE;
1929 
1930  // if (*FilterString || *String)
1931 
1932  /*
1933  * If the filter string is empty BUT the source string is not empty,
1934  * OR vice-versa, we cannot have a match.
1935  */
1936  if ( (!*FilterString && *String) || (*FilterString && !*String) )
1937  return FALSE;
1938 
1939  /*
1940  * If the filter string filters for at least a non-empty string,
1941  * browse it and search for a string that matches the source string.
1942  */
1943  // else if (*FilterString && *String)
1944  {
1945  pStr = FilterString;
1946  while (*pStr)
1947  {
1948  if (wcsicmp(pStr, String) == 0)
1949  {
1950  /* We have a match, break the loop */
1951  break;
1952  }
1953 
1954  pStr += (wcslen(pStr) + 1);
1955  }
1956  if (!*pStr) // && *String
1957  {
1958  /* We do not have a match */
1959  return FALSE;
1960  }
1961  }
1962 
1963  /* We have a match */
1964  return TRUE;
1965 }
1966 
1967 /*
1968  * The events enumerator thread.
1969  */
1970 static DWORD WINAPI
1972 {
1973  PEVENTLOGFILTER EventLogFilter = (PEVENTLOGFILTER)lpParameter;
1974  PEVENTLOG EventLog;
1975 
1976  ULONG LogIndex;
1977  HANDLE hEventLog;
1978  PEVENTLOGRECORD pEvlr = NULL;
1979  PBYTE pEvlrEnd;
1980  PBYTE pEvlrBuffer;
1981  DWORD dwWanted, dwRead, dwNeeded, dwStatus = ERROR_SUCCESS;
1982  DWORD dwTotalRecords = 0, dwCurrentRecord = 0;
1983  DWORD dwFlags, dwMaxLength;
1984  size_t cchRemaining;
1985  LPWSTR lpszSourceName;
1986  LPWSTR lpszComputerName;
1987  BOOL bResult = TRUE; /* Read succeeded */
1989  PSID pLastSid = NULL;
1990 
1991  UINT uStep = 0, uStepAt = 0, uPos = 0;
1992 
1993  WCHAR szWindowTitle[MAX_PATH];
1994  WCHAR szStatusText[MAX_PATH];
1995  WCHAR szLocalDate[MAX_PATH];
1996  WCHAR szLocalTime[MAX_PATH];
1997  WCHAR szEventID[MAX_PATH];
1998  WCHAR szEventTypeText[MAX_LOADSTRING];
1999  WCHAR szCategoryID[MAX_PATH];
2000  WCHAR szUsername[MAX_PATH];
2001  WCHAR szNoUsername[MAX_PATH];
2002  WCHAR szCategory[MAX_PATH];
2003  WCHAR szNoCategory[MAX_PATH];
2004  PWCHAR lpTitleTemplateEnd;
2005 
2006  SYSTEMTIME time;
2007  LVITEMW lviEventItem;
2008 
2009  /* Save the current event log filter globally */
2010  EventLogFilter_AddRef(EventLogFilter);
2011  ActiveFilter = EventLogFilter;
2012 
2013 
2015  EventLog = EventLogFilter->EventLogs[0];
2016 
2017  // FIXME: Use something else instead of EventLog->LogName !!
2018 
2019  /*
2020  * Use a different formatting, whether the event log filter holds
2021  * only one log, or many logs (the latter case is WIP TODO!)
2022  */
2023  if (EventLogFilter->NumOfEventLogs <= 1)
2024  {
2025  StringCchPrintfExW(szWindowTitle,
2026  ARRAYSIZE(szWindowTitle),
2027  &lpTitleTemplateEnd,
2028  &cchRemaining,
2029  0,
2030  szTitleTemplate, szTitle, EventLog->LogName); /* i = number of characters written */
2031  dwMaxLength = (DWORD)cchRemaining;
2032  if (!EventLog->ComputerName)
2033  GetComputerNameW(lpTitleTemplateEnd, &dwMaxLength);
2034  else
2035  StringCchCopyW(lpTitleTemplateEnd, dwMaxLength, EventLog->ComputerName);
2036 
2037  StringCbPrintfW(szStatusText,
2038  sizeof(szStatusText),
2040  EventLog->LogName,
2041  0,
2042  0);
2043  }
2044  else
2045  {
2046  // TODO: Use a different title & implement filtering for multi-log filters !!
2047  // (EventLogFilter->NumOfEventLogs > 1)
2049  L"Many-logs filtering is not implemented yet!!",
2050  L"Event Log",
2052  }
2053 
2054  /* Set the window title */
2055  SetWindowTextW(hwndMainWindow, szWindowTitle);
2056 
2057  /* Update the status bar */
2058  StatusBar_SetText(hwndStatus, 0, szStatusText);
2059 
2060 
2061  /* Disable list view redraw */
2063 
2064  /* Clear the list view and free the cached records */
2066  FreeRecords();
2067 
2072 
2073  /* Do a loop over the logs enumerated in the filter */
2074  // FIXME: For now we only support 1 event log per filter!
2075  LogIndex = 0;
2076  // for (LogIndex = 0; LogIndex < EventLogFilter->NumOfEventLogs; ++LogIndex)
2077  {
2078 
2079  EventLog = EventLogFilter->EventLogs[LogIndex];
2080 
2081  /* Open the event log */
2082  if (EventLog->Permanent)
2083  hEventLog = OpenEventLogW(EventLog->ComputerName, EventLog->LogName);
2084  else
2085  hEventLog = OpenBackupEventLogW(EventLog->ComputerName, EventLog->LogName); // FileName
2086 
2087  if (hEventLog == NULL)
2088  {
2090  goto Cleanup;
2091  }
2092 
2093  // GetOldestEventLogRecord(hEventLog, &dwThisRecord);
2094 
2095  /* Get the total number of event log records */
2096  GetNumberOfEventLogRecords(hEventLog, &dwTotalRecords);
2097 
2098  if (dwTotalRecords > 0)
2099  {
2102  }
2103  else
2104  {
2107  }
2108 
2109  /* Set up the event records cache */
2110  g_RecordPtrs = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwTotalRecords * sizeof(*g_RecordPtrs));
2111  if (!g_RecordPtrs)
2112  {
2113  // ShowWin32Error(GetLastError());
2114  goto Quit;
2115  }
2116  g_TotalRecords = dwTotalRecords;
2117 
2119  goto Quit;
2120 
2121  LoadStringW(hInst, IDS_NOT_AVAILABLE, szNoUsername, ARRAYSIZE(szNoUsername));
2122  LoadStringW(hInst, IDS_NONE, szNoCategory, ARRAYSIZE(szNoCategory));
2123 
2125  uStepAt = (dwTotalRecords / 100) + 1;
2126 
2127  dwFlags = EVENTLOG_SEQUENTIAL_READ | (Settings.bNewestEventsFirst ? EVENTLOG_FORWARDS_READ : EVENTLOG_BACKWARDS_READ);
2128 
2129  /* 0x7ffff is the maximum buffer size ReadEventLog will accept */
2130  dwWanted = 0x7ffff;
2131  pEvlr = HeapAlloc(hProcessHeap, 0, dwWanted);
2132 
2133  if (!pEvlr)
2134  goto Quit;
2135 
2136  while (dwStatus == ERROR_SUCCESS)
2137  {
2138  bResult = ReadEventLogW(hEventLog, dwFlags, 0, pEvlr, dwWanted, &dwRead, &dwNeeded);
2139  dwStatus = GetLastError();
2140 
2141  if (!bResult && dwStatus == ERROR_INSUFFICIENT_BUFFER)
2142  {
2143  pEvlr = HeapReAlloc(hProcessHeap, 0, pEvlr, dwNeeded);
2144  dwWanted = dwNeeded;
2145 
2146  if (!pEvlr)
2147  break;
2148 
2149  bResult = ReadEventLogW(hEventLog, dwFlags, 0, pEvlr, dwNeeded, &dwRead, &dwNeeded);
2150 
2151  if (!bResult)
2152  break;
2153  }
2154  else if (!bResult)
2155  {
2156  /* Exit on other errors (ERROR_HANDLE_EOF) */
2157  break;
2158  }
2159 
2160  pEvlrBuffer = (LPBYTE)pEvlr;
2161  pEvlrEnd = pEvlrBuffer + dwRead;
2162 
2163  while (pEvlrBuffer < pEvlrEnd)
2164  {
2165  PEVENTLOGRECORD pEvlrTmp = (PEVENTLOGRECORD)pEvlrBuffer;
2166  PWSTR lpszUsername, lpszCategoryName;
2167  g_RecordPtrs[dwCurrentRecord] = NULL;
2168 
2169  // ProgressBar_StepIt(hwndStatusProgress);
2170  uStep++;
2171  if (uStep % uStepAt == 0)
2172  {
2173  ++uPos;
2175  }
2176 
2178  goto Quit;
2179 
2180  /* Filter by event type */
2181  if (!FilterByType(EventLogFilter, pEvlrTmp))
2182  goto SkipEvent;
2183 
2184  /* Get the event source name and filter it */
2185  lpszSourceName = (LPWSTR)(pEvlrBuffer + sizeof(EVENTLOGRECORD));
2186  if (!FilterByString(EventLogFilter->Sources, lpszSourceName))
2187  goto SkipEvent;
2188 
2189  /* Get the computer name and filter it */
2190  lpszComputerName = (LPWSTR)(pEvlrBuffer + sizeof(EVENTLOGRECORD) + (wcslen(lpszSourceName) + 1) * sizeof(WCHAR));
2191  if (!FilterByString(EventLogFilter->ComputerNames, lpszComputerName))
2192  goto SkipEvent;
2193 
2194  /* Compute the event time */
2195  EventTimeToSystemTime(pEvlrTmp->TimeWritten, &time);
2196  GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, szLocalDate, ARRAYSIZE(szLocalDate));
2197  GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &time, NULL, szLocalTime, ARRAYSIZE(szLocalTime));
2198 
2199  /* Get the username that generated the event, and filter it */
2200  lpszUsername = GetEventUserName(pEvlrTmp, &pLastSid, szUsername) ? szUsername : szNoUsername;
2201 
2202  if (!FilterByString(EventLogFilter->Users, lpszUsername))
2203  goto SkipEvent;
2204 
2205  // TODO: Filter by event ID and category
2206  GetEventType(pEvlrTmp->EventType, szEventTypeText);
2207 
2208  lpszCategoryName = GetEventCategory(EventLog->LogName, lpszSourceName, pEvlrTmp, szCategory) ? szCategory : szNoCategory;
2209 
2210  StringCbPrintfW(szEventID, sizeof(szEventID), L"%u", (pEvlrTmp->EventID & 0xFFFF));
2211  StringCbPrintfW(szCategoryID, sizeof(szCategoryID), L"%u", pEvlrTmp->EventCategory);
2212 
2213  g_RecordPtrs[dwCurrentRecord] = HeapAlloc(hProcessHeap, 0, pEvlrTmp->Length);
2214  RtlCopyMemory(g_RecordPtrs[dwCurrentRecord], pEvlrTmp, pEvlrTmp->Length);
2215 
2216  lviEventItem.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
2217  lviEventItem.iItem = 0;
2218  lviEventItem.iSubItem = 0;
2219  lviEventItem.lParam = (LPARAM)g_RecordPtrs[dwCurrentRecord];
2220  lviEventItem.pszText = szEventTypeText;
2221 
2222  switch (pEvlrTmp->EventType)
2223  {
2224  case EVENTLOG_SUCCESS:
2226  lviEventItem.iImage = 0;
2227  break;
2228 
2229  case EVENTLOG_WARNING_TYPE:
2230  lviEventItem.iImage = 1;
2231  break;
2232 
2233  case EVENTLOG_ERROR_TYPE:
2234  lviEventItem.iImage = 2;
2235  break;
2236 
2238  lviEventItem.iImage = 3;
2239  break;
2240 
2242  lviEventItem.iImage = 4;
2243  break;
2244  }
2245 
2246  lviEventItem.iItem = ListView_InsertItem(hwndListView, &lviEventItem);
2247 
2248  ListView_SetItemText(hwndListView, lviEventItem.iItem, 1, szLocalDate);
2249  ListView_SetItemText(hwndListView, lviEventItem.iItem, 2, szLocalTime);
2250  ListView_SetItemText(hwndListView, lviEventItem.iItem, 3, lpszSourceName);
2251  ListView_SetItemText(hwndListView, lviEventItem.iItem, 4, lpszCategoryName);
2252  ListView_SetItemText(hwndListView, lviEventItem.iItem, 5, szEventID);
2253  ListView_SetItemText(hwndListView, lviEventItem.iItem, 6, lpszUsername);
2254  ListView_SetItemText(hwndListView, lviEventItem.iItem, 7, lpszComputerName);
2255 
2256 SkipEvent:
2257  pEvlrBuffer += pEvlrTmp->Length;
2258  dwCurrentRecord++;
2259  }
2260  }
2261 
2262 Quit:
2263 
2264  if (pEvlr)
2265  HeapFree(hProcessHeap, 0, pEvlr);
2266 
2267  /* Close the event log */
2268  CloseEventLog(hEventLog);
2269 
2270  } // end-for (LogIndex)
2271 
2272  /* All events loaded */
2273 
2274 Cleanup:
2275 
2278 
2279  // FIXME: Use something else instead of EventLog->LogName !!
2280 
2281  /*
2282  * Use a different formatting, whether the event log filter holds
2283  * only one log, or many logs (the latter case is WIP TODO!)
2284  */
2285  if (EventLogFilter->NumOfEventLogs <= 1)
2286  {
2287  StringCbPrintfW(szStatusText,
2288  sizeof(szStatusText),
2290  EventLog->LogName,
2291  dwTotalRecords,
2293  }
2294  else
2295  {
2296  // TODO: Use a different title & implement filtering for multi-log filters !!
2297  // (EventLogFilter->NumOfEventLogs > 1)
2298  }
2299 
2300  /* Update the status bar */
2301  StatusBar_SetText(hwndStatus, 0, szStatusText);
2302 
2303  /* Resume list view redraw */
2305 
2306  EventLogFilter_Release(EventLogFilter);
2307 
2310 
2311  return 0;
2312 }
2313 
2314 /*
2315  * The purpose of this thread is to serialize the creation of the events
2316  * enumeration thread, since the Event Log Viewer currently only supports
2317  * one view, one event list, one enumeration.
2318  */
2319 static DWORD WINAPI
2321 {
2322  HANDLE WaitHandles[2];
2323  DWORD WaitResult;
2324 
2325  WaitHandles[0] = hStartStopEnumEvent; // End-of-application event
2326  WaitHandles[1] = hStartEnumEvent; // Command event
2327 
2328  while (TRUE)
2329  {
2330  WaitResult = WaitForMultipleObjects(ARRAYSIZE(WaitHandles),
2331  WaitHandles,
2332  FALSE, // WaitAny
2333  INFINITE);
2334  switch (WaitResult)
2335  {
2336  case WAIT_OBJECT_0 + 0:
2337  {
2338  /* End-of-application event signaled, quit this thread */
2339 
2340  /* Stop the previous enumeration */
2341  if (hEnumEventsThread)
2342  {
2343  if (hStopEnumEvent)
2344  {
2347  // NOTE: The following is done by the enumeration thread just before terminating.
2348  // hStopEnumEvent = NULL;
2349  }
2350 
2353  }
2354 
2355  /* Clear the list view and free the cached records */
2357  FreeRecords();
2358 
2359  /* Reset the active filter */
2360  ActiveFilter = NULL;
2361 
2362  return 0;
2363  }
2364 
2365  case WAIT_OBJECT_0 + 1:
2366  {
2367  /* Restart a new enumeration if needed */
2368  PEVENTLOGFILTER EventLogFilter;
2369 
2370  /* Stop the previous enumeration */
2371  if (hEnumEventsThread)
2372  {
2373  if (hStopEnumEvent)
2374  {
2377  // NOTE: The following is done by the enumeration thread just before terminating.
2378  // hStopEnumEvent = NULL;
2379  }
2380 
2383  }
2384 
2385  /* Clear the list view and free the cached records */
2387  FreeRecords();
2388 
2389  /* Reset the active filter */
2390  ActiveFilter = NULL;
2391 
2392  EventLogFilter = InterlockedExchangePointer((PVOID*)&EnumFilter, NULL);
2393  if (!EventLogFilter)
2394  break;
2395 
2396  // Manual-reset event
2398  if (!hStopEnumEvent)
2399  break;
2400 
2402  0,
2404  (LPVOID)EventLogFilter,
2406  NULL);
2407  if (!hEnumEventsThread)
2408  {
2410  hStopEnumEvent = NULL;
2411  break;
2412  }
2413  // CloseHandle(hEnumEventsThread);
2415 
2416  break;
2417  }
2418 
2419  default:
2420  {
2421  /* Unknown command, must never go there! */
2422  return GetLastError();
2423  }
2424  }
2425  }
2426 
2427  return 0;
2428 }
2429 
2430 VOID
2432 {
2433  /* Signal the enumerator thread we want to enumerate events */
2434  InterlockedExchangePointer((PVOID*)&EnumFilter, EventLogFilter);
2436  return;
2437 }
2438 
2439 
2442 {
2443  TVITEMEXW tvItemEx;
2444  HTREEITEM hti;
2445 
2446  if (phti)
2447  *phti = NULL;
2448 
2449  /* Get index of selected item */
2451  if (hti == NULL)
2452  return NULL; // No filter
2453 
2454  tvItemEx.mask = TVIF_PARAM;
2455  tvItemEx.hItem = hti;
2456 
2457  TreeView_GetItem(hwndTreeView, &tvItemEx);
2458 
2459  if (phti)
2460  *phti = tvItemEx.hItem;
2461 
2462  return (PEVENTLOGFILTER)tvItemEx.lParam;
2463 }
2464 
2465 
2466 VOID
2468 {
2469  WIN32_FIND_DATAW FindData;
2470  HANDLE hFind;
2471  PEVENTLOG EventLog;
2472  PEVENTLOGFILTER EventLogFilter;
2473  SIZE_T cchFileName;
2474  HTREEITEM hItem = NULL;
2475 
2476  /* Check whether the file actually exists */
2477  hFind = FindFirstFileW(lpszFileName, &FindData);
2478  if (hFind == INVALID_HANDLE_VALUE)
2479  {
2481  return;
2482  }
2483  FindClose(hFind);
2484 
2485  /* Allocate a new event log entry */
2486  EventLog = AllocEventLog(NULL, lpszFileName, FALSE);
2487  if (EventLog == NULL)
2488  {
2490  return;
2491  }
2492 
2493  /* Allocate a new event log filter entry for this event log */
2494  EventLogFilter = AllocEventLogFilter(// LogName,
2495  TRUE, TRUE, TRUE, TRUE, TRUE,
2496  NULL, NULL, NULL,
2497  1, &EventLog);
2498  if (EventLogFilter == NULL)
2499  {
2501  EventLog_Free(EventLog);
2502  return;
2503  }
2504 
2505  /* Add the event log and the filter into their lists */
2506  InsertTailList(&EventLogList, &EventLog->ListEntry);
2507  InsertTailList(&EventLogFilterList, &EventLogFilter->ListEntry);
2508 
2509  /* Retrieve and cache the event log file */
2510  cchFileName = wcslen(lpszFileName) + 1;
2511  EventLog->FileName = HeapAlloc(GetProcessHeap(), 0, cchFileName * sizeof(WCHAR));
2512  if (EventLog->FileName)
2513  StringCchCopyW(EventLog->FileName, cchFileName, lpszFileName);
2514 
2516  (LPWSTR)lpszFileName,
2517  2, 3, (LPARAM)EventLogFilter);
2518 
2519  /* Select the event log */
2520  if (hItem)
2521  {
2522  // TreeView_Expand(hwndTreeView, htiUserLogs, TVE_EXPAND);
2525  }
2528 }
2529 
2530 VOID
2532 {
2533  WCHAR szFileName[MAX_PATH];
2534 
2535  ZeroMemory(szFileName, sizeof(szFileName));
2536 
2537  sfn.lpstrFile = szFileName;
2538  sfn.nMaxFile = ARRAYSIZE(szFileName);
2539 
2540  if (!GetOpenFileNameW(&sfn))
2541  return;
2542  sfn.lpstrFile[sfn.nMaxFile-1] = UNICODE_NULL;
2543 
2545 }
2546 
2547 VOID
2549 {
2550  PEVENTLOG EventLog;
2551  HANDLE hEventLog;
2552  WCHAR szFileName[MAX_PATH];
2553 
2554  /* Bail out if there is no available filter */
2555  if (!EventLogFilter)
2556  return;
2557 
2558  ZeroMemory(szFileName, sizeof(szFileName));
2559 
2560  sfn.lpstrFile = szFileName;
2561  sfn.nMaxFile = ARRAYSIZE(szFileName);
2562 
2563  if (!GetSaveFileNameW(&sfn))
2564  return;
2565 
2566  EventLogFilter_AddRef(EventLogFilter);
2567 
2568  EventLog = EventLogFilter->EventLogs[0];
2569  hEventLog = OpenEventLogW(EventLog->ComputerName, EventLog->LogName);
2570 
2571  EventLogFilter_Release(EventLogFilter);
2572 
2573  if (!hEventLog)
2574  {
2576  return;
2577  }
2578 
2579  if (!BackupEventLogW(hEventLog, szFileName))
2581 
2582  CloseEventLog(hEventLog);
2583 }
2584 
2585 VOID
2587 {
2588  /* Bail out if there is no available filter */
2589  if (!EventLogFilter)
2590  return;
2591 
2592  if (InterlockedCompareExchangePointer((PVOID*)&ActiveFilter, NULL, NULL) == EventLogFilter)
2593  {
2594  /* Signal the enumerator thread we want to stop enumerating events */
2595  // EnumEvents(NULL);
2596  InterlockedExchangePointer((PVOID*)&EnumFilter, NULL);
2598  }
2599 
2600  /*
2601  * The deletion of the item automatically triggers a TVN_SELCHANGED
2602  * notification, that will reset the ActiveFilter (in case the item
2603  * selected is a filter). Otherwise we reset it there.
2604  */
2606 
2607  /* Remove the filter from the list */
2608  RemoveEntryList(&EventLogFilter->ListEntry);
2609  EventLogFilter_Release(EventLogFilter);
2610 
2611  // /* Select the default event log */
2612  // // TreeView_Expand(hwndTreeView, htiUserLogs, TVE_EXPAND);
2613  // TreeView_SelectItem(hwndTreeView, hItem);
2614  // TreeView_EnsureVisible(hwndTreeView, hItem);
2617 }
2618 
2619 
2620 BOOL
2622 {
2623  BOOL Success;
2624  PEVENTLOG EventLog;
2625  HANDLE hEventLog;
2626  WCHAR szFileName[MAX_PATH];
2627  WCHAR szMessage[MAX_LOADSTRING];
2628 
2629  /* Bail out if there is no available filter */
2630  if (!EventLogFilter)
2631  return FALSE;
2632 
2633  ZeroMemory(szFileName, sizeof(szFileName));
2634  ZeroMemory(szMessage, sizeof(szMessage));
2635 
2636  LoadStringW(hInst, IDS_CLEAREVENTS_MSG, szMessage, ARRAYSIZE(szMessage));
2637 
2638  sfn.lpstrFile = szFileName;
2639  sfn.nMaxFile = ARRAYSIZE(szFileName);
2640 
2642  {
2643  case IDCANCEL:
2644  return FALSE;
2645 
2646  case IDNO:
2647  sfn.lpstrFile = NULL;
2648  break;
2649 
2650  case IDYES:
2651  if (!GetSaveFileNameW(&sfn))
2652  return FALSE;
2653  break;
2654  }
2655 
2656  EventLogFilter_AddRef(EventLogFilter);
2657 
2658  EventLog = EventLogFilter->EventLogs[0];
2659  hEventLog = OpenEventLogW(EventLog->ComputerName, EventLog->LogName);
2660 
2661  EventLogFilter_Release(EventLogFilter);
2662 
2663  if (!hEventLog)
2664  {
2666  return FALSE;
2667  }
2668 
2669  Success = ClearEventLogW(hEventLog, sfn.lpstrFile);
2670  if (!Success)
2672 
2673  CloseEventLog(hEventLog);
2674  return Success;
2675 }
2676 
2677 
2678 VOID
2679 Refresh(IN PEVENTLOGFILTER EventLogFilter)
2680 {
2681  /* Bail out if there is no available filter */
2682  if (!EventLogFilter)
2683  return;
2684 
2685  /* Reenumerate the events through the filter */
2686  EnumEvents(EventLogFilter);
2687 }
2688 
2689 
2690 ATOM
2692 {
2693  WNDCLASSEXW wcex;
2694 
2695  wcex.cbSize = sizeof(wcex);
2696  wcex.style = 0;
2697  wcex.lpfnWndProc = WndProc;
2698  wcex.cbClsExtra = 0;
2699  wcex.cbWndExtra = 0;
2700  wcex.hInstance = hInstance;
2701  wcex.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_EVENTVWR));
2703  wcex.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); // COLOR_WINDOW + 1
2706  wcex.hIconSm = (HICON)LoadImageW(hInstance,
2708  IMAGE_ICON,
2709  16,
2710  16,
2711  LR_SHARED);
2712 
2713  return RegisterClassExW(&wcex);
2714 }
2715 
2716 
2717 BOOL
2719  OUT PWCHAR lpModuleName, // TODO: Add IN DWORD BufLen
2720  OUT PDWORD pdwMessageID)
2721 {
2722  BOOL Success = FALSE;
2723  LONG Result;
2724  HKEY hLogKey;
2725  WCHAR *KeyPath;
2726  SIZE_T cbKeyPath;
2727  DWORD dwType, cbData;
2728  DWORD dwMessageID = 0;
2730 
2731  /* Use a default value for the message ID */
2732  *pdwMessageID = 0;
2733 
2734  cbKeyPath = (wcslen(EVENTLOG_BASE_KEY) + wcslen(lpLogName) + 1) * sizeof(WCHAR);
2735  KeyPath = HeapAlloc(GetProcessHeap(), 0, cbKeyPath);
2736  if (!KeyPath)
2737  return FALSE;
2738 
2739  StringCbCopyW(KeyPath, cbKeyPath, EVENTLOG_BASE_KEY);
2740  StringCbCatW(KeyPath, cbKeyPath, lpLogName);
2741 
2742  Result = RegOpenKeyExW(hkMachine, KeyPath, 0, KEY_QUERY_VALUE, &hLogKey);
2743  HeapFree(GetProcessHeap(), 0, KeyPath);
2744  if (Result != ERROR_SUCCESS)
2745  return FALSE;
2746 
2747  cbData = sizeof(szModuleName);
2748  Result = RegQueryValueExW(hLogKey,
2749  L"DisplayNameFile",
2750  NULL,
2751  &dwType,
2752  (LPBYTE)szModuleName,
2753  &cbData);
2754  if ((Result != ERROR_SUCCESS) || (dwType != REG_EXPAND_SZ && dwType != REG_SZ))
2755  {
2756  szModuleName[0] = UNICODE_NULL;
2757  }
2758  else
2759  {
2760  /* NULL-terminate the string and expand it */
2761  szModuleName[cbData / sizeof(WCHAR) - 1] = UNICODE_NULL;
2762  GetExpandedFilePathName(lpComputerName, szModuleName, lpModuleName, ARRAYSIZE(szModuleName));
2763  Success = TRUE;
2764  }
2765 
2766  /*
2767  * If we have a 'DisplayNameFile', query for 'DisplayNameID';
2768  * otherwise it's not really useful. 'DisplayNameID' is optional.
2769  */
2770  if (Success)
2771  {
2772  cbData = sizeof(dwMessageID);
2773  Result = RegQueryValueExW(hLogKey,
2774  L"DisplayNameID",
2775  NULL,
2776  &dwType,
2777  (LPBYTE)&dwMessageID,
2778  &cbData);
2779  if ((Result != ERROR_SUCCESS) || (dwType != REG_DWORD))
2780  dwMessageID = 0;
2781 
2782  *pdwMessageID = dwMessageID;
2783  }
2784 
2785  RegCloseKey(hLogKey);
2786 
2787  return Success;
2788 }
2789 
2790 
2791 VOID
2793 {
2794  LONG Result;
2795  HKEY hEventLogKey, hLogKey;
2796  DWORD dwNumLogs = 0;
2797  DWORD dwIndex, dwMaxKeyLength;
2798  DWORD dwType;
2799  PEVENTLOG EventLog;
2800  PEVENTLOGFILTER EventLogFilter;
2801  LPWSTR LogName = NULL;
2803  DWORD lpcName;
2804  DWORD dwMessageID;
2806  HTREEITEM hRootNode = NULL, hItem = NULL, hItemDefault = NULL;
2807 
2809  {
2810  /* We are connected to some other computer, close the old connection */
2812  hkMachine = NULL;
2813  }
2814  if (!lpComputerName || !*lpComputerName)
2815  {
2816  /* Use the local computer registry */
2818  }
2819  else
2820  {
2821  /* Connect to the remote computer registry */
2822  Result = RegConnectRegistry(lpComputerName, HKEY_LOCAL_MACHINE, &hkMachine);
2823  if (Result != ERROR_SUCCESS)
2824  {
2825  /* Connection failed, display a message and bail out */
2826  hkMachine = NULL;
2828  return;
2829  }
2830  }
2831 
2832  /* Open the EventLog key */
2833  Result = RegOpenKeyExW(hkMachine, EVENTLOG_BASE_KEY, 0, KEY_READ, &hEventLogKey);
2834  if (Result != ERROR_SUCCESS)
2835  {
2836  return;
2837  }
2838 
2839  /* Retrieve the number of event logs enumerated as registry keys */
2840  Result = RegQueryInfoKeyW(hEventLogKey, NULL, NULL, NULL, &dwNumLogs, &dwMaxKeyLength,
2841  NULL, NULL, NULL, NULL, NULL, NULL);
2842  if (Result != ERROR_SUCCESS)
2843  {
2844  goto Quit;
2845  }
2846  if (!dwNumLogs)
2847  goto Quit;
2848 
2849  /* Take the NULL terminator into account */
2850  ++dwMaxKeyLength;
2851 
2852  /* Allocate the temporary buffer */
2853  LogName = HeapAlloc(GetProcessHeap(), 0, dwMaxKeyLength * sizeof(WCHAR));
2854  if (!LogName)
2855  goto Quit;
2856 
2857  /* Enumerate and retrieve each event log name */
2858  for (dwIndex = 0; dwIndex < dwNumLogs; dwIndex++)
2859  {
2860  lpcName = dwMaxKeyLength;
2861  Result = RegEnumKeyExW(hEventLogKey, dwIndex, LogName, &lpcName, NULL, NULL, NULL, NULL);
2862  if (Result != ERROR_SUCCESS)
2863  continue;
2864 
2865  /* Take the NULL terminator into account */
2866  ++lpcName;
2867 
2868  /* Allocate a new event log entry */
2869  EventLog = AllocEventLog(lpComputerName, LogName, TRUE);
2870  if (EventLog == NULL)
2871  continue;
2872 
2873  /* Allocate a new event log filter entry for this event log */
2874  EventLogFilter = AllocEventLogFilter(// LogName,
2875  TRUE, TRUE, TRUE, TRUE, TRUE,
2876  NULL, NULL, NULL,
2877  1, &EventLog);
2878  if (EventLogFilter == NULL)
2879  {
2880  EventLog_Free(EventLog);
2881  continue;
2882  }
2883 
2884  /* Add the event log and the filter into their lists */
2885  InsertTailList(&EventLogList, &EventLog->ListEntry);
2886  InsertTailList(&EventLogFilterList, &EventLogFilter->ListEntry);
2887 
2888  EventLog->FileName = NULL;
2889 
2890  /* Retrieve and cache the event log file */
2891  Result = RegOpenKeyExW(hEventLogKey,
2892  LogName,
2893  0,
2895  &hLogKey);
2896  if (Result == ERROR_SUCCESS)
2897  {
2898  lpcName = 0;
2899  Result = RegQueryValueExW(hLogKey,
2900  L"File",
2901  NULL,
2902  &dwType,
2903  NULL,
2904  &lpcName);
2905  if ((Result != ERROR_SUCCESS) || (dwType != REG_EXPAND_SZ && dwType != REG_SZ))
2906  {
2907  // Windows' EventLog uses some kind of default value, we do not.
2908  EventLog->FileName = NULL;
2909  }
2910  else
2911  {
2912  lpcName = ROUND_DOWN(lpcName, sizeof(WCHAR));
2913  EventLog->FileName = HeapAlloc(GetProcessHeap(), 0, lpcName);
2914  if (EventLog->FileName)
2915  {
2916  Result = RegQueryValueExW(hLogKey,
2917  L"File",
2918  NULL,
2919  &dwType,
2920  (LPBYTE)EventLog->FileName,
2921  &lpcName);
2922  if (Result != ERROR_SUCCESS)
2923  {
2924  HeapFree(GetProcessHeap(), 0, EventLog->FileName);
2925  EventLog->FileName = NULL;
2926  }
2927  else
2928  {
2929  EventLog->FileName[lpcName / sizeof(WCHAR) - 1] = UNICODE_NULL;
2930  }
2931  }
2932  }
2933 
2934  RegCloseKey(hLogKey);
2935  }
2936 
2937  /* Get the display name for the event log */
2938  lpDisplayName = NULL;
2939 
2940  ZeroMemory(szModuleName, sizeof(szModuleName));
2941  if (GetDisplayNameFileAndID(LogName, szModuleName, &dwMessageID))
2942  {
2943  /* Retrieve the message string without appending extra newlines */
2944  lpDisplayName =
2945  GetMessageStringFromDll(szModuleName,
2948  dwMessageID,
2949  0,
2950  NULL);
2951  }
2952 
2953  /*
2954  * Select the correct tree root node, whether the log is a System
2955  * or an Application log. Default to Application log otherwise.
2956  */
2957  hRootNode = htiAppLogs;
2958  for (lpcName = 0; lpcName < ARRAYSIZE(SystemLogs); ++lpcName)
2959  {
2960  /* Check whether the log name is part of the system logs */
2961  if (wcsicmp(LogName, SystemLogs[lpcName]) == 0)
2962  {
2963  hRootNode = htiSystemLogs;
2964  break;
2965  }
2966  }
2967 
2968  hItem = TreeViewAddItem(hwndTreeView, hRootNode,
2969  (lpDisplayName ? lpDisplayName : LogName),
2970  2, 3, (LPARAM)EventLogFilter);
2971 
2972  /* Try to get the default event log: "Application" */
2973  if ((hItemDefault == NULL) && (wcsicmp(LogName, SystemLogs[0]) == 0))
2974  {
2975  hItemDefault = hItem;
2976  }
2977 
2978  /* Free the buffer allocated by FormatMessage */
2979  if (lpDisplayName)
2980  LocalFree(lpDisplayName);
2981  }
2982 
2983  HeapFree(GetProcessHeap(), 0, LogName);
2984 
2985 Quit:
2986  RegCloseKey(hEventLogKey);
2987 
2988  /* Select the default event log */
2989  if (hItemDefault)
2990  {
2991  // TreeView_Expand(hwndTreeView, hRootNode, TVE_EXPAND);
2992  TreeView_SelectItem(hwndTreeView, hItemDefault);
2993  TreeView_EnsureVisible(hwndTreeView, hItemDefault);
2994  }
2997 
2998  return;
2999 }
3000 
3001 VOID
3003 {
3005  PEVENTLOG EventLog;
3006 
3007  while (!IsListEmpty(&EventLogList))
3008  {
3009  Entry = RemoveHeadList(&EventLogList);
3010  EventLog = (PEVENTLOG)CONTAINING_RECORD(Entry, EVENTLOG, ListEntry);
3011  EventLog_Free(EventLog);
3012  }
3013 
3014  return;
3015 }
3016 
3017 VOID
3019 {
3021  PEVENTLOGFILTER EventLogFilter;
3022 
3023  while (!IsListEmpty(&EventLogFilterList))
3024  {
3025  Entry = RemoveHeadList(&EventLogFilterList);
3026  EventLogFilter = (PEVENTLOGFILTER)CONTAINING_RECORD(Entry, EVENTLOGFILTER, ListEntry);
3027  EventLogFilter_Free(EventLogFilter);
3028  }
3029 
3030  ActiveFilter = NULL;
3031 
3032  return;
3033 }
3034 
3035 BOOL
3037 {
3038  RECT rcClient, rs;
3039  LONG StatusHeight;
3040  HIMAGELIST hSmall;
3041  LVCOLUMNW lvc = {0};
3042  WCHAR szTemp[256];
3043 
3044  /* Create the main window */
3045  rs = Settings.wpPos.rcNormalPosition;
3047  szTitle,
3049  rs.left, rs.top,
3050  (rs.right != CW_USEDEFAULT && rs.left != CW_USEDEFAULT) ? rs.right - rs.left : CW_USEDEFAULT,
3051  (rs.bottom != CW_USEDEFAULT && rs.top != CW_USEDEFAULT) ? rs.bottom - rs.top : CW_USEDEFAULT,
3052  NULL,
3053  NULL,
3054  hInstance,
3055  NULL);
3056  if (!hwndMainWindow)
3057  return FALSE;
3058 
3059  /* Create the status bar */
3060  hwndStatus = CreateWindowExW(0, // no extended styles
3061  STATUSCLASSNAMEW, // status bar
3062  L"", // no text
3063  WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, // styles
3064  0, 0, 0, 0, // x, y, cx, cy
3065  hwndMainWindow, // parent window
3066  (HMENU)100, // window ID
3067  hInstance, // instance
3068  NULL); // window data
3069 
3070  GetClientRect(hwndMainWindow, &rcClient);
3071  GetWindowRect(hwndStatus, &rs);
3072  StatusHeight = rs.bottom - rs.top;
3073 
3074  /* Create a progress bar in the status bar (hidden by default) */
3076  hwndStatusProgress = CreateWindowExW(0, // no extended styles
3077  PROGRESS_CLASSW, // status bar
3078  NULL, // no text
3079  WS_CHILD | PBS_SMOOTH, // styles
3080  rs.left, rs.top, // x, y
3081  rs.right - rs.left, rs.bottom - rs.top, // cx, cy
3082  hwndStatus, // parent window
3083  NULL, // window ID
3084  hInstance, // instance
3085  NULL); // window data
3086  /* Remove its static edge */
3090 
3091  /* Initialize the splitter default positions */
3092  nVSplitPos = Settings.nVSplitPos;
3093  nHSplitPos = Settings.nHSplitPos;
3094 
3095  /* Create the TreeView */
3097  WC_TREEVIEWW,
3098  NULL,
3099  // WS_CHILD | WS_VISIBLE | TVS_HASLINES | TVS_SHOWSELALWAYS,
3101  0, 0,
3102  nVSplitPos - SPLIT_WIDTH/2,
3103  (rcClient.bottom - rcClient.top) - StatusHeight,
3105  NULL,
3106  hInstance,
3107  NULL);
3108 
3109  /* Create the ImageList */
3112  ILC_COLOR32 | ILC_MASK, // ILC_COLOR24
3113  1, 1);
3114 
3115  /* Add event type icons to the ImageList: closed/opened folder, event log (normal/viewed) */
3120 
3121  /* Assign the ImageList to the Tree View */
3123 
3124  /* Add the event logs nodes */
3125  // "System Logs"
3126  LoadStringW(hInstance, IDS_EVENTLOG_SYSTEM, szTemp, ARRAYSIZE(szTemp));
3127  htiSystemLogs = TreeViewAddItem(hwndTreeView, NULL, szTemp, 0, 1, (LPARAM)NULL);
3128  // "Application Logs"
3129  LoadStringW(hInstance, IDS_EVENTLOG_APP, szTemp, ARRAYSIZE(szTemp));
3130  htiAppLogs = TreeViewAddItem(hwndTreeView, NULL, szTemp, 0, 1, (LPARAM)NULL);
3131  // "User Logs"
3132  LoadStringW(hInstance, IDS_EVENTLOG_USER, szTemp, ARRAYSIZE(szTemp));
3133  htiUserLogs = TreeViewAddItem(hwndTreeView, NULL, szTemp, 0, 1, (LPARAM)NULL);
3134 
3135  /* Create the Event details pane (optional) */
3137  if (hwndEventDetails)
3138  {
3142  nVSplitPos + SPLIT_WIDTH/2,
3143  nHSplitPos + SPLIT_WIDTH/2,
3144  (rcClient.right - rcClient.left) - nVSplitPos - SPLIT_WIDTH/2,
3145  (rcClient.bottom - rcClient.top) - nHSplitPos - SPLIT_WIDTH/2 - StatusHeight,
3146  SWP_NOZORDER | SWP_NOACTIVATE | (Settings.bShowDetailsPane ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
3147  }
3148 
3149  /* Create the ListView */
3151  WC_LISTVIEWW,
3152  NULL,
3154  nVSplitPos + SPLIT_WIDTH/2,
3155  0,
3156  (rcClient.right - rcClient.left) - nVSplitPos - SPLIT_WIDTH/2,
3157  hwndEventDetails && Settings.bShowDetailsPane
3158  ? nHSplitPos - SPLIT_WIDTH/2
3159  : (rcClient.bottom - rcClient.top) - StatusHeight,
3161  NULL,
3162  hInstance,
3163  NULL);
3164 
3165  /* Add the extended ListView styles */
3167 
3168  /* Create the ImageList */
3171  ILC_COLOR32 | ILC_MASK, // ILC_COLOR24
3172  1, 1);
3173 
3174  /* Add event type icons to the ImageList */
3180 
3181  /* Assign the ImageList to the List View */
3183 
3184  /* Now set up the listview with its columns */
3185  lvc.mask = LVCF_TEXT | LVCF_WIDTH;
3186  lvc.cx = 90;
3187  LoadStringW(hInstance,
3189  szTemp,
3190  ARRAYSIZE(szTemp));
3191  lvc.pszText = szTemp;
3193 
3194  lvc.cx = 70;
3195  LoadStringW(hInstance,
3197  szTemp,
3198  ARRAYSIZE(szTemp));
3199  lvc.pszText = szTemp;
3201 
3202  lvc.cx = 70;
3203  LoadStringW(hInstance,
3205  szTemp,
3206  ARRAYSIZE(szTemp));
3207  lvc.pszText = szTemp;
3209 
3210  lvc.cx = 150;
3211  LoadStringW(hInstance,
3213  szTemp,
3214  ARRAYSIZE(szTemp));
3215  lvc.pszText = szTemp;
3217 
3218  lvc.cx = 100;
3219  LoadStringW(hInstance,
3221  szTemp,
3222  ARRAYSIZE(szTemp));
3223  lvc.pszText = szTemp;
3225 
3226  lvc.cx = 60;
3227  LoadStringW(hInstance,
3229  szTemp,
3230  ARRAYSIZE(szTemp));
3231  lvc.pszText = szTemp;
3233 
3234  lvc.cx = 120;
3235  LoadStringW(hInstance,
3237  szTemp,
3238  ARRAYSIZE(szTemp));
3239  lvc.pszText = szTemp;
3241 
3242  lvc.cx = 100;
3243  LoadStringW(hInstance,
3245  szTemp,
3246  ARRAYSIZE(szTemp));
3247  lvc.pszText = szTemp;
3249 
3250  /* Initialize the save Dialog */
3251  ZeroMemory(&sfn, sizeof(sfn));
3253 
3255 
3256  sfn.lStructSize = sizeof(sfn);
3257  sfn.hwndOwner = hwndMainWindow;
3258  sfn.hInstance = hInstance;
3259  sfn.lpstrFilter = szSaveFilter;
3260  sfn.lpstrInitialDir = NULL;
3262  sfn.lpstrDefExt = NULL;
3263 
3264  ShowWindow(hwndMainWindow, Settings.wpPos.showCmd);
3266 
3267  return TRUE;
3268 }
3269 
3271 {
3272  RECT rs;
3273  LONG StatusHeight;
3274  LONG_PTR dwExStyle;
3275  HDWP hdwp;
3276 
3277  /* Resize the status bar -- now done in WM_SIZE */
3278  // SendMessageW(hwndStatus, WM_SIZE, 0, 0);
3279  GetWindowRect(hwndStatus, &rs);
3280  StatusHeight = rs.bottom - rs.top;
3281 
3282  /*
3283  * Move the progress bar -- Take into account for extra size due to the static edge
3284  * (AdjustWindowRectEx() does not seem to work for the progress bar).
3285  */
3290  rs.left, rs.top, rs.right - rs.left, rs.bottom - rs.top,
3293 
3294  /*
3295  * TODO: Adjust the splitter positions:
3296  * - Vertical splitter (1) : fixed position from the left window side.
3297  * - Horizontal splitter (2): fixed position from the bottom window side.
3298  */
3299  nVSplitPos = min(max(nVSplitPos, SPLIT_WIDTH/2), cx - SPLIT_WIDTH/2); // OK
3300  nHSplitPos = min(max(nHSplitPos, SPLIT_WIDTH/2), cy - SPLIT_WIDTH/2 - StatusHeight); // FIXME!
3301 
3302  hdwp = BeginDeferWindowPos(3);
3303 
3304  if (hdwp)
3305  hdwp = DeferWindowPos(hdwp,
3306  hwndTreeView,
3307  HWND_TOP,
3308  0, 0,
3309  nVSplitPos - SPLIT_WIDTH/2,
3310  cy - StatusHeight,
3312 
3313  if (hdwp)
3314  hdwp = DeferWindowPos(hdwp,
3315  hwndListView,
3316  HWND_TOP,
3317  nVSplitPos + SPLIT_WIDTH/2, 0,
3318  cx - nVSplitPos - SPLIT_WIDTH/2,
3319  hwndEventDetails && Settings.bShowDetailsPane
3320  ? nHSplitPos - SPLIT_WIDTH/2
3321  : cy - StatusHeight,
3323 
3324  if (hwndEventDetails && Settings.bShowDetailsPane && hdwp)
3325  hdwp = DeferWindowPos(hdwp,
3327  HWND_TOP,
3328  nVSplitPos + SPLIT_WIDTH/2,
3329  nHSplitPos + SPLIT_WIDTH/2,
3330  cx - nVSplitPos - SPLIT_WIDTH/2,
3331  cy - nHSplitPos - SPLIT_WIDTH/2 - StatusHeight,
3333 
3334  if (hdwp)
3335  EndDeferWindowPos(hdwp);
3336 }
3337 
3338 
3341 {
3342  RECT rect;
3343 
3344  switch (uMsg)
3345  {
3346  case WM_CREATE:
3347  hMainMenu = GetMenu(hWnd);
3348  break;
3349 
3350  case WM_DESTROY:
3351  {
3352  GetWindowPlacement(hwndMainWindow, &Settings.wpPos);
3353  PostQuitMessage(0);
3354  break;
3355  }
3356 
3357  case WM_NOTIFY:
3358  {
3359  LPNMHDR hdr = (LPNMHDR)lParam;
3360 
3361  if (hdr->hwndFrom == hwndListView)
3362  {
3363  switch (hdr->code)
3364  {
3365  case LVN_ITEMCHANGED:
3366  {
3367  LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
3368 
3369  if ( (pnmv->uChanged & LVIF_STATE) && /* The state has changed */
3370  (pnmv->uNewState & LVIS_SELECTED) /* The item has been (de)selected */ )
3371  {
3372  if (hwndEventDetails)
3374  }
3375  break;
3376  }
3377 
3378  case NM_DBLCLK:
3379  case NM_RETURN:
3381  break;
3382  }
3383  }
3384  else if (hdr->hwndFrom == hwndTreeView)
3385  {
3386  switch (hdr->code)
3387  {
3388  case TVN_BEGINLABELEDIT:
3389  {
3390  HTREEITEM hItem = ((LPNMTVDISPINFO)lParam)->item.hItem;
3391 
3392  /* Disable label editing for root nodes */
3393  return ((hItem == htiSystemLogs) ||
3394  (hItem == htiAppLogs) ||
3395  (hItem == htiUserLogs));
3396  }
3397 
3398  case TVN_ENDLABELEDIT:
3399  {
3400  TVITEMW item = ((LPNMTVDISPINFO)lParam)->item;
3401  HTREEITEM hItem = item.hItem;
3402 
3403  /* Disable label editing for root nodes */
3404  if ((hItem == htiSystemLogs) ||
3405  (hItem == htiAppLogs) ||
3406  (hItem == htiUserLogs))
3407  {
3408  return FALSE;
3409  }
3410 
3411  if (item.pszText)
3412  {
3413  LPWSTR pszText = item.pszText;
3414 
3415  /* Trim leading whitespace */
3416  while (*pszText && iswspace(*pszText))
3417  ++pszText;
3418 
3419  if (!*pszText)
3420  return FALSE;
3421 
3422  return TRUE;
3423  }
3424  else
3425  {
3426  return FALSE;
3427  }
3428  }
3429 
3430  case TVN_SELCHANGED:
3431  {
3432  PEVENTLOGFILTER EventLogFilter =
3433  (PEVENTLOGFILTER)((LPNMTREEVIEW)lParam)->itemNew.lParam;
3434 
3435  // FIXME: It might be nice to reference here the filter,
3436  // so that we don't have to reference/dereference it many times
3437  // in the other functions???
3438 
3439  // FIXME: This is a hack!!
3440  if (hwndEventDetails && EventLogFilter)
3441  {
3442  SendMessageW(hwndEventDetails, EVT_SETFILTER, 0, (LPARAM)EventLogFilter);
3443  }
3444 
3445  if (EventLogFilter)
3446  {
3447  /*
3448  * If we have selected a filter, enable the menu commands;
3449  * they will possibly be updated after events enumeration.
3450  */
3456  }
3457  else
3458  {
3464  }
3465 
3466  /*
3467  * The enumeration thread that is triggered by EnumEvents
3468  * will set a new value for the 'ActiveFilter'.
3469  */
3470  if (EventLogFilter)
3471  EnumEvents(EventLogFilter);
3472 
3473  break;
3474  }
3475  }
3476  }
3477  break;
3478  }
3479 
3480  case WM_COMMAND:
3481  {
3482  /* Parse the menu selections */
3483  switch (LOWORD(wParam))
3484  {
3485  case IDM_OPEN_EVENTLOG:
3486  OpenUserEventLog();
3487  break;
3488 
3489  case IDM_SAVE_EVENTLOG:
3491  break;
3492 
3493  case IDM_CLOSE_EVENTLOG:
3494  {
3495  HTREEITEM hti;
3496  PEVENTLOGFILTER EventLogFilter = GetSelectedFilter(&hti);
3497  CloseUserEventLog(EventLogFilter, hti);
3498  break;
3499  }
3500 
3501  case IDM_CLEAR_EVENTS:
3502  {
3503  PEVENTLOGFILTER EventLogFilter = GetSelectedFilter(NULL);
3504  if (EventLogFilter && ClearEvents(EventLogFilter))
3505  Refresh(EventLogFilter);
3506  break;
3507  }
3508 
3509  case IDM_RENAME_EVENTLOG:
3510  if (GetFocus() == hwndTreeView)
3512  break;
3513 
3514  case IDM_EVENTLOG_SETTINGS:
3515  {
3516  PEVENTLOGFILTER EventLogFilter = GetSelectedFilter(NULL);
3517  // TODO: Check the returned value?
3518  if (EventLogFilter)
3519  EventLogProperties(hInst, hWnd, EventLogFilter);
3520  break;
3521  }
3522 
3523  case IDM_LIST_NEWEST:
3524  {
3526  if (!Settings.bNewestEventsFirst)
3527  {
3528  Settings.bNewestEventsFirst = TRUE;
3530  }
3531  break;
3532  }
3533 
3534  case IDM_LIST_OLDEST:
3535  {
3537  if (Settings.bNewestEventsFirst)
3538  {
3539  Settings.bNewestEventsFirst = FALSE;
3541  }
3542  break;
3543  }
3544 
3545  case IDM_EVENT_DETAILS:
3546  {
3547  // LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE)lParam;
3548  PEVENTLOGFILTER EventLogFilter = GetSelectedFilter(NULL);
3549  if (/*lpnmitem->iItem != -1 &&*/ EventLogFilter)
3550  {
3551  EventLogFilter_AddRef(EventLogFilter);
3554  hWnd,
3555  EventDetails,
3556  (LPARAM)EventLogFilter);
3557  EventLogFilter_Release(EventLogFilter);
3558  }
3559  break;
3560  }
3561 
3562  case IDM_REFRESH:
3564  break;
3565 
3567  {
3568  Settings.bShowDetailsPane = !Settings.bShowDetailsPane;
3570  MF_BYCOMMAND | (Settings.bShowDetailsPane ? MF_CHECKED : MF_UNCHECKED));
3571 
3572  GetClientRect(hWnd, &rect);
3573  if (Settings.bShowDetailsPane)
3574  {
3575  ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
3577  }
3578  else
3579  {
3581  ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
3582  }
3583 
3584  break;
3585  }
3586 
3587  case IDM_LIST_GRID_LINES:
3588  {
3589  Settings.bShowGrid = !Settings.bShowGrid;
3591  MF_BYCOMMAND | (Settings.bShowGrid ? MF_CHECKED : MF_UNCHECKED));
3592 
3594  break;
3595  }
3596 
3597  case IDM_SAVE_SETTINGS:
3598  {
3599  Settings.bSaveSettings = !Settings.bSaveSettings;
3601  MF_BYCOMMAND | (Settings.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
3602  break;
3603  }
3604 
3605  case IDM_ABOUT:
3606  {
3607  HICON hIcon;
3608  WCHAR szCopyright[MAX_LOADSTRING];
3609 
3611  LoadStringW(hInst, IDS_COPYRIGHT, szCopyright, ARRAYSIZE(szCopyright));
3612  ShellAboutW(hWnd, szTitle, szCopyright, hIcon);
3613  DeleteObject(hIcon);
3614  break;
3615  }
3616 
3617  case IDM_HELP:
3619  L"Help not implemented yet!",
3620  L"Event Log",
3622  break;
3623 
3624  case IDM_EXIT:
3625  DestroyWindow(hWnd);
3626  break;
3627 
3628  default:
3629  return DefWindowProcW(hWnd, uMsg, wParam, lParam);
3630  }
3631  break;
3632  }
3633 
3634  case WM_INITMENU:
3635  {
3636  if ((HMENU)wParam != hMainMenu)
3637  break;
3638 
3640  Settings.bNewestEventsFirst ? IDM_LIST_NEWEST : IDM_LIST_OLDEST,
3641  MF_BYCOMMAND);
3642 
3643  if (!hwndEventDetails)
3644  {
3647  }
3649  MF_BYCOMMAND | (Settings.bShowDetailsPane ? MF_CHECKED : MF_UNCHECKED));
3650 
3652  MF_BYCOMMAND | (Settings.bShowGrid ? MF_CHECKED : MF_UNCHECKED));
3653 
3655  MF_BYCOMMAND | (Settings.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
3656 
3657  break;
3658  }
3659 
3660 #if 0
3661  case WM_INITMENUPOPUP:
3662  lParam = lParam;
3663  break;
3664 
3665  case WM_CONTEXTMENU:
3666  lParam = lParam;
3667  break;
3668 #endif
3669 
3670  case WM_SETCURSOR:
3671  {
3672  POINT pt;
3673 
3674  if (LOWORD(lParam) != HTCLIENT)
3675  goto Default;
3676 
3677  GetCursorPos(&pt);
3678  ScreenToClient(hWnd, &pt);
3679 
3680  /* Set the cursor for the vertical splitter */
3681  if (pt.x >= nVSplitPos - SPLIT_WIDTH/2 && pt.x < nVSplitPos + SPLIT_WIDTH/2 + 1)
3682  {
3683  RECT rs;
3684  GetClientRect(hWnd, &rect);
3685  GetWindowRect(hwndStatus, &rs);
3686  if (pt.y >= rect.top && pt.y < rect.bottom - (rs.bottom - rs.top))
3687  {
3689  return TRUE;
3690  }
3691  }
3692  else
3693  /* Set the cursor for the horizontal splitter, if the Event details pane is displayed */
3694  if (hwndEventDetails && Settings.bShowDetailsPane &&
3695  (pt.y >= nHSplitPos - SPLIT_WIDTH/2 && pt.y < nHSplitPos + SPLIT_WIDTH/2 + 1))
3696  {
3697  // RECT rs;
3698  GetClientRect(hWnd, &rect);
3699  // GetWindowRect(hwndStatus, &rs);
3700  if (pt.x >= nVSplitPos + SPLIT_WIDTH/2 + 1 /* rect.left + (rs.bottom - rs.top) */ &&
3701  pt.x < rect.right)
3702  {
3704  return TRUE;
3705  }
3706  }
3707  goto Default;
3708  }
3709 
3710  case WM_LBUTTONDOWN:
3711  {
3712  INT x = GET_X_LPARAM(lParam);
3713  INT y = GET_Y_LPARAM(lParam);
3714 
3715  /* Reset the splitter state */
3716  bSplit = 0;
3717 
3718  /* Capture the cursor for the vertical splitter */
3719  if (x >= nVSplitPos - SPLIT_WIDTH/2 && x < nVSplitPos + SPLIT_WIDTH/2 + 1)
3720  {
3721  bSplit = 1;
3722  SetCapture(hWnd);
3723  }
3724  else
3725  /* Capture the cursor for the horizontal splitter, if the Event details pane is displayed */
3726  if (hwndEventDetails && Settings.bShowDetailsPane &&
3727  (y >= nHSplitPos - SPLIT_WIDTH/2 && y < nHSplitPos + SPLIT_WIDTH/2 + 1))
3728  {
3729  bSplit = 2;
3730  SetCapture(hWnd);
3731  }
3732  break;
3733  }
3734 
3735  case WM_LBUTTONUP:
3736  case WM_RBUTTONDOWN:
3737  {
3738  if (GetCapture() != hWnd)
3739  break;
3740 
3741  /* Adjust the correct splitter position */
3742  if (bSplit == 1)
3743  nVSplitPos = GET_X_LPARAM(lParam);
3744  else if (bSplit == 2)
3745  nHSplitPos = GET_Y_LPARAM(lParam);
3746 
3747  /* If we are splitting, resize the windows */
3748  if (bSplit != 0)
3749  {
3750  GetClientRect(hWnd, &rect);
3751  ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
3752  }
3753 
3754  /* Reset the splitter state */
3755  bSplit = 0;
3756 
3757  ReleaseCapture();
3758  break;
3759  }
3760 
3761  case WM_MOUSEMOVE:
3762  {
3763  if (GetCapture() != hWnd)
3764  break;
3765 
3766  /* Move the correct splitter */
3767  if (bSplit == 1)
3768  {
3769  INT x = GET_X_LPARAM(lParam);
3770 
3771  GetClientRect(hWnd, &rect);
3772 
3773  x = min(max(x, SPLIT_WIDTH/2), rect.right - rect.left - SPLIT_WIDTH/2);
3774  if (nVSplitPos != x)
3775  {
3776  nVSplitPos = x;
3777  ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
3778  }
3779  }
3780  else if (bSplit == 2)
3781  {
3782  RECT rs;
3783  INT y = GET_Y_LPARAM(lParam);
3784 
3785  GetClientRect(hWnd, &rect);
3786  GetWindowRect(hwndStatus, &rs);
3787 
3788  y = min(max(y, SPLIT_WIDTH/2), rect.bottom - rect.top - SPLIT_WIDTH/2 - (rs.bottom - rs.top));
3789  if (nHSplitPos != y)
3790  {
3791  nHSplitPos = y;
3792  ResizeWnd(rect.right - rect.left, rect.bottom - rect.top);
3793  }
3794  }
3795  break;
3796  }
3797 
3798  case WM_SIZE:
3799  {
3800  if (wParam != SIZE_MINIMIZED)
3801  {
3803  ResizeWnd(LOWORD(lParam), HIWORD(lParam));
3804  break;
3805  }
3806  /* Fall through the default case */
3807  }
3808 
3809  default: Default:
3810  return DefWindowProcW(hWnd, uMsg, wParam, lParam);
3811  }
3812 
3813  return 0;
3814 }
3815 
3816 
3817 static
3818 VOID
3820 {
3821  LPWSTR lpLogName = EventLog->LogName;
3822 
3823  DWORD Result, dwType;
3824  DWORD dwMaxSize = 0, dwRetention = 0;
3825  BOOL Success;
3826  WIN32_FIND_DATAW FileInfo; // WIN32_FILE_ATTRIBUTE_DATA
3828  WCHAR wszBuf[MAX_PATH];
3829  WCHAR szTemp[MAX_LOADSTRING];
3830  LPWSTR FileName;
3831 
3832  HKEY hLogKey;
3833  WCHAR *KeyPath;
3834  DWORD cbData;
3835  SIZE_T cbKeyPath;
3836 
3837  if (EventLog->Permanent)
3838  {
3839 
3840  cbKeyPath = (wcslen(EVENTLOG_BASE_KEY) + wcslen(lpLogName) + 1) * sizeof(WCHAR);
3841  KeyPath = HeapAlloc(GetProcessHeap(), 0, cbKeyPath);
3842  if (!KeyPath)
3843  {
3844  goto Quit;
3845  }
3846 
3847  StringCbCopyW(KeyPath, cbKeyPath, EVENTLOG_BASE_KEY);
3848  StringCbCatW(KeyPath, cbKeyPath, lpLogName);
3849 
3850  if (RegOpenKeyExW(hkMachine, KeyPath, 0, KEY_QUERY_VALUE, &hLogKey) != ERROR_SUCCESS)
3851  {
3852  HeapFree(GetProcessHeap(), 0, KeyPath);
3853  goto Quit;
3854  }
3855  HeapFree(GetProcessHeap(), 0, KeyPath);
3856 
3857 
3858  cbData = sizeof(dwMaxSize);
3859  Result = RegQueryValueExW(hLogKey,
3860  L"MaxSize",
3861  NULL,
3862  &dwType,
3863  (LPBYTE)&dwMaxSize,
3864  &cbData);
3865  if ((Result != ERROR_SUCCESS) || (dwType != REG_DWORD))
3866  {
3867  // dwMaxSize = 512 * 1024; /* 512 kBytes */
3868  dwMaxSize = 0;
3869  }
3870  /* Convert in KB */
3871  dwMaxSize /= 1024;
3872 
3873  cbData = sizeof(dwRetention);
3874  Result = RegQueryValueExW(hLogKey,
3875  L"Retention",
3876  NULL,
3877  &dwType,
3878  (LPBYTE)&dwRetention,
3879  &cbData);
3880  if ((Result != ERROR_SUCCESS) || (dwType != REG_DWORD))
3881  {
3882  /* On Windows 2003 it is 604800 (secs) == 7 days */
3883  dwRetention = 0;
3884  }
3885  /* Convert in days, rounded up */ // ROUND_UP
3886  // dwRetention = ROUND_UP(dwRetention, 24*3600) / (24*3600);
3887  dwRetention = (dwRetention + 24*3600 - 1) / (24*3600);
3888 
3889 
3890  RegCloseKey(hLogKey);
3891 
3892  }
3893 
3894 
3895 Quit:
3896 
3897  SetDlgItemTextW(hDlg, IDC_DISPLAYNAME, lpLogName); // FIXME!
3898  SetDlgItemTextW(hDlg, IDC_LOGNAME, lpLogName);
3899 
3900  FileName = EventLog->FileName;
3901  if (FileName && *FileName)
3902  {
3903  /* Expand the file name. If the log file is on a remote computer, retrieve the network share form of the file name. */
3904  GetExpandedFilePathName(EventLog->ComputerName, FileName, wszBuf, ARRAYSIZE(wszBuf));
3905  FileName = wszBuf;
3906  }
3907  else
3908  {
3909  FileName = L"";
3910  }
3911  SetDlgItemTextW(hDlg, IDC_LOGFILE, FileName);
3912 
3913  if (FileName && *FileName)
3914  {
3915  /*
3916  * The general problem here (and in the shell as well) is that
3917  * GetFileAttributesEx fails for files that are opened without
3918  * shared access. To retrieve file information for those we need
3919  * to use something else: FindFirstFile, on the full file name.
3920  */
3921  Success = GetFileAttributesExW(FileName,
3923  (LPWIN32_FILE_ATTRIBUTE_DATA)&FileInfo);
3924  if (!Success)
3925  {
3926  HANDLE hFind = FindFirstFileW(FileName, &FileInfo);
3927  Success = (hFind != INVALID_HANDLE_VALUE);
3928  if (Success)
3929  FindClose(hFind);
3930  }
3931  }
3932  else
3933  {
3934  Success = FALSE;
3935  }
3936 
3937  /* Starting there, FileName becomes invalid because we are reusing wszBuf */
3938 
3939  if (Success)
3940  {
3941  FileSize.u.LowPart = FileInfo.nFileSizeLow;
3942  FileSize.u.HighPart = FileInfo.nFileSizeHigh;
3943  if (FormatFileSizeWithBytes(&FileSize, wszBuf, ARRAYSIZE(wszBuf)))
3944  SetDlgItemTextW(hDlg, IDC_SIZE_LABEL, wszBuf);
3945 
3946  LoadStringW(hInst, IDS_NOT_AVAILABLE, szTemp, ARRAYSIZE(szTemp));
3947 
3948  if (GetFileTimeString(&FileInfo.ftCreationTime, wszBuf, ARRAYSIZE(wszBuf)))
3949  SetDlgItemTextW(hDlg, IDC_CREATED_LABEL, wszBuf);
3950  else
3951  SetDlgItemTextW(hDlg, IDC_CREATED_LABEL, szTemp);
3952 
3953  if (GetFileTimeString(&FileInfo.ftLastWriteTime, wszBuf, ARRAYSIZE(wszBuf)))
3954  SetDlgItemTextW(hDlg, IDC_MODIFIED_LABEL, wszBuf);
3955  else
3956  SetDlgItemTextW(hDlg, IDC_MODIFIED_LABEL, szTemp);
3957 
3958  if (GetFileTimeString(&FileInfo.ftLastAccessTime, wszBuf, ARRAYSIZE(wszBuf)))
3959  SetDlgItemTextW(hDlg, IDC_ACCESSED_LABEL, wszBuf);
3960  else
3961  SetDlgItemTextW(hDlg, IDC_MODIFIED_LABEL, szTemp);
3962  }
3963  else
3964  {
3965  LoadStringW(hInst, IDS_NOT_AVAILABLE, szTemp, ARRAYSIZE(szTemp));
3966 
3967  SetDlgItemTextW(hDlg, IDC_SIZE_LABEL, szTemp);
3968  SetDlgItemTextW(hDlg, IDC_CREATED_LABEL, szTemp);
3969  SetDlgItemTextW(hDlg, IDC_MODIFIED_LABEL, szTemp);
3970  SetDlgItemTextW(hDlg, IDC_ACCESSED_LABEL, szTemp);
3971  }
3972 
3973  if (EventLog->Permanent)
3974  {
3977 
3978  SetDlgItemInt(hDlg, IDC_EDIT_MAXLOGSIZE, dwMaxSize, FALSE);
3979  SetDlgItemInt(hDlg, IDC_EDIT_EVENTS_AGE, dwRetention, FALSE);
3980 
3981  if (dwRetention == 0)
3982  {
3986  }
3987  else if (dwRetention == INFINITE)
3988  {
3992  }
3993  else
3994  {
3998  }
3999  }
4000  else
4001  {
4002  // TODO: Hide the unused controls! Or, just use another type of property sheet!
4003  }
4004 }
4005 
4006 /* Message handler for EventLog Properties dialog */
4009 {
4010  PEVENTLOG EventLog;
4011 
4012  EventLog = (PEVENTLOG)GetWindowLongPtrW(hDlg, DWLP_USER);
4013 
4014  switch (uMsg)
4015  {
4016  case WM_INITDIALOG:
4017  {
4018  EventLog = (PEVENTLOG)((LPPROPSHEETPAGE)lParam)->lParam;
4019  SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)EventLog);
4020 
4021  InitPropertiesDlg(hDlg, EventLog);
4022 
4023  PropSheet_UnChanged(GetParent(hDlg), hDlg);
4024  return (INT_PTR)TRUE;
4025  }
4026 
4027  case WM_DESTROY:
4028  return (INT_PTR)TRUE;
4029 
4030  case WM_COMMAND:
4031  switch (LOWORD(wParam))
4032  {
4033  case IDOK:
4034  case IDCANCEL:
4035  EndDialog(hDlg, LOWORD(wParam));
4036  return (INT_PTR)TRUE;
4037 
4039  {
4043  break;
4044  }
4045 
4047  {
4051  break;
4052  }
4053 
4054  case IDC_NO_OVERWRITE:
4055  {
4059  break;
4060  }
4061 
4062  case IDHELP:
4063  MessageBoxW(hDlg,
4064  L"Help not implemented yet!",
4065  L"Event Log",
4067  return (INT_PTR)TRUE;
4068 
4069  default:
4070  break;
4071  }
4072  break;
4073  }
4074 
4075  return (INT_PTR)FALSE;
4076 }
4077 
4078 INT_PTR
4080 {
4081  INT_PTR ret = 0;
4082  PROPSHEETHEADERW psh;
4083  PROPSHEETPAGEW psp[1]; // 2
4084 
4085  /*
4086  * Bail out if there is no available filter, or if the filter
4087  * contains more than one log.
4088  */
4089  if (!EventLogFilter)
4090  return 0;
4091 
4092  EventLogFilter_AddRef(EventLogFilter);
4093 
4094  if (EventLogFilter->NumOfEventLogs > 1 ||
4095  EventLogFilter->EventLogs[0] == NULL)
4096  {
4097  goto Quit;
4098  }
4099 
4100  /* Header */
4101  psh.dwSize = sizeof(psh);
4102  psh.dwFlags = PSH_PROPSHEETPAGE /*| PSH_USEICONID */ | PSH_PROPTITLE | PSH_HASHELP /*| PSH_NOCONTEXTHELP */ /*| PSH_USECALLBACK */;
4103  psh.hInstance = hInstance;
4104  psh.hwndParent = hWndParent;
4105  // psh.pszIcon = MAKEINTRESOURCEW(IDI_APPICON); // Disabled because it only sets the small icon; the big icon is a stretched version of the small one.
4106  psh.pszCaption = EventLogFilter->EventLogs[0]->LogName;
4107  psh.nStartPage = 0;
4108  psh.ppsp = psp;
4109  psh.nPages = ARRAYSIZE(psp);
4110  // psh.pfnCallback = PropSheetCallback;
4111 
4112  /* Log properties page */
4113  psp[0].dwSize = sizeof(psp[0]);
4114  psp[0].dwFlags = PSP_HASHELP;
4115  psp[0].hInstance = hInstance;
4117  psp[0].pfnDlgProc = EventLogPropProc;
4118  psp[0].lParam = (LPARAM)EventLogFilter->EventLogs[0];
4119 
4120 #if 0
4121  /* TODO: Log sources page */
4122  psp[1].dwSize = sizeof(psp[1]);
4123  psp[1].dwFlags = PSP_HASHELP;
4124  psp[1].hInstance = hInstance;
4126  psp[1].pfnDlgProc = GeneralPageWndProc;
4127  psp[0].lParam = (LPARAM)EventLogFilter->EventLogs[0];
4128 #endif
4129 
4130  /* Create the property sheet */
4131  ret = PropertySheetW(&psh);
4132 
4133 Quit:
4134  EventLogFilter_Release(EventLogFilter);
4135  return ret;
4136 }
4137 
4138 /* Message handler for Event Details dialog */
4139 static HWND hWndDetailsCtrl = NULL; // May go into the DWLP_USER
4140 static HWND hWndGrip = NULL;
4141 static INT cxMin, cyMin; // In window coordinates
4142 static INT cxOld, cyOld; // In client coordinates
4143 
4146 {
4147  switch (uMsg)
4148  {
4149  case WM_INITDIALOG:
4150  {
4151  LONG_PTR dwStyle;
4152  INT sbVXSize, sbHYSize;
4153  RECT rcWnd, rect;
4154 
4155  hWndDetailsCtrl = CreateEventDetailsCtrl(hInst, hDlg, lParam);
4156  if (!hWndDetailsCtrl)
4157  {
4158  EndDialog(hDlg, 0);
4159  return (INT_PTR)TRUE;
4160  }
4161 
4162  /* Create a size grip if the dialog has a sizing border */
4163  GetClientRect(hDlg, &rcWnd);
4164  dwStyle = GetWindowLongPtrW(hDlg, GWL_STYLE);
4165  sbVXSize = GetSystemMetrics(SM_CXVSCROLL);
4166  sbHYSize = GetSystemMetrics(SM_CYHSCROLL);
4167  if (dwStyle & WS_THICKFRAME /* == WS_SIZEBOX */)
4168  {
4170  NULL,
4172  rcWnd.right - sbVXSize,
4173  rcWnd.bottom - sbHYSize,
4174  sbVXSize, sbHYSize,
4175  hDlg,
4176  NULL,
4177  hInst,
4178  NULL);
4179  }
4180 
4181  // SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)hWndDetailsCtrl);
4182 
4183  /*
4184  * Compute the minimum window size (in window coordinates) by
4185  * adding the widths/heights of the "Help" and "Close" buttons,
4186  * together with the margins, and add some minimal spacing
4187  * between the buttons.
4188  */
4189  GetWindowRect(hDlg, &rcWnd);
4190  cxMin = cyMin = 0;
4191 
4192  GetWindowRect(GetDlgItem(hDlg, IDHELP), &rect);
4193  cxMin += (rect.right - rect.left) + (rect.left - rcWnd.left); // == (rect.right - rcWnd.left);
4194  cyMin += (rect.bottom - rect.top) + (rcWnd.bottom - rect.bottom); // == (rcWnd.bottom - rect.top);
4195 
4196  GetWindowRect(GetDlgItem(hDlg, IDOK), &rect);
4197  cxMin += (rect.right - rect.left) + (rcWnd.right - rect.right); // == (rcWnd.right - rect.left);
4198  cyMin += (rect.bottom - rect.top) + (rcWnd.bottom - rect.bottom); // == (rcWnd.bottom - rect.top);
4199 
4200  /*
4201  * Convert the window rect from window to client coordinates
4202  * in order to retrieve the sizes of the left and top margins,
4203  * and add some extra space.
4204  */
4205  MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rcWnd, sizeof(RECT)/sizeof(POINT));
4206 
4207  cxMin += -2*rcWnd.left; // Minimal spacing between the buttons == 2 * left margin
4208  cyMin += -rcWnd.top + 12; // Add some space on top
4209 
4210  GetClientRect(hDlg, &rcWnd);
4211  cxOld = rcWnd.right - rcWnd.left;
4212  cyOld = rcWnd.bottom - rcWnd.top;
4213 
4214  /* Show event info on dialog control */
4216 
4217  // SetWindowPos(hWndDetailsCtrl, NULL,
4218  // 0, 0,
4219  // (rcWnd.right - rcWnd.left),
4220  // (rcWnd.bottom - rcWnd.top),
4221  // SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
4222 
4223  /*
4224  * Hide the placeholder static control and show the event details
4225  * control instead. Note that the placeholder is here so far just
4226  * to get the dimensions right in the dialog resource editor.
4227  * I plan to remove it and use a custom control with a suitable
4228  * window class for it, that would create the event details control
4229  * instead.
4230  */
4233  return (INT_PTR)TRUE;
4234  }
4235 
4236  case WM_DESTROY:
4240  return (INT_PTR)TRUE;
4241 
4242  case WM_COMMAND:
4243  switch (LOWORD(wParam))
4244  {
4245  case IDOK:
4246  case IDCANCEL:
4247  EndDialog(hDlg, LOWORD(wParam));
4248  return (INT_PTR)TRUE;
4249 
4250  case IDHELP:
4251  MessageBoxW(hDlg,
4252  L"Help not implemented yet!",
4253  L"Event Log",
4255  return (INT_PTR)TRUE;
4256 
4257  default:
4258  break;
4259  }
4260  break;
4261 
4262  case WM_SETCURSOR:
4263  if (((HWND)wParam == hWndGrip) && (LOWORD(lParam) == HTCLIENT))
4264  {
4267  return (INT_PTR)TRUE;
4268  }
4269  break;
4270 
4271  case WM_SIZING:
4272  {
4273  /* Forbid resizing the dialog smaller than its minimal size */
4274  PRECT dragRect = (PRECT)lParam;
4275 
4276  if ((wParam == WMSZ_LEFT) || (wParam == WMSZ_TOPLEFT) || (wParam == WMSZ_BOTTOMLEFT))
4277  {
4278  if (dragRect->right - dragRect->left < cxMin)
4279  dragRect->left = dragRect->right - cxMin;
4280  }
4281 
4282  if ((wParam == WMSZ_RIGHT) || (wParam == WMSZ_TOPRIGHT) || (wParam == WMSZ_BOTTOMRIGHT))
4283  {
4284  if (dragRect->right - dragRect->left < cxMin)
4285  dragRect->right = dragRect->left + cxMin;
4286  }
4287 
4288  if ((wParam == WMSZ_TOP) || (wParam == WMSZ_TOPLEFT) || (wParam == WMSZ_TOPRIGHT))
4289  {
4290  if (dragRect->bottom - dragRect->top < cyMin)
4291  dragRect->top = dragRect->bottom - cyMin;
4292  }
4293 
4294  if ((wParam == WMSZ_BOTTOM) || (wParam == WMSZ_BOTTOMLEFT) || (wParam == WMSZ_BOTTOMRIGHT))
4295  {
4296  if (dragRect->bottom - dragRect->top < cyMin)
4297  dragRect->bottom = dragRect->top + cyMin;
4298  }
4299 
4301  return (INT_PTR)TRUE;
4302  }
4303 
4304  case WM_SIZE:
4305  {
4306  INT cx = LOWORD(lParam);
4307  INT cy = HIWORD(lParam);
4308 
4309  HDWP hdwp;
4310  HWND hItemWnd;
4311  RECT rect;
4312 
4313  hdwp = BeginDeferWindowPos(4);
4314 
4315  /* Resize the event details control window */
4316 
4317  hItemWnd = hWndDetailsCtrl;
4318  GetWindowRect(hItemWnd, &rect);
4319  MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
4320 
4321  if (hdwp)
4322  hdwp = DeferWindowPos(hdwp,
4323  hItemWnd,
4324  HWND_TOP,
4325  0, 0,
4326  (rect.right - rect.left) + (cx - cxOld),
4327  (rect.bottom - rect.top) + (cy - cyOld),
4329 
4330  /* Move the buttons */
4331 
4332  hItemWnd = GetDlgItem(hDlg, IDHELP);
4333  GetWindowRect(hItemWnd, &rect);
4334  MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
4335 
4336  if (hdwp)
4337  hdwp = DeferWindowPos(hdwp,
4338  hItemWnd,
4339  HWND_TOP,
4340  rect.left,
4341  rect.top + (cy - cyOld),
4342  0, 0,
4344 
4345  hItemWnd = GetDlgItem(hDlg, IDOK);
4346  GetWindowRect(hItemWnd, &rect);
4347  MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
4348 
4349  if (hdwp)
4350  hdwp = DeferWindowPos(hdwp,
4351  hItemWnd,
4352  HWND_TOP,
4353  rect.left + (cx - cxOld),
4354  rect.top + (cy - cyOld),
4355  0, 0,
4357 
4358  /* Move the size grip */
4359  if (hWndGrip && hdwp)
4360  {
4361  GetWindowRect(hWndGrip, &rect);
4362  MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
4363 
4364  hdwp = DeferWindowPos(hdwp,
4365  hWndGrip,
4366  HWND_TOP,
4367  rect.left + (cx - cxOld),
4368  rect.top + (cy - cyOld),
4369  0, 0,
4371  }
4372 
4373  if (hdwp)
4374  EndDeferWindowPos(hdwp);
4375 
4376  /* Hide the size grip if we are in maximized mode */
4377  if (hWndGrip)
4378  ShowWindow(hWndGrip, (wParam == SIZE_MAXIMIZED) ? SW_HIDE : SW_SHOW);
4379 
4380  cxOld = cx;
4381  cyOld = cy;
4382 
4384  return (INT_PTR)TRUE;
4385  }
4386  }
4387 
4388  return (INT_PTR)FALSE;
4389 }
DWORD *typedef PVOID
Definition: winlogon.h:61
#define IDC_SIZEWE
Definition: winuser.h:689
#define WS_CLIPSIBLINGS
Definition: pedump.c:618
LPWSTR lpThousandSep
Definition: winnls.h:627
#define STATUSCLASSNAMEW
Definition: commctrl.h:1906
struct _ULARGE_INTEGER::@3736 u
HANDLE WINAPI OpenEventLogW(IN LPCWSTR lpUNCServerName, IN LPCWSTR lpSourceName)
Definition: eventlog.c:985
#define LOCALE_SGROUPING
Definition: winnls.h:44
static PWSTR Image
Definition: gflags.c:21
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:4693
void TrimNulls(LPWSTR s)
Definition: eventvwr.c:1450
static int argc
Definition: ServiceArgs.c:12
#define WMSZ_BOTTOMRIGHT
Definition: winuser.h:2425
#define IN
Definition: typedefs.h:38
DWORD Flags
Definition: commdlg.h:373
INT_PTR EventLogProperties(HINSTANCE, HWND, PEVENTLOGFILTER)
Definition: eventvwr.c:4079
#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:2337
unsigned short WORD
Definition: ntddk_ex.h:93
#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:3210
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:2150
#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:3322
LPCPROPSHEETPAGEW ppsp
Definition: prsht.h:290
BYTE bSplit
Definition: eventvwr.c:75
#define LVCF_WIDTH
Definition: commctrl.h:2557
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:2269
enum _SID_NAME_USE SID_NAME_USE
LPCWSTR pszTemplate
Definition: prsht.h:209
long y
Definition: polytest.cpp:48
int cbWndExtra
Definition: winuser.h:3173
#define ERROR_SUCCESS
Definition: deptool.c:10
static INT cyMin
Definition: eventvwr.c:4141
#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:1752
UINT uNewState
Definition: commctrl.h:3006
LIST_ENTRY ListEntry
Definition: eventvwr.h:104
LPWSTR lpDecimalSep
Definition: winnls.h:626
#define IDM_ABOUT
Definition: resource.h:29
VOID BuildLogListAndFilterList(IN LPCWSTR lpComputerName)
Definition: eventvwr.c:2792
struct _Entry Entry
Definition: kefuncs.h:640
#define IDYES
Definition: winuser.h:829
#define IDS_CLEAREVENTS_MSG
Definition: resource.h:95
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:2558
USHORT MaximumLength
Definition: env_spec_w32.h:370
LPCWSTR lpstrInitialDir
Definition: commdlg.h:371
long x
Definition: polytest.cpp:48
BOOL Information
Definition: eventvwr.h:114
INT nHSplitPos
Definition: eventvwr.c:74
#define LVS_SHOWSELALWAYS
Definition: commctrl.h:2237
#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:1598
WORD ATOM
Definition: dimm.idl:113
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
#define IDM_SAVE_SETTINGS
Definition: resource.h:79
#define SIZE_MAXIMIZED
Definition: winuser.h:2461
#define KEY_READ
Definition: nt_native.h:1023
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
#define pt(x, y)
Definition: drawing.c:79
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define WM_INITMENUPOPUP
Definition: winuser.h:1722
#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:1779
WINDOWPLACEMENT wpPos
Definition: eventvwr.c:130
VOID DisplayUsage(VOID)
Definition: eventvwr.c:181
static SIZE_T FileSize
Definition: cabinet.c:52
BOOL WINAPI BackupEventLogW(IN HANDLE hEventLog, IN LPCWSTR lpBackupFileName)
Definition: eventlog.c:245
#define LVS_REPORT
Definition: commctrl.h:2232
#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:704
#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:3471
#define IDM_LIST_OLDEST
Definition: resource.h:74
static INT cxMin
Definition: eventvwr.c:4141
#define IDC_STATIC
Definition: calc.h:41
#define HKEY_CURRENT_USER
Definition: winreg.h:11
BOOL InitInstance(HINSTANCE)
Definition: eventvwr.c:3036
#define DATE_SHORTDATE
Definition: winnls.h:193
#define FORMAT_MESSAGE_ARGUMENT_ARRAY
Definition: winbase.h:405
#define FORMAT_MESSAGE_FROM_STRING
Definition: winbase.h:402
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
Definition: loader.c:286
unsigned char * LPBYTE
Definition: typedefs.h:52
INT_PTR CALLBACK EventLogPropProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: eventvwr.c:4008
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1827
#define iswdigit(_c)
Definition: ctype.h:667
#define IDS_NONE
Definition: resource.h:122
#define TVS_LINESATROOT
Definition: commctrl.h:3216
#define MAKELPARAM(l, h)
Definition: winuser.h:3915
LPCWSTR pszText
Definition: msvc.h:103
#define LVN_ITEMCHANGED
Definition: commctrl.h:3101
LPWSTR lpstrFile
Definition: commdlg.h:367
*nSize LPSTR _Inout_ LPDWORD nSize
Definition: winbase.h:2024
BOOL SaveSettings(VOID)
Definition: eventvwr.c:511
#define IDS_STATUS_MSG
Definition: resource.h:88
#define CALLBACK
Definition: compat.h:27
#define WM_SETREDRAW
Definition: winuser.h:1598
#define WC_LISTVIEWW
Definition: commctrl.h:2227
BOOL WINAPI UpdateWindow(_In_ HWND)
HWND hWnd
Definition: settings.c:17
_Check_return_ _CRTIMP wchar_t *__cdecl wcstok(_Inout_opt_z_ wchar_t *_Str, _In_z_ const wchar_t *_Delim)
UINT uMsg
Definition: precomp.h:45
HTREEITEM htiSystemLogs
Definition: eventvwr.c:89
PVOID *typedef PWSTR
Definition: winlogon.h:66
DWORD g_TotalRecords
Definition: eventvwr.c:98
#define LVS_EX_FULLROWSELECT
Definition: commctrl.h:2704
LONG top
Definition: windef.h:297
UINT Grouping
Definition: winnls.h:625
HANDLE HWND
Definition: compat.h:13
HMENU hMainMenu
Definition: eventvwr.c:87
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define LPNMTREEVIEW
Definition: commctrl.h:3610
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
HWND CreateEventDetailsCtrl(HINSTANCE hInstance, HWND hParentWnd, LPARAM lParam)
Definition: evtdetctl.c:937
ULONG NumOfEventLogs
Definition: eventvwr.h:134
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
LPWSTR lpszzUserLogsToLoad
Definition: eventvwr.c:92
#define IDM_REFRESH
Definition: resource.h:76
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:679
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1635
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
static HWND hWndGrip
Definition: eventvwr.c:4140
#define GWL_EXSTYLE
Definition: winuser.h:845
#define HWND_TOP
Definition: winuser.h:1193
GLuint buffer
Definition: glext.h:5915
#define SM_CYSMICON
Definition: winuser.h:1003
HICON hIcon
Definition: winuser.h:3175
HWND WINAPI SetFocus(_In_opt_ HWND)
VOID EventLogFilter_Free(IN PEVENTLOGFILTER EventLogFilter)
Definition: eventvwr.c:1411
#define IDM_LIST_NEWEST
Definition: resource.h:73
#define IDS_EVENTLOG_INFORMATION_TYPE
Definition: resource.h:103
#define WMSZ_TOP
Definition: winuser.h:2420
#define IDC_LOGNAME
Definition: resource.h:47
#define IDS_USAGE
Definition: resource.h:3
BOOL WINAPI SetWindowTextW(_In_ HWND, _In_opt_ LPCWSTR)
BOOL WINAPI ReadEventLogW(IN HANDLE hEventLog, IN DWORD dwReadFlags, IN DWORD dwRecordOffset, OUT LPVOID lpBuffer, IN DWORD nNumberOfBytesToRead, OUT DWORD *pnBytesRead, OUT DWORD *pnMinNumberOfBytesNeeded)
Definition: eventlog.c:1154
#define WS_CHILD
Definition: pedump.c:617
BOOL AuditFailure
Definition: eventvwr.h:118
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
#define GetWindowLongPtrW
Definition: winuser.h:4698
#define TVIF_SELECTEDIMAGE
Definition: commctrl.h:3238
uint16_t * PWCHAR
Definition: typedefs.h:54
#define ListView_InsertItem(hwnd, pitem)
Definition: commctrl.h:2378
__u16 time
Definition: mkdosfs.c:366
LONG left
Definition: windef.h:296
#define SWP_NOZORDER
Definition: winuser.h:1232
BOOL WINAPI ShowWindow(_In_ HWND, _In_ int)
#define EVENT_PARAMETER_MESSAGE_FILE
Definition: eventvwr.c:58
BOOL WINAPI GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
Definition: compname.c:339
int32_t INT_PTR
Definition: typedefs.h:62
#define InsertTailList(ListHead, Entry)
#define IDC_NO_OVERWRITE
Definition: resource.h:59
#define WS_CLIPCHILDREN
Definition: pedump.c:619
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:2635
DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, __ms_va_list *args)
Definition: format_msg.c:583
BOOL WINAPI ConvertSidToStringSidW(PSID Sid, LPWSTR *StringSid)
Definition: security.c:3255
#define WCHAR
Definition: msvc.h:43
LONG right
Definition: windef.h:298
BOOL WINAPI FileTimeToLocalFileTime(IN CONST FILETIME *lpFileTime, OUT LPFILETIME lpLocalFileTime)
Definition: time.c:211
DWORD WINAPI WaitForMultipleObjects(IN DWORD nCount, IN CONST HANDLE *lpHandles, IN BOOL bWaitAll, IN DWORD dwMilliseconds)
Definition: synch.c:151
#define IDI_INFORMATIONICON
Definition: resource.h:8
BOOL WINAPI DestroyWindow(_In_ HWND)
#define IDC_OVERWRITE_AS_NEEDED
Definition: resource.h:55
HWND hwndStatus
Definition: eventvwr.c:85
LPWSTR pszText
Definition: commctrl.h:3287
PWSTR ComputerNames
Definition: eventvwr.h:131
#define TV_INSERTSTRUCTW
Definition: commctrl.h:3343
#define DWORD
Definition: msvc.h:34
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
#define CreateWindowW(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4185
int32_t INT
Definition: typedefs.h:56
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
PEVENTLOGFILTER ActiveFilter
Definition: eventvwr.c:104
#define IDS_COLUMNCATEGORY
Definition: resource.h:115
& rect
Definition: startmenu.cpp:1413
BOOL WINAPI EndDialog(_In_ HWND, _In_ INT_PTR)
DWORD DWORD
Definition: winlogon.h:84
#define IDS_EVENTLOG_UNKNOWN_TYPE
Definition: resource.h:107
HINSTANCE hInst
Definition: eventvwr.c:65
STRSAFEAPI StringCbCatW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:342
static char ** argv
Definition: ServiceArgs.c:11
#define SPLIT_WIDTH
Definition: eventvwr.c:62
#define DWLP_MSGRESULT
Definition: winuser.h:864
BOOL WINAPI GetSaveFileNameW(LPOPENFILENAMEW ofn)
Definition: filedlg.c:4282
HKEY hkMachine
Definition: eventvwr.c:95
HWND hwndEventDetails
Definition: eventvwr.c:84
struct tagNMHDR * LPNMHDR
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:597
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
DWORD lStructSize
Definition: commdlg.h:360
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
LONG WINAPI RegCreateKeyExW(_In_ HKEY hKey, _In_ LPCWSTR lpSubKey, _In_ DWORD Reserved, _In_opt_ LPWSTR lpClass, _In_ DWORD dwOptions, _In_ REGSAM samDesired, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _Out_ PHKEY phkResult, _Out_opt_ LPDWORD lpdwDisposition)
Definition: reg.c:1094
#define IDC_SIZENS
Definition: winuser.h:690
#define WMSZ_TOPLEFT
Definition: winuser.h:2421
#define IDS_EVENTLOG_SUCCESS
Definition: resource.h:106
LIST_ENTRY EventLogFilterList
Definition: eventvwr.c:103
_SEH2_TRY
Definition: create.c:4250
#define SWP_HIDEWINDOW
Definition: winuser.h:1226
UINT_PTR WPARAM
Definition: windef.h:207
STRSAFEAPI StringCchCatW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:325
HWND hwndMainWindow
Definition: eventvwr.c:81
#define StatusBar_GetItemRect(hwndCtl, index, lprc)
Definition: eventvwr.h:64
static const LPCWSTR SystemLogs[]
Definition: eventvwr.c:45
#define IDHELP
Definition: resource_2.h:8
#define EVENTLOG_BACKWARDS_READ
Definition: winnt_old.h:2627
#define EVT_DISPLAY
Definition: evtdetctl.h:15
#define ILC_COLOR32
Definition: commctrl.h:343
uint32_t ULONG_PTR
Definition: typedefs.h:63
BOOL WINAPI SetDlgItemTextW(_In_ HWND, _In_ int, _In_ LPCWSTR)