[Lazarus] Shell notifications

2013-08-20 Thread Antonio Fortuny

Hi Folks.

Do you know any component / tool to allow an application to be notified 
by the host OS when something changes in a disk directory ?

Both Windows & Linux.

Thanks,

Antonio.




--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-20 Thread Mark Morgan Lloyd

Antonio Fortuny wrote:

Hi Folks.

Do you know any component / tool to allow an application to be notified 
by the host OS when something changes in a disk directory ?

Both Windows & Linux.


I think on Linux that you need something like the File Alteration 
Monitor (FAM) daemon, but I don't know how universally it's implemented.


--
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-20 Thread Michael Van Canneyt



On Tue, 20 Aug 2013, Mark Morgan Lloyd wrote:


Antonio Fortuny wrote:

Hi Folks.

Do you know any component / tool to allow an application to be notified by 
the host OS when something changes in a disk directory ?

Both Windows & Linux.


I think on Linux that you need something like the File Alteration Monitor 
(FAM) daemon, but I don't know how universally it's implemented.


Nothing that complicated.

Just use inotify. The inotify unit is in the rtl.

I didn't get around to writing a cross-platform component for this yet.

Michael.

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-20 Thread Henry Vermaak
On Tue, Aug 20, 2013 at 02:22:02PM +0200, Antonio Fortuny wrote:
> Hi Folks.
> 
> Do you know any component / tool to allow an application to be
> notified by the host OS when something changes in a disk directory ?
> Both Windows & Linux.

inotify on linux (together with select()).  I'm told
FindFirstChangeNotification() is the thing to use on Windows, but I've
never tried.

Henry

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-20 Thread Antonio Fortuny


Le 20/08/2013 14:56, Henry Vermaak a écrit :

On Tue, Aug 20, 2013 at 02:22:02PM +0200, Antonio Fortuny wrote:

Hi Folks.

Do you know any component / tool to allow an application to be
notified by the host OS when something changes in a disk directory ?
Both Windows & Linux.

inotify on linux (together with select()).  I'm told

Couldn'f find any inotify.* unit into my FPC/Lazarus installation
Only an inotify.h

FindFirstChangeNotification() is the thing to use on Windows, but I've
never tried.
I did and it runs OK as it is part of the kernel32.dll. But I'll have to 
run into a loop as this shell function is not event driven. I'll maybe 
make a wrapper onto it using a separated thread.


Thanks.

Antonio.


Henry

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus






--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-20 Thread Henry Vermaak
On Tue, Aug 20, 2013 at 03:21:01PM +0200, Antonio Fortuny wrote:
> Le 20/08/2013 14:56, Henry Vermaak a écrit :
> >On Tue, Aug 20, 2013 at 02:22:02PM +0200, Antonio Fortuny wrote:
> >>Hi Folks.
> >>
> >>Do you know any component / tool to allow an application to be
> >>notified by the host OS when something changes in a disk directory ?
> >>Both Windows & Linux.
> >inotify on linux (together with select()).  I'm told
> Couldn'f find any inotify.* unit into my FPC/Lazarus installation
> Only an inotify.h

It's in the linux unit, since inotify is linux specific.

> >FindFirstChangeNotification() is the thing to use on Windows, but I've
> >never tried.
> I did and it runs OK as it is part of the kernel32.dll. But I'll
> have to run into a loop as this shell function is not event driven.
> I'll maybe make a wrapper onto it using a separated thread.

You can use a wait function (e.g. WaitForMultipleObjects) with the
handle that FindFirstChangeNotification() returns.  So start a thread,
get the handle, use wait function and call an event when the wait
function indicated that something happened with the handle.  Repeat.

You'll have to do something similar for the linux implementation: start
a thread, get inotify fd, add that to fpselect(), call some event
when fpselect() indicates that the fd is readable. Repeat.

Henry

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-20 Thread Antonio Fortuny

  
  

Le 20/08/2013 15:46, Henry Vermaak a
  écrit :


  On Tue, Aug 20, 2013 at 03:21:01PM +0200, Antonio Fortuny wrote:

  
Le 20/08/2013 14:56, Henry Vermaak a écrit :


  On Tue, Aug 20, 2013 at 02:22:02PM +0200, Antonio Fortuny wrote:

  
Hi Folks.

Do you know any component / tool to allow an application to be
notified by the host OS when something changes in a disk directory ?
Both Windows & Linux.

  
  inotify on linux (together with select()).  I'm told


Couldn'f find any inotify.* unit into my FPC/Lazarus installation
Only an inotify.h

  
  
It's in the linux unit, since inotify is linux specific.


  

  FindFirstChangeNotification() is the thing to use on Windows, but I've
never tried.


I did and it runs OK as it is part of the kernel32.dll. But I'll
have to run into a loop as this shell function is not event driven.
I'll maybe make a wrapper onto it using a separated thread.

  
  
You can use a wait function (e.g. WaitForMultipleObjects) with the
handle that FindFirstChangeNotification() returns.  So start a thread,
get the handle, use wait function and call an event when the wait
function indicated that something happened with the handle.  Repeat.

This was in my mind too.

  

You'll have to do something similar for the linux implementation: start
a thread, get inotify fd, add that to fpselect(), call some event
when fpselect() indicates that the fd is readable. Repeat.

I'll try a little bit later.

Thanks,

Antonio.


  

Henry



-- 
  

  
  
  
  
 Antonio
Fortuny
  Senior Software engineer
  
  220, avenue de la Liberté
  L-4602 Niederkorn
  Tel.: +352 58 00 93 - 93
  www.sitasoftware.lu

  
  
  
  

  

  

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-21 Thread Michael Schnell

On 08/20/2013 02:56 PM, Henry Vermaak wrote:

... together with select()..


In Object Pascal I think this should be encapsulated in a thread and 
same fires a main Thread event (via TThread.Queue, TThread.Synchronize, 
or Application.QueueAsyncCall) to notify the user (aka Main Thread).


-Michael


--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-21 Thread Mark Morgan Lloyd

Michael Schnell wrote:

On 08/20/2013 02:56 PM, Henry Vermaak wrote:

... together with select()..


In Object Pascal I think this should be encapsulated in a thread and 
same fires a main Thread event (via TThread.Queue, TThread.Synchronize, 
or Application.QueueAsyncCall) to notify the user (aka Main Thread).


I know it's the obvious way, but surely there is something more elegant 
than having a thread which exists solely to transfer the result of a 
select() to the main part of the app, and then repeats.


--
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-21 Thread Henry Vermaak
On Wed, Aug 21, 2013 at 12:36:56PM +, Mark Morgan Lloyd wrote:
> Michael Schnell wrote:
> >On 08/20/2013 02:56 PM, Henry Vermaak wrote:
> >>... together with select()..
> >
> >In Object Pascal I think this should be encapsulated in a thread
> >and same fires a main Thread event (via TThread.Queue,
> >TThread.Synchronize, or Application.QueueAsyncCall) to notify the
> >user (aka Main Thread).
> 
> I know it's the obvious way, but surely there is something more
> elegant than having a thread which exists solely to transfer the
> result of a select() to the main part of the app, and then repeats.

Well, the thread exists only because of the blocking nature of the
wait/select function.  If that's the only task of the application the
thread isn't needed, of course.

It's more portable and self contained than the alternatives I can think
of.  The most efficient way to do this would probably be to plumb it
straight into the event loop that is in use (if there is one).  E.g. you
can add file descriptors to the glib event loop.  I don't know how that
can be done with the Windows message loop, mind you.  This approach
isn't easy to abstract, though.

Henry

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-21 Thread Michael Schnell

On 08/21/2013 02:36 PM, Mark Morgan Lloyd wrote:
I know it's the obvious way, but surely there is something more 
elegant than having a thread which exists solely to transfer the 
result of a select() to the main part of the app, and then repeats 


I suppose a thread is the only way to do this in a portable way.

The cost of a thread is close to zero. It just blocks in the requests 
and does a single turn for any change.


-Michael

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-21 Thread Mark Morgan Lloyd

Michael Schnell wrote:

On 08/21/2013 02:36 PM, Mark Morgan Lloyd wrote:
I know it's the obvious way, but surely there is something more 
elegant than having a thread which exists solely to transfer the 
result of a select() to the main part of the app, and then repeats 


I suppose a thread is the only way to do this in a portable way.

The cost of a thread is close to zero. It just blocks in the requests 
and does a single turn for any change.


[Noting also Henry's comment] I suppose that, at least for unix 
platforms, you could have a single app-wide thread which selects on 
designated handles and syncs a magic number to the foreground. The 
tricky bit, which would merit attention from somebody who really knows 
the native APIs, would be adding and removing handles on the fly.


--
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-21 Thread Flávio Etrusco
On Wed, Aug 21, 2013 at 9:36 AM, Mark Morgan Lloyd
 wrote:
> Michael Schnell wrote:
>>
>> On 08/20/2013 02:56 PM, Henry Vermaak wrote:
>>>
>>> ... together with select()..
>>
>>
>> In Object Pascal I think this should be encapsulated in a thread and same
>> fires a main Thread event (via TThread.Queue, TThread.Synchronize, or
>> Application.QueueAsyncCall) to notify the user (aka Main Thread).
>
>
> I know it's the obvious way, but surely there is something more elegant than
> having a thread which exists solely to transfer the result of a select() to
> the main part of the app, and then repeats.
>
>
> --
> Mark Morgan Lloyd
> markMLl .AT. telemetry.co .DOT. uk

IMO there should be a basic component which just provides the platform
abstraction to block/wait on the change notification (probably
inheriting from SyncObjs.THandleObjects?), and build on that to
implement the daemon/thread.

Unless, of course, it make the design for handling several events with
a single thread much more cluttered; but at least Windows
(FindFirstChangeNotification) and Linux (inotify) provide
wait/blocking-read semantics for these events...

-Flávio

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-22 Thread Antonio Fortuny

Hi All.

I've built some code which works fine under Linux.
I'm now working on the Windows part using FindFirstChangeNotificationA 
to get the directory handle and ReadDirectoryChangesW to fetch events data.
And I'm blocked there. The receiving buffer is set to 32kb. After 
changing a file content, ReadDirectoryChangesW does not return any error 
but the return length is crazy (28 megs) and nothing in the returned 
buffer contents looks right.
After reading some ms docs I've read thah the buffer has to be DWORD 
aligned.

So there is may question: how to do that ?

Thanks,

Antonio.



--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-22 Thread Antonio Fortuny

See the code in attachment

I changed the code a little bit adding the OVERLAP parameter and events 
to use the async method.

Now the same function returns error code 6

Antonio.
procedure TFrmMain.StartNotify(const FolderName: String);

  {$IFDEF LINUX}
  function decodeMask(Mask:Longint):string;
  var
 Rslt:String;
  begin
 Rslt:='';
 if (Mask and IN_ACCESS)=IN_ACCESS then
Rslt:=Rslt+' File was accessed.';
 if (Mask and IN_MODIFY)=IN_MODIFY then
Rslt:=Rslt+' File was modified.';
 if (Mask and IN_ATTRIB)=IN_ATTRIB then
Rslt:=Rslt+' Attribute was changed.';
 if (Mask and IN_CLOSE_WRITE)=IN_CLOSE_WRITE then
Rslt:=Rslt+' Writtable file was closed.';
 if (Mask and IN_CLOSE_NOWRITE)=IN_CLOSE_NOWRITE then
Rslt:=Rslt+' Unwrittable file was closed.';
 if (Mask and IN_CLOSE)=IN_CLOSE then
Rslt:=Rslt+' File was closed.';
 if (Mask and IN_OPEN)=IN_OPEN then
Rslt:=Rslt+' File was opened.';
 if (Mask and IN_MOVED_FROM)=IN_MOVED_FROM then
Rslt:=Rslt+' File was moved from ';
 if (Mask and IN_MOVED_TO)=IN_MOVED_TO then
Rslt:=Rslt+' File was moved to ';
 if (Mask and IN_MOVE)=IN_MOVE then
Rslt:=Rslt+' File is moving';
 if (Mask and IN_CREATE)=IN_CREATE then
Rslt:=Rslt+' Subfile was created';
 if (Mask and IN_DELETE)=IN_DELETE then
Rslt:=Rslt+' Subfile was deleted';
 if (Mask and IN_DELETE_SELF)=IN_DELETE_SELF then
Rslt:=Rslt+' Self was deleted';
 if (Mask and IN_MOVE_SELF)=IN_MOVE_SELF then
Rslt:=Rslt+' Self was moved';
 if (Mask and IN_UNMOUNT)=IN_UNMOUNT then
Rslt:=Rslt+' Filesystem was unmounted';
 if (Mask and IN_Q_OVERFLOW)=IN_Q_OVERFLOW then
Rslt:=Rslt+' Event queued overflowed';
 if (Mask and IN_IGNORED)=IN_IGNORED then
Rslt:=Rslt+' File was ignored';
 if (Mask and IN_ONLYDIR)=IN_ONLYDIR then
Rslt:=Rslt+' Only watch the path if it is a directory';
 if (Mask and IN_DONT_FOLLOW)=IN_DONT_FOLLOW then
Rslt:=Rslt+' Do not follow a sym link';
 if (Mask and IN_MASK_ADD)=IN_MASK_ADD then
Rslt:=Rslt+' Add to the mast of an already existing watch';
 if (Mask and IN_ISDIR)=IN_ISDIR then
Rslt:=Rslt+' Event occurred against dir';
 if (Mask and IN_ONESHOT)=IN_ONESHOT then
Rslt:=Rslt+' Only send event once';
 decodeMask:=Rslt;
  end;
  {$ENDIF}
  {$IFDEF MSWINDOWS}
  function decodeMask(Mask:Longint):string;
  var
Rslt:String;
  begin
Result := '';
if (Mask and FILE_ACTION_ADDED) = FILE_ACTION_ADDED then
  Result := Result + ' file ADDED';
if (Mask and FILE_ACTION_REMOVED) = FILE_ACTION_REMOVED then
  Result := Result + ' file REMOVED';
if (Mask and FILE_ACTION_MODIFIED) = FILE_ACTION_MODIFIED then
  Result := Result + ' file CHANGED';
  end;
  {$ENDIF}

var
  wFolderName: String;
  FileName: String;
  Timeout: Integer=200;
  Buffer: PChar;
  PData: Pointer;
  P: Integer;
  {$IFDEF LINUX}
  Ret: Integer;
  instance_handle: cint;
  notify_handle: cint;
  rfds: tfdset;
  length: Integer;
  iEvent: inotify_event;
  buflen: Integer=(SizeOf(iEvent) + 16) * 512;
  evnt: Pinotify_event;
  TotalRead: TSsize;
  FileName: String;
  {$ENDIF}
  {$IFDEF MSWINDOWS}
  wHandle: THANDLE;
  Ret: Integer;
  Res: BOOL;
  pFileInfo: PFILE_NOTIFY_INFORMATION;
  buflen: DWORD=SizeOf(FILE_NOTIFY_INFORMATION) * 512;
  TotalRead: DWORD;
  Error: Integer;
  Overlap: OVERLAPPED;
  events: array[0..1] of THANDLE;
  Ev1: TEvent;
  Ev2: TEvent;
  {$ENDIF}
begin
  wFolderName := ExcludeTrailingPathDelimiter(Trim(FolderName));
  {$IFDEF MSWINDOWS}
  wHandle := FindFirstChangeNotificationA(PChar(wFolderName), 
DWORD(LongBool(False)), FILE_NOTIFY_CHANGE_SIZE + 
FILE_NOTIFY_CHANGE_LAST_WRITE);
  try
if wHandle = INVALID_HANDLE_VALUE then begin
  MessageDlg('Error','Invalid notify handle', mtError, [mbOK], 0, mbOK);
  Exit
end;
Ev1 := TEvent.Create(nil, False, False, 'FEV1_tralala');
Ev2 := TEvent.Create(nil, False, False, 'FEV2_tralala');
events[0] := THANDLE(Ev1.Handle);
events[1] := THANDLE(Ev2.Handle);
FillMemory(@Overlap, SizeOf(OVERLAPPED), byte(#0));
Overlap.hEvent := THANDLE(Ev1.Handle);
FStopNotify := False;
PData := nil;
buflen := 32 * 1024;
ReAllocMem(PData, buflen);
//Buffer := system.Align(PData, 16);
Buffer := PData;
while not FStopNotify do begin
  Ret := WaitForSingleObject(wHandle, 200);
  if Ret = WAIT_OBJECT_0 then begin
FillMemory(PData, buflen, byte(#0));

Res := ReadDirectoryChangesW(wHandle, Buffer, buflen, False,
FILE_NOTIFY_CHANGE_FILE_NAME + FILE_NOTIFY_CHANGE_SIZE + 
FILE_NOTIFY_CHANGE_LAST_WRITE, @TotalRead, @Overlap, nil);
if not Res then begin
  Error := GetLastError;
  FStopNotify := True;
  Memo1.Lines.Add(Format('error on read changes: %d %s', [Error, 
SysErrorMessage(Error)]));
  Brea

Re: [Lazarus] Shell notifications

2013-08-22 Thread Sven Barth

Am 22.08.2013 13:33, schrieb Antonio Fortuny:

See the code in attachment

I changed the code a little bit adding the OVERLAP parameter and 
events to use the async method.

Now the same function returns error code 6
Error code 6 is ERROR_INVALID_HANDLE (would be nice if you'd mention the 
error message as well next time when you're already using 
SysErrorMessage). FindFirstChangeNotification returns a notification 
handle, but ReadDirectoryChanges requires a directory handle (with 
FILE_LIST_DIRECTORY priviledge), so you need to open the directory yourself.


Regards,
Sven

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-22 Thread Henry Vermaak
On Thu, Aug 22, 2013 at 01:49:28PM +0200, Sven Barth wrote:
> Am 22.08.2013 13:33, schrieb Antonio Fortuny:
> >See the code in attachment
> >
> >I changed the code a little bit adding the OVERLAP parameter and
> >events to use the async method.
> >Now the same function returns error code 6
> Error code 6 is ERROR_INVALID_HANDLE (would be nice if you'd mention
> the error message as well next time when you're already using
> SysErrorMessage). FindFirstChangeNotification returns a notification
> handle, but ReadDirectoryChanges requires a directory handle (with
> FILE_LIST_DIRECTORY priviledge), so you need to open the directory
> yourself.

To add to this, the remarks section on msdn says this:

"To obtain a handle to a directory, use the CreateFile function with the
FILE_FLAG_BACKUP_SEMANTICS flag."

In addition to this you're also passing an OVERLAPPED record to
ReadDirectoryChangesW(), so you'll have to use FILE_FLAG_OVERLAPPED when
you open the directory, too.

Henry

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


Re: [Lazarus] Shell notifications

2013-08-22 Thread Antonio Fortuny


Le 22/08/2013 14:06, Henry Vermaak a écrit :

On Thu, Aug 22, 2013 at 01:49:28PM +0200, Sven Barth wrote:

Am 22.08.2013 13:33, schrieb Antonio Fortuny:

See the code in attachment

I changed the code a little bit adding the OVERLAP parameter and
events to use the async method.
Now the same function returns error code 6

Error code 6 is ERROR_INVALID_HANDLE (would be nice if you'd mention
the error message as well next time when you're already using
SysErrorMessage). FindFirstChangeNotification returns a notification
handle, but ReadDirectoryChanges requires a directory handle (with
FILE_LIST_DIRECTORY priviledge), so you need to open the directory
yourself.

To add to this, the remarks section on msdn says this:

"To obtain a handle to a directory, use the CreateFile function with the
FILE_FLAG_BACKUP_SEMANTICS flag."

In addition to this you're also passing an OVERLAPPED record to
ReadDirectoryChangesW(), so you'll have to use FILE_FLAG_OVERLAPPED when
you open the directory, too.

This did it. Don't even need FindFirstChangeNotification
Thanks

Antonio.


Henry

--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus






--
___
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus