Форум: "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