⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eventlogthread.cpp

📁 Ever wanted to just type tail -f error_log on Windows?Envious of your Unix friends who can track cha
💻 CPP
字号:
/*
 * Tail for Win32 - a Windows version of the UNIX 'tail -f' command.
 * 
 * Author: Paul Perkins (paul@objektiv.org.uk)
 * 
 * Copyright(c)
 *
 * This program is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by the Free 
 * Software Foundation; either version 2 of the License, or (at your option) 
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with 
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 
 * Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * $Id: EventLogThread.cpp,v 1.7 2003/11/12 09:25:25 paulperkins Exp $
 * 
 */

#include "stdafx.h"
#include <io.h>
#include <stdio.h>

#include "utils.h"

#include "eventlogthread.h"

// Function to call on update.
// From TailView.cpp.
extern BOOL InsertText (
  CTailView*      pView,
  char*           pszText,
  BOOL            bDoColouring,
  long*           plMatchCount,
  BOOL*           pbMatch);

void GetEventLogType (
  unsigned short uEventType,
  char* pszType)
{
  switch (uEventType)
  {
  case EVENTLOG_SUCCESS:
    sprintf (pszType, "EVENTLOG_SUCCESS");
    break;

  case EVENTLOG_ERROR_TYPE:
    sprintf (pszType, "EVENTLOG_ERROR_TYPE");

    break;
  
  case EVENTLOG_WARNING_TYPE:
    sprintf (pszType, "EVENTLOG_WARNING_TYPE");

    break;
  
  case EVENTLOG_INFORMATION_TYPE:
    sprintf (pszType, "EVENTLOG_INFORMATION_TYPE");

    break;
  
  case EVENTLOG_AUDIT_SUCCESS:
    sprintf (pszType, "EVENTLOG_AUDIT_SUCCESS");

    break;
  
  case EVENTLOG_AUDIT_FAILURE:
    sprintf (pszType, "EVENTLOG_AUDIT_FAILURE");

    break;

  default:
    sprintf (pszType, "UNKNOWN");

    break;


  }
}

UINT EventLogThread (
  LPVOID pParams)
{
  EVENT_LOG_THREAD_PARAMS* parms;
  HANDLE    fch = NULL;
  HANDLE    hEventLog = NULL;
  HANDLE    haEvents[2];
  HANDLE    hDie;
  DWORD     dwFileSize = 0;
  DWORD     dwNewFileSize = 0;
  DWORD     dwOldFileSize = 0;
  DWORD     dwRtn;
  HWND      hwndEdit = NULL;
  char      szNewPath[_MAX_PATH] = "";
  char      szEvent[_MAX_PATH] = "";
  BOOL      bFirst = TRUE;
  BOOL      bIgnoreHotStartup = FALSE;
  BOOL      bUpdated = FALSE;
  BOOL      bDebug = FALSE;
  BOOL      bPaused = FALSE;
  int       nTimeout = 0;
  char*     pszNewLines = NULL;
  CTailView* pView = NULL;                        
  BOOL      bRtn = FALSE;
  BOOL      bFileGone = FALSE;
  UINT      uiFlags = 0;                          // Type of drive containing file.
	EVENTLOGRECORD* pBuffer = NULL;                 // Buffer for changed lines.
	DWORD     dwBytesRead = 0;                      // Number of bytes read from file.
	BOOL      bReadOK = FALSE;                      // Read succeeded.
  DWORD     dwBufferSize = 0;                     // Size of buffer to allocate for changed segment.
  DWORD     dwBytesNeeded = 0;                    // Size of buffer needed for next record.
  long      lMatches = 0;                         // Number of matches found against keyword list.
  BOOL      bMatch = FALSE;                       // A match against list was found in this scan.
  DWORD     dwMaxInitFileSize = 100 * 1024;       // Size of file before considering only getting last n bytes.
  DWORD     dwInitFileSize = dwMaxInitFileSize;   // Size of chunk to bite off end of large file at startup.
  BOOL      bLastChunk = FALSE;                   // Only bite off last chunk of file.
  char      szComputerName[1024] = "";
  char      szUNCComputerName[1024] = "";
  DWORD     dwCNBufferSize = 0;
  DWORD     dwOldestRecord = 0;
  DWORD     dwCurrentRecord = 1;                  // Event log records seem to be '1' based.
  DWORD     dwRecordsToRead = 0;

  if (!pParams)
  {
    ::MessageBox (AfxGetMainWnd()->GetSafeHwnd(), "PANIC: EventLogThread: No document!", "Tail for Win32", MB_OK | MB_ICONSTOP);

    return 1;
  }

  parms = (EVENT_LOG_THREAD_PARAMS*) pParams;

//  strcpy (gszFileName, parms->szFileName);

  pView = parms->pView;

  bIgnoreHotStartup = parms->bIgnoreHotStartup;

  // Open the event log.
//  hEventLog = OpenEventLog ("", parms->szFileName);

  dwCNBufferSize = sizeof (szComputerName);

  GetComputerName (szComputerName, &dwCNBufferSize);

  sprintf (szUNCComputerName, "\\\\%s", szComputerName);

  LogMessage ("Computer name is %s", szUNCComputerName);

  hEventLog = OpenEventLog (szUNCComputerName, "Application");

  if (hEventLog == NULL)
  {
    ::MessageBox (hwndEdit, "Could not open Event Log", "Tail for Win32", MB_OK | MB_ICONSTOP);

    LogDebugMessage ("Could not open Event Log '%s'.",
                parms->szFileName);                  
    
    return 0;
  }

  // Create the change event.
  // PP: Need to change the name of the event.
  fch = CreateEvent (NULL, TRUE, FALSE, parms->szEvent); 

  if (fch == NULL)
  {
    ::MessageBox (hwndEdit, "Could not create wait event.", "Tail for Win32", MB_OK | MB_ICONSTOP);

    LogDebugMessage ("Could not CreateEvent '%s'.",
                parms->szEvent);                  
    
    return 0;
  }

  if (!NotifyChangeEventLog (hEventLog, fch))
  {
    ::MessageBox (hwndEdit, "Could not NotifyChangeEventLog.", "Tail for Win32", MB_OK | MB_ICONSTOP);

    LogDebugMessage ("Could not NotifyChangeEventLog.");                  

    return 0;
  }

  if (!(hDie = OpenEvent (EVENT_ALL_ACCESS, FALSE, parms->szDieEvent)))
  {
    hDie = CreateEvent (NULL, TRUE, FALSE, parms->szDieEvent); 
  }

  if (hDie == NULL)
  {
    LogDebugMessage ("CreateEvent (hDie) failed");

    return 0;
  }
  else
  {
    LogMessage ("Debug: CreateEvent (hDie) succeeded");
  }

  bDebug = parms->bDebug;
  bPaused = parms->bPaused;
  nTimeout = parms->nTimeout;
  hwndEdit = parms->hEdit;
//  strcpy (szFileName, parms->szFileName);

  // Set up the wait event array.
  haEvents[0] = hDie;
  haEvents[1] = fch;

  // The main loop.
  // Keep going 'til we get told to go away.
  while (1)
  {  
    if (!bFirst)
    {
			LogMessage ("Debug: Waiting for event log  change...");

      // Wait for the *directory* change or die event to occur.
      dwRtn = WaitForMultipleObjects (2, haEvents, FALSE, INFINITE);  

      if (dwRtn == WAIT_FAILED)
      {
        LogDebugMessage ("WaitForMultipleObjects failed - returned %ld", dwRtn);
      }
      else
      {
				if (dwRtn == WAIT_OBJECT_0)
				{
	        LogDebugMessage ("WaitForMultipleObjects triggered from die event", dwRtn);
				}
				else if (dwRtn == (WAIT_OBJECT_0 + 1))
				{
	        LogMessage ("Debug: WaitForMultipleObjects triggered from file wait event", dwRtn);
		
//              MessageBeep (MB_ICONINFORMATION);
				}
      }

      switch (dwRtn)
      {
        case WAIT_TIMEOUT:
          // Wait got bored, start waiting again.
          if (bDebug)
          {
            LogMessage ("Debug: Wait timed out.");
          }

          continue;

        case WAIT_OBJECT_0:
          // We're dead.      
          LogMessage ("Debug: Received kill event.");

/*          bRtn = FindCloseChangeNotification (fch);

          if (bDebug)
          {          
            if (!bRtn)
            {
              LogDebugMessage ("FindCloseChangeNotification failed - returned %ld", bRtn);
            }
            else
            {
              LogDebugMessage ("FindCloseChangeNotification returned %ld", bRtn);
            }
          } */

          bRtn = CloseHandle (hDie);

          if (bDebug)
          {
            if (!bRtn)
            {
              LogDebugMessage ("CloseHandle (hDie) failed - returned %ld", bRtn);
            }
            else
            {
              LogDebugMessage ("CloseHandle (hDie) succeeded - returned %ld", bRtn);
            }
          }

          return 0;

        case WAIT_ABANDONED:    
        case WAIT_ABANDONED + 1:    
          ::MessageBox (hwndEdit, "Wait abandoned!", "Tail for Win32", MB_OK | MB_ICONSTOP);

          LogMessage ("Wait abandoned!");

//          FindCloseChangeNotification (fch);

          CloseHandle (hDie);

          return 1;

        default:
          LogMessage ("Debug: Received event log change event.");

          break;
      }

      if (dwRtn != (WAIT_OBJECT_0 + 1))
      {
        LogDebugMessage ("WaitForMultipleObjects returned %ld. In a pickle.", dwRtn);
        ::MessageBox (hwndEdit, "WaitForMultipleObjects in a pickle!!", "Tail for Win32", MB_OK | MB_ICONSTOP);

//          FindCloseChangeNotification (fch);

        CloseHandle (hDie);

        return 1;
      }
    } /* End if (!bFirst) */

    // Open the file we're interested in to see if it has changed size.
    GetNumberOfEventLogRecords (hEventLog, &dwNewFileSize);

    // Save away the old file size.
    dwOldFileSize = dwFileSize;

    // If the file has changed size, update the view.
    if (dwNewFileSize != dwOldFileSize)
    {
      GetOldestEventLogRecord (hEventLog, &dwOldestRecord);

      dwRecordsToRead = dwNewFileSize - dwOldFileSize;

      LogMessage ("Debug: Event log has changed size (was %ld, now %ld)", dwOldFileSize, dwNewFileSize);

      dwFileSize = dwNewFileSize;

      dwBufferSize = 1024;

      LogMessage ("Allocating %ld bytes for buffer", dwBufferSize);      

      pBuffer = (EVENTLOGRECORD*) malloc (dwBufferSize);

      while (dwRecordsToRead > 0)
      {
        // Get the data from the event log. 
        // Try with a small buffer first.
        dwBytesRead = 1;
        dwBytesNeeded = 1;
  			
        memset ((void*)pBuffer, 0, dwBufferSize);

        if (0 == ReadEventLog (hEventLog, 
                               EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ,
                               dwCurrentRecord,
                               pBuffer,
                               dwBufferSize,
                               &dwBytesRead,
                               &dwBytesNeeded))
        {
          DWORD dwError = 0;
        
          free ((void*) pBuffer);

          dwError = GetLastError ();

          // Get the number of bytes needed.
          if (ERROR_INSUFFICIENT_BUFFER == dwError)
          {
            dwBufferSize = dwBytesNeeded;

  			    LogMessage ("Reallocating %ld bytes for buffer for record %ld.", dwBufferSize, dwCurrentRecord);      

            pBuffer = (EVENTLOGRECORD*) malloc (dwBufferSize);

            memset ((void*)pBuffer, 0, dwBufferSize);

            if (0 == ReadEventLog (hEventLog, 
                       EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ,
                       dwCurrentRecord,
                       pBuffer,
                       dwBufferSize,
                       &dwBytesRead,
                       &dwBytesNeeded))
            {
              ::MessageBox (AfxGetMainWnd()->GetSafeHwnd(), "Cannot read log record even after expanding buffer!.", 
                            "Tail for Win32", MB_OK | MB_ICONERROR);

              LogDebugMessage (dwError, "Could not read log record %ld even after expanding buffer!", dwCurrentRecord);

              return 0;
            }

          }
          else
          {
            ::MessageBox (AfxGetMainWnd()->GetSafeHwnd(), "Cannot read log record.", 
                          "Tail for Win32", MB_OK | MB_ICONERROR);

            LogDebugMessage (dwError, "Could not read log record %ld.", dwCurrentRecord);

            return 0;
          }
        }

        if (dwNewFileSize < dwOldFileSize)
        {
          // Event log has been truncated.
          ::MessageBox (AfxGetMainWnd()->GetSafeHwnd(), "Event Log has been truncated. Not yet supported!.", 
                        "Tail for Win32", MB_OK | MB_ICONINFORMATION);
  			  LogMessage ("Debug: Event Log has been truncated - not yet supported!!");      
        
          return 0;
        }

      char szNewEntry[10 * 1024] = "";
      char szTimestamp[1024] = "";
      char szType[1024] = "";
//      char szStrings[10 * 1024] = "";
      char szStrings[128] = "";
      char szSource[1024] = "";
      char* pszData = 0;

/*      if (pBuffer->DataLength > 0)
      {
        pszData = (char*) malloc (pBuffer->DataLength + 1);

        memset ((void*)pszData, 0, pBuffer->DataLength + 1);
  
        strncpy (pszData, (LPSTR)((LPBYTE)pBuffer + pBuffer->DataOffset), pBuffer->DataLength);
      } */

      GetTimeStamp ((time_t*)&pBuffer->TimeWritten, szTimestamp);
      GetEventLogType (pBuffer->EventType, szType);

      strcpy (szSource, (LPSTR)((LPBYTE)pBuffer + sizeof (EVENTLOGRECORD)));

      if (pBuffer->NumStrings > 0)
      {
        strncpy (szStrings, (LPSTR) ((LPBYTE)pBuffer + pBuffer->StringOffset), sizeof (szStrings) - 1);

        szStrings[sizeof (szStrings) - 1] = '\0';
      }

      sprintf (szNewEntry, "%s %s %s %ld [%s]\n", 
                szTimestamp, szType, szSource, pBuffer->EventID, szStrings);

/*      if (pBuffer->DataLength > 0)
      {
        free ((void*)pszData);
      } */

      pszNewLines = &szNewEntry[0];

      // Update the window, doing syntax highlighting, setting counters if matches found.
      bUpdated = InsertText (pView, pszNewLines, !(bFirst && bIgnoreHotStartup), &lMatches, &bMatch);

      dwRecordsToRead--;
      dwCurrentRecord++;
    }

    free ((void*) pBuffer); 

		bFirst = FALSE;
  } // Go back and wait for another change.

// Close the notification handle.
//    bRtn = FindCloseChangeNotification (fch);
  }

  CloseHandle (hDie);

  return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -