Господа!
Подскажите пожалуйста срочно.
Вот есть код:
hDir := CreateFile ('C:\2',GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE
or FILE_SHARE_DELETE,nil,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0);
if hDir = INVALID_HANDLE_VALUE
then begin ShowMessage(SysErrorMessage(GetLastError)); exit; end;
GetMem(lpBuf,BUF_SIZE);
repeat
ZeroMemory(lpBuf,BUF_SIZE);
if not ReadDirectoryChangesW(hDir,lpBuf,BUF_SIZE,true,FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_LAST_WRITE,@cbReturn,nil,nil)
then Break;
Ptr:=lpBuf;
repeat
GetMem(FileName,PFileNotifyInformation(Ptr).FileNameLength+2);
ZeroMemory(FileName,PFileNotifyInformation(Ptr).FileNameLength+2);
lstrcpynW(FileName,PFileNotifyInformation(Ptr).FileName,
PFileNotifyInformation(Ptr).FileNameLength div 2+1);
FreeMem(FileName);
case PFileNotifyInformation(Ptr).Action of
FILE_ACTION_ADDED : Файл был создан;
FILE_ACTION_REMOVED : Файл был удален;
FILE_ACTION_MODIFIED : Файл был изменен;
until false;
until false;
FreeMem(lpBuf);
PFileNotifyInformation(Ptr).FileName -delphi говорит не знаю!
в чём проблема? может я чего не подключил?
Заранее спасибо.
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
10-03-2008 16:36 | Комментарий к предыдущим ответам
10-03-2008 10:06 | Комментарий к предыдущим ответам
Небольшой модинг:
uses
Windows, Classes, SysUtils;
const
FILE_NOTIFY_CHANGE = 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;
procedure TFileThread.Stack;
var
hDir, cbReturn: dword;
lpBuf: pointer;
Ptr: PFileNotifyInformation;
FileName: PWideChar;
OldName: WideString;
const
BUF_SIZE = 256;
begin
if FDir = '' then Exit;
hDir:=CreateFile(PChar(FDir+PathDelim), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE
or FILE_SHARE_DELETE, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if hDir = INVALID_HANDLE_VALUE then Exit;
GetMem(lpBuf, BUF_SIZE);
ZeroMemory(lpBuf, BUF_SIZE);
if(ReadDirectoryChangesW(hDir, lpBuf, BUF_SIZE, FChild, FILE_NOTIFY_CHANGE, @cbReturn, nil, nil))
or (cbReturn <> 0) then
begin
Ptr := lpBuf;
OldName :='';
repeat
GetMem(FileName,Ptr^.FileNameLength+2);
ZeroMemory(FileName,Ptr^.FileNameLength+2);
LstrcpynW(FileName,addr(Ptr^.FileName),Ptr.FileNameLength div 2+1);
case Ptr.Action of
FILE_ACTION_ADDED: DoCreate(FDir+PathDelim+FileName);
FILE_ACTION_REMOVED: DoDelete(FDir+PathDelim+FileName);
FILE_ACTION_MODIFIED: DoRefresh(FDir+PathDelim+FileName);
FILE_ACTION_RENAMED_OLD_NAME: OldName := FileName;
FILE_ACTION_RENAMED_NEW_NAME: DoRename(FDir+PathDelim+OldName, FDir+PathDelim+FileName);
end;
FreeMem(FileName);
if Ptr^.NextEntryOffset = 0 then break else
Inc(Cardinal(Ptr),Ptr^.NextEntryOffset);
until false;
end;
FreeMem(lpBuf);
CloseHandle(hDir);
end;
procedure TFileThread.Execute;
begin
while not Terminated do
begin
if FSync then Synchronize(Stack) else Stack;
DoChange;
end;
end;
procedure TFileThread.DoChange;
begin
if Assigned(FOnChange) then FOnChange(Self);
end;
procedure TFileThread.DoCreate(const FileName: string);
begin
if Assigned(FOnCreate) then FOnCreate(Self, FileName);
end;
procedure TFileThread.DoDelete(const FileName: string);
begin
if Assigned(FOnDelete) then FOnDelete(Self, FileName);
end;
procedure TFileThread.DoRefresh(const FileName: string);
begin
if Assigned(FOnRefresh) then FOnRefresh(Self, FileName);
end;
procedure TFileThread.DoRename(const FileName: string; const NewFileName: string);
begin
if Assigned(FOnRename) then FOnRename(Self, FileName, NewFileName);
end;
Вот такой код я использую в с воей программе, надеюсь он правильный...
unit ShellFileChange;
{$WARNINGS OFF}
{$HINTS OFF}
interface
uses
Windows, Classes, SysUtils;
const
FILE_NOTIFY_CHANGE = 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;
procedure TFileThread.Stack;
var
hDir, cbReturn: dword;
lpBuf: pointer;
Ptr: PFileNotifyInformation;
FileName: PWideChar;
OldName: WideString;
const
BUF_SIZE = 256;
begin
hDir:=CreateFile(PChar(FPath), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE
or FILE_SHARE_DELETE, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if hDir = INVALID_HANDLE_VALUE then Exit;
GetMem(lpBuf, BUF_SIZE);
ZeroMemory(lpBuf, BUF_SIZE);
if(ReadDirectoryChangesW(hDir, lpBuf, BUF_SIZE, true, FILE_NOTIFY_CHANGE, @cbReturn, nil, nil))
or (cbReturn <> 0) then
begin
Ptr := lpBuf;
OldName :='';
repeat
GetMem(FileName,Ptr^.FileNameLength+2);
ZeroMemory(FileName,Ptr^.FileNameLength+2);
LstrcpynW(FileName,addr(Ptr^.FileName),Ptr.FileNameLength div 2+1);
case Ptr.Action of
FILE_ACTION_ADDED: DoCreate(FPath+FileName);
FILE_ACTION_REMOVED: DoDelete(FPath+FileName);
FILE_ACTION_MODIFIED: DoRefresh(FPath+FileName);
FILE_ACTION_RENAMED_OLD_NAME: OldName := FileName;
FILE_ACTION_RENAMED_NEW_NAME: DoRename(FPath+OldName, FPath+FileName);
end;
FreeMem(FileName);
if Ptr^.NextEntryOffset = 0 then break;
Inc(integer(Ptr),Ptr^.NextEntryOffset);
until false;
end;
FreeMem(lpBuf);
CloseHandle(hDir);
end;
procedure TFileThread.Execute;
begin
while not Terminated do
begin
Stack;
DoChange;
end;
end;
procedure TFileThread.DoChange;
begin
if Assigned(FOnChange) then FOnChange(Self);
end;
procedure TFileThread.DoCreate(const FileName: string);
begin
if Assigned(FOnCreate) then FOnCreate(Self, FileName);
end;
procedure TFileThread.DoDelete(const FileName: string);
begin
if Assigned(FOnDelete) then FOnDelete(Self, FileName);
end;
procedure TFileThread.DoRefresh(const FileName: string);
begin
if Assigned(FOnRefresh) then FOnRefresh(Self, FileName);
end;
procedure TFileThread.DoRename(const FileName: string; const NewFileName: string);
begin
if Assigned(FOnRename) then FOnRename(Self, FileName, NewFileName);
end;
Можно сделать что то бодобное, но сразу говорю - что это только способ - он нагружает ЦП на 50%,
и проверяет только имеющиеся пути. Я писал этот код для своей программы, но
не стал его использовать.
TFileChange = class(TThread)
public
procedure DoWork;
procedure Execute; override;
end;
if Item.FileAttr and faDirectory = 0 then // Если это файл
begin
if Not FileExists(Item.FileName) then // Если файла нет то удаляем его из списка
begin
Form1.ListView_Delete(I);
Break;
end
else
begin
FindFirst(Item.FileName, faAnyFile, SearchRec); // иначе обновляем
SHGetFileInfo(PChar(Item.FileName), faAnyFile, SHFileInfo, SizeOf(TSHFileInfo), SHGFI_TYPENAME);
if (Item.FileAttr <> SearchRec.Attr) or
(Item.FileSize <> SearchRec.Size) or
(Item.FileDate <> FileDateToDateTime(SearchRec.Time)) or
(Item.FileTime <> FileDateToDateTime(SearchRec.Time)) or
(Item.FileType <> SHFileInfo.szTypeName) then
begin
Form1.ListView_Refresh(Item, SearchRec.Size, SearchRec.Attr, FileDateToDateTime(SearchRec.Time),
FileDateToDateTime(SearchRec.Time),true);
end;
FindClose(SearchRec);
end;
end
else
begin
if Not DirectoryExists(Item.FileName) then // Если директория не существует то удаляем из списка
begin
Form1.ListView_Delete(I);
Break;
end
else
begin
FindFirst(Item.FileName, faAnyFile, SearchRec); // иначе обновляем
SHGetFileInfo(PChar(Item.FileName), faAnyFile, SHFileInfo, SizeOf(TSHFileInfo), SHGFI_TYPENAME);
if (Item.FileAttr <> SearchRec.Attr) or
(Item.FileSize <> SearchRec.Size) or
(Item.FileDate <> FileDateToDateTime(SearchRec.Time)) or
(Item.FileTime <> FileDateToDateTime(SearchRec.Time)) or
(Item.FileType <> SHFileInfo.szTypeName) then
begin
Form1.ListView_Refresh(Item, SearchRec.Size, SearchRec.Attr, FileDateToDateTime(SearchRec.Time),
FileDateToDateTime(SearchRec.Time),true);
end;
FindClose(SearchRec);
end;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FileChange:=TFileChange.Create(false);
FileChange.Priority:=tpLowest;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FileChange.Terminate;
FileChange.Free;
end;
Хочу снова поднять тему...
Код работает...добавление файлов фиксируется точно, а вот удаление - нет.
Точнее так: удаляем до 6ти файлов - фиксируются все, а если удалить больше файлов - фиксируется только первый удаленный.
Всю голову сломал...
10-03-2007 12:17 | Комментарий к предыдущим ответам
В догонку: если вместо
ReadDirectoryChangesW(hDir,lpBuf,BUF_SIZE,true,FILE_NOTIFY_CHANGE_FILE_NAME
or FILE_NOTIFY_CHANGE_LAST_WRITE,@cbReturn,nil,nil))
написать это:
ReadDirectoryChangesW(hDir,lpBuf,BUF_SIZE,true,FILE_NOTIFY_CHANGE_FILE_NAME,@cbReturn,nil,nil)) то всё ловится чётко...
10-03-2007 12:04 | Вопрос к автору: запрос дополнительной информации
У меня вопросик по коду, преведённому товарищем Python'ом:
вся эта конструкция работает...только одно НО :
Если, допустим, скопировать откудато штук 100 файлов(может даже меньше) в "мониторимый" каталог, то ReadDirectoryChangesW поймает только 2 или 3 файла(когда как) и вылетит из циклов...
В чём может быть проблема...или ОНО так и должно работать?
>>> until false;
И хорошо, что программа не откомпилировалась. Потому что в нашем случае такая конструкция просто приводят к зависанию программы. Потому что во вложенном цикле нет команды break или exit, приводящих к завершению работы!
А PFileNotifyInformation просто нигде не объявлен (во всяком случае, я нигде не нашел его объявления). Поэтому его придется объявлять руками. Вот полный код:
procedure TForm1.Button1Click(Sender: TObject);
Const BUF_SIZE=256;
Type PFileNotifyInformation=^TFileNotifyInformation;
TFileNotifyInformation=packed record
NextEntryOffset:dword;
Action:dword;
FileNameLength:dword;
FileName:WideChar;
end;
var hDir,cbReturn:dword;
lpBuf:pointer;
Ptr:PFileNotifyInformation;
FileName:PWideChar;
OldName:widestring;
begin
hDir:=CreateFile('E:\EXE',GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE
or FILE_SHARE_DELETE,nil,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0);
if hDir=INVALID_HANDLE_VALUE then begin ShowMessage(SysErrorMessage(GetLastError));exit;end;
GetMem(lpBuf,BUF_SIZE);
repeat
ZeroMemory(lpBuf,BUF_SIZE);
if(not ReadDirectoryChangesW(hDir,lpBuf,BUF_SIZE,true,FILE_NOTIFY_CHANGE_FILE_NAME
or FILE_NOTIFY_CHANGE_LAST_WRITE,@cbReturn,nil,nil))or(cbReturn=0)then Break;
// пользователь не сможет прервать ожидание, если захочет. Это нужно либо вынести в отдельный
// поток, либо использовать синхронный ввод/вывод
Ptr:=lpBuf;OldName:='';
repeat
GetMem(FileName,Ptr^.FileNameLength+2);
ZeroMemory(FileName,Ptr^.FileNameLength+2);
lstrcpynW(FileName,addr(Ptr^.FileName),Ptr.FileNameLength div 2+1);
case Ptr.Action of // здесь нужно разместить реальные процедуры обработки данных
FILE_ACTION_ADDED:ShowMessage('File '+FileName+' was created.');
FILE_ACTION_REMOVED:ShowMessage('File '+FileName+' was removed.');
FILE_ACTION_MODIFIED:ShowMessage('File '+FileName+' was modified.');
FILE_ACTION_RENAMED_OLD_NAME:OldName:=FileName;
FILE_ACTION_RENAMED_NEW_NAME:ShowMessage('File '+OldName+' renamed to '+FileName+'.');
end;
FreeMem(FileName);
if Ptr^.NextEntryOffset=0 then break;
Inc(integer(Ptr),Ptr^.NextEntryOffset);
until false;
until false; // как пользователь сможет прервать работу вечного цикла? Выход происходит лишь по ошибке...
FreeMem(lpBuf); // этот код ни разу не вызывается - программа останется в цикле до первой ошибки
CloseHandle(hDir);
end;
Надеюсь, все понятно? Я просто переписал объявления в программу и исправил некоторые несуразицы в коде. Однако, программа на мой взгляд требует некоторой доработки (см. комментарии).
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.