I have written a file system watcher for our project. Suddenly, it stopped getting events properly. I found out, that after GetOverlappedResult
returns true, the result data are empty and so is bytes returned.
This is how I create file handle for watching a directory:
_directoryHandle = ::CreateFileA("some path", FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
This is how I start watching:
BOOL _watchRequestResult = false;
OVERLAPPED _ovl = { 0 };
static constexpr DWORD ResultDataSize = 20;
FILE_NOTIFY_INFORMATION _resultData[ResultDataSize] = { 0 };
_watchRequestResult = ::ReadDirectoryChangesW(
_directoryHandle,
(LPVOID)_resultData,
ResultDataSize,
TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME,
NULL,
&_ovl,
NULL
);
After I use WaitForMultipleObjects
to wait for the event (there's more than one), this is how I try to fetch the results:
DWORD _ovlBytesReturned;
if (::GetOverlappedResult(GetDirectoryHandle(), &_ovl, &_ovlBytesReturned, FALSE))
{
// Read results
}
But suddenly when I copy file to watched directory the event fires - but I can see in the debugger that _ovlBytesReturned
is 0
and _resultData
also is just zeroes.
Is there any flag I could try changing to fix this? I'm quite sure it used to work, I have no idea what could have changed.
I already tried to change false to true in GetOverlappedResult(GetDirectoryHandle(), &_ovl, &_ovlBytesReturned, FALSE)
, in case there was additional need for waiting. It did not have any effect.
FILE_NOTIFY_INFORMATION
is at least 16 bytes (for 0wchar_t
s long filenames) and you tellReadDirectoryChangesW
that you only have 20 bytes in the buffer (nBufferLength
) - so overlapped results will have problems to fit. Usesizeof(_resultData)
instead ofResultDataSize
for thenBufferLength
- but I think you should increase the size of the buffer a lot. 16*20 bytes isn't much when stuff starts happening.Also note that you can't use
_resultData[ index+1 ]
to get to the next result.FILE_NOTIFY_INFORMATION
is variable length, the nextFILE_NOTIFY_INFORMATION
isNextEntryOffset
bytes ahead (with 0 meaning that you're at the last overlapped result).You also need to create and assign an event handle (
hEvent
) in yourOVERLAPPED
structure in order forGetOverlappedResult()
to work unless you use a completion routine instead - and the directory handle must be open all the time or you'll miss events.Pseudo code:
Here's an example with those things in place.