![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
ReadDirectoryChangesW
Dennis I. Komarov © (2010-10-11 11:59:00)При повторном вызове функции в асинхронном режиме что происходит в системе, если изменений в директории не было? Функция возвращает правду.
Return Values
If the function succeeds, the return value is nonzero. For synchronous calls, this means that the operation succeeded. For asynchronous calls, this indicates that the operation was successfully queued.
Dennis I. Komarov (2010-10-12 14:57:00) [1]
> При большом желании можно получить размер прочитанных данных
Ну дык мало ли. Собственно код [32], а все остальное уже после...
Еще можно добавить GetLastError на всех отлупах, но пока не знаю как будет реализована синхронизация с основным потоком, т.ч. это после...
Игорь Шевченко (2010-10-12 14:45:00) [2]Dennis I. Komarov © (12.10.10 14:07) [36]
> ParseNotificationBuffer (FBuffer, Files);
> не раскрыта :)
учитесь именовать функции :)
> нигде не используется
А зачем ей где-то еще использоваться ? Здесь это лишнее подтвержение корректного окончания операции ввода-вывода. При большом желании можно получить размер прочитанных данных, но так как данные в буфере у ReadDirectiryChangesW имеет самоописательную структуру, то размер в общем-то не имеет значения
Dennis I. Komarov (2010-10-12 14:07:00) [3]
> Игорь Шевченко © (11.10.10 18:35) [33]
Это не краткий :)
Меня интересовало использование ее в конкретном Вашем коде, т.к. кроме
if not GetOverlappedResult (FDirectoryHandle, FOverlapped, BytesRead,
false) then
begin
DoOnError(SysErrorMessage(GetLastError));
Terminate;
Break; //Неизвестная ошибка при попытке получения результата окончания
//асинхронной операции ввода-вывода
end;
нигде не используется, а
ParseNotificationBuffer (FBuffer, Files);
не раскрыта :)
Игорь Шевченко (2010-10-12 10:52:00) [4]Вариант (12.10.10 06:33) [34]
> function fails with ERROR_NOTIFY_ENUM_DIR
Вот по этому признаку и можно разветвить работу - то ли пересканировать каталог вручную, то ли вызвать функцию еще раз. У меня в коде не предусмотрено, а надо бы.
Спасибо за науку :)
Вариант (2010-10-12 06:33:00) [5]
> Игорь Шевченко © (11.10.10 16:09) [26]
Спорим дальше;-)
> Хоть какая задержка
> "When you first call ReadDirectoryChangesW, the system allocates
> a buffer to store change information. This buffer is associated
> with the directory handle until it is closed
Добавим продолжение оттуда же
> If the buffer overflows,
> the changes are discarded and the function fails with ERROR_NOTIFY_ENUM_DIR.
>
Так как буфер не резиновый и если в директории будут происходить изменения и за интервал времени X не будет вызвано следующего ReadDirectoryChangesW, то есть вероятность переполнения буфера и потери событий мониторинга. Функция вернет ошибку.
Игорь Шевченко (2010-10-11 18:35:00) [6]
> Можно краткий комментарий по этой функции?
можно.
http://msdn.microsoft.com/en-us/library/ms683209(VS.85).aspx
Dennis I. Komarov (2010-10-11 17:45:00) [7]
> Игорь Шевченко © (11.10.10 17:15) [31]
>
Вычитывал про нее :)
if dwWaitStatus <> WAIT_TIMEOUT then begin
if GetOverlappedResult(hDir, lpOverlapped, cbReturn, false) then begin
Ptr:=lpBuf;
while PFileNotifyInformation(Ptr).NextEntryOffset <> 0 do begin
GetLocalTime(sTime);
GetMem(FileName, PFileNotifyInformation(Ptr).FileNameLength + 2);
try
lstrcpynW(FileName, PFileNotifyInformation(Ptr).FileName, PFileNotifyInformation(Ptr).FileNameLength div 2 + 1);
// Обрабатываем что произошло...
// Отправляем основному потоку (если надо)
finally
FreeMem(FileName);
end;
Inc(Cardinal(Ptr), PFileNotifyInformation(Ptr).NextEntryOffset);
end;
if not ReadDirectoryChangesW(hDir, lpBuf, BufSize, true, FILE_NOTIFY_CHANGE, @cbReturn, @lpOverlapped, nil) then
Exit;
end;
end;
Можно краткий комментарий по этой функции?
Игорь Шевченко (2010-10-11 17:15:00) [8]
> используется GetOverlappedResult
а почему ты не используешь ?
Dennis I. Komarov (2010-10-11 16:23:00) [9]
> Игорь Шевченко © (11.10.10 16:12) [29]
dwWaitStatus := WaitForSingleObject(lpOverlapped.hEvent, 1000);
vs
WaitResult := WaitForMultipleObjects(2, @FEventsToWait, false, INFINITE);
+ используется GetOverlappedResult
Игорь Шевченко (2010-10-11 16:12:00) [10]Dennis I. Komarov © (11.10.10 16:10) [28]
Ты видишь, в чем разница между твоим и моим кодом ?
Dennis I. Komarov (2010-10-11 16:10:00) [11]
> Вариант (11.10.10 15:50) [24]
да, немного недопоняли :)
Развлекайтесь дальше: :)
unit dirchange;
interface
uses
Classes, Windows, SysUtils;
const
BufSize: Integer = 16 * 1024;
type
PFileNotifyInformation = ^TFileNotifyInformation;
TFileNotifyInformation = record
NextEntryOffset: DWORD;
Action: DWORD;
FileNameLength:DWORD;
FileName: array [0..255] of WideChar;
end;
TThreadDirChange = class(TThread)
private
Directory: string;
FILE_NOTIFY_CHANGE: Cardinal;
protected
procedure Execute; override;
end;
implementation
procedure TThreadDirChange.Execute;
var
lpOverlapped: OVERLAPPED;
dwWaitStatus: Cardinal;
hDir: THandle;
lpBuf, Ptr: Pointer;
cbReturn: Cardinal;
FileName: PWideChar;
sTime: _SYSTEMTIME;
begin
hDir:=CreateFile(PAnsiChar(IncludeTrailingBackSlash(Directory)), GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
nil, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
try
if hDir <> INVALID_HANDLE_VALUE then begin
ZeroMemory(@lpOverlapped, SizeOf(TOverlapped));
lpOverlapped.hEvent := CreateEvent(nil, true, false, nil);
GetMem(lpBuf, BufSize);
try
ZeroMemory(lpBuf, BufSize);
if ReadDirectoryChangesW(hDir, lpBuf, BufSize, true, FILE_NOTIFY_CHANGE, @cbReturn, @lpOverlapped, nil) then begin
while not Terminated do begin
dwWaitStatus := WaitForSingleObject(lpOverlapped.hEvent, 1000);
if dwWaitStatus <> WAIT_TIMEOUT then begin
Ptr:=lpBuf;
while PFileNotifyInformation(Ptr).NextEntryOffset <> 0 do begin
GetLocalTime(sTime);
GetMem(FileName, PFileNotifyInformation(Ptr).FileNameLength + 2);
try
lstrcpynW(FileName, PFileNotifyInformation(Ptr).FileName, PFileNotifyInformation(Ptr).FileNameLength div 2 + 1);
// Обрабатываем что произошло...
// Отправляем основному потоку (если надо)
finally
FreeMem(FileName);
end;
Inc(Cardinal(Ptr), PFileNotifyInformation(Ptr).NextEntryOffset);
end;
if not ReadDirectoryChangesW(hDir, lpBuf, BufSize, true, FILE_NOTIFY_CHANGE, @cbReturn, @lpOverlapped, nil) then
Exit;
end;
end;
end;
finally
FreeMem(lpBuf);
end;
end;
finally
CloseHandle(hDir);
end;
end;
end.
Игорь Шевченко (2010-10-11 16:10:00) [12]мой пост [26] к Вариант (11.10.10 15:45) [23]
Игорь Шевченко (2010-10-11 16:09:00) [13]
> Там это будет только если будет большая задержка в DoOnNewFile,
> чего я думаю там нет
Хоть какая задержка
"When you first call ReadDirectoryChangesW, the system allocates a buffer to store change information. This buffer is associated with the directory handle until it is closed
....
Directory changes that occur between calls to this function are added to the buffer and then returned with the next call"
Вариант (2010-10-11 15:57:00) [14]
> Dennis I. Komarov © (11.10.10 15:45) [22]
> Тогда код в [8] также не приведет к потери данных (если
> ZeroMemory вынести из цикла...
>
Приведут и это легко эмулировать в отладчике, причем каждый раз. В реальной ситуации это необязательно повторится, но вероятность есть все равно.
> И пляски со вторым буфером не нужны..
А вот второй буфер и не обязателен, если действия выполняются быстро, но работа по обработке с буфером должна завершиться до повторного вызова ReadDirectoryChangesW, иначе потери так же возможны.
PS: Если что-то непонятно или есть желание спорить, то завтра я уже в дороге домой:-)
Вариант (2010-10-11 15:50:00) [15]
> Dennis I. Komarov © (11.10.10 15:45) [22]
Я так понял, что я или плохо объяснил или что-то ты не так понял. Еще раз возвращаясь к твоем у самому первому вопросу
> Dennis I. Komarov © (11.10.10 11:59)
> При повторном вызове функции в асинхронном режиме что происходит
> в системе, если изменений в директории не было? Функция
> возвращает правду.
Хотя система и скажет тебе, что все ок (а может и не скажет), но вызывать повторно ReadDirectoryChangesW не дождавшись завершения предыдущего вызова по hEvent в твоем случае нельзя - это может привести к потере изменений. Если же ты получил сработку hEvent, то доступ к твоему буферу разрешен. Изменения продолжают писаться в другой "системный" буфер, из которого они передадутся в твой буфер только при следующем вызове ReadDirectoryChangesW...
Вариант (2010-10-11 15:45:00) [16]
> Dennis I. Komarov © (11.10.10 15:38) [20]
> т.е. теоретически (как заметил Вариант) во время обработки
> буфера прошедшие изменения будут проигнорированы.
Я вот такого не говорил прилагательно к
> Игорь Шевченко © (11.10.10 15:16) [18]
Там это будет только если будет большая задержка в DoOnNewFile, чего я думаю там нет. И в этом коде нет повторного вызова ReadDirectoryChangesW, когда нет завершения еще певрого вызова...., что было в твоем первом варианте
Dennis I. Komarov (2010-10-11 15:45:00) [17]
> Вариант (11.10.10 15:37) [19]
Тогда код в [8] также не приведет к потери данных (если ZeroMemory вынести из цикла... И пляски со вторым буфером не нужны...
Игорь Шевченко (2010-10-11 15:42:00) [18]Dennis I. Komarov © (11.10.10 15:38) [20]
> т.е. теоретически (как заметил Вариант) во время обработки
> буфера прошедшие изменения будут проигнорированы...
Не будут
Dennis I. Komarov (2010-10-11 15:38:00) [19]
> Игорь Шевченко © (11.10.10 15:16) [18]
Ну, получим подобное, т.е. если получаем событие "есть изменения" - начинаем обрабатывать полученный буфер и только после выполняется ReadDir..W, т.е. теоретически (как заметил Вариант) во время обработки буфера прошедшие изменения будут проигнорированы...
Вариант (2010-10-11 15:37:00) [20]
> Dennis I. Komarov © (11.10.10 15:10) [17]
> Во время выполнения копирования могут произойти изменения
> в директории. Получается они будут потеряны :(
Нет. Во время первого вызова ReadDirectoryChangesW распределяет в системе буфер, для записи изменений. Куда и продолжают писаться измененияв директории между вызовами функции. Потери могут быть, если буфер будет переполнен. Что возможно при больших паузах между вызовами
ReadDirectoryChangesW, которая и "чистит" этот буфер.
Из MSDN
>
>
> When you first call ReadDirectoryChangesW, the system allocates
> a buffer to store change information. This buffer is associated
> with the directory handle until it is closed and its size
> does not change during its lifetime. Directory changes that
> occur between calls to this function are added to the buffer
> and then returned with the next call. If the buffer overflows,
> the changes are discarded and the function fails with ERROR_NOTIFY_ENUM_DIR.
>
>