1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Collections;
  8 using System.Windows.API;
  9 
 10 namespace System.Windows.IO
 11 {
 12     public delegate void DirectoryChangedFunction(const string& directoryPath);
 13     
 14     public class delegate void DirectoryChangedMethod(const string& directoryPath);
 15     
 16     public class DirectoryChangeNotifier
 17     {
 18         public nothrow DirectoryChangeNotifier() : 
 19             notificationHandle(null)waitCanceledEventHandle(null)directoryPath()firstTime(true)waiting(false)
 20         {
 21         }
 22         public nothrow DirectoryChangeNotifier(void* notificationHandle_const string& directoryPath_) : 
 23             notificationHandle(notificationHandle_)waitCanceledEventHandle(CreateEvent())directoryPath(directoryPath_)firstTime(true)waiting(false)
 24         {
 25         }
 26         public ~DirectoryChangeNotifier()
 27         {
 28             try
 29             {
 30                 if (waiting)
 31                 {
 32                     CancelWait();
 33                 }
 34                 if (notificationHandle != null)
 35                 {
 36                     FindCloseChangeNotification(notificationHandle);
 37                 }
 38                 if (waitCanceledEventHandle != null)
 39                 {
 40                     CloseEvent(waitCanceledEventHandle);
 41                 }
 42             }
 43             catch (const Exception&)
 44             {
 45             }
 46         }
 47         public suppress DirectoryChangeNotifier(const DirectoryChangeNotifier&);
 48         public suppress void operator=(const DirectoryChangeNotifier&);
 49         public DirectoryChangeNotifier(DirectoryChangeNotifier&& that) : 
 50             notificationHandle(that.notificationHandle)waitCanceledEventHandle(that.waitCanceledEventHandle)directoryPath(that.directoryPath)firstTime(that.firstTime)waiting(that.waiting)
 51         {
 52             that.notificationHandle = null;
 53             that.waitCanceledEventHandle = null;
 54             that.directoryPath.Clear();
 55             that.firstTime = false;
 56             that.waiting = false;
 57         }
 58         public default nothrow void operator=(DirectoryChangeNotifier&& that);
 59         public void WaitAndCallWhenDirectoryChanged(DirectoryChangedFunction callback)
 60         {
 61             if (WaitUntilDirectoryChangedOrWaitCanceled())
 62             {
 63                 callback(directoryPath);
 64             }
 65         }
 66         public void WaitAndCallWhenDirectoryChanged(DirectoryChangedMethod callback)
 67         {
 68             if (WaitUntilDirectoryChangedOrWaitCanceled())
 69             {
 70                 callback(directoryPath);
 71             }
 72         }
 73         public bool WaitUntilDirectoryChangedOrWaitCanceled()
 74         {
 75             if (firstTime)
 76             {
 77                 firstTime = false;
 78             }
 79             else
 80             {
 81                 FindNextChangeNotification(notificationHandle);
 82             }
 83             List<void*> handles;
 84             handles.Add(notificationHandle);
 85             handles.Add(waitCanceledEventHandle);
 86             waiting = true;
 87             int index = WaitForMultipleObjects(handles);
 88             waiting = false;
 89             return index == 0;
 90         }
 91         public void CancelWait()
 92         {
 93             if (waiting)
 94             {
 95                 waiting = false;
 96                 SetEvent(waitCanceledEventHandle);
 97             }
 98         }
 99         void* notificationHandle;
100         void* waitCanceledEventHandle;
101         string directoryPath;
102         bool firstTime;
103         bool waiting;
104     }
105     
106     public static class Directory
107     {
108         public static DirectoryChangeNotifier NotifyChanged(const string& directoryPath)
109         {
110             if (System.IO.Directory.Exists(directoryPath))
111             {
112                 void* handle = FindFirstChangeNotification(directoryPath);
113                 return DirectoryChangeNotifier(handledirectoryPath);
114             }
115             else
116             {
117                 throw System.IO.FileSystemException("directory '" + directoryPath + "' does not exist");
118             }
119         }
120     }    
121 }