Seite 1 von 1

KeepTrackOnDirs - Verzeichnisüberwachung

Verfasst: 09.05.2008 14:20
von dige
Hi folks, da ich sehr of dateien aus diversen anwendungen heraus speichere und dann immer suchen muss (wegen vergesslichkeit) wo die denn nun liegen habe ich mal schnell ein tool programmiert, das ein ausgwähltes verzeichnis inkl. aller unterverzeichnisse überwacht und in einer liste anzeigt.

die erkannten dateien können per dragn drop direkt weiterverarbeitet werden.
viel spaß damit - und bitte vorschläge wenn man das besser machen kann!

Code: Alles auswählen

; Watch a folder and all subfolder for changes
; dige 5/2008
; Compile with ThreadSafe enabled!!

; #FILE_NOTIFY_CHANGE_FILE_NAME
; #FILE_NOTIFY_CHANGE_DIR_NAME
; #FILE_NOTIFY_CHANGE_ATTRIBUTES
; #FILE_NOTIFY_CHANGE_SIZE
; #FILE_NOTIFY_CHANGE_LAST_WRITE
; #FILE_NOTIFY_CHANGE_SECURITY

Structure WatchFolder
  Dir.s
  WaitMillisecs.l
  hChngObject.l
  ThreadID.l
  Flag.b
EndStructure

Structure FileList
  FileName.s
  FileSize.l
  Date_Created.l
  Date_Accessed.l
  Date_Modified.l
  Flag.b
EndStructure

Global NewList WF.WatchFolder()

Procedure   DragNDropFile()
  Protected File.s, Result.s
  
  For i = 0 To CountGadgetItems(1)-1
    If GetGadgetItemState(1, i) & #PB_ListIcon_Selected
      File = GetGadgetItemText(1, i)
      File = Trim(StringField( File, 2, ">" ))
      If File : Result + File + Chr(10) : EndIf
    EndIf
  Next i 
  
  If Result : DragFiles(Result) : EndIf
  
EndProcedure
Procedure   DoWatchFolder(*WF.WatchFolder)
  Protected NewList FL.FileList(), DirID.l, Found.b, File.s, Count.l
  
  Macro GetFileStuff
    FL()\FileSize      = FileSize (FL()\FileName)
    FL()\Date_Created  = GetFileDate( FL()\FileName, #PB_Date_Created )
    FL()\Date_Accessed = GetFileDate( FL()\FileName, #PB_Date_Accessed )
    FL()\Date_Modified = GetFileDate( FL()\FileName, #PB_Date_Modified )
  EndMacro
  
  
  With *WF
    DirID = ExamineDirectory(#PB_Any, \Dir, "*.*")  
    ; Add files
    If DirID
      While NextDirectoryEntry(DirID)
        If DirectoryEntryType(DirID) = #PB_DirectoryEntry_File
          If AddElement( FL() )
            FL()\FileName      = \Dir + "\" + DirectoryEntryName(DirID)
            GetFileStuff
          Else
            ProcedureReturn
          EndIf
        EndIf
      Wend
      FinishDirectory(DirID)
    EndIf
    
    While \Flag = 0
      \hChngObject=FindFirstChangeNotification_(\Dir, #Null, #FILE_NOTIFY_CHANGE_FILE_NAME|#FILE_NOTIFY_CHANGE_SIZE|#FILE_NOTIFY_CHANGE_LAST_WRITE)
      
      If WaitForSingleObject_(\hChngObject, \WaitMillisecs) = 0
        Count = 0
        Repeat
          DirID = ExamineDirectory(#PB_Any, \Dir, "*.*")  
          ; check files
          If DirID
            ForEach FL()
              FL()\Flag = 0
            Next
            
            While NextDirectoryEntry(DirID)
              If DirectoryEntryType(DirID) = #PB_DirectoryEntry_File
                Found = #False
                ForEach FL()
                  If FL()\FileName = \Dir + "\" + DirectoryEntryName(DirID)
                    Found = 1
                    
                    If FL()\FileSize <> FileSize (FL()\FileName) : Found = 2 : EndIf
                    If FL()\Date_Created <> GetFileDate( FL()\FileName, #PB_Date_Created )   : Found = 3 : EndIf
                    If FL()\Date_Accessed <> GetFileDate( FL()\FileName, #PB_Date_Accessed ) : Found = 4 : EndIf
                    If FL()\Date_Modified <> GetFileDate( FL()\FileName, #PB_Date_Modified ) : Found = 5 : EndIf
                    
                    File = FL()\FileName
                    GetFileStuff
                    FL()\Flag = Found
                  
                    Break
                  EndIf
                Next
                
                File = ""
                
                If Not Found
                  If AddElement( FL() )
                    FL()\FileName      = \Dir + "\" + DirectoryEntryName(DirID)
                    FL()\FileSize      = FileSize (FL()\FileName)
                    GetFileStuff
                    File = FL()\FileName
                    FL()\Flag = 6
                    Found = 6     ; New File
                  EndIf
                EndIf
              EndIf
              
              If File
                Select Found
                  Case 2     : File = "NewFileSize > " + File
                  Case 3,4,5 : File = "NewDate > " + File
                  Case 6     : File = "NewFile > " + File
                EndSelect
                
                If Found <> 1 : Count + 1 : AddGadgetItem( 1, -1, "[" + Str(\ThreadID) + "] " + File ) : EndIf
                File = ""
              EndIf
  
            Wend
            
            FinishDirectory(DirID)
            
            ForEach FL()
              If FL()\Flag = 0
                AddGadgetItem( 1, -1, "Deleted: " + FL()\FileName )
                DeleteElement( FL() )
                Count + 1
              EndIf
            Next
            
          Else
            Break 2
          EndIf
        Until Count = 0
      EndIf
      
      FindNextChangeNotification_(\hChngObject)
    Wend
    
    If \hChngObject
      FindCloseChangeNotification_(\hChngObject)
    EndIf
    
    ClearList( FL () )
    
    \ThreadID = 0
  EndWith
EndProcedure
Procedure   InitWatchFolder ( Dir.s )
  
  If Right(Dir, 1) = "\" : Dir = Left(Dir, Len(Dir) - 1) : EndIf
  DirID = ExamineDirectory(#PB_Any, Dir, "*.*")  
  
  If DirID
    AddElement( WF() )
    With WF()
      \Dir = Dir
      \WaitMillisecs = 2000; wait 1sec. to decrease cpu load
      \ThreadID = CreateThread(@DoWatchFolder(), @WF())
      ThreadPriority( \ThreadID,  1 ) ; decreas cpu load
    EndWith
    AddGadgetItem(1, -1, "Add: " + Dir )
    
    While NextDirectoryEntry(DirID)
      If DirectoryEntryType(DirID) = #PB_DirectoryEntry_Directory
        If DirectoryEntryName(DirID) <> "." And DirectoryEntryName(DirID) <> ".."
          InitWatchFolder( Dir + "\" + DirectoryEntryName(DirID) )
        EndIf
      EndIf
    Wend
    FinishDirectory(DirID)
  EndIf
EndProcedure
Procedure.b QuitWatchFolder()
  Protected Quit.b
  
  ForEach WF()
    If WF()\ThreadID And IsThread( WF()\ThreadID )
      WF()\Flag = 1
    EndIf
  Next
  
  TimeOut = ElapsedMilliseconds() + 50000
  Repeat
    Delay(200)
    Count = 0
    ForEach WF()
      If WF()\ThreadID
        Count + 1
      EndIf
    Next
  Until Count = 0 Or TimeOut < ElapsedMilliseconds()
  
  If Count = 0 : Quit = 1 : Else : Quit = 2 : EndIf
  AddGadgetItem(1, -1, "QuitCode: " + Str(Quit))
  
  ProcedureReturn Quit
EndProcedure

;{ MainLoop
If OpenWindow(0, 100, 200, 350, 400, "KeepTrackOnDirs by DiGe", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
  If CreateGadgetList(WindowID(0))
    ListIconGadget( 1, 0, 0, 350, 380, "", 345, #PB_ListIcon_MultiSelect|#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect )
    ButtonGadget( 2, 0, 380, 100, 20, "Clear List" )
    ButtonGadget( 3, 100, 380, 100, 20, "Quit Watch" )
  EndIf
  
  #INIFILE = "WatchFolder.ini"
  Dir.s    = ""
  
  FileID = ReadFile( #PB_Any, #INIFILE )
  If FileID
    While Not Eof(FileID)
      Dir = ReadString( FileID )
      If Dir
        InitWatchFolder( Dir )
      EndIf
    Wend
    CloseFile(FileID)
    
  Else
    Dir = PathRequester( "WatchFolder", "" )
    If Dir : InitWatchFolder( Dir ) : EndIf
  EndIf
   
  AddGadgetItem( 1, -1, "Watching " + Str(CountList(WF())) + " Folder(s)")
  
  Repeat
    EventID.l = WaitWindowEvent()
    If EventID = #PB_Event_CloseWindow
      Quit = QuitWatchFolder()
    ElseIf EventID = #PB_Event_Gadget
        
      Select EventGadget()
        Case 1 : If EventType() = #PB_EventType_DragStart : DragNDropFile () : EndIf
        Case 2 : ClearGadgetItemList(1)  
        Case 3 : Quit = QuitWatchFolder()  
      EndSelect
    EndIf
  Until Quit
  While WindowEvent() : Wend
  Delay(1000)
EndIf
;}
End

Verfasst: 09.05.2008 14:27
von STARGÅTE
bei großen Verzeichnissen gibs n lange Pause wo das Programm "Hängt" (keine Rückmeldung etc.) vllt solltest du da lieber n Thread machen.

Außerdem ist es extrem nervig das wenn ich den Ordner "C:\Dokumente und Einstellungen\Martin\Eigene Dateien\Daten" durchsuchen lasse, in jeder Zeile noch mal diese Verzeichnis mit dabei steht, dass könnte mal weglassen und das verzeichnis als Variable Speichern. Ist dann übersichtlicher.

Verfasst: 11.05.2008 09:42
von Arachnophobia
Einen Code zur Verzeichnisüberwachung gab es vor einiger Zeit schon mal im englischen Forum.
Hab jetzt leider keine Zeit zu suchen, müßte aber einfach zu finden sein.

Verfasst: 11.05.2008 21:29
von mueckerich
Arachnophobia hat geschrieben:Einen Code zur Verzeichnisüberwachung gab es vor einiger Zeit schon mal im englischen Forum.
Hab jetzt leider keine Zeit zu suchen, müßte aber einfach zu finden sein.

Code: Alles auswählen

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; App Name: ReadDirectoryChangesW
; Author  : Sparkie
; Date    : April 23, 2005
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Check for NT4/2000/XP/2003
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Select OSVersion()
  Case #PB_OS_Windows_NT_4
    osResult = #True
  Case #PB_OS_Windows_2000
    osResult = #True
  Case #PB_OS_Windows_XP
    osResult = #True
  Case #PB_OS_Windows_Server_2003
    osResult = #True
  Default
    osResult = #False
EndSelect
os$ = "Windows NT4" + #CRLF$ + "Windows 2000" + #CRLF$ + "Windows XP" + #CRLF$ + "Windows Server 2003"
If osResult = #False
  MessageRequester("Incorrect OS", "This program requires one of the following OS's:" + #CRLF$ + os$)
  End
EndIf
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Window Enumerations
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Enumeration
  #Win_Main
EndEnumeration
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Gadget Enumerations
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Enumeration
  #Button_Dir
  #Text_Dir
  #ListIcon_RDCW
EndEnumeration
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Constants for use in ReadDirectoryChangesW function
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Use these flags in the CallFunctionFast(*pRDCW, ...) line
#FILE_NOTIFY_CHANGE_FILE_NAME = 1
; Any file name change in the watched directory or subtree
; causes a change notification wait operation to return.
; Changes include renaming, creating, or deleting a file name.
#FILE_NOTIFY_CHANGE_DIR_NAME = 2
; Any directory-name change in the watched directory or
; subtree causes a change notification wait operation to return.
; Changes include creating or deleting a directory.
#FILE_NOTIFY_CHANGE_ATTRIBUTES = 4
; Any attribute change in the watched directory or subtree causes
; a change notification wait operation to return.
#FILE_NOTIFY_CHANGE_SIZE = 8
; Any file-size change in the watched directory or subtree causes
; a change notification wait operation to return. The operating
; system detects a change in file size only when the file is written
; to the disk. For operating systems that use extensive caching,
; detection occurs only when the cache is sufficiently flushed.
#FILE_NOTIFY_CHANGE_LAST_WRITE = $10
; Any change to the last write-time of files in the watched directory
; or subtree causes a change notification wait operation to return. The
; operating system detects a change to the last write-time only when
; the file is written to the disk. For operating systems that use extensive
; caching, detection occurs only when the cache is sufficiently flushed.
#FILE_NOTIFY_CHANGE_LAST_ACCESS = $20
;Any change to the last access time of files in the watched directory or
; subtree causes a change notification wait operation to return.
#FILE_NOTIFY_CHANGE_CREATION = $40
;Any change to the creation time of files in the watched directory or subtree
; causes a change notification wait operation to return.
#FILE_NOTIFY_CHANGE_SECURITY = $100
; Any security-descriptor change in the watched directory or subtree causes a
; change notification wait operation to return.
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Constants for myFILE_NOTIFY_INFORMATION (*fni) actions
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#FILE_SHARE_DELETE = 4
#FILE_ACTION_ADDED = 1
#FILE_ACTION_REMOVED = 2
#FILE_ACTION_MODIFIED = 3
#FILE_ACTION_RENAMED_OLD_NAME = 4
#FILE_ACTION_RENAMED_NEW_NAME = 5
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Constants for myFILE_NOTIFY_INFORMATION offsets
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; This is how we access information when more than 1 action
; occurs for a file in our watched directory
#ActionOffset = 4
#CharLenOffset = 8
#FileNameOffset = 12
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; FILE_NOTIFY_INFORMATION structure
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Structure myFILE_NOTIFY_INFORMATION
  NextEntryOffset.l
  action.l
  FileNameLength.l
  FileName.w[1]
EndStructure
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Globals
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Pointer to ReadDirectoryChangesW function
Global *pRDCW
; pointer ot myFILE_NOTIFY_INFORMATION structure
Global *fni.myFILE_NOTIFY_INFORMATION
; Handle to our watched directory
Global hDir
; Variable for ending app when #True
Global quit
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Open KERNEL32.DLL for ReadDirectoryChangesW function
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
If OpenLibrary(0, "KERNEL32.DLL")
  ; Get pointer to ReadDirectoryChangesW function
  *pRDCW = GetFunction(0, "ReadDirectoryChangesW")
  If *pRDCW = 0
    ; If function not found, close KERNEL32.DLL and quit
    CloseLibrary(0)
    MessageRequester("Error", "ReadDirectoryChangesW function not found.")
    End
  EndIf
Else
  ; If KERNEL32.DLL not found, quit
  MessageRequester("Error", "KERNEL32.DLL not found.")
  End
EndIf
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Procedure to convert Unicode file name to ANSI
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Procedure.s UniZuAnsi(*uni.l, uLen)
  ansi$ = Space(uLen)
  WideCharToMultiByte_(#CP_ACP, 0, *uni, -1, @ansi$, uLen, #Null, #Null)
  ProcedureReturn ansi$ 
EndProcedure
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Procedure to retrieve our directory changes
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; fniOffset is used for muliple action on 1 file
Procedure GetRDCWInfo(fniOffset)
  ; Get the action
  action = PeekL(*fni + #ActionOffset + fniOffset)
  ; Get a time stamp for this action
  timeStamp$ = FormatDate("%mm/%dd/%yyyy %hh:%ii:%ss", Date())
  ; Get the UNI lenght of the file name
  uniLen = PeekL(*fni + #CharLenOffset + fniOffset)
  ; Get the ANSI version of the file name
  fileName$ = UniZuAnsi(*fni + #FileNameOffset + fniOffset, uniLen/2)
  ; Set the string to be displayed for the action
  Select action
    Case #FILE_ACTION_ADDED
      action$ = "was added to directory."
    Case #FILE_ACTION_REMOVED
      action$ = "was removed from directory."
    Case #FILE_ACTION_MODIFIED
      action$ = "attribute or time stamp modified."
    Case #FILE_ACTION_RENAMED_OLD_NAME
      action$ = "was renamed."
    Case #FILE_ACTION_RENAMED_NEW_NAME
      action$ = "is the new file name."
  EndSelect
  ; Add the info to the ListIconGadget
  AddGadgetItem(#ListIcon_RDCW, -1, fileName$ + Chr(10) + action$ + Chr(10) + timeStamp$)
  LogWriteString(fileName$ + " -|- " + action$)
EndProcedure
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Procedure (Thread) to set the ReadDirectoryChangesW calls
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Procedure RDCW(dir)
  ; Allocate memory for our myFILE_NOTIFY_INFORMATION pointer
  *fni = AllocateMemory(1024)
  ; Loop calls to ReadDirectoryChangesW
  ; We're watching for rename, delete, create, write
  ; Bei Parameter 5 (#False = Überwachung von Verzeichniss, #True = Überwachung des kompletten Laufwerks)
  ;  While CallFunctionFast(*pRDCW, dir, *fni, 1024, #False, #FILE_NOTIFY_CHANGE_FILE_NAME | #FILE_NOTIFY_CHANGE_DIR_NAME | #FILE_NOTIFY_CHANGE_LAST_WRITE, @size, #Null, #Null)
  While CallFunctionFast(*pRDCW, dir, *fni, 1024, #True, #FILE_NOTIFY_CHANGE_FILE_NAME | #FILE_NOTIFY_CHANGE_DIR_NAME | #FILE_NOTIFY_CHANGE_LAST_WRITE, @Size, #Null, #Null)
    ; Get the info for offset 0
    GetRDCWInfo(0)
    ; See if there are more entries for this call
    nextEntry = *fni\NextEntryOffset
    ; If so, get the info
    While nextEntry > 0
      If previousEntry = nextEntry
        Break
      EndIf
      GetRDCWInfo(nextEntry)
      ; See if there are more entries for this call
      nextEntry = PeekL(*fni + nextEntry)
      previousEntry = nextEntry
    Wend
    ; No more entries, go to next ReadDirectoryChangesW call
  Wend
EndProcedure
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Main window and gadgets
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


LogInit("DirWatch.log")
If OpenWindow(0, 0, 0, 545, 350, "ReadDirectoryChangesW", #PB_Window_SystemMenu | #PB_Window_ScreenCentered ) And CreateGadgetList(WindowID(0))
  ButtonGadget(#Button_Dir, 5, 5, 150, 20, "Select Directory to watch")
  TextGadget(#Text_Dir, 5, 5, 535, 20, "")
  DisableGadget(#Text_Dir, 1)
  ListIconGadget(#ListIcon_RDCW, 5, 40, 535, 300, "File", 200, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_GridLines)
  AddGadgetColumn(#ListIcon_RDCW, 1, "Action", 200)
  AddGadgetColumn(#ListIcon_RDCW, 2, "Time", 130)
  quit = #False
  ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  ; Main event loop
  ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  Repeat
    event = WaitWindowEvent()
    Select event
      Case #PB_Event_Gadget 
        Select EventGadget()
          Case (#Button_Dir)
            ; Button pressed for getting directory to watch
            myPath$ = PathRequester("Select a Folder to watch", "F:")
            ; If there is a valid path, start our ReadDirectoryChangesW thread
            If myPath$
              DisableGadget(#Button_Dir, 1)
              ; Get a handle to our watched directory
              hDir = CreateFile_(myPath$, #FILE_LIST_DIRECTORY, #FILE_SHARE_WRITE | #FILE_SHARE_READ | #FILE_SHARE_DELETE, #Null, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, #Null)
              ; --> Our thread for change notifications with the directory handle
              myThread = CreateThread(@RDCW(), hDir)
              DisableGadget(#Text_Dir, 0)
              SetGadgetText(#Text_Dir, myPath$ + " is being watched.")
            EndIf
        EndSelect
      Case #PB_Event_CloseWindow
        FreeMemory(*fni)
        ; Kill our ReadDirectoryChangesW thread
        KillThread(myThread)
        ; Close handle to our watched directory
        CloseHandle_(hDir)
        ; If KERNEL32.DLL is open, close it
        If IsLibrary(0)
          CloseLibrary(0)
        EndIf
        quit = #True
    EndSelect
  Until quit 
EndIf
End 
; IDE Options = PureBasic v3.94 (Windows - x86)
; CursorPosition = 165
; FirstLine = 112
; Folding = o
; Executable = D:\ChkDrive.exe