![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблема с ReadDirectoryChangesW
GrEG © (2004-09-20 20:07:00)Доброго всем времени суток.
Возникла необходимость написать простенький контролер изменений содержимого директории. FindFirstChangeNotification с последующим вызовом FindNextChangeNotification не подходит, так как нужно точно знать какие файлы были добавлены/удалены из папки. Решил воспользоваться ReadDirectoryChangesW в синхронном режиме, но сразу возникли две проблемы:
1) как прервать вызов функции?
2) при включеном контролере не удается переименовать файл в контролируемой директории.
С первой проблемой удалось кое-как разобраться, хотя и достаточно грубо: ReadDirectoryChangesW вызывается в отдельном потоке и, при необходимости, поток убивается через TerminateThread (с последующим освобождением ресурсов и Handle'ов).
Со второй проблемой справиться не удалось, MSDN также ситуацию не прояснил. Выяснил, что блокировка возможности переименования файлов происходит после получения Handle контролируемой директории:
hDir:=CreateFile(
PChar(FPath),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_DELETE,
nil,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
0);
Вызов делаю в соответствии с рекомендациями Win32 help и MSDN.
Сталкивался ли кто-нибудь с подобной проблемой?
GrEG (2004-09-21 08:44:00) [1]Всем спасибо. Разобрался. Проблема с переименованием возникает из-за "неправильного" открытия директории. Если вызывать CreateFile c dwShareMode = FILE_SHARE_READ or FILE_SHARE_DELETE, то при попытке переименования файла возникает "Ошибка при совместном доступе к файлу". Если же dwShareMode = FILE_SHARE_READ or FILE_SHARE_DELETE or FILE_SHARE_WRITE, то все работает как и ожидалось - проблема исчезает: можно спокойно копировать, удалять, переименовывать файлы.
Что интересно, в хэлпе описан именно первый способ вызова.
GrEG (2004-09-21 08:00:00) [2]Спасибо, попробую. Я не настаиваю, но ведь придется в любом случае вызывать CreateFile для получения Handle директории. А блокировка возможности переименования происходит именно после этого вызова, еще до первого вызова ReadDirectoryChangesW.
Evgeny V (2004-09-21 06:46:00) [3]Лучше - это использовать асинхронный режим, OVERLAPPED
hDir := CreateFile(
Pchar(DirName),
FILE_LIST_DIRECTORY, FILE_SHARE_READ or FILE_SHARE_DELETE or FILLE_SHARE_WRITE,
nil, OPEN_EXISTING , FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
Тогда в потоке можно ждать сигнала об изменении в директории и например команды закрытия потока
MO.Offset:=0;
MO.OffsetHigh:=0;
MO.hEvent:=REvent;
ReadDirectoryChangesW(hDir,p,8192,false,FILE_NOTIFY_CHANGE_FILE_NAME or
FILE_NOTIFY_CHANGE_LAST_WRITE ,@i,@MO,nil);
где MO -OVERLAPPED структура
Как вариант, создав еще Event в конструкторе потока, например CloseEvent, который устанавливаем в нашем деструкторе потока, общая идея кода будет примерно такой для Execute -
// b - это array [0..1] of Thandle;
b[0]:=CloseEvent;// event закрытия потока
b[1]:=REvent;// event изменения диретории
MO.Offset:=0;
MO.OffsetHigh:=0;
MO.hEvent:=REvent;
hDir := CreateFile(
Pchar(DirName),
FILE_LIST_DIRECTORY, FILE_SHARE_READ or FILE_SHARE_DELETE or FILLE_SHARE_WRITE,
nil, OPEN_EXISTING , FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
ReadDirectoryChangesW(hDir,p,8192,false,FILE_NOTIFY_CHANGE_FILE_NAME or
FILE_NOTIFY_CHANGE_LAST_WRITE ,@i,@MO,nil);
while not terminated do
begin
sig:=WaitForMultipleObjects(2,@b,false,INFINITE);
if sig = (WAIT_OBJECT_0) then // поток должен завершить работу
begin
ResetEvent(CloseEvent);
Terminate;
break;
end;
if sig = WAIT_OBJECT_0+1 then
begin
ResetEvent(REvent);
// делаем что надо по сигналу изменения директории
......
// не забудем снова вызвать ReadDirectoryChangesW
ReadDirectoryChangesW(hDir,p,8192,false,FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME or
FILE_NOTIFY_CHANGE_LAST_WRITE ,@i,@MO,nil);
end;
end;// end While
// не забудем закрыть хэндл при выхоже из Execute,
if hDir <> INVALID_HANDLE_VALUE then
CloseHandle(hDir);
XProger (2004-09-21 02:06:00) [4]А системные сообщения (BROADCAST) в винде такой информации не носят с собой?
jack128 (2004-09-20 22:46:00) [5]Fay © (20.09.04 22:39) [3]
хыарашо.
:-)) Мой диагноз - 2 литра пива :-))
Fay (2004-09-20 22:39:00) [6]не лудше, а хыарашо.
jack128 (2004-09-20 22:22:00) [7]
> С первой проблемой удалось кое-как разобраться, хотя и
> достаточно грубо: ReadDirectoryChangesW вызывается в
> отдельном потоке и, при необходимости, поток убивается
> через TerminateThread (с последующим освобождением
> ресурсов и Handle'ов).
А может лудше в асинхронный режим перейти??
GrEG (2004-09-20 20:09:00) [8]Да, все проверялось на WinXP+SP1 и на Win2k+SP4. Поведение абсолютно идентично.