Not completely understand. Now reading occurs when a message from the thread is recieved. I can implement a completion routine, in that case messaging is not needed? What the issues may the current way cause?
Code: Select all
#NoEnv
SetBatchLines -1
folderPath1 := A_Desktop
folderPath2 := A_ScriptDir
FILE_NOTIFY_CHANGE_FILE_NAME := 0x1
FILE_NOTIFY_CHANGE_DIR_NAME := 0x2
FILE_NOTIFY_CHANGE_ATTRIBUTES := 0x4
FILE_NOTIFY_CHANGE_SIZE := 0x8
notifyFilter := FILE_NOTIFY_CHANGE_FILE_NAME
| FILE_NOTIFY_CHANGE_DIR_NAME
| FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
OnDirectoryChanges(folderPath1, "UserFunc", notifyFilter)
OnDirectoryChanges(folderPath2, "UserFunc", notifyFilter)
UserFunc(filePath, action) {
MsgBox % A_ThisFunc . "`n" . ["Added", "Removed", "Modified", "Renamed, old name", "Renamed, new name"][action] ": " filePath
}
OnDirectoryChanges(dirPath, procName := -1, notifyFilter := 3) {
static DirList := {}, EventList, WM_ReadDirectoryChanges := 0xFFF
IsObject(EventList) || EventList := DirectoryChangesEventListener(-1, 0, 0)
if (procName = -1) {
return EventList[DirList[dirPath]].UserDefinedProc.Name
}
else if (procName = "") {
if DirList.HasKey(dirPath) && eventHandle := DirList.Delete(dirPath)
return EventList.Delete(eventHandle).UserDefinedProc.Name
}
else if IsFunc(procName) {
if DirList.HasKey(dirPath) && eventHandle := DirList.Delete(dirPath)
priorProcName := EventList.Delete(eventHandle).UserDefinedProc.Name
else priorProcName := procName
if OnMessage(WM_ReadDirectoryChanges) != "DirectoryChangesEventListener"
OnMessage(WM_ReadDirectoryChanges, "DirectoryChangesEventListener")
Event := new _Event
Event.Proc := new _AsyncReadDirectoryChanges(dirPath, notifyFilter)
Event.Wait := new _AsyncWaitFunc(Event.handle, A_ScriptHWND, WM_ReadDirectoryChanges)
Event.UserDefinedProc := Func(procName)
Event.dirPath := dirPath
DirList[dirPath] := Event.handle
EventList[Event.handle] := Event
Event.Proc()
Event.Wait()
return priorProcName
}
else return false
}
DirectoryChangesEventListener(wParam, lParam, msg) {
static EventList := {}, WM_ReadDirectoryChanges := 0xFFF
if (msg = WM_ReadDirectoryChanges && Event := EventList[wParam]) {
action := Event.Proc.GetEventType()
name := Event.Proc.GetObjectName()
path := Event.dirPath . "\" . name
Proc := Event.UserDefinedProc
%Proc%(path, action)
Event.Proc()
Event.Wait()
}
else if (wParam = -1)
return EventList
}
class _Event
{
__New() {
this.handle := DllCall("CreateEvent", "Int", 0, "Int", 0, "Int", 1, "Int", 0, "Ptr")
this.SetCapacity("overlapped", A_PtrSize*3 + 8)
addr := this.GetAddress("overlapped")
DllCall("RtlZeroMemory", "Ptr", addr, "Ptr", A_PtrSize*3 + 8)
NumPut(this.handle, addr + A_PtrSize*2 + 8, "Ptr")
}
__Delete() {
DllCall("CloseHandle", "Ptr", this.handle)
}
}
class _AsyncWaitFunc
{
__New(eventObjHandle, hWnd, msg, timeout := -1) {
if !this.startAddress := CreateWaitFunc(eventObjHandle, hWnd, msg, timeout)
throw Exception("Failed to create wait function.`n`nError code:`t" . A_LastError)
}
__Call(EventObj) {
if IsObject(EventObj) {
if this.threadHandle {
DllCall("TerminateThread", "Ptr", this.threadHandle, "UInt", 0)
DllCall("CloseHandle", "Ptr", this.threadHandle)
}
if !this.threadHandle := DllCall("CreateThread", "Int", 0, "Int", 0, "Ptr", this.startAddress, "Int", 0, "UInt", 0, "Int", 0, "Ptr")
throw Exception("Failed to create thread.`n`nError code:`t" . A_LastError)
return this.threadHandle
}
}
__Delete() {
if this.threadHandle {
DllCall("TerminateThread", "Ptr", this.threadHandle, "UInt", 0)
DllCall("CloseHandle", "Ptr", this.threadHandle)
}
}
}
class _AsyncReadDirectoryChanges
{
__New(dirPath, notifyFilter) {
static FILE_SHARE_READ := 1
, FILE_SHARE_WRITE := 2
, OPEN_EXISTING := 3
, FILE_FLAG_OVERLAPPED := 0x40000000
, FILE_FLAG_BACKUP_SEMANTICS := 0x02000000
this.SetCapacity("buffer", 1024)
this.notifyFilter := notifyFilter
this.handle := DllCall("CreateFile", "Str", dirPath, "UInt", 1, "UInt", FILE_SHARE_READ|FILE_SHARE_WRITE, "Int", 0
, "UInt", OPEN_EXISTING
, "UInt", FILE_FLAG_OVERLAPPED|FILE_FLAG_BACKUP_SEMANTICS, "Int", 0, "Ptr")
}
GetEventType() {
return NumGet(this.GetAddress("buffer") + 4, "UInt")
}
GetObjectName() {
bufferRef := this.GetAddress("buffer")
return StrGet(bufferRef + 12, NumGet(bufferRef + 8, "UInt")//2)
}
__Call(EventObj) {
if IsObject(EventObj) {
return DllCall("ReadDirectoryChanges", "Ptr", this.handle, "Ptr", this.GetAddress("buffer"), "UInt", 1024, "Int", 1
, "UInt", this.notifyFilter, "UInt", 0, "Ptr", EventObj.GetAddress("overlapped"), "Int", 0)
}
}
__Delete() {
DllCall("CloseHandle", "Ptr", this.handle)
}
}
CreateWaitFunc(Handle, hWnd, Msg, Timeout=-1)
{
static MEM_COMMIT := 0x1000, PAGE_EXECUTE_READWRITE := 0x40
ptr := DllCall("VirtualAlloc", "Ptr", 0, "Ptr", A_PtrSize = 4 ? 49 : 85, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")
hModule := DllCall("GetModuleHandle", "Str", "kernel32.dll", "Ptr")
pWaitForSingleObject := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "WaitForSingleObject", "Ptr")
hModule := DllCall("GetModuleHandle", "Str", "user32.dll", "Ptr")
pSendMessageW := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "SendMessageW", "Ptr")
NumPut(pWaitForSingleObject, ptr*1)
NumPut(pSendMessageW, ptr + A_PtrSize)
if (A_PtrSize = 4) {
NumPut(0x68, ptr + 8, "UChar")
NumPut(Timeout, ptr + 9, "UInt"), NumPut(0x68, ptr + 13, "UChar")
NumPut(Handle, ptr + 14), NumPut(0x15FF, ptr + 18, "UShort")
NumPut(ptr, ptr + 20), NumPut(0x6850, ptr + 24, "UShort")
NumPut(Handle, ptr + 26), NumPut(0x68, ptr + 30, "UChar")
NumPut(Msg, ptr + 31, "UInt"), NumPut(0x68, ptr + 35, "UChar")
NumPut(hWnd, ptr + 36), NumPut(0x15FF, ptr + 40, "UShort")
NumPut(ptr+4, ptr + 42), NumPut(0xC2, ptr + 46, "UChar"), NumPut(4, ptr + 47, "UShort")
}
else {
NumPut(0x53, ptr + 16, "UChar")
NumPut(0x20EC8348, ptr + 17, "UInt"), NumPut(0xBACB8948, ptr + 21, "UInt")
NumPut(Timeout, ptr + 25, "UInt"), NumPut(0xB948, ptr + 29, "UShort")
NumPut(Handle, ptr + 31), NumPut(0x15FF, ptr + 39, "UShort")
NumPut(-45, ptr + 41, "UInt"), NumPut(0xB849, ptr + 45, "UShort")
NumPut(Handle, ptr + 47), NumPut(0xBA, ptr + 55, "UChar")
NumPut(Msg, ptr + 56, "UInt"), NumPut(0xB948, ptr + 60, "UShort")
NumPut(hWnd, ptr + 62), NumPut(0xC18941, ptr + 70, "UInt")
NumPut(0x15FF, ptr + 73, "UShort"), NumPut(-71, ptr + 75, "UInt")
NumPut(0x20C48348, ptr + 79, "UInt"), NumPut(0xC35B, ptr + 83, "UShort")
}
Return ptr + A_PtrSize*2
}