FileSystemWatcher issue - hanging

Posted by oedev on 31-Mar-2014 10:20

Hello All,

I have been working with the FileSystemWatcher class, and using a simple implementation can monitor a directory for file changes;

USING Progress.Lang.*.

CLASS FileSystemWatcher: 

    DEFINE VARIABLE watcher AS System.IO.FileSystemWatcher.

    CONSTRUCTOR PUBLIC FileSystemWatcher() :

        DEFINE VARIABLE notifyEnum AS System.Enum NO-UNDO.
  
        MESSAGE "Watcher running" 
            VIEW-AS ALERT-BOX INFORMATION.
        
        watcher = NEW System.IO.FileSystemWatcher().
        watcher:Path = "c:\temp\watch".
        watcher:EnableRaisingEvents = TRUE.
        watcher:Filter = "*.*".
        
        notifyEnum = System.IO.NotifyFilters:FileName.
        notifyEnum = Progress.Util.EnumHelper:Or(notifyEnum, System.IO.NotifyFilters:LastAccess).
        notifyEnum = Progress.Util.EnumHelper:Or(notifyEnum, System.IO.NotifyFilters:LastWrite).
        notifyEnum = Progress.Util.EnumHelper:Or(notifyEnum, System.IO.NotifyFilters:DirectoryName).
        notifyEnum = Progress.Util.EnumHelper:Or(notifyEnum, System.IO.NotifyFilters:Attributes).
        
        watcher:NotifyFilter = CAST(notifyEnum, System.IO.NotifyFilters).
       
        watcher:Created:Subscribe(handler_File).
        watcher:Changed:Subscribe(handler_File).
        watcher:Renamed:Subscribe(handler_Renamed).
        WAIT-FOR System.Windows.Forms.Application:Run().    

    END.

    METHOD PRIVATE VOID handler_File(sender AS CLASS System.Object, e AS CLASS System.IO.FileSystemEventArgs):
    
        MESSAGE 
            e:FullPath skip
            e:Name 
            VIEW-AS ALERT-BOX INFORMATION.

        IF e:name = "stop.txt" THEN
        DO:
            MESSAGE "Stopping" 
                VIEW-AS ALERT-BOX INFORMATION.
            QUIT.
        END.

    END METHOD. 
    
    METHOD PRIVATE VOID handler_Renamed (sender AS CLASS System.Object, e AS CLASS System.IO.RenamedEventArgs):

        MESSAGE
            "Renamed" skip 
            e:OldName skip
            e:Name skip
            e:FullPath skip
            VIEW-AS ALERT-BOX INFORMATION.

        IF e:name = "stop.txt" THEN
        DO:
            MESSAGE "Stopping" 
                VIEW-AS ALERT-BOX INFORMATION.
            QUIT.
        END.
    END METHOD. 
    

END CLASS.

However, when I try implement a directory watcher in a ABL Form, when the file handler event is raised then the session hangs. A debug message in the file handler method is displayed, but then the session hangs. Any ideas?

Thanks!

Posted by Fernando Souza on 31-Mar-2014 10:55

This is a multi-threaded .NET object and we do not support that in the ABL. Which OpenEdge version are you running with? Newer OpenEdge versions will give you an error message that explain that this is not supported.

All Replies

Posted by oedev on 31-Mar-2014 10:34

I've re-produced the issue using a simple ABL form, code below. I instantiate the form using the following code;

DEFINE VARIABLE DWatcher AS CLASS DirectoryWatcherTester NO-UNDO. 
DWatcher = NEW DirectoryWatcherTester( ). 
DWatcher:DoWait( ). 


Code for the DirectoryWatcherTester;

 
 /*------------------------------------------------------------------------
    File        : DirectoryWatcherTester
    Purpose     : 
    Syntax      : 
    Description : 
    Author(s)   : 
    Created     : Mon Mar 31 15:52:45 BST 2014
    Notes       : 
  ----------------------------------------------------------------------*/

USING Progress.Lang.*.
USING Progress.Windows.Form.
USING System.Windows.Forms.*.


CLASS DirectoryWatcherTester INHERITS Form: 
	
	DEFINE PRIVATE VARIABLE components AS System.ComponentModel.IContainer NO-UNDO.
    DEFINE VARIABLE watcher AS System.IO.FileSystemWatcher.
    
		
	CONSTRUCTOR PUBLIC DirectoryWatcherTester (  ):
		
		
        SUPER().
        InitializeComponent().
        
        DEFINE VARIABLE notifyEnum AS System.Enum NO-UNDO.
        
        MESSAGE "Watcher running" 
            VIEW-AS ALERT-BOX INFORMATION.
        
        watcher = NEW System.IO.FileSystemWatcher().
        watcher:Path = "c:\temp\watch".
        watcher:EnableRaisingEvents = TRUE.
        watcher:Filter = "*.*".
        
        notifyEnum = System.IO.NotifyFilters:FileName.
        notifyEnum = Progress.Util.EnumHelper:Or(notifyEnum, System.IO.NotifyFilters:LastAccess).
        notifyEnum = Progress.Util.EnumHelper:Or(notifyEnum, System.IO.NotifyFilters:LastWrite).
        notifyEnum = Progress.Util.EnumHelper:Or(notifyEnum, System.IO.NotifyFilters:DirectoryName).
        notifyEnum = Progress.Util.EnumHelper:Or(notifyEnum, System.IO.NotifyFilters:Attributes).
        
        watcher:NotifyFilter = CAST(notifyEnum, System.IO.NotifyFilters).
       
        watcher:Created:Subscribe(handler_File).
        watcher:Changed:Subscribe(handler_File).
       
        CATCH e AS Progress.Lang.Error:
            UNDO, THROW e.
        END CATCH.

	END CONSTRUCTOR.

	/*------------------------------------------------------------------------------
			Purpose:  																	  
			Notes:  																	  
	------------------------------------------------------------------------------*/


	METHOD PRIVATE VOID InitializeComponent(  ):
		
        /* NOTE: The following method is automatically generated.
        
        We strongly suggest that the contents of this method only be modified using the
        Visual Designer to avoid any incompatible modifications.
        
        Modifying the contents of this method using a code editor will invalidate any support for this file. */
        THIS-OBJECT:SuspendLayout().
        /*  */
        /* DirectoryWatcherTester */
        /*  */
        THIS-OBJECT:ClientSize = NEW System.Drawing.Size(292, 266).
        THIS-OBJECT:Name = "DirectoryWatcherTester".
        THIS-OBJECT:Text = "DirectoryWatcherTester".
        THIS-OBJECT:ResumeLayout(FALSE).
        CATCH e AS Progress.Lang.Error:
            UNDO, THROW e.
        END CATCH.
	END METHOD.

	DESTRUCTOR PUBLIC DirectoryWatcherTester ( ):

		IF VALID-OBJECT(components) THEN DO:
			CAST(components, System.IDisposable):Dispose().
		END.

	END DESTRUCTOR.
	
    METHOD PUBLIC VOID DoWait( ). 
        /* Display and wait for the non-modal form to close */ 
        WAIT-FOR Application:Run( INPUT THIS-OBJECT ). 
    END METHOD.
     	
     	
   METHOD PRIVATE VOID handler_File(sender AS CLASS System.Object, e AS CLASS System.IO.FileSystemEventArgs):
    
        MESSAGE 
            e:FullPath skip
            e:Name 
            VIEW-AS ALERT-BOX INFORMATION.
        

    END METHOD.      	

END CLASS.


As soon as a file is dropped into the monitored directory, the form hangs.

Posted by Fernando Souza on 31-Mar-2014 10:55

This is a multi-threaded .NET object and we do not support that in the ABL. Which OpenEdge version are you running with? Newer OpenEdge versions will give you an error message that explain that this is not supported.

Posted by oedev on 31-Mar-2014 11:45

Using 10.2B.

Any explanation why my first example works without issues?

Posted by Fernando Souza on 31-Mar-2014 12:02

10.2B didn't show the message, it started in Release OE 11.  It "works" by chance, but even there it can stop working at any point or start giving you unpredictable behavior since the AVM is not multi-threaded.

This thread is closed