Monitor FileSystem Changes ReadDirectoryChangesW

Share your advanced PureBasic knowledge/code with the community.
jpfiste
User
User
Posts: 18
Joined: Thu Feb 18, 2010 10:05 pm

Monitor FileSystem Changes ReadDirectoryChangesW

Post by jpfiste »

Hello,

in previous thread http://www.purebasic.fr/english/viewtop ... rychangesw I've postet a example for ReadDirectoryChangesW. Due to conflicts in a current project I changed the function call because my previous version didn't work well. Now here is the new code as a simple sample.

What does the code?
The code creates a thread that executes the ReadDirectoryChangesW synchronous for a non-blocking app. The main app is a simple window loop with a listbox that displays the changes. The observed dir is C:\Test (you can simply change it in the test code).

What was wrong with the previous version?
Simply all. The buffer (*lpBufer) must not declared as FILE_NOTIFY_INFORMATION. The Buffer should simple be a allocated pointer of the size <= 64K. When a change happens the ReadDirectoryChangesW return. The filled buffer is structured as FILE_NOTIFY_INFORMATION. One Entry - One Change.

Code: Select all

; Notify filter values
#FILE_NOTIFY_CHANGE_FILE_NAME = 1
#FILE_NOTIFY_CHANGE_DIR_NAME = 2
#FILE_NOTIFY_CHANGE_ATTRIBUTES = 4
#FILE_NOTIFY_CHANGE_SIZE = 8
#FILE_NOTIFY_CHANGE_LAST_WRITE = $10
#FILE_NOTIFY_CHANGE_LAST_ACCESS = $20
#FILE_NOTIFY_CHANGE_CREATION = $40
#FILE_NOTIFY_CHANGE_SECURITY = $100
#FILE_NOTIFY_CHANGE_ALL = $17F

; not defined in purebasic
#FILE_SHARE_DELETE = 4

; Notify events
Enumeration
  #FILE_ACTION_ADDED = 1
  #FILE_ACTION_REMOVED
  #FILE_ACTION_MODIFIED
  #FILE_ACTION_RENAMED_OLD_NAME
  #FILE_ACTION_RENAMED_NEW_NAME
EndEnumeration

; Needed for creating a watching thread
Structure WatchFSParam_t
  Directory.s
  Filter.l
EndStructure

; structure for the needed
Structure FILE_NOTIFY_INFORMATION
  NextEntryOffset.l
  Action.l
  FileNameLength.l
  Filename.s{512}
EndStructure

Import "kernel32.lib"
  ReadDirectoryChangesW(hDirectory.l, *lpBuffer, nbBufferLen.l, bWatchSubTree.b, dwNotifyFilter.l, *lpBytesReturned.l, *lpOverlapped.OVERLAPPED, lpCompletitionRoutine)
EndImport

Procedure WatchDirOrFile(*params.WatchFSParam_t)
  
  Protected *buffer = AllocateMemory(32*1024)
  Protected *ovlp.OVERLAPPED = AllocateMemory(SizeOf(OVERLAPPED))
  Protected dwOffset.l = 0
  Protected *pInfo.FILE_NOTIFY_INFORMATION
  
  hDir = CreateFile_(*params\Directory, #FILE_LIST_DIRECTORY, #FILE_SHARE_READ | #FILE_SHARE_WRITE | #FILE_SHARE_DELETE, #Null, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, #Null)
  
  While ReadDirectoryChangesW(hDir, *buffer, MemorySize(*buffer), #True, *params\Filter, bytesRead, *ovlp, #Null)
    
    dwOffset = 0
    
    Repeat
      
      *pInfo = *buffer + dwOffset
      
      filename$ = PeekS(@*pInfo\Filename, *pInfo\FileNameLength, #PB_Unicode)
      
      action$ = #NULL$

      Select *pInfo\Action
        Case #FILE_ACTION_ADDED
          action$ = "ADDED"
        Case #FILE_ACTION_MODIFIED
          action$ = "MODIFIED"
        Case #FILE_ACTION_REMOVED
          action$ = "REMOVED"
        Case #FILE_ACTION_RENAMED_NEW_NAME
          action$ = "RENAMED_NEWNAME"
        Case #FILE_ACTION_RENAMED_OLD_NAME
          action$ = "RENAMED_OLDNAME"
      EndSelect
      
      AddGadgetItem (0, -1, filename$ + " " + action$)
      
      dwOffset + *pInfo\NextEntryOffset
      
    Until *pInfo\NextEntryOffset = 0
    
  Wend
  
EndProcedure

Procedure.l WatchFileSystem(DirectoryName.s, NotifyFilter.l = #FILE_NOTIFY_CHANGE_FILE_NAME)
  
  *watcherparams.WatchFSParam_t = AllocateMemory(SizeOf(WatchFSParam_t))
  *watcherparams\Directory = DirectoryName
  *watcherparams\Filter = NotifyFilter
 
  CreateThread(@WatchDirOrFile(), *watcherparams)
  
EndProcedure



; USAGE
If OpenWindow(0, 0, 0, 320, 240, "FileSystemWatch", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  ListViewGadget(0, 10, 10, 300, 200)

  WatchFileSystem("C:\Test")

  Repeat
    Event = WaitWindowEvent()
    Delay(5)
  Until Event = #PB_Event_CloseWindow
  
EndIf


Enjoy the code
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: Monitor FileSystem Changes ReadDirectoryChangesW

Post by Tenaja »

Thanks for sharing! This is exactly what I was looking for in this post:
http://purebasic.fr/english/viewtopic.php?f=17&t=46986


Perhaps somebody more knowledgeable than I can answer this: after the program has run, and this program reports file deletions, why are they not in the (Win7) recycle bin? Is there any (simple) way to recover them?

Thanks again!
jpfiste
User
User
Posts: 18
Joined: Thu Feb 18, 2010 10:05 pm

Re: Monitor FileSystem Changes ReadDirectoryChangesW

Post by jpfiste »

Nice, that the code could help you. But don't forget: It's a very basic example. No pointer will be cleared. This is necessary for a productive release because on more changes the reading can cause error due to offset problems. This example should only show the way how the function ReadDirectoryChanges should be used.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Monitor FileSystem Changes ReadDirectoryChangesW

Post by rsts »

Tenaja wrote:after the program has run, and this program reports file deletions, why are they not in the (Win7) recycle bin? Is there any (simple) way to recover them?

Thanks again!
after the program has run - which program the one in this thread?
and this program reports file deletions - this program? Does not report deletions. Do you mean REMOVED?

cheers
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: Monitor FileSystem Changes ReadDirectoryChangesW

Post by Tenaja »

Yes, sorry, my English was not clear; I did not learn English until after I could walk, and it was my first language, so I was not so good at languages yet. :mrgreen:

How is this?
My goal is to view temporary files that a program uses. After my "watched" program has run, and jpfiste's program reports a file has been ADDED and then REMOVED, why are the REMOVED files not in the (Win7) recycle bin? Is there any (simple) way to recover them?


...apparently, I inferred that REMOVED meant deleted... is there a way to remove a file without deleting it?
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Monitor FileSystem Changes ReadDirectoryChangesW

Post by rsts »

A file will be reported "REMOVED" if it's moved to another location, in which case it will not be in the recycle bin.

It is also possible to bypass the recycle bin on deletions, which would result in "REMOVED" with nothing in the recycle bin.

Are you experiencing a case where a file is being deleted (not simply removed) and should be in the recycle bin but is not?

cheers
moogle
Enthusiast
Enthusiast
Posts: 372
Joined: Tue Feb 14, 2006 9:27 pm
Location: London, UK

Re: Monitor FileSystem Changes ReadDirectoryChangesW

Post by moogle »

There's a little bug where filename$ contains the previous file characters instead of being reset.

ie if it says

"New folder1234" created

and the next action is creating a new folder called "Test"

it will display "Testfolder1234" as the "folder1234" part is still there and the "New " part has been overwritten.
Image
jpfiste
User
User
Posts: 18
Joined: Thu Feb 18, 2010 10:05 pm

Re: Monitor FileSystem Changes ReadDirectoryChangesW

Post by jpfiste »

Ok.

The file is removed from the folder. It's only the change. Deleting and removing is for Readdirectorychanges the same if you have the filter FILE_NAME. You can also play a little with the filters.

Of course there is a bug with reading multiple changes. As I said - it's a minimal example that should demonstrate how the call of ReadDirectoryChangesW should be done. To fix the bug *lpBuffer after the Repeat-Loop (And Allocate it new) and Clear the *pInfo. Then the filename changes are correct.
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Re: Monitor FileSystem Changes ReadDirectoryChangesW

Post by Thunder93 »

Thanks jpfiste!

Experienced the following;

Manually delete: Text Document - Copy - Copy.txt
FileSystemWatch: New Text Document - Copy - Copy.txt REMOVED

Manually Delete: Text Document.txt
FileSystemWatch: New Text Document.txtopy - Copy.txt REMOVED


Edited: Please visit http://www.purebasic.fr/english/viewtop ... 13&t=54038 for the fix.
Last edited by Thunder93 on Fri Mar 22, 2013 12:37 am, edited 2 times in total.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Re: Monitor FileSystem Changes ReadDirectoryChangesW

Post by Thunder93 »

My change to address the incorrect filenames length worked good for single file changes but there’s still problem under simultaneous file changes...

I gave up on that code, Sparkie 2005 works good - http://www.purebasic.fr/english/viewtop ... c&start=17
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: Monitor FileSystem Changes ReadDirectoryChangesW

Post by jassing »

jpfiste wrote:This example should only show the way how the function ReadDirectoryChanges should be used.
Is there a better, more complete, example?
Post Reply