Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2005.11.06;
Скачать: [xml.tar.bz2];

Вниз

ReadDirectoryChangesW   Найти похожие ветки 

 
iskatel ©   (2005-08-19 20:53) [0]

нарыл тут ф-цию, но не знаю как с ней быть, она, если в синхронном режиме, работает как wait функция, но это неудобно, так как непонятно как прервать поток который стоит на ней (терминировать не подходит, потому что хз, мож в данный момент не стоит, а обрабатывает, тогда будет потеря данных)

в асинхронном же режиме, с использованием overlapped тоже не совсем ясно, судя по справке

For asynchronous completion, you can receive notification in one of three ways:

Using the GetOverlappedResult function. To receive notification through GetOverlappedResult, do not specify a completion routine in the lpCompletionRoutine parameter. Be sure to set the hEvent member of the OVERLAPPED structure to a unique event.
Using the GetQueuedCompletionStatus function. To receive notification through GetQueuedCompletionStatus, do not specify a completion routine in lpCompletionRoutine. Associate the directory handle hDirectory with a completion port by calling the CreateIoCompletionPort function.
Using a completion routine. To receive notification through a completion routine, do not associate the directory with a completion port. Specify a completion routine in lpCompletionRoutine. This routine is called whenever the operation has been completed or canceled while the thread is in an alertable wait state. The hEvent member of the OVERLAPPED structure is not used by the system, so you can use it yourself.

только третий вариант более - менее тянет, можно использовать WaitForMultipleObject, но непонятно на кой икс эта самая CompletionRoutine если мне нужен всего лищь event... у кого нить есть пример? или знает кто нить точно как да что?


 
tesseract ©   (2005-08-20 12:00) [1]

>>она, если в синхронном режиме, работает как wait функция,
wait функции в синхронном режиме не работают
и Callback функцию задавать необязяательно, можно nil
>> WaitForMultipleObject
а WaitForSingleObject  чем не хорош?
>> GetOverlappedResult  -
Там есть таймер ожидания
>> как прервать поток который стоит на ней
Потока на ней не стоит, стоит заявка на обработку сообщения (типа хука )
Для отмены CancelIO должен работать.


 
iskatel ©   (2005-08-30 02:33) [2]

один фиг непонятно, сделал так, не знаю правильно ли...
while((waitresult=WaitForSingleObjectEx(term,600000,true))!=WAIT_OBJECT_0)
           {
           switch (waitresult)
              {
              case WAIT_IO_COMPLETION:
                 {
                 fni=(FILE_NOTIFY_INFORMATION *)buf;
                 nextoffs=fni->NextEntryOffset;
                 do {
                    switch (fni->Action)
                       {
                       case FILE_ACTION_ADDED    :
                       case FILE_ACTION_MODIFIED  :kd.Keep(getname(fni),0);
                       break;
                       case FILE_ACTION_REMOVED :kd.Keep(getname(fni),1);
                       }
                    fni=(FILE_NOTIFY_INFORMATION *)((int)fni+nextoffs);
                    } while (nextoffs);
              }
              break;
              case WAIT_TIMEOUT: kd.ForceKeep();
              }
           Win32Check(ReadDirectoryChangesW( hDir, buf, sizeof(buf),true,FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE,
                    &br, &ov, FileIOCompletionRoutine));

           }

term - это эвент на завершение потока


 
iskatel ©   (2005-08-30 02:36) [3]

блин, пропустил перед всем этим еще один вызов

Win32Check(ReadDirectoryChangesW( hDir, buf, sizeof(buf),true,FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE,
                   &br, &ov, FileIOCompletionRoutine));


 
iskatel ©   (2005-08-30 02:37) [4]

сама FileIOCompletionRoutine у меня ничего не делает, тока выдает эксцепшн если нет данных в буфере

VOID WINAPI FileIOCompletionRoutine(
  DWORD dwErrorCode, // completion code
  DWORD dwNumberOfBytesTransfered, // number of bytes transferred
  LPOVERLAPPED lpOverlapped  // pointer to structure with I/O information  
  )
{
if(!dwNumberOfBytesTransfered) throw Exception("dwNumberOfBytesTransfered ==0");
}


 
tesseract ©   (2005-08-30 09:49) [5]

Функция ждёт появления нового файла, в каталоге fDirectory, при появлениии файла пишет в него.


fHandle:=FindFirstChangeNotification(fDirectory,true,FILE_NOTIFY_CHANGE_FILE_NAME);
 repeat
  r:=WaitForSingleObject(fHandle,500);
  if r=WAIT_OBJECT_0 then
   begin
   if WatchList.Count=0 then continue;
    tCrit.Acquire;
     try
     for i:=0 to WatchList.count-1 do
       begin
       if WatchList.count<=i then break;
       if WatchList[i]="" then continue;
       if FindFirst(fDirectory+WatchList[i],faAnyFile,FileSearch)=0 then
        begin
        repeat
         if (FileSearch.Name=Watchlist[i]) and FileExists(fDirectory+WatchList[i]) then
          begin
          sleep(100);
           AssignFile(fFile,fDirectory+WatchList[i]);
           ReWrite(fFile);
           WriteLn(fFile,WeightList[i]);
           WeightList[i]:="";
           CloseFile(fFile);
         end; // FileSearch
         until FindNext(FileSearch)<>0
       end;// Findfirst
       FindClose(FileSearch);
       end;
    finally
     tcrit.Release;
    end;
   end;// if r=Wait_OBJECT_0
//if not
FindNextChangeNotification(fHandle);//
// then break;
 until Terminated;
FindCloseChangeNotification(fHandle);



 
panov ©   (2005-08-30 10:28) [6]

http://delphimaster.net/view/4-1122522944/


 
iskatel ©   (2005-08-30 14:45) [7]

2 tesseract - это не то, накой х мне каждый раз сканировать каталог, если ReadDirectoryChangesW сразу выдает какой файл изменен, и какие изменения в нем произошли?

2panov - эт тоже не то, в том примере ф-ция работает в синхронном режиме

2ALL - основная проблема в том, что я не представляю как завершить поток, если ф-ция в синхронном режиме, т.к. он приостанавливается на ней, и сообщить ему что пора завершаться невозможно... в асинхронном же можно, и даже тот код что я привел работает, но ощущение кривизны написанного не покидает меня, хотелось бы правильный пример...


 
Игорь Шевченко ©   (2005-08-30 15:47) [8]

iskatel ©   (30.08.05 14:45) [7]


> 2ALL - основная проблема в том, что я не представляю как
> завершить поток, если ф-ция в синхронном режиме, т.к. он
> приостанавливается на ней, и сообщить ему что пора завершаться
> невозможно...


Что я делал:

unit FolderMonitor;

{$IFDEF VER140}
{$WARN SYMBOL_PLATFORM OFF}
{$ENDIF}
interface
uses
 Windows, FolderMonitorThread;

type
 TDirectoryChangeEvent = procedure (const FileName: string;
   Param: LPARAM) of object;

 TFMParamKind = (pkWindow, pkThread);

 TFolderMonitor = class
 private
   FMonitorThread: TMonitorThread;
   FDirectoryHandle: HFILE;
   FDirName: string;
   FBuffer: PChar;
   FParam: LPARAM;
   FOnChange: TDirectoryChangeEvent;
   FStopEvent: THandle;
   FFMParamKind: TFMParamKind;

   procedure NewFile(const FileName: string);
   procedure OnError(const ErrMsg: string);
   procedure ReadFolderContents;
 public
   constructor Create (const ADirName: string; AParam: LPARAM;
     AFMParamKind: TFMParamKind = pkWindow);
   destructor Destroy; override;
   procedure StartMonitor;
   procedure StopMonitor;
   property DirName: string read FDirName;
   property OnChange: TDirectoryChangeEvent read FOnChange write FOnChange;
 end;

implementation
uses
 SysUtils, CommonConsts;

const
 FOLDER_MONITOR_BUFFER_SIZE = 65530;

{ TFolderMonitor }

constructor TFolderMonitor.Create(const ADirName: string; AParam: LPARAM;
 AFMParamKind: TFMParamKind);
begin
 FParam := AParam;
 FFMParamKind := AFMParamKind;
 FDirectoryHandle := INVALID_HANDLE_VALUE;
 FDirName := ExcludeTrailingBackSlash(ADirName);
 FDirectoryHandle := CreateFile(PChar(ADirName), GENERIC_READ,
   FILE_SHARE_READ or FILE_SHARE_DELETE, nil, OPEN_EXISTING,
   FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
 Win32Check(FDirectoryHandle <> INVALID_HANDLE_VALUE);
 FBuffer := AllocMem(FOLDER_MONITOR_BUFFER_SIZE);
 if not Assigned(FBuffer) then
   raise EOutOfMemory.Create("Not enough memory");
end;

destructor TFolderMonitor.Destroy;
begin
 if FStopEvent <> 0 then begin
   CloseHandle(FStopEvent);
   FStopEvent := 0;
 end;
 if Assigned(FBuffer) then begin
   FreeMem(FBuffer);
   FBuffer := nil;
 end;
 if FDirectoryHandle <> INVALID_HANDLE_VALUE then begin
   CloseHandle(FDirectoryHandle);
   FDirectoryHandle := INVALID_HANDLE_VALUE;
 end;
 inherited;
end;

procedure TFolderMonitor.NewFile(const FileName: string);
var
 FullName: string;
begin
 FullName := IncludeTrailingBackslash(FDirName)+FileName;
 if FFMParamKind = pkWindow then
   PostMessage(HWND(FParam), UM_INCOMINGFILE, 0, LPARAM(NewStr(FullName)))
 else
   PostThreadMessage(FParam, UM_INCOMINGFILE, 0, LPARAM(NewStr(FullName)));
end;

procedure TFolderMonitor.OnError(const ErrMsg: string);
begin
 if FFMParamKind = pkWindow then
   PostMessage(HWND(FParam), UM_ERROR, 0, LPARAM(NewStr(ErrMsg)))
 else
   PostThreadMessage(FParam, UM_ERROR, 0, LPARAM(NewStr(ErrMsg)));
end;

procedure TFolderMonitor.ReadFolderContents;
var
 Status: Integer;
 F: SysUtils.TSearchRec;
 OldDirectory: string;
begin
 OldDirectory := GetCurrentDir;
 SetCurrentDir (FDirName);
 try
   Status := FindFirst("*.*", faAnyFile, F);
   try
     while Status = 0 do begin
       if (F.Attr and faDirectory) = 0 then
         NewFile(F.Name);
       Status := FindNext(F);
     end;
   finally
     FindClose(F);
   end;
 finally
   SetCurrentDir(OldDirectory);
 end;
end;

procedure TFolderMonitor.StartMonitor;
begin
 FStopEvent := CreateEvent (nil, true, false, nil);
 Win32Check(FStopEvent <> 0);
 ReadFolderContents;
 FMonitorThread := TMonitorThread.Create (FStopEvent, FDirectoryHandle);
 FMonitorThread.OnNewFile := NewFile;
 FMonitorThread.OnError := OnError;
 FMonitorThread.Resume;
end;

procedure TFolderMonitor.StopMonitor;
begin
 SetEvent (FStopEvent);
 if Assigned(FMonitorThread) then begin
   FMonitorThread.WaitFor;
   FMonitorThread := nil;
 end;
end;

end.


Продолжение следует...


 
Игорь Шевченко ©   (2005-08-30 15:48) [9]

unit FolderMonitorConsts;

interface
uses
 Windows;

type
 FILE_NOTIFY_INFORMATION = packed record
   NextEntryOffset: DWORD;
   Action: DWORD;
   FileNameLength: DWORD;
   FileName: array[0..0] of WideChar;
 end;
 PFILE_NOTIFY_INFORMATION = ^FILE_NOTIFY_INFORMATION;

implementation

end.


Продолжение следует...


 
Игорь Шевченко ©   (2005-08-30 15:49) [10]

unit FolderMonitorThread;

interface
uses
 Windows, Classes;

type
 TOnNewFileEvent = procedure (const FileName: string) of object;
 TOnErrorEvent = procedure (const ErrMsg: string) of object;

 TMonitorThread = class(TThread)
 private
   FEventsToWait: array[0..1] of THandle;
   FDirectoryHandle: THandle;
   FOverlapped: OVERLAPPED;
   FBuffer: PChar;
   FOnNewFile: TOnNewFileEvent;
   FOnError: TOnErrorEvent;
 protected
   procedure Execute; override;
   procedure DoOnNewFile (const FileName: string); dynamic;
   procedure DoOnError (const ErrMsg: string); dynamic;
 public
   constructor Create (AStopEvent, ADirectoryHandle: THandle);
   destructor Destroy; override;
   property OnNewFile: TOnNewFileEvent read FOnNewFile write FOnNewFile;
   property OnError: TOnErrorEvent read FOnError write FOnError;
 end;

implementation
uses
 SysUtils, FolderMonitorConsts, CommonConsts;

const
 FOLDER_MONITOR_BUFFER_SIZE = 65530;

procedure ParseNotificationBuffer (Buffer: PChar; AFiles: TStrings);
var
 PEntry: PFILE_NOTIFY_INFORMATION;
 MoreEntries: Boolean;
begin
 AFiles.Clear;
 PEntry := PFILE_NOTIFY_INFORMATION(Buffer);
 MoreEntries := true;
 while MoreEntries do begin
   if PEntry^.NextEntryOffset = 0 then
     MoreEntries := false;
   if PEntry^.Action = FILE_ACTION_ADDED then
     AFiles.Add(WideCharLenToString(PEntry^.FileName,
       PEntry^.FileNameLength div SizeOf(WideChar)));
   PEntry := PFILE_NOTIFY_INFORMATION(PChar(PEntry) + PEntry^.NextEntryOffset);
 end;
end;
 
{ TMonitorThread }

constructor TMonitorThread.Create(AStopEvent, ADirectoryHandle: THandle);
begin
 inherited Create(true);
 FEventsToWait[0] := AStopEvent;
 FEventsToWait[1] := CreateEvent(nil, true, false, nil);
 FOverlapped.hEvent := FEventsToWait[1];
 FDirectoryHandle := ADirectoryHandle;
 FBuffer := AllocMem(FOLDER_MONITOR_BUFFER_SIZE);
 if not Assigned(FBuffer) then
   SetEvent(AStopEvent);
end;

destructor TMonitorThread.Destroy;
begin
 CloseHandle(FEventsToWait[1]);
 if Assigned(FBuffer) then begin
   FreeMem (FBuffer);
   FBuffer := nil;
 end;
 inherited;
end;

procedure TMonitorThread.DoOnError(const ErrMsg: string);
begin
 if Assigned(FOnError) then
   FOnError(ErrMsg);
end;

procedure TMonitorThread.DoOnNewFile (const FileName: string);
begin
 if Assigned(FOnNewFile) then
   FOnNewFile(FileName);
end;

procedure TMonitorThread.Execute;
var
 BytesRead: DWORD;
 WaitResult: DWORD;
 Files: TStringList;
 I: Integer;
begin
 //Не убили ли нас еще при рождении ?
 if WaitForSingleObject(FEventsToWait[0], 1) <> WAIT_TIMEOUT then
   Exit;
 while not Terminated do begin
   if not ReadDirectoryChangesW (FDirectoryHandle, FBuffer,
       FOLDER_MONITOR_BUFFER_SIZE, false, FILE_NOTIFY_CHANGE_FILE_NAME,
       @BytesRead, @FOverlapped, nil) then begin
     DoOnError(SysErrorMessage(GetLastError));
     Terminate;
     Break; //Невозможно поставить запрос наблюдения каталога в очередь
   end;
   WaitResult := WaitForMultipleObjects(2, @FEventsToWait, false, INFINITE);
   if WaitResult = WAIT_OBJECT_0 then begin
     Terminate;
     Break; //Получен внешний запрос на окончание наблюдения
   end else if WaitResult <> WAIT_OBJECT_0+1 then begin
     DoOnError(SysErrorMessage(GetLastError));
     Terminate;
     Break; //Неизвестная ошибка
   end else begin
     //Закончилась операция чтения изменений в каталоге
     if not GetOverlappedResult (FDirectoryHandle, FOverlapped, BytesRead,
         false) then begin
       DoOnError(SysErrorMessage(GetLastError));
       Terminate;
       Break; //Неизвестная ошибка при попытке получения результата окончания
              //асинхронной операции ввода-вывода
     end;
     // Сейчас в буфере находится BytesRead байт информации об изменениях в
     // каталоге
     Files := TStringList.Create;
     try
       ParseNotificationBuffer (FBuffer, Files);
       for I:=0 to Pred(Files.Count) do
         DoOnNewFile(Files[I]);
     finally
       Files.Free;
     end;
   end;
 end;
end;

end.


Мне требовалось следить только за созданием новых файлов в указанных каталогах


 
iskatel ©   (2005-08-31 10:28) [11]

такой вариант я тоже пробовал, и он тоже работал, но меня смущает то что wait функции не указаны среди возможных вариантов в справке, написано что только при использовании FileIOCompletionRoutine эвент в структуре overlapped не используется системой... хотя непонятно как его использует система, но всеже есть сомнения не грохнется ли все это в один прекрасный момент...


 
Игорь Шевченко ©   (2005-08-31 11:13) [12]

iskatel ©   (31.08.05 10:28) [11]


> но меня смущает то что wait функции не указаны среди возможных
> вариантов в справке


Читай другую справку.


> но всеже есть сомнения не грохнется ли все это в один прекрасный
> момент...


Не грохнется.


 
tesseract ©   (2005-08-31 14:02) [13]

Не советую использовать infinite в ожидании. Подумай как из потока выходить будешь если приспичит.

Не знаю сработает лив такой ситуации CancelIO.


 
Игорь Шевченко ©   (2005-08-31 14:39) [14]

tesseract ©   (31.08.05 14:02) [13]


> Подумай как из потока выходить будешь если приспичит.


А типа код почитать не судьба ? :)


 
tesseract ©   (2005-08-31 21:43) [15]

Я просто всё не просмотрел. Так вот за чем WaitForMultipleObjects.  Интересное решение, хотя и громоздское.


 
имя   (2005-08-31 21:50) [16]

Удалено модератором
Примечание: Вам на ввв.грамота.ру - читать лекции.



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2005.11.06;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.041 c
4-1125559948
Vcoder
2005-09-01 11:32
2005.11.06
Как получить Caption окна?


3-1127653315
Prohodil Mimo
2005-09-25 17:01
2005.11.06
Где-нибудь есть документация по системным таблицам IB FB?


14-1129121709
Сергей Орлик
2005-10-12 16:55
2005.11.06
Delphi 2006 or C++Builder 2006 or C#Builder 2006 = BDS 2006


1-1129547919
WondeRu
2005-10-17 15:18
2005.11.06
ActiveX Form by GUID?


1-1129371372
DelphiLexx
2005-10-15 14:16
2005.11.06
Как в TRadioGroup разместить символ &amp;#948; - дельта?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский