Code archives/File Utilities/File System Watcher

This code has been declared by its author to be Public Domain code.

Download source code

File System Watcher by JoshK2010
This will detect file changes and emit events when they occur. Does not work with Windows 98.
SuperStrict

Import pub.win32
Import brl.eventqueue
Import brl.standardio
Import brl.threads
Import brl.random

Private

'Externs
Extern "win32"
	Function GetOverlappedResult:Int(hFile:Int,lpOverlapped:OVERLAPPED,lpNumberOfBytesTransferred:Byte Ptr,bWait:Int)
	Function ReadDirectoryChangesW(hDirectory:Int,lpBuffer:Byte Ptr,nBufferLength:Int,bWatchSubtree:Int,dwNotifyFilter:Int,lpBytesReturned:Byte Ptr,lpOverlapped:OVERLAPPED,lpCompletionRoutine:Byte Ptr)
	Function CreateFileA(lpFileName$z,dwDesiredAccess:Int,dwShareMode:Int,lpSecurityAttributes:Byte Ptr,dwCreationDisposition:Int,dwFlagsAndAttributes:Int,hTemplateFile:Int)
	Function CloseHandle:Int(hObject:Int)
	Function CreateEventA:Int(lpEventAttributes:Int,bManualReset:Int,bInitialState:Int,lpName$z)
	'Function GetLastError:Int()
EndExtern


'Constants
Const FILE_FLAG_BACKUP_SEMANTICS:Int=$02000000
Const FILE_FLAG_OVERLAPPED:Int=$40000000

Const GENERIC_READ:Int=$80000000 
Const FILE_SHARE_READ:Int=$00000001
Const OPEN_EXISTING:Int=3

Const INVALID_HANDLE_VALUE:Int=-1
Const FILE_SHARE_WRITE:Int=$00000002

Const WAIT_FAILED% = $FFFFFFFF 
Const WAIT_OBJECT_0%  = $0 
Const WAIT_ABANDONED% = $80 
Const WAIT_TIMEOUT% = $102

Const FILE_NOTIFY_CHANGE_FILE_NAME:Int=$00000001
Const FILE_NOTIFY_CHANGE_DIR_NAME:Int=$00000002
Const FILE_NOTIFY_CHANGE_ATTRIBUTES:Int=$00000004
Const FILE_NOTIFY_CHANGE_SIZE:Int=$00000008
Const FILE_NOTIFY_CHANGE_LAST_WRITE:Int=$00000010
Const FILE_NOTIFY_CHANGE_LAST_ACCESS:Int=$00000020
Const FILE_NOTIFY_CHANGE_CREATION:Int=$00000040
Const FILE_NOTIFY_CHANGE_SECURITY:Int=$00000100

'Types
Type OVERLAPPED
	Field Internal:Int
	Field InternalHigh:Int
	Field Offset:Int
	Field OffsetHigh:Int
	Field hEvent:Int=CreateEventA(0,0,False,Null)
	
	Method Delete()
		If hEvent CloseHandle(hEvent)
	EndMethod
	
EndType

Const FILE_ACTION_ADDED:Int=$00000001
Const FILE_ACTION_REMOVED:Int=$00000002
Const FILE_ACTION_MODIFIED:Int=$00000003
Const FILE_ACTION_RENAMED_OLD_NAME:Int=$00000004
Const FILE_ACTION_RENAMED_NEW_NAME:Int=$00000005

Public

'Event constants
Const EVENT_FILECREATED:Int=6870001
Const EVENT_FILEDELETED:Int=6870002
Const EVENT_FILERENAMED:Int=6870003
Const EVENT_FILEMODIFIED:Int=6870004


'FileSystemWatcher type
Type TFileSystemWatcher
	
	Const flags:Int=FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_LAST_WRITE
	
	Field path:String
	Field recursive:Int
	Field buffer:Byte[1024]
	Field hfile:Int
	Field overlap:OVERLAPPED=New OVERLAPPED
	Field mode:Int
	Field renamedfilepreviousname:String
	
	Method Delete()
		If hfile CloseHandle(hfile)
	EndMethod
	
	Function Create:TFileSystemWatcher(path:String="",recursive:Int=True)
		Local filesystemwatcher:TFileSystemWatcher
		
		filesystemwatcher=New TFileSystemWatcher
		filesystemwatcher.path=RealPath(path)
		filesystemwatcher.recursive=recursive
		filesystemwatcher.hfile=CreateFileA(filesystemwatcher.path,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,Null,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED,0)
		If filesystemwatcher.hfile=0 Return Null
		Return filesystemwatcher
	EndFunction
	
	Method Update()
		Local bytesreturned:Int
		Local bytestransferred:Int
		Local event:TEvent		
		Local bank:TBank
		Local stream:TStream
		Local NextEntryOffset:Int
		Local Action:Int
		Local FileNameLength:Int
		Global FileName:String
		Local pos:Int
		Local b:Int
		
		If mode=0
			ReadDirectoryChangesW(Self.hfile,buffer,buffer.length,Self.recursive,Self.flags,Null,Self.overlap,Null)
			mode=1
		EndIf
		
		If GetOverlappedResult(Self.hfile,overlap,Varptr bytesreturned,False)
			mode=0
			If bytesreturned
				bank=CreateStaticBank(buffer,bytesreturned)
				stream=CreateBankStream(bank)
				
				While Not stream.Eof()
					pos=stream.pos()
					NextEntryOffset=stream.ReadInt()
				'	Print "NextEntryOffset: "+NextEntryOffset
					Action=stream.ReadInt()
				'	Print "Action: "+action
					FileNameLength=stream.ReadInt()
					If FileNameLength=0 Notify "DAMN"
				'	Print "FileNameLength: "+FileNameLength
					'FileName=stream.ReadString(FileNameLength)
					filename=Self.path+"/"
					'Print "STARTING: "+filenamelength
					For Local n:Int=0 To filenamelength/2-1
						b=stream.ReadByte()
						filename:+Chr(b)
						stream.ReadByte()
						'Print b+", "+Chr(b)
					Next
					'Print ""
					filename=filename.Replace("\","/")
					event=New TEvent
					event.source=filename
					Select action
						Case FILE_ACTION_ADDED
							event.id=EVENT_FILECREATED
							'Print Int(Byte Ptr(event.extra))
							'Print "File ~q"+filename+"~q created."
						Case FILE_ACTION_REMOVED
							event.id=EVENT_FILEDELETED
							'Print "File ~q"+filename+"~q deleted."
						Case FILE_ACTION_MODIFIED
							event.id=EVENT_FILEMODIFIED
							'Print "File ~q"+filename+"~q modified."							
						Case FILE_ACTION_RENAMED_OLD_NAME
							renamedfilepreviousname=filename
							event=Null
						Case FILE_ACTION_RENAMED_NEW_NAME
							event.id=EVENT_FILERENAMED
							event.extra=renamedfilepreviousname
							'Print renamedfilepreviousname[1]
							'Print renamedfilepreviousname	
							renamedfilepreviousname=""
							'Print "File renamed from ~q"+String(event.extra)+"~q to ~q"+String(event.source)+"~q."
					EndSelect
					If event EmitEvent(event)
					If NextEntryOffset stream.seek(pos+NextEntryOffset) Else Exit
				Wend
				'Print "DONE"
			EndIf
		EndIf
	EndMethod
	
EndType

Function CreateFileSystemWatcher:TFileSystemWatcher(path:String,recursive:Int=True)
	Return TFileSystemWatcher.Create(path,recursive)
EndFunction

Comments

None.

Code Archives Forum