From 66893f980f13b12faa04ff756b096cd1b815b82f Mon Sep 17 00:00:00 2001 From: Jorge Rocha Gualtieri Date: Sat, 22 Feb 2020 18:10:28 -0300 Subject: [PATCH] Fix "Monitoring" not detecting all file changes issue This patch adds an active monitor to detect changes on files since Windows isn't honoring FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE on ReadDirectoryChangesW correctly if the file writer keep it opened. This solution is based on GNU tail for Windows does. It does it at static void tail_forever (struct File_spec *f, int nfiles, double sleep_interval) on tail.c. Fix #3142, fix #4955, fix #4527, close #7969 --- PowerEditor/src/NppIO.cpp | 13 ++++- .../ReadDirectoryChanges/ReadFileChanges.cpp | 47 +++++++++++++++++++ .../ReadDirectoryChanges/ReadFileChanges.h | 29 ++++++++++++ PowerEditor/visual.net/notepadPlus.vcxproj | 3 ++ 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 PowerEditor/src/WinControls/ReadDirectoryChanges/ReadFileChanges.cpp create mode 100644 PowerEditor/src/WinControls/ReadDirectoryChanges/ReadFileChanges.h diff --git a/PowerEditor/src/NppIO.cpp b/PowerEditor/src/NppIO.cpp index 504b3837..9bcbbf17 100644 --- a/PowerEditor/src/NppIO.cpp +++ b/PowerEditor/src/NppIO.cpp @@ -35,6 +35,7 @@ #include "VerticalFileSwitcher.h" #include "functionListPanel.h" #include "ReadDirectoryChanges.h" +#include "ReadFileChanges.h" #include #include @@ -60,13 +61,16 @@ DWORD WINAPI Notepad_plus::monitorFileOnChange(void * params) CReadDirectoryChanges changes; changes.AddDirectory(folderToMonitor, true, dwNotificationFlags); + CReadFileChanges fChanges; + fChanges.AddFile(fullFileName, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE); + HANDLE changeHandles[] = { buf->getMonitoringEvent(), changes.GetWaitHandle() }; bool toBeContinued = true; while (toBeContinued) { - DWORD waitStatus = ::WaitForMultipleObjects(_countof(changeHandles), changeHandles, FALSE, INFINITE); + DWORD waitStatus = ::WaitForMultipleObjects(_countof(changeHandles), changeHandles, FALSE, 250); switch (waitStatus) { case WAIT_OBJECT_0 + 0: @@ -102,7 +106,11 @@ DWORD WINAPI Notepad_plus::monitorFileOnChange(void * params) } } break; - + case WAIT_TIMEOUT: + if (fChanges.DetectChanges()) { + ::PostMessage(h, NPPM_INTERNAL_RELOADSCROLLTOEND, reinterpret_cast(buf), 0); + } + break; case WAIT_IO_COMPLETION: // Nothing to do. break; @@ -112,6 +120,7 @@ DWORD WINAPI Notepad_plus::monitorFileOnChange(void * params) // Just for sample purposes. The destructor will // call Terminate() automatically. changes.Terminate(); + fChanges.Terminate(); delete monitorInfo; return EXIT_SUCCESS; } diff --git a/PowerEditor/src/WinControls/ReadDirectoryChanges/ReadFileChanges.cpp b/PowerEditor/src/WinControls/ReadDirectoryChanges/ReadFileChanges.cpp new file mode 100644 index 00000000..ee0496cf --- /dev/null +++ b/PowerEditor/src/WinControls/ReadDirectoryChanges/ReadFileChanges.cpp @@ -0,0 +1,47 @@ +#include "ReadFileChanges.h" + + + +CReadFileChanges::CReadFileChanges() +{ + _szFile = NULL; + _dwNotifyFilter = 0; +} + + +CReadFileChanges::~CReadFileChanges() +{ +} + + +BOOL CReadFileChanges::DetectChanges() { + + WIN32_FILE_ATTRIBUTE_DATA fInfo; + BOOL rValue = FALSE; + ::GetFileAttributesEx(_szFile, GetFileExInfoStandard, &fInfo); + + if ((_dwNotifyFilter & FILE_NOTIFY_CHANGE_SIZE) && (fInfo.nFileSizeHigh != _lastFileInfo.nFileSizeHigh || fInfo.nFileSizeLow != _lastFileInfo.nFileSizeLow)) { + rValue = TRUE; + } + + if ((_dwNotifyFilter & FILE_NOTIFY_CHANGE_LAST_WRITE) && (fInfo.ftLastWriteTime.dwHighDateTime != _lastFileInfo.ftLastWriteTime.dwHighDateTime || fInfo.ftLastWriteTime.dwLowDateTime != _lastFileInfo.ftLastWriteTime.dwLowDateTime)) { + rValue = TRUE; + } + + _lastFileInfo = fInfo; + return rValue; +} + +void CReadFileChanges::AddFile(LPCTSTR szFile, DWORD dwNotifyFilter) +{ + _szFile = szFile; + _dwNotifyFilter = dwNotifyFilter; + ::GetFileAttributesEx(szFile, GetFileExInfoStandard, &_lastFileInfo); +} + + +void CReadFileChanges::Terminate() +{ + _szFile = NULL; + _dwNotifyFilter = 0; +} diff --git a/PowerEditor/src/WinControls/ReadDirectoryChanges/ReadFileChanges.h b/PowerEditor/src/WinControls/ReadDirectoryChanges/ReadFileChanges.h new file mode 100644 index 00000000..272fa5dc --- /dev/null +++ b/PowerEditor/src/WinControls/ReadDirectoryChanges/ReadFileChanges.h @@ -0,0 +1,29 @@ +#pragma once + + +#include + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + + +#include + + +class CReadFileChanges +{ +public: + CReadFileChanges(); + ~CReadFileChanges(); + void AddFile(LPCTSTR szDirectory, DWORD dwNotifyFilter); + BOOL DetectChanges(); + void Terminate(); + +private: + LPCTSTR _szFile; + DWORD _dwNotifyFilter; + WIN32_FILE_ATTRIBUTE_DATA _lastFileInfo; + +}; + diff --git a/PowerEditor/visual.net/notepadPlus.vcxproj b/PowerEditor/visual.net/notepadPlus.vcxproj index 80ff92bf..f801b02a 100755 --- a/PowerEditor/visual.net/notepadPlus.vcxproj +++ b/PowerEditor/visual.net/notepadPlus.vcxproj @@ -394,6 +394,7 @@ copy ..\src\contextMenu.xml ..\bin64\contextMenu.xml + @@ -673,6 +674,8 @@ copy ..\src\contextMenu.xml ..\bin64\contextMenu.xml + +