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
This commit is contained in:
Jorge Rocha Gualtieri 2020-02-22 18:10:28 -03:00 committed by Don HO
parent e309ec23ec
commit 66893f980f
No known key found for this signature in database
GPG Key ID: 6C429F1D8D84F46E
4 changed files with 90 additions and 2 deletions

View File

@ -35,6 +35,7 @@
#include "VerticalFileSwitcher.h"
#include "functionListPanel.h"
#include "ReadDirectoryChanges.h"
#include "ReadFileChanges.h"
#include <tchar.h>
#include <unordered_set>
@ -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<WPARAM>(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;
}

View File

@ -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;
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <stdio.h>
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#endif
#include <windows.h>
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;
};

View File

@ -394,6 +394,7 @@ copy ..\src\contextMenu.xml ..\bin64\contextMenu.xml
<ClCompile Include="..\src\WinControls\FileBrowser\fileBrowser.cpp" />
<ClCompile Include="..\src\WinControls\ReadDirectoryChanges\ReadDirectoryChanges.cpp" />
<ClCompile Include="..\src\WinControls\ReadDirectoryChanges\ReadDirectoryChangesPrivate.cpp" />
<ClCompile Include="..\src\WinControls\ReadDirectoryChanges\ReadFileChanges.cpp" />
</ItemGroup>
<ItemGroup>
<Image Include="..\src\icons\allChars_off.ico" />
@ -673,6 +674,8 @@ copy ..\src\contextMenu.xml ..\bin64\contextMenu.xml
<ClInclude Include="..\src\WinControls\ReadDirectoryChanges\ReadDirectoryChanges.h" />
<ClInclude Include="..\src\WinControls\ReadDirectoryChanges\ReadDirectoryChangesPrivate.h" />
<ClInclude Include="..\src\WinControls\ReadDirectoryChanges\ThreadSafeQueue.h" />
<ClInclude Include="..\src\WinControls\ReadDirectoryChanges\ReadFileChanges.h" />
</ItemGroup>
<ItemGroup>
<Manifest Include="..\src\notepad++.exe.manifest" />