As a baseline, the objective is to watch folders and move files if parameters are met.
My thought of getting this completed was to
- Decide what folders need to be watched
- Set up what files need to be moved either by file type or by an extended parameter
- send that file to the appropriate folder based on when it was created/extended parameter
and then viewtopic.php?f=6&t=8384&hilit=watchfolder to watch the specific folders in question
so here is the background code needed for the watch folders and the extended properties
Code: Select all
#Persistent
WatchFolder(Folder, UserFunc, SubTree := False, Watch := 0x03) {
Static DummyObject := {Base: {__Delete: Func("WatchFolder").Bind("**END", "")}}
Static TimerID := "**" . A_TickCount
Static TimerFunc := Func("WatchFolder").Bind(TimerID, "")
Static MAXIMUM_WAIT_OBJECTS := 64
Static MAX_DIR_PATH := 260 - 12 + 1
Static SizeOfLongPath := MAX_DIR_PATH << !!A_IsUnicode
Static SizeOfFNI := 0xFFFF ; size of the FILE_NOTIFY_INFORMATION structure buffer (64 KB)
Static SizeOfOVL := 32 ; size of the OVERLAPPED structure (64-bit)
Static WatchedFolders := {}
Static EventArray := []
Static WaitObjects := 0
Static BytesRead := 0
Static Paused := False
; ===============================================================================================================================
If (Folder = "")
Return False
SetTimer, % TimerFunc, Off
RebuildWaitObjects := False
; ===============================================================================================================================
If (Folder = TimerID) { ; called by timer
If (ObjCount := EventArray.Count()) && !Paused {
ObjIndex := DllCall("WaitForMultipleObjects", "UInt", ObjCount, "Ptr", &WaitObjects, "Int", 0, "UInt", 0, "UInt")
While (ObjIndex >= 0) && (ObjIndex < ObjCount) {
Event := NumGet(WaitObjects, ObjIndex * A_PtrSize, "UPtr")
Folder := EventArray[Event]
If DllCall("GetOverlappedResult", "Ptr", Folder.Handle, "Ptr", Folder.OVLAddr, "UIntP", BytesRead, "Int", True) {
Changes := []
FNIAddr := Folder.FNIAddr
FNIMax := FNIAddr + BytesRead
OffSet := 0
PrevIndex := 0
PrevAction := 0
PrevName := ""
Loop {
FNIAddr += Offset
OffSet := NumGet(FNIAddr + 0, "UInt")
Action := NumGet(FNIAddr + 4, "UInt")
Length := NumGet(FNIAddr + 8, "UInt") // 2
Name := Folder.Name . "\" . StrGet(FNIAddr + 12, Length, "UTF-16")
IsDir := InStr(FileExist(Name), "D") ? 1 : 0
If (Name = PrevName) {
If (Action = PrevAction)
Continue
If (Action = 1) && (PrevAction = 2) {
PrevAction := Action
Changes.RemoveAt(PrevIndex--)
Continue
}
}
If (Action = 4)
PrevIndex := Changes.Push({Action: Action, OldName: Name, IsDir: 0})
Else If (Action = 5) && (PrevAction = 4) {
Changes[PrevIndex, "Name"] := Name
Changes[PrevIndex, "IsDir"] := IsDir
}
Else
PrevIndex := Changes.Push({Action: Action, Name: Name, IsDir: IsDir})
PrevAction := Action
PrevName := Name
} Until (Offset = 0) || ((FNIAddr + Offset) > FNIMax)
If (Changes.Length() > 0)
Folder.Func.Call(Folder.Name, Changes)
DllCall("ResetEvent", "Ptr", Event)
DllCall("ReadDirectoryChangesW", "Ptr", Folder.Handle, "Ptr", Folder.FNIAddr, "UInt", SizeOfFNI
, "Int", Folder.SubTree, "UInt", Folder.Watch, "UInt", 0
, "Ptr", Folder.OVLAddr, "Ptr", 0)
}
ObjIndex := DllCall("WaitForMultipleObjects", "UInt", ObjCount, "Ptr", &WaitObjects, "Int", 0, "UInt", 0, "UInt")
Sleep, 0
}
}
}
; ===============================================================================================================================
Else If (Folder = "**PAUSE") { ; called to pause/resume watching
Paused := !!UserFunc
RebuildObjects := Paused
}
; ===============================================================================================================================
Else If (Folder = "**END") { ; called to stop watching
For Event, Folder In EventArray {
DllCall("CloseHandle", "Ptr", Folder.Handle)
DllCall("CloseHandle", "Ptr", Event)
}
WatchedFolders := {}
EventArray := []
Paused := False
Return True
}
; ===============================================================================================================================
Else { ; called to add, update, or remove folders
Folder := RTrim(Folder, "\")
VarSetCapacity(LongPath, MAX_DIR_PATH << !!A_IsUnicode, 0)
If !DllCall("GetLongPathName", "Str", Folder, "Ptr", &LongPath, "UInt", MAX_DIR_PATH)
Return False
VarSetCapacity(LongPath, -1)
Folder := LongPath
If (WatchedFolders.HasKey(Folder)) { ; update or remove
Event := WatchedFolders[Folder]
FolderObj := EventArray[Event]
DllCall("CloseHandle", "Ptr", FolderObj.Handle)
DllCall("CloseHandle", "Ptr", Event)
EventArray.Delete(Event)
WatchedFolders.Delete(Folder)
RebuildWaitObjects := True
}
If InStr(FileExist(Folder), "D") && (UserFunc <> "**DEL") && (EventArray.Count() < MAXIMUM_WAIT_OBJECTS) {
If (IsFunc(UserFunc) && (UserFunc := Func(UserFunc)) && (UserFunc.MinParams >= 2)) && (Watch &= 0x017F) {
Handle := DllCall("CreateFile", "Str", Folder . "\", "UInt", 0x01, "UInt", 0x07, "Ptr",0, "UInt", 0x03
, "UInt", 0x42000000, "Ptr", 0, "UPtr")
If (Handle > 0) {
Event := DllCall("CreateEvent", "Ptr", 0, "Int", 1, "Int", 0, "Ptr", 0)
FolderObj := {Name: Folder, Func: UserFunc, Handle: Handle, SubTree: !!SubTree, Watch: Watch}
FolderObj.SetCapacity("FNIBuff", SizeOfFNI)
FNIAddr := FolderObj.GetAddress("FNIBuff")
DllCall("RtlZeroMemory", "Ptr", FNIAddr, "Ptr", SizeOfFNI)
FolderObj["FNIAddr"] := FNIAddr
FolderObj.SetCapacity("OVLBuff", SizeOfOVL)
OVLAddr := FolderObj.GetAddress("OVLBuff")
DllCall("RtlZeroMemory", "Ptr", OVLAddr, "Ptr", SizeOfOVL)
NumPut(Event, OVLAddr + 8, A_PtrSize * 2, "Ptr")
FolderObj["OVLAddr"] := OVLAddr
DllCall("ReadDirectoryChangesW", "Ptr", Handle, "Ptr", FNIAddr, "UInt", SizeOfFNI, "Int", SubTree
, "UInt", Watch, "UInt", 0, "Ptr", OVLAddr, "Ptr", 0)
EventArray[Event] := FolderObj
WatchedFolders[Folder] := Event
RebuildWaitObjects := True
}
}
}
If (RebuildWaitObjects) {
VarSetCapacity(WaitObjects, MAXIMUM_WAIT_OBJECTS * A_PtrSize, 0)
OffSet := &WaitObjects
For Event In EventArray
Offset := NumPut(Event, Offset + 0, 0, "Ptr")
}
}
; ===============================================================================================================================
If (EventArray.Count() > 0)
SetTimer, % TimerFunc, -100
Return (RebuildWaitObjects) ; returns True on success, otherwise False
}
Filexpro( sFile := "", Kind := "", P* ) { ; v.90 By SKAN on D1CC @ goo.gl/jyXFo9
Local
Static xDetails
If ( sFile = "" )
{ ; Deinit static variable
xDetails := ""
Return
}
fex := {}, _FileExt := ""
Loop, Files, % RTrim(sfile,"\*/."), DF
{
If not FileExist( sFile:=A_LoopFileLongPath )
{
Return
}
SplitPath, sFile, _FileExt, _Dir, _Ext, _File, _Drv
If ( p[p.length()] = "xInfo" ) ; Last parameter is xInfo
{
p.Pop() ; Delete parameter
fex.SetCapacity(11) ; Make room for Extra info
fex["_Attrib"] := A_LoopFileAttrib
fex["_Dir"] := _Dir
fex["_Drv"] := _Drv
fex["_Ext"] := _Ext
fex["_File"] := _File
fex["_File.Ext"] := _FileExt
fex["_FilePath"] := sFile
fex["_FileSize"] := A_LoopFileSize
fex["_FileTimeA"] := A_LoopFileTimeAccessed
fex["_FileTimeC"] := A_LoopFileTimeCreated
fex["_FileTimeM"] := A_LoopFileTimeModified
}
Break
}
If Not ( _FileExt ) ; Filepath not resolved
{
Return
}
objShl := ComObjCreate("Shell.Application")
objDir := objShl.NameSpace(_Dir)
objItm := objDir.ParseName(_FileExt)
If ( VarSetCapacity(xDetails) = 0 ) ; Init static variable
{
i:=-1, xDetails:={}, xDetails.SetCapacity(309)
While ( i++ < 309 )
{
xDetails[ objDir.GetDetailsOf(0,i) ] := i
}
xDetails.Delete("")
}
If ( Kind and Kind <> objDir.GetDetailsOf(objItm,11) ) ; File isn't desired kind
{
Return
}
i:=0, nParams:=p.Count(), fex.SetCapacity(nParams + 11)
While ( i++ < nParams )
{
Prop := p[i]
If ( (Dot:=InStr(Prop,".")) and (Prop:=(Dot=1 ? "System":"") . Prop) )
{
fex[Prop] := objItm.ExtendedProperty(Prop)
Continue
}
If ( PropNum := xDetails[Prop] ) > -1
{
fex[Prop] := ObjDir.GetDetailsOf(objItm,PropNum)
Continue
}
}
fex.SetCapacity(-1)
Return fex
} ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Code: Select all
WatchFolder("C:\Users\The Lich Omoi\Pictures\Drawings", "myFunc"),
WatchFolder("C:\Users\The Lich Omoi\Pictures\Camera Roll", "myFunc")
; These are the folders to watch for new files being added. I think I may need to make a var with all the folder paths to watch somehow instead?
return
watchedDir := "C:\Users\The Lich Omoi\Pictures\"
watchedFolders := "Camera Roll", "Drawings"
; maybe something like this?
myFunc( directory, changes) {
for k, change in changes
; 1 means new file was added
if (change.action = 1) {
gosub foldersorter ;????? this is a confusion point for me. I'm trying to go to the relevant function based on what folder got a new file
return
}
}
foldersorterCameraRoll:
;Camera Roll folder organizer
srcPath := "C:\Users\The Lich Omoi\Pictures\Camera Roll"
destPath := "C:\Users\The Lich Omoi\Pictures\Camera Roll"
extsToSort := jpg,png,tiff
cameraModel := Filexpro( A_LoopFileLongPath,, "Camera Model" )
FormatTime, dateTaken, Filexpro( A_LoopFileLongPath,, "Date Taken" ), MMM yyyy
Loop, Files, %srcPath% "\*." %extsToSort% ; Goes through src Path and looks for exts we have defined
{
file := A_LoopFileFullPath ; save file full path
SubFolder := %cameraModel% "\" %destPath% "\" %dateTaken% ; look for subfolder named after month day and hour of the file mmddhh
if !InStr(FileExist(SubFolder), "D") ; if that folder does not exist
FileCreateDir, % SubFolder ; create folder
FileMove, % file , % SubFolder "\" *.* ; move file to destination
}
foldersorterDrawings:
;Drawings folder organizer
srcPath := "C:\Users\The Lich Omoi\Pictures\Drawings"
destPath := "C:\Users\The Lich Omoi\Pictures\Drawings"
extsToSort := jpg,png,tiff,clip
cameraModel := Filexpro( A_LoopFileLongPath,, "Camera Model" )
FormatTime, dateCreated, Filexpro( A_LoopFileLongPath,, "Date Created" ), MMM yyyy
Loop, Files, %srcPath% "\*." %extsToSort% ; Goes through src Path and looks for exts we have defined
{
file := A_LoopFileFullPath ; save file full path
SubFolder := %dateCreated% "\" %destPath% "\" %dateTaken% ; look for subfolder named after month day and hour of the file mmddhh
if !InStr(FileExist(SubFolder), "D") ; if that folder does not exist
FileCreateDir, % SubFolder ; create folder
FileMove, % file , % SubFolder "\" *.* ; move file to destination
}
my thought was to make it go to the appropriate function based on where the new file was found EX: new drawing was placed in the drawings folder, and then it would fire the appropriate sorter based on that directory. However, I don't think I've set up my functions correctly and i don't know how to make it go to a subroutine while also looping as most of this code has been frankensteined together.
any help would be appreciated as I continue to see how i can fix this! Thank you!