For me, replacing DirectoryWatcher.Windows.TDirectoryWatcherWindows.StopThread method with
procedure TDirectoryWatcherWindows.StopThread;
var
StopEvent: TEvent;
begin
StopEvent := TEvent.Create(Nil, False, False, FTermEventName);
StopEvent.SetEvent;
Sleep(100);
StopEvent.Free;
end;
masks the problem, but obviously Sleep can't be the correct solution. I almost sure you forgot Thread.WaitFor somewhere.
Also, although it would be better suited as separate issue... anyhow, you could use BindIoCompletionCallback function (or its non-anachronistic *ThreadpoolIo equivalents) on the directory handle, so that ReadDirectoryChangesW would post a task to the thread pool after real completion, instead of blocking wait in the persistent thread.