Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > ReadDirectoryChangesW


Автор: Maverick 7.4.2004, 14:56
Posol.... Вы упомянули ReadDirectoryChangesW для слежения за каталогом... У меня в некоторых прогах такое наворочено в этих целях, что вообще-то стало стыдно.... Help у меня на эту функцию не отзывается... Она что в какую-то библиотеку входит стороннюю, или апишная? Да и как-то я механизм даже понять не могу....

Нельзя ли по-подробнее.... Заранее благодарен....

Автор: Susel 7.4.2004, 16:50
Серж, запусти Пуск|Программы|Borland Delphi 6.0|Help|MS SDK Help Filses|Win32 Programmer's Reference...
Мог бы просто позвонить или зайти... biggrin.gif biggrin.gif biggrin.gif

Автор: Maverick 7.4.2004, 17:22
Susel, спасибо..... но ты же Дельфи не любишь... не хотел мучить....

The ReadDirectoryChangesW function returns information describing the changes occurring within a directory.

Это я подозревал.... Но как ей пользоваться? Ведь Posol упоминал, что она сама следить будет.... Все равно не понимаю как, ведь это не событие, оно не возникает само от факта изменения в каталоге.... Значит ее все-таки надо запускать с промежутком во времени....? в чем тогда выйгрыш?

кому интересно начало, то оно вот здесь.... в конце....
http://forum.vingrad.ru/index.php?showtopic=20799

Автор: p0s0l 7.4.2004, 21:46
Сам когда-то пробовал, щас довёл до ума...
Там ReadDirectoryChangesW в потоке живёт (для удобства)...

Вот он: zip 5 кб...

Добавлено @ 21:55
Если влом качать, то вот само слежение:
Код

var
 Dir : string = 'C:\'; \\ имя каталога
 SubDirs : boolean; \\ следить за подкаталогами ?

type
 FILE_NOTIFY_INFORMATION = record
   NextEntryOffset: DWORD;
   Action: DWORD;
   FileNameLength: DWORD;
   FileName: array [0..0] of WCHAR;
 end;

var
 hDir : THandle;
 Buf : pointer;
 Returned, BufSize : dword;
 adr : DWORD;
 fni : ^FILE_NOTIFY_INFORMATION absolute adr;
 s : string;
 ws : WideString;

const
 wcs = SizeOf(WideChar); // = 2
 FILE_LIST_DIRECTORY       = ($0001); // directory

begin
 hDir := CreateFile(PChar(Dir),
                    FILE_LIST_DIRECTORY,
                    FILE_SHARE_READ or FILE_SHARE_DELETE,
                    nil,
                    OPEN_EXISTING,
                    FILE_FLAG_BACKUP_SEMANTICS,
                    0);

 if hDir = INVALID_HANDLE_VALUE then Exit;

 BufSize := 16*1024*1024; // 16 mb
 GetMem(Buf, BufSize);

 repeat
   if ReadDirectoryChangesW(hDir, Buf, BufSize, SubDirs,
      FILE_NOTIFY_CHANGE_FILE_NAME or
      FILE_NOTIFY_CHANGE_DIR_NAME or
      FILE_NOTIFY_CHANGE_ATTRIBUTES or
      FILE_NOTIFY_CHANGE_SIZE or
      FILE_NOTIFY_CHANGE_LAST_WRITE or
      FILE_NOTIFY_CHANGE_LAST_ACCESS or
      FILE_NOTIFY_CHANGE_CREATION or
      FILE_NOTIFY_CHANGE_SECURITY, @Returned, nil, nil) then
   begin
     Adr := Cardinal(Buf);
     while Adr < (Cardinal(Buf) + Returned) do
     begin
       case fni^.Action of
         FILE_ACTION_ADDED            : s := 'Added';
         FILE_ACTION_REMOVED          : s := 'Removed';
         FILE_ACTION_MODIFIED         : s := 'Modified';
         FILE_ACTION_RENAMED_OLD_NAME : s := 'Renamed from';
         FILE_ACTION_RENAMED_NEW_NAME : s := 'Renamed to';
         else s := '0x' + IntToHex(fni^.Action, 8);
       end;
       SetLength(ws, fni^.FileNameLength div wcs);
       Move(fni^.FileName, ws[1], fni^.FileNameLength);
       ListBox1.Items.Add(s + ' "' + ws + '"');
       Inc(adr, fni^.FileNameLength - wcs + SizeOf(fni^));
     end;
   end;
 until False;
 CloseHandle(hDir);
 FreeMem(Buf);
end;


Цитата
Все равно не понимаю как, ведь это не событие, оно не возникает само от факта изменения в каталоге...

Да нет вообще-то, при изменении содержимого каталога генерятся события, их можно дождаться с помощью FindFirstChangeNotification / FindNextChangeNotification + WaitFor*Object...
А ReadDirectoryChangesW сама дожидается следующего изменения, при этом выполнение потока приостанавливается.
Правда, можно в CreateFile указать FILE_FLAG_OVERLAPPED, тогда ReadDirectoryChangesW будет асинхронной... Ну это кому как удобнее...

Автор: Maverick 8.4.2004, 09:41
Спасибо огромное.... Сколько иногда ненужной работы делаем.... по незнанию.... Сколько раз убеждаюсь....

Автор: 2fank 3.4.2008, 14:16
А как следить за сетевой папкой?

Автор: dma 3.4.2008, 18:48
указать сетевой путь, и будет следить за сетевой папкой

Автор: Alexeis 3.4.2008, 20:54
  В принципе, директория это тоже файл, но будет ли это работать для сетевых? Ведь на своем диске можно сделать придумать событие для драйвера HDD, которое буде оповещать о таких вещах, а как такое сделать для чужого драйвера?

Автор: 2fank 3.4.2008, 22:30
Цитата(dma @ 3.4.2008,  18:48)
указать сетевой путь, и будет следить за сетевой папкой

указал "\\mycomp\1" - не работает

Updated
оказывается нужно сменить
Код

BufSize := 16*1024*1024; // 16 mb

на
Код

BufSize := 64*1024;


Цитата

ReadDirectoryChangesW fails with ERROR_INVALID_PARAMETER when the buffer length is greater than 64 KB and the application is monitoring a directory over the network. This is due to a packet size limitation with the underlying file sharing protocols: Server Message Block (SMB) on Windows Me/98/95, and Common Internet File System (CIFS) on Windows Server 2003/XP/2000.

Автор: corpsehunter 29.7.2008, 10:26
а если вешаешь это слежение на флэху, то она блокирует ее и не дает извлечь. Можно это как-нибудь исправить?

Автор: Riply 30.7.2008, 07:43
Цитата(corpsehunter @  29.7.2008,  10:26 Найти цитируемый пост)
а если вешаешь это слежение на флэху, то она блокирует ее и не дает извлечь


Ничего удивительного: у нас есть открытые Handl`ы, вот система и говорит, что работа с флешкой не закончена. 
Если я не ошибаюсь, то единственно возможное решение: отлавливать "попытку безопасного отключения" и снимать слежение.

Автор: corpsehunter 30.7.2008, 13:03
Цитата(Riply @ 30.7.2008,  07:43)
Если я не ошибаюсь, то единственно возможное решение: отлавливать "попытку безопасного отключения" и снимать слежение.

ну это логично, и мне это же приходило в голову... а как его отлавливать? оО

Автор: zhefran 17.9.2008, 12:14
В коде p0s0l, есть один нюанс из-за которого нельзя переименовать файлы и папки в корне каталога.
Там нужно добавить при создание хэндла такое:
 
Код

hDir := CreateFile(PChar(Dir),
                     FILE_LIST_DIRECTORY,
                     FILE_SHARE_READ or FILE_SHARE_DELETE or FILE_SHARE_WRITE, //Добавлено or FILE_SHARE_WRITE.
                     nil,
                     OPEN_EXISTING,
                     FILE_FLAG_BACKUP_SEMANTICS,
                     0);

Автор: zhefran 23.9.2008, 11:30
Нашел при исполнения кода еще один нюанс! При попытке остановки роботы потока кнопкой, поток все равно продолжает свою роботу!!! smile 

Автор: Qu1nt 23.9.2008, 13:11
Могу предположить:
ThreadForScan:
Код

  until False or Terminated; // чтобы цикл знал, когда ему необходимо остановиться)

DlgMain:
Код

  Thread1 := TScanThread.Create(False, edDir.Text, cbSubDirs.Checked);
  Thread1.FreeOnTerminate := True; // во избежание утечек памяти = )

Автор: zhefran 23.9.2008, 13:25
Не работает!!! :(

Автор: Qu1nt 23.9.2008, 13:31
Я скачал пример с первой странички. Изменил строчку (102-ю):
Код

  until False or Terminated; // добавил Terminated

У меня работает.

Автор: zhefran 23.9.2008, 16:24
У меня уже тоже, но все равно - после нажатия на кнопку "Стоп" еще одно (только одно) действие проскакивает!

Автор: Qu1nt 23.9.2008, 19:45
Это естественно, поток то не сразу завершается. Как вариант, можно поставить проверку в цикле, перед добавлением элементов в список.
Код

  if Terminated then
    Break;


Автор: zhefran 24.9.2008, 10:22
Работа! Спасибо! smile  smile 

Автор: corpsehunter 19.2.2009, 15:01
Цитата(zhefran @ 23.9.2008,  11:30)
Нашел при исполнения кода еще один нюанс! При попытке остановки роботы потока кнопкой, поток все равно продолжает свою роботу!!! smile

дааа-даа, тот же косяк заметил
а вот это:

Код

  until False or Terminated; // чтобы цикл знал, когда ему необходимо остановиться)


нифига не помогает почему-то... и FreeOnTerminate тоже..

Автор: MetalFan 19.2.2009, 15:09
Цитата(corpsehunter @  19.2.2009,  15:01 Найти цитируемый пост)
  until False or Terminated; // чтобы цикл знал, когда ему необходимо остановиться)

может
Код

  until false or false or Terminated

 поможет? smile

Добавлено через 3 минуты и 21 секунду
а по теме. чтобы не зависало, вызывайте ReadDirectoryChangesW в асинхронном режиме

Автор: corpsehunter 20.2.2009, 14:36
Цитата(MetalFan @ 19.2.2009,  15:09)

может
Код

  until false or false or Terminated

 поможет? smile

это тоже самое=)) нее, не поможет, даж пробовать не буду=))


Цитата(MetalFan @ 19.2.2009,  15:09)
а по теме. чтобы не зависало, вызывайте ReadDirectoryChangesW в асинхронном режиме

в смысле? это как?

Автор: alberologic 28.10.2011, 13:21
А можно как нибудь вместо "c:\" подставить "Мой компьютер"
Чтобы мониторить все диски?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)