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

📄 filereaderthread.cpp

📁 Ever wanted to just type tail -f error_log on Windows?Envious of your Unix friends who can track cha
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    bUseTimeout = TRUE;
  }
  else
  {
    fch = FindFirstChangeNotification (szNewPath, FALSE, FILE_NOTIFY_CHANGE_SIZE);
//    fch = FindFirstChangeNotification (szNewPath, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);

    if (fch == INVALID_HANDLE_VALUE)
    {
      LogMessage ("Could not register file change notification on '%s'. "
                    "The file may not be on a local filesystem - using polling to "
                    "detect file changes.", parms->szFileName);                  

      bUseTimeout = FALSE;
    }
    else
    {
      LogMessage ("Using file change notification on '%s' to detect file changes. (fch = %08x)", parms->szFileName, fch);                  
    }
  }

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

  if (hDie == NULL)
  {
    LogDebugMessage ("CreateEvent (hDie) failed");
  }
  else
  {
    LogMessage ("Debug: CreateEvent (hDie) succeeded");
  }

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

  if (hReload == NULL)
  {
    LogDebugMessage ("CreateEvent (hReload) failed");
  }
  else
  {
    LogMessage ("Debug: CreateEvent (hReload) succeeded");
  }

#ifndef NO_HANDLER_THREAD

  // Create the handler thread.
  memset (&stFileHandlerParams, 0, sizeof (FILE_HANDLER_PARAMS));

  stFileHandlerParams.pView = pView;
  stFileHandlerParams.pdwOldFileSize = &dwOldFileSize;
  stFileHandlerParams.pdwNewFileSize = &dwNewFileSize;
  sprintf (stFileHandlerParams.szDieEvent, "HANDLER_%s_DIE", parms->szDieEvent);
  sprintf (stFileHandlerParams.szGoEvent, "HANDLER_%s_GO", parms->szDieEvent);
  stFileHandlerParams.pbFirst = &bFirst;
  stFileHandlerParams.pbIgnoreHotStartup = &bIgnoreHotStartup;
  stFileHandlerParams.hwndEdit = parms->hEdit;
  strcpy (stFileHandlerParams.szFileName, parms->szFileName);

  if (!AfxBeginThread ((AFX_THREADPROC) FileHandlerThread, (LPVOID) &stFileHandlerParams))
  {
    LogMessage ("Could not create handler thread.");
    ::AfxMessageBox ("Could not create handler thread.");

    return 1;
  }

#endif // #ifndef NO_HANDLER_THREAD

  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;
  haEvents[2] = hReload;

  // The main loop.
  // Keep going 'til we get told to go away.
  while (1)
  {  
    if (!bFirst)
    {
      if (bUseTimeout)
      {
        // Use different array for non-local (polled) files.
        haEvents[0] = hDie;
        haEvents[1] = hReload;

        dwRtn = WaitForMultipleObjects (2, haEvents, FALSE, nTimeout);  

        if (dwRtn == WAIT_FAILED)
        {
          LogDebugMessage ("WaitForMultipleObjects failed - returned %ld", dwRtn);
        }
        else if (dwRtn == WAIT_OBJECT_DIE)
				{
	        LogDebugMessage ("WaitForMultipleObjects triggered from die event", dwRtn);
				}
        else if (dwRtn == WAIT_TIMEOUT)
        {
	        LogMessage ("Debug: WaitForMultipleObjects triggered from polling interval timeout", dwRtn);
        }
				else if (dwRtn == WAIT_OBJECT_POLL_RELOAD)
				{
	        LogMessage ("Debug: WaitForMultipleObjects triggered from keyword reload event", dwRtn);

          ReloadKeywords (pView);		
				}

        // We've been killed.
        if (dwRtn == WAIT_OBJECT_DIE)
        {
          CloseHandle (hDie);

#ifndef NO_HANDLER_THREAD

          // Kill the handler thread.
          HANDLE hHandlerDie;

          hHandlerDie = OpenEvent (EVENT_ALL_ACCESS, FALSE, stFileHandlerParams.szDieEvent);

          // Release the threads and then reset the event automatically.
          PulseEvent (hHandlerDie);

          CloseHandle (hHandlerDie);
#endif // #ifndef NO_HANDLER_THREAD

          return 0;
        }

        LogMessage ("Debug: WaitForSingleObject (polling) fired");

        dwRtn = WAIT_OBJECT_FILEUPDATE;
      }
      else
      {
				LogMessage ("Debug: Waiting for file change...");

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

        if (dwRtn == WAIT_FAILED)
        {
          LogDebugMessage ("WaitForMultipleObjects failed - returned %ld", dwRtn);
        }
        else
        {
					if (dwRtn == WAIT_OBJECT_DIE)
					{
	          LogDebugMessage ("WaitForMultipleObjects triggered from die event", dwRtn);
					}
					else if (dwRtn == (WAIT_OBJECT_FILEUPDATE))
					{
	          LogMessage ("Debug: WaitForMultipleObjects triggered from file wait event", dwRtn);			
					}
					else if (dwRtn == (WAIT_OBJECT_RELOAD))
					{
	          LogMessage ("Debug: WaitForMultipleObjects triggered from keyword reload event", dwRtn);

            ReloadKeywords (pView);
					}
        }
      }

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

          continue;

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

          if (!bUseTimeout)
          {
            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);
            }
          }

#ifndef NO_HANDLER_THREAD

          hHandlerDie = OpenEvent (EVENT_ALL_ACCESS, FALSE, stFileHandlerParams.szDieEvent);

          // Release the threads and then reset the event automatically.
          PulseEvent (hHandlerDie);

          CloseHandle (hHandlerDie);

#endif // #ifndef NO_HANDLER_THREAD

          return 0;

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

          LogMessage ("Wait abandoned!");

          if (!bUseTimeout)
          {
            FindCloseChangeNotification (fch);
          }

          CloseHandle (hDie);

          return 1;

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

          break;
      }

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

        if (!bUseTimeout)
        {
          FindCloseChangeNotification (fch);
        }

        CloseHandle (hDie);

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

    // Open the file we're interested in to see if it has changed size.
    dwNewFileSize = GetFileSizeBytes (szFileName);

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

    // If the file has changed size, update the view.
    if (dwNewFileSize != dwOldFileSize)
    {
      // Save the new size.
      dwFileSize = dwNewFileSize;

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

#ifndef NO_HANDLER_THREAD
      hHandlerGo = OpenEvent (EVENT_ALL_ACCESS, FALSE, stFileHandlerParams.szGoEvent);

      // Release the threads and then reset the event automatically.
      PulseEvent (hHandlerGo);

      CloseHandle (hHandlerGo);
#endif

#ifdef NO_HANDLER_THREAD

      hFile = CreateFile (szFileName, 
                          GENERIC_READ, 
                          FILE_SHARE_READ | FILE_SHARE_WRITE, 
                          NULL, 
                          OPEN_EXISTING, 
                          FILE_ATTRIBUTE_NORMAL, 
                          NULL);

      if ((hFile == INVALID_HANDLE_VALUE) && !bFileGone)
      {
        ::AfxMessageBox ("Hmmm... Looks like the file has been deleted. I'll wait.");

        bFileGone = TRUE;

        UpdateStatusBar (pView, "Waiting for file...");

        continue;
      }

      if (bFileGone)
      {
        // We're now here, so the file must have come back.
        bFileGone = FALSE;
      }

      // Work out the size of the buffer needed to hold the changed lines.
      // if (bFirst && bIgnoreHotStartup) // Warlock, commented out, changed below
      if (bFirst) // Warlock, still load when bIgnoreHotStartup is on
      {
        // See if the file is larger than the maximum size.
        // If so, only bite off the last few lines to save memory.
        // PP: This logic will need to change for cases where the file has 
        // been truncated and the initial contents are still huge.
        if (dwNewFileSize > dwMaxInitFileSize)
        {
          bLastChunk = TRUE;
          dwBufferSize = dwInitFileSize;
        }
        else
        {
          // Org.
          dwBufferSize = dwNewFileSize + 1;
        }
      }
      else  // Most times - just load the changed lines.
      {
        if (dwNewFileSize > dwOldFileSize)
        {
          dwBufferSize = (dwNewFileSize - dwOldFileSize) + 1;
        }
        else
        {
          // File has been truncated.
  			  LogMessage ("Debug: File has been truncated.");      

          dwBufferSize = dwNewFileSize + 1;

//          dwOldFileSize = 0;
          dwChangeType = CHANGE_FULL;
        }
      }

			LogMessage ("Debug: Allocating %ld bytes for buffer", dwBufferSize);      
      
      pszBuffer = (char*) malloc (dwBufferSize);

      if (pszBuffer == NULL)
      {
        ::MessageBox (AfxGetMainWnd()->GetSafeHwnd(), "Could not allocate memory for file!", 
                      "Tail for Win32", MB_OK | MB_ICONSTOP);

        CloseHandle (hDie);
        if (!bUseTimeout)
        {
          bRtn = FindCloseChangeNotification (fch);
        }
        return 1;
      }

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

      if (bLastChunk)
      {
        DWORD rtn;

    		LogMessage ("Debug: File is larger than %ld, only reading last %ld bytes.", dwMaxInitFileSize, dwBufferSize);      

        rtn = SetFilePointer (hFile, 1 - dwBufferSize, NULL, FILE_END);

        LogMessage ("Debug: File pointer now set to %ld", rtn);
      }
      else
      {
        if (bFirst && (dwNewFileSize > dwMaxInitFileSize))
        {
          LogMessage ("Debug: File is larger than %ld, only reading last %ld bytes.", dwMaxInitFileSize, dwBufferSize);      

          SetFilePointer (hFile, dwBufferSize, NULL, FILE_END);
        }
        else
        {
          if (dwNewFileSize < dwOldFileSize)
          {
            SetFilePointer (hFile, 0, NULL, FILE_BEGIN);
          }
          else
          {
            // Org.
            SetFilePointer (hFile, dwOldFileSize, NULL, FILE_BEGIN);
          }
        }
      }

      bReadOK = ReadFile (hFile, (LPVOID) pszBuffer, dwBufferSize - 1, &dwBytesRead, NULL);

      CloseHandle (hFile);     	

      if (bReadOK)
      {
        if (bLastChunk)
        {
          GetChangedLines (pszBuffer, &pszNewLines, dwOldFileSize, dwBufferSize, &dwChangeType, FALSE);
          bLastChunk = FALSE;
          if (bFirst && (dwNewFileSize > dwMaxInitFileSize)) // Warlock, neat: skip/blank the chopped line.
          {
            pszNewLinesSkip = strchr( pszNewLines, '\n' ); 
            LogMessage ("Debug: Skipping chopped line, jumping forward %ld Bytes.", pszNewLinesSkip - pszNewLines);
            pszNewLines = pszNewLinesSkip;
          }
        }
        else
        {
          if (dwNewFileSize < dwOldFileSize)
          {
            pszNewLines = pszBuffer;
          }
          else
          {
            // Org.
            GetChangedLines (pszBuffer, &pszNewLines, dwOldFileSize, dwNewFileSize, &dwChangeType, FALSE);
          }
        }

        // Clear the window down first.
        if (dwChangeType == CHANGE_FULL)
        {
          ::SetWindowText (hwndEdit, "");
        }

        bMatch = FALSE;

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

      free ((void*) pszBuffer); 

#endif // #ifdef NO_HANDLER_THREAD

    } // if (dwNewFileSize != dwOldFileSize)

    if (!bUseTimeout)
    {
			bRtn = FindNextChangeNotification (fch);

			if (!bRtn)
			{
				LogDebugMessage ("FindNextChangeNotification failed - returned %ld", bRtn);
			}
			else
			{
				LogMessage ("Debug: FindNextChangeNotification returned %ld", bRtn);
			}
		}

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

// Close the notification handle.
  if (!bUseTimeout)
  {
    bRtn = FindCloseChangeNotification (fch);

    if (bRtn)
    {
      LogMessage ("Final FindCloseChangeNotification returned %ld", bRtn);
    }
    else
    {
      LogDebugMessage ("Final FindCloseChangeNotification falied - returned %ld", bRtn);
    }
  }

  CloseHandle (hDie);

  return 0;
}

⌨️ 快捷键说明

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