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!
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.
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.
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.
Using 10.2B.
Any explanation why my first example works without issues?
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.