powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / ReadDirectoryChangesW инициировать срабатывание без реальной записи в синхронном режиме
6 сообщений из 6, страница 1 из 1
ReadDirectoryChangesW инициировать срабатывание без реальной записи в синхронном режиме
    #40079821
hlopotun
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем доброго дня,

хотелось бы работать с этой функцией в синхронном режиме т.к. асинхронный сильно всё усложняет ( например ).
Ход мысли такой, если мы имеем THandle папки логично было бы предположить что ему можно послать сообщение которое приведёт к срабатыванию ReadDirectoryChangesW. Можно конечно что то тупо записать в папку но это подходит только для случая если "слушатель" имеет право на запись в эту папку.
Среди флагов фильтра на события в папке: 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
на роль выключателя наверное подходят только FILE_NOTIFY_CHANGE_LAST_ACCESS т.к. остальные требуют права на запись (хотя возможно и этот флаг требует права на запись, ещё не проверил).
Из описания функции сделать однозначный вывод каким сообщением можно вывести её из ожидания сделать не получается. Тут и тут человек разбирался с проблеммой но всё выглядит немного запутанно.
Хорошо было бы заглянуть в исходники ReadDirectoryChangesW, возможно тогда можно было бы понять как обойти эту проблему и вывести ReadDirectoryChangesW из режима ожидания через PostMessage или ещё как.

п.с. TShellChangeNotifier не подходит т.к. вроде не даёт информации о том какой файл изменился.

Спасибо если кто подскажет хорошую идею.
...
Рейтинг: 0 / 0
ReadDirectoryChangesW инициировать срабатывание без реальной записи в синхронном режиме
    #40079822
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hlopotun
хотелось бы работать с этой функцией в синхронном режиме
Очень странное желание.

Ну используйте тогда FindFirstChangeNotification
...
Рейтинг: 0 / 0
ReadDirectoryChangesW инициировать срабатывание без реальной записи в синхронном режиме
    #40079826
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот код, работающий уже лет 15

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
unit wfsU;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  Windows, SysUtils, Classes, ActiveX;

type
  // Структура с информацией об изменении в файловой системе (передается в callback процедуру)
  PInfoCallback = ^TFileNotifyInfo;
  TFileNotifyInfo = record
    Action      : Integer; // тип изменения (константы FILE_ACTION_XXX)
    Path        : string;  // путь, по которому было изменение
    OldFileName : string;  // имя файла до переименования
    NewFileName : string;  // имя файла после переименования
  end;

  // callback процедура, вызываемая при изменении в файловой системе
  TWatchFileSystemCallback = procedure (const AInfo: TFileNotifyInfo) of object;

  TWFS = class(TThread)
  private
    FPath           : string;
    FFilter         : Cardinal;
    FSubTree        : Boolean;
    FInfoCallback   : TWatchFileSystemCallback;

    FWatchHandle    : THandle;
    FCompletionPort : THandle;
    FOldFileName    : string;
  private
    procedure HandleEvent(AFileNotifyInfo: Pointer);
  protected
    procedure Execute; override;
    procedure DoProcess;
  public
  { Запуск мониторинга файловой системы
  Праметры:
    APath    - имя папки для мониторинга
    AFilter  - комбинация констант FILE_NOTIFY_XXX
    ASubTree - мониторить ли все подпапки заданной папки
    AInfoCallback - адрес callback процедуры, вызываемой при изменении в файловой системе}
    constructor Create(const APath: string; AFilter: Cardinal; ASubTree: Boolean;
      AInfoCallback: TWatchFileSystemCallback);
    destructor Destroy; override;
    procedure Stop;
  end;

function TestFileAccess(const AFileName: string): Cardinal;

implementation

uses
  UThreads;

const
  FILE_LIST_DIRECTORY   = $0001;

type
  {$IF not Declared(ULONG_PTR)}
    {$IFDEF CPUX64}
    ULONG_PTR = UInt64;
    {$ELSE}
    ULONG_PTR = Cardinal;
    {$ENDIF}
  {$IFEND}

  PFileNotifyInformation = ^TFileNotifyInformation;
  TFileNotifyInformation = record
     NextEntryOffset : DWORD;
     Action          : DWORD;
     FileNameLength  : DWORD;
     FileName        : array[0..0] of WideChar;
  end;

function TestFileAccess(const AFileName: string): Cardinal;
var
  LHandle: THandle;
begin
  LHandle := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  if LHandle <> INVALID_HANDLE_VALUE then begin
    CloseHandle(LHandle);
    Result := 0;
  end else
    Result := GetLastError;
end;

{ TWFS }

constructor TWFS.Create(const APath: string; AFilter: Cardinal; ASubTree: Boolean;
  AInfoCallback: TWatchFileSystemCallback);
begin
  inherited Create(False);
  {$IFOPT D+}
  NameThreadForDebugging('TWFS', ThreadID);
  {$ENDIF}
  TThreadNamesManager.SetThreadMapName(Format('%s.%s', [ExtractFileName(GetModuleName(HInstance)), ClassName]), ThreadID);
  FreeOnTerminate := True;
  FPath := IncludeTrailingPathDelimiter(APath);
  FFilter := AFilter;
  FSubTree := ASubTree;
  FOldFileName := EmptyStr;
  FInfoCallback := AInfoCallback;

  FWatchHandle:=CreateFile(PChar(FPath), FILE_LIST_DIRECTORY,
    FILE_SHARE_READ or FILE_SHARE_DELETE or FILE_SHARE_WRITE, nil,
    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
  Win32Check(FWatchHandle <> INVALID_HANDLE_VALUE);
  FCompletionPort := CreateIoCompletionPort(FWatchHandle, 0, Longint(Pointer(Self)), 0);
  Win32Check(LongBool(FCompletionPort));
end;

destructor TWFS.Destroy;
begin
  PostQueuedCompletionStatus(FCompletionPort, 0, 0, nil);
  CloseHandle(FCompletionPort);
  CloseHandle(FWatchHandle);
  TThreadNamesManager.RemoveThreadMapName(ThreadID);
  inherited Destroy;
end;

procedure TWFS.Execute;
begin
  CoInitializeEx(nil, COINIT_MULTITHREADED or COINIT_SPEED_OVER_MEMORY);
  try
    DoProcess;
  finally
    CoUninitialize;
  end;
end;

procedure TWFS.DoProcess;
const
  CWatchBufSize = 1024 * 1024;
var
  LCompletionKey: ULONG_PTR;
  LOverlapped: TOverlapped;
  LOverlappedPtr: POverlapped;
  LWatchBuf: Pointer;
  LBytesWrite: DWORD;
  LNumBytes: Cardinal;
begin
  {$OPTIMIZATION ON}
  LOverlappedPtr := @LOverlapped;
  FillChar(LOverlapped, SizeOf(LOverlapped), 0);
  GetMem(LWatchBuf, CWatchBufSize);
  try
    while not Terminated do begin
      FillChar(LWatchBuf^, CWatchBufSize, 0);
      LBytesWrite := 0;
      Win32Check(ReadDirectoryChangesW(FWatchHandle, LWatchBuf, CWatchBufSize,
        FSubTree, FFilter, @LBytesWrite, LOverlappedPtr, nil));
      GetQueuedCompletionStatus(FCompletionPort, LNumBytes, LCompletionKey, LOverlappedPtr, INFINITE);
      if LCompletionKey <> 0 then
        HandleEvent(LWatchBuf)
      else
        Terminate;
    end;
  finally
    FreeMem(LWatchBuf);
  end;
end;

procedure TWFS.HandleEvent(AFileNotifyInfo: Pointer);
var
  LFileNotifyInfo: PFileNotifyInformation absolute AFileNotifyInfo;
  LInfoCallback: TFileNotifyInfo;
  LOffset: DWORD;
begin
  repeat
    LInfoCallback.Action := LFileNotifyInfo^.Action;
    LInfoCallback.Path := FPath;
    LInfoCallback.NewFileName := WideCharLenToString(
      @LFileNotifyInfo^.FileName[0], LFileNotifyInfo^.FileNameLength shr 1);
    case LFileNotifyInfo^.Action of
      FILE_ACTION_RENAMED_OLD_NAME: FOldFileName := LInfoCallback.NewFileName;
      FILE_ACTION_RENAMED_NEW_NAME: begin
        LInfoCallback.OldFileName := FOldFileName;
        FOldFileName := EmptyStr;
      end;
    end;
    FInfoCallback(LInfoCallback);
    LOffset := LFileNotifyInfo^.NextEntryOffset;
    LFileNotifyInfo := PFileNotifyInformation(ULONG_PTR(LFileNotifyInfo) + LOffset);
  until (LOffset = 0) or Terminated;
end;

procedure TWFS.Stop;
var
  LPID: THandle;
  LHandle: THandle;
begin
  LPID := GetCurrentProcess;
  Win32Check(DuplicateHandle(LPID, Handle, LPID, @LHandle, 0, False, DUPLICATE_SAME_ACCESS));
  try
    Terminate;
    Win32Check(PostQueuedCompletionStatus(FCompletionPort, 0, 0, nil));
    Win32Check(WaitForSingleObject(LHandle, INFINITE) <> WAIT_FAILED);
  finally
    CloseHandle(LHandle);
  end;
end;

end.

...
Рейтинг: 0 / 0
ReadDirectoryChangesW инициировать срабатывание без реальной записи в синхронном режиме
    #40079832
kapas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
...
Рейтинг: 0 / 0
ReadDirectoryChangesW инициировать срабатывание без реальной записи в синхронном режиме
    #40079843
hlopotun
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
kapas, _Vasilisk_,

спасибо за пример и ссылку. Углубился в изучение ...
...
Рейтинг: 0 / 0
ReadDirectoryChangesW инициировать срабатывание без реальной записи в синхронном режиме
    #40079850
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Любой асинхронный режим легко превращается в синхронный втыкновением
WaitForMultipleObjects(), куда точно так же легко добавляется возможность его выбить с
помощью дополнительного события.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / ReadDirectoryChangesW инициировать срабатывание без реальной записи в синхронном режиме
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]