-
> Dennis I. Komarov (23.10.2007 16:00:18) [18]
Какой еще хендл у процедуры?
-
> [19] Сергей М. © (23.10.07 16:16)
Нет, я отвернулся в сторону GetOverLappedResult.
> Ты передал параметром overladded-структуру, в которой поле > hEvent = 0, вместо того чтобы содержать хэндл ивент-объекта.
или в данном случае это будет @OnDirectoryChange? Или ивент-объект не есть процедура?
-
> ивент-объект не есть процедура? >
Конечно не процедура.
ивент-объект создается вызовом CreateEvent()
-
uses
Main;
type
PFileNotifyInformation = ^TFileNotifyInformation;
TFileNotifyInformation = packed record
NextEntryOffset: DWORD;
Action: DWORD;
FileNameLength:DWORD;
FileName: WideChar;
end;
procedure TThreadSend.Execute;
var
FTP: TIdFTP;
SearchRec: TSearchRec;
FindResult: Integer;
ClientCode: string;
FTPLogin: string;
HomeDir: string;
hDir: THandle;
lpBuf: Pointer;
lpOverlapped: POverlapped;
hOnDirChange: THandle;
begin
FreeOnTerminate:=false;
hOnDirChange:=CreateEvent(nil, false, true, PChar('OnChangeDirectory');
hDir := CreateFile ( 'c:\test', GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
if hDir <> INVALID_HANDLE_VALUE then begin
GetMem(lpBuf, 64*1204);
GetMem(lpOverlapped, SizeOf(lpOverlapped));
try
ZeroMemory(lpBuf, SizeOf(lpBuf));
lpOverlapped^.hEvent:=hOnDirChange;
ReadDirectoryChangesW(hDir, lpBuf, SizeOf(lpBuf), true, FILE_NOTIFY_CHANGE_FILE_NAME, nil, lpOverlapped, nil);
finally
FreeMem(lpBuf); FreeMem(lpOverlapped);
end;
end;
end;
end.
Похоже? И как отлавливать теперь это событие?
-
> GetMem(lpOverlapped, SizeOf(lpOverlapped));
SizeOf(lpOverlapped) всегда равен 4, потому что это указатель. Либо разыменовывай его для взятия размера либо объяви переменную TOverlapped, тогда и GetMem не потребуется.
> ZeroMemory(lpBuf, SizeOf(lpBuf));
Здесь та же самая грубая ошибка.
> как отлавливать теперь это событие?
Любой удобной функцией ожидания - WaitForSingleObject, MsgWaitForMultipleObjects и иже с ними.
-
> > GetMem(lpOverlapped, SizeOf(lpOverlapped)); > > ZeroMemory(lpBuf, SizeOf(lpBuf));
Ой мама, это как это я??? Это я не специально :)
-
unit u_send;
interface
uses
Classes, Windows, SysUtils, StrUtils, DateUtils,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdFTP, IniFiles;
type
OnDirectoryChange = procedure(Sender: TObject);
TThreadSend = class(TThread)
private
protected
procedure Execute; override;
end;
var
TCP: TIdTCPClient;
implementation
uses
Main;
type
PFileNotifyInformation = ^TFileNotifyInformation;
TFileNotifyInformation = packed record
NextEntryOffset: DWORD;
Action: DWORD;
FileNameLength:DWORD;
FileName: WideChar;
end;
procedure TThreadSend.Execute;
var
hDir: THandle;
hDirChangeEvent: THandle;
lpBuf: Pointer;
lpOverlapped: POverlapped;
begin
FreeOnTerminate:=false;
hDirChangeEvent:=CreateEvent(nil, false, true, PChar('OnChangeDirecory'));
hDir := CreateFile ( 'c:\test', GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
if hDir <> INVALID_HANDLE_VALUE then begin
GetMem(lpBuf, 64*1024);
GetMem(lpOverlapped, SizeOf(lpOverlapped^));
try
ZeroMemory(lpBuf, 64*1024);
lpOverlapped^.hEvent:=hDirChangeEvent;
ReadDirectoryChangesW(hDir, lpBuf, SizeOf(lpBuf), true, FILE_NOTIFY_CHANGE_FILE_NAME, nil, lpOverlapped, nil);
while not Terminated do begin
if WaitForSingleObject(hDirChangeEvent, 5000) = WAIT_OBJECT_0 then begin
ReadDirectoryChangesW(hDir, lpBuf, SizeOf(lpBuf), true, FILE_NOTIFY_CHANGE_FILE_NAME, nil, lpOverlapped, nil);
end;
end;
finally
FreeMem(lpBuf); FreeMem(lpOverlapped);
end;
end;
end;
end.
??? :)
-
> //Сюда должны попасть если в директории есть изменения
Да.
> //С помощью GetOverLappedResult > //Если при чтении из lpBuf узнаем, что появился > новый файл, тогда отправляем его споследствиями
Да, но при условии что ф-ция вернула True
> // Тут наверное надо обнулить lpBuf
Нафига ?
И вообще заведи себе привычку вызывать WinAPI-функции как функции - возвращаемые ими результаты следует анализировать, ибо от них напрямую зависит дальнейшее правильное ветвление алгоритма.
> WaitForSingleObject(hDirChangeEvent, 5000)
Тебя не смущает, что в течение этих 5 сек. таймаута ожидания сигнала ивента твой поток не будет реагировать на флаг Terminated ?
-
> FreeOnTerminate:=false;
Это лишнее.
> GetMem(lpOverlapped, SizeOf(lpOverlapped^));
Почему бы не сделать переменную Overlapped: TOverlapped локальной или полем класса ? Она ж крохотная, есть ли резон динамически распределять под нее память ?
> CreateEvent(nil, false, true, PChar('OnChangeDirecory'));
Почему true ? Он же у тебя сразу и просигналит, в то время как никаких изменений еще и в помине не было ...
Да и имя ивента не обязательно.
-
> И вообще заведи себе привычку вызывать WinAPI-функции как > функции - возвращаемые ими результаты следует анализировать, > ибо от них напрямую зависит дальнейшее правильное ветвление > алгоритма.
Угу. Это же пока черновик :) Ну мне сейчас хочется разобраться в логике ассинхронного вызова.
> > //Сюда должны попасть если в директории есть изменения > > > Да.
Логично предположить, что при этом запрос в очереди уже отсутствует!?
> > WaitForSingleObject(hDirChangeEvent, 5000) > > > Тебя не смущает, что в течение этих 5 сек. таймаута ожидания > сигнала ивента твой поток не будет реагировать на флаг Terminated > ?
Ну вообще не смущает. Если при остановки вся это бодяга остановится через пять сек. меня это не очень расстроит, хотя сделую 1000 :) Уговорил.
> > GetMem(lpOverlapped, SizeOf(lpOverlapped^)); > > > Почему бы не сделать переменную Overlapped: TOverlapped > локальной или полем класса ? Она ж крохотная, есть ли резон > динамически распределять под нее память ?
А разница?
> > CreateEvent(nil, false, true, PChar('OnChangeDirecory') > ); > > > Почему true ? Он же у тебя сразу и просигналит, в то время > как никаких изменений еще и в помине не было ...
Да, тут не правильно перевел "F1" :)
> Да и имя ивента не обязательно.
Ну пускай будет :)
-
> Логично предположить, что при этом запрос в очереди уже > отсутствует!?
Конечно. Его результаты выбраны из очереди в указанный тобой буфер.
> сделую 1000 :) Уговорил
Да я тебя не уговаривал) Просто есть гораздо более изящные решения для преодоления этой "проблемы")
-
> есть гораздо более изящные решения
Пример? :)
-
WaitFoeMultipleObjects, MsgWaitFoeMultipleObjects
-
> [32] Сергей М. © (25.10.07 12:55)
А в чем принципиальная разница? Чем оно "изящней"?
-
Тем что поток приобретает способность немедленно реагировать не только на твой overlapped-ивент, но и на другие ивенты и/или сообщения.
-
Я думал изящность имено в решении, а не в возможностях
Есть приложение (возможно служба) задача которой транспортировка файлов с диска (не факт что локального) в сеть (FTP-сервер), и аналогично обратное. За каждое из действий отвечает свой поток. Ранее он (который отправлял) просто сканил папки на отправку (FindFirst/Next, ну сам видел). Более на него никаких функций не накладывается (разве что лог ). Другую смысловую нагрузку он не несет. Реакция на Terminated в течении секунды - это даже более чем :) .
Непонятна такая вешь: Мы посавили запрос в очередь. По некоему событию, мы получаем факт, что этот запрос обработался и в указанном месте появились изменения. Данные об изменениях храняться по адресу lpBuf. Далее мы отправляем аналогичный запрос в очередь. 1. На черта нам тогда функция GetOverlappedResult и 2. В то время, пока мы обрабатываем ин-цию об изменениех, происходящие изменения не фиксируются?
-
> 1. На черта нам тогда функция GetOverlappedResult
Мало ли что могло произойти во время исполнения запроса ! Ф-ция как раз и покажет, успешно ли выполнен запрос. А сигнал ивента лишь фиксирует факт завершения (успешного или неуспешного) асинхронной операции.
> пока мы обрабатываем ин-цию об изменениех, происходящие > изменения не фиксируются?
Нет. Поэтому следует как можно быстрей после сигнала ивента принять решение о постановке очередного запроса и лишь потом разбирать результаты текущего выполненного.
-
> Нет. Поэтому следует как можно быстрей после сигнала ивента > принять решение о постановке очередного запроса и лишь потом > разбирать результаты текущего выполненного.
Гм... Но для этого все равно понадобится какое то время, т.е. Получили сигнал события, далее по идее запроса в очереди нет, следует отправить его еще раз, отправлять с тем же указателем на буфер низя - можем потерять его, следовательно, предварительно надо сохранить данные, это потребует некоторого времени, за которое могут произойти изменения, начинаю подумывать о том, что "сканить" диск всетаки надежнее
> Мало ли что могло произойти во время исполнения запроса > ! > Ф-ция как раз и покажет, успешно ли выполнен запрос. > А сигнал ивента лишь фиксирует факт завершения (успешного > или неуспешного) асинхронной операции.
hFile - чего она сюда хочет?
-
> чего она сюда хочет?
hDir твой она хочет.
-
> "сканить" диск всетаки надежнее
С чего бы ?
Explorer, заметь, использует именно ReadDirectoryChangesW
|