Using .NET Filesystem watcher

Posted by MBeynon on 17-Jan-2018 09:57

Hello (again),

I'm trying to implement a filesystem watcher but have come unstuck with the parameters for my subscribed onChange method.

    DEFINE VARIABLE FileSystemWatcher AS CLASS System.IO.FileSystemWatcher.
    FileSystemWatcher = NEW System.IO.FileSystemWatcher("C:\MyDIRToWatch").
   
    FileSystemWatcher:NotifyFilter = System.IO.NotifyFilters:LastWrite.
    FileSystemWatcher:Filter = "*.*".
    FileSystemWatcher:Changed:Subscribe(OnChange).
    FileSystemWatcher:EnableRaisingEvents = TRUE.

    METHOD PRIVATE FINAL VOID OnChange(  Does anyone know what goes here?  ):
        
        RETURN.

    END METHOD.

Could anyone point me in the right direction please. The code examples I've found have been in c# and not too helpful.

As always, thanks for the help :-)

Mark.

Posted by Roger Blanchard on 17-Jan-2018 10:00

the docs say

object source, FileSystemEventArgs e

so I abl I would think

source as System.Object, e as FileSystemEventArgs

All Replies

Posted by Roger Blanchard on 17-Jan-2018 10:00

the docs say

object source, FileSystemEventArgs e

so I abl I would think

source as System.Object, e as FileSystemEventArgs

Posted by MBeynon on 17-Jan-2018 10:06

Thanks :-)

Posted by Richard.Kelters on 18-Jan-2018 03:44

You can use the classbrowser for this

Posted by MBeynon on 18-Jan-2018 07:08

Yeah, I'd missed that. However, it's not possible to run this in OE as the filewatcher is multithreaded and OE is not. The code fires for the first file change but then hangs!

Posted by Brian K. Maher on 18-Jan-2018 07:14

You can write a wrapper in C# or VB and handle the messaging in that and forward new events to us on the main thread.  Others have done this and maybe someone can provide some sample code to work from.

Posted by bbrennan on 18-Jan-2018 09:14

I too would like to see a sample of this sort of wrapper.  The Filesystem Watcher seems to be a useful technique for a project we are researching.
 
Bob Brennan
Integrated Manufacturing Systems, Inc.
(603) 424-0109

Posted by tbergman on 19-Jan-2018 09:16

I did a little looking into this and it appears that a simple change to the code will make this OK to use in a single threaded environment like Progress.

Adding the line FileSystemWatcher:SynchronizingObject = this-object. will cause the methods used by the Change, delete etc. events to use the thread that started the form.

I've tested this in a form and with this line, no crashes occur. Without it, crashes are immediate. 

Very little testing has been done, YMMV

Posted by DenDuze on 18-Mar-2019 14:35

Mhhh I tried this "Adding the line FileSystemWatcher:SynchronizingObject = this-object."  but then I get a syntax-error "Incompatible data types in expression or assignment. (223)"

assign oFileSystemWatcher                                    = new System.IO.FileSystemWatcher(p-NMpath, p-INfilter)

          oFileSystemWatcher:NotifyFilter                   = System.IO.NotifyFilters:filename  

          oFileSystemWatcher:SynchronizingObject = this-object.

Has someone tried that solution with :SynchronizingObject = this-object.?

How can I make this work?

I also found some sollution to that 15740 error by using a helper-class but I do not understand how that works so ...

Regards

Didier

Posted by Ken McIntosh on 18-Mar-2019 15:18

Have you tried casting THIS-OBJECT to System.ComponentModel.ISynchronizeInvoke?

e.g.

oFileSystemWatcher:SynchronizingObject = CAST(this-object,System.ComponentModel.ISynchronizeInvoke)

Posted by Laura Stern on 18-Mar-2019 15:22

Right - what Ken said.  But obviously, whatever THIS-OBJECT is, really has to be something that implements ISynchronizeInvoke, or the CAST will not work either.

Posted by DenDuze on 19-Mar-2019 07:23

Hi,

Again this is not completly clear to me.

I tried adding the oFileSystemWatcher:SynchronizingObject = cast(this-object, "System.ComponentModel.ISynchronizeInvoke").

Now I have no syntax-error but I get a run-time error (like Laura said)

Ongeldig cast van filesystemwatcher naar System.ComponentModel.ISynchronizeInvoke, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089. (12869)

When I then add the implement ISunchronizeInvoke (and all needed methods/properties) it compiles fine but when the program runs I still get the 15740 error (multi threaded and Progress single threaded.

So I guess this oFileSystemWatcher:SynchronizingObject doesn't work as expected/explained.

Isn't there someone that used the System.IO.FileSystemWatcher from a Progress process (or some other class that leads to that 15740 that error)?

How did you prevent that 15740 error:

You are trying to use a multi-threaded .NET object in a way that is not supported.  The ABL cannot be called on a thread other than the main thread. (15740)

The ABL is single threaded.  You will see this error if you use a .NET object that employs multiple threads and attempts to call back to the ABL on a thread other than the main processing thread.

Regards

Didier

Posted by Laura Stern on 19-Mar-2019 13:05

In general, you cannot prevent error 15740.  If the class sends events on other threads, it cannot be used from the ABL.  It makes total sense that the class would be doing this as it is watching when changes are happening in the file system.  Those changes can happen at any point, asynchronous to what is happening on the main thread.

But look at the SynchronizingObject property.  I'm not sure I'm reading what it says correctly.  But maybe that will help you.

Posted by Laura Stern on 19-Mar-2019 13:05

In general, you cannot prevent error 15740.  If the class sends events on other threads, it cannot be used from the ABL.  It makes total sense that the class would be doing this as it is watching when changes are happening in the file system.  Those changes can happen at any point, asynchronous to what is happening on the main thread.

But look at the SynchronizingObject property.  I'm not sure I'm reading what it says correctly.  But maybe that will help you.

Posted by DenDuze on 20-Mar-2019 12:54

Ok, it looks like this works ;-)

First i created a dummy System.Windows.Forms.Form object and assigned the SynchronizingObject with the handle of that Form-object.

Now the 15740 error does not arise and - it looks like - the events fire and are handled like I expected.

Still need some testing and not sure if there are some drawbacks by creating that dummy Form-object (I don't think so) but it looks promising

Thanks

Posted by Laura Stern on 20-Mar-2019 13:04

:-)

Posted by Lieven De Foor on 21-Mar-2019 08:55

You might be able to use System.Windows.Forms.Control instead of Form, as that is the base class that implements this interface.

Or you could try implementing the interface yourself, but I'm unsure that will be possible or work...

Posted by DenDuze on 21-Mar-2019 09:05

Yes i could but what are the benefits of using System.Windows.Forms.Control instead of Form,

Posted by jquerijero on 21-Mar-2019 19:23

As Brian alluded to, a class wrapper has the basic structure.

1. Define a Delegate for SomeMethodDelegate(SomeParemeter)

2. Public property of type Control  (or any method to pass a form or widget)

3. Component that fires event on a different thread

4. Event Handler for Component's event

         Inside call SomeMethod(SomeParameter)

5. SomeMethod(SomeParameter)

         if form.InvokeRequired

             form.Invoke(new SomeMethodDelegate(SomeMethod), new object[] { SomeParameter })

         else

            you can either call a public method of form passing SomeParameter or

            you can raise a custom event passing SomeParameter (I prefer this approach)

NOTE: if you define a delegate with the same signature as Event Handler, you won't need a separate SomeMethod

This thread is closed