注意:这是ahkv2版本的脚本
ui := Gui.New(), ui.MarginX := ui.MarginY := 20
ui.Add("Text", , '文件夹监视'), ui.Add("Edit", 'xm y+5 w730 cGray +ReadOnly vFolder', A_Desktop)
ui.Add("Button", 'x+m yp w50 +Default', '...').OnEvent('Click', 'SelectFolder')
ui.Add("Text", 'xm y+10', '选项')
for _ in [['xm y+10 vSubTree', '子目录'], ['x+5 yp vFiles Checked', '文件名'], ['x+5 yp vFolders Checked', '目录名'], ['x+5 yp vAttributes', '属性'],
['x+5 yp vSize', '文件大小'], ['x+5 yp vLast_write', '最后写入时间'], ['x+5 yp vLast_access', '最后访问时间'], ['x+5 yp vCreation', '创建时间'], ['x+5 yp vSecurity', '安全描述符']]
ui.Add("Checkbox", _[1], _[2])
ui.Add("ListView", 'xm w800 r15 vLV', ['修改时间','路径','行为','文件(夹)名','旧文件(夹)名',' '])
ui.Add("Button", 'xm w100 vStart', '开始').OnEvent('Click', 'StartorStop')
ui.Add("Button", 'x+m yp wp vStop +Disabled', '停止').OnEvent('Click', 'StartorStop')
ui.Add("Button", 'x+m yp wp', '清除').OnEvent('Click', (ctl, *) => ctl.Gui['LV'].Delete())
ui.Title := '文件夹监视', ui.Show(), ui.OnEvent('Close', (*) => ExitApp())
return
SelectFolder(ctl, *) {
ui := ctl.Gui
if (folder := DirSelect())
ui['Folder'].Text := folder, ui['Start'].Enabled := true
}
StartorStop(ctl, *) {
static mon := '', _ := OnExit((*) => (mon := ''))
ui := ctl.Gui
if (ctl.Name = 'Start') {
ui.Submit(false), filter := 0
if !InStr(FileExist(ui['Folder'].Text), 'D')
return MsgBox(ui['Folder'].Text '不是一个有效的文件夹', 'Error')
for i, v in ['Files', 'Folders', 'Attributes', 'Size', 'Last_write', 'Last_access', 'Creation', 'Security']
filter |= ui[v].Value ? [1, 2, 4, 8, 16, 32, 64, 256][i] : 0
mon := FileMonitoring.New(ui['Folder'].Text, filter, Func('update'), ui['SubTree'].Value), ui['Start'].Enabled := !(ui['Stop'].Enabled := true)
} else mon := '', ui['Start'].Enabled := !(ui['Stop'].Enabled := false)
update(change) {
ui['LV'].Add('vis', FormatTime(, 'yyyy/MM/dd hh:mm:ss'), ui['Folder'].Text, ['新建', '删除', '修改', '重命名'][change.Action], change.Name, change.HasOwnProp('OldName') ? change.OldName : '', '')
ui['LV'].ModifyCol()
}
}
class FileMonitoring {
static NOTIFY := {FILE_NAME: 0x1, DIR_NAME: 0x2, ATTRIBUTES: 0x4, CHANGE_SIZE: 0x8,
LAST_WRITE: 0x10, LAST_ACCESS: 0x20, CREATION: 0x40, SECURITY: 0x100} ; FILE_NOTIFY_CHANGE
__New(folderPath, notifyFilter, UserFunc, watchSubtree := false) {
this.Event := FileMonitoring._Event.New(), this.buffer := BufferAlloc(1024), pBuffer := this.buffer.Ptr, this.overlapped := BufferAlloc(A_PtrSize * 3 + 8), this.pOverlapped := this.overlapped.Ptr
this.Directory := FileMonitoring._ReadDirectoryChanges.New(folderPath, notifyFilter, watchSubtree, pBuffer, this.pOverlapped, this.Event.Ptr)
this.EventSignal := FileMonitoring._EventSignal.New(this.Directory, this.Event.Ptr, pBuffer, UserFunc), this.EventSignal.folderPath := folderPath, this.Directory.Read()
}
__Delete() {
DllCall('CancelIoEx', 'Ptr', this.Directory.Handle, 'Ptr', this.pOverlapped)
this.Event.Set(), this.EventSignal.Clear(), this.Directory.Clear(), this.buffer := ''
}
class _Event {
__New() => (this.Ptr := DllCall('CreateEvent', 'Int', 0, 'Int', 0, 'Int', 0, 'Int', 0, 'Ptr'))
Set() => DllCall('SetEvent', 'Ptr', this)
__Delete() => DllCall('CloseHandle', 'Ptr', this)
}
class _EventSignal {
__New(Directory, hEvent, pBuffer, UserFunc) {
for v in ['Directory', 'hEvent', 'pBuffer']
this.%v% := %v%
OnMessage(this.WM_EVENTSIGNAL := DllCall('RegisterWindowMessage', 'Str', 'WM_EVENTSIGNAL', 'UInt'), this.OnEvent := ObjBindMethod(this, 'On_WM_EVENTSIGNAL'))
this.UserFunc := IsObject(UserFunc) ? UserFunc : Func(UserFunc), this.startAddress := this.CreateWaitFunc(this.hEvent, A_ScriptHwnd, this.WM_EVENTSIGNAL)
this.Thread := FileMonitoring._EventSignal._Thread.New(this.startAddress)
}
On_WM_EVENTSIGNAL(wp, *) {
if !(wp = this.hEvent && DllCall('GetOverlappedResult', 'Ptr', this.hEvent, 'Ptr', this.pBuffer, 'UInt*', written := 0, 'UInt', false))
return
addr := this.pBuffer, offset := 0, preName := '', preAction := 0
Loop {
addr += offset, Action := NumGet(addr + 4, 'UInt'), Name := StrGet(addr + 12, NumGet(addr + 8, 'UInt') // 2, 'UTF-16')
if (Name == preName && Action == preAction)
continue
if (Action = 4) {
Change := {Action: Action, OldName: Name}, preName := Name, preAction := Action
continue
} else if (Action = 5 && preAction = 4) {
Change.Path := this.folderPath '' Name, Change.Name := Name
} else Change := {Action: Action, Name: Name, Path: this.folderPath '' Name}
SetTimer(this.UserFunc.Bind(Change), -1), preName := Name, preAction := Action
} until !(offset := NumGet(addr + 0, 'UInt'))
this.Thread.Wait(), this.Thread := FileMonitoring._EventSignal._Thread.New(this.startAddress), this.Directory.Read()
}
CreateWaitFunc(Handle, hWnd, Msg, Timeout := -1) {
ptr := DllCall('VirtualAlloc', 'Ptr', 0, 'Ptr', A_PtrSize = 4 ? 49 : 85, 'UInt', MEM_COMMIT := 0x1000, 'UInt', PAGE_EXECUTE_READWRITE := 0x40, 'Ptr')
pWaitForSingleObject := DllCall('GetProcAddress', 'Ptr', DllCall('GetModuleHandle', 'Str', 'kernel32.dll', 'Ptr'), 'AStr', 'WaitForSingleObject', 'Ptr')
pPostMessageW := DllCall('GetProcAddress', 'Ptr', DllCall('GetModuleHandle', 'Str', 'user32.dll', 'Ptr'), 'AStr', 'PostMessageW', 'Ptr')
NumPut('Ptr', pWaitForSingleObject, 'Ptr', pPostMessageW, ptr + 0)
if (A_PtrSize = 4) {
NumPut('UChar', 0x68, ptr + 8), NumPut('UInt', Timeout, ptr + 9), NumPut('UChar', 0x68, ptr + 13)
NumPut('Ptr', Handle, ptr + 14), NumPut('UShort', 0x15FF, ptr + 18), NumPut('Ptr', ptr, ptr + 20)
NumPut('UShort', 0x6850, ptr + 24), NumPut('Ptr', Handle, ptr + 26), NumPut('UChar', 0x68, ptr + 30)
NumPut('UInt', Msg, ptr + 31), NumPut('UChar', 0x68, ptr + 35), NumPut('Ptr', hWnd, ptr + 36), NumPut('UShort', 0x15FF, ptr + 40)
NumPut('Ptr', ptr + 4, ptr + 42), NumPut('UChar', 0xC2, ptr + 46), NumPut('UShort', 4, ptr + 47)
} else {
NumPut('UChar', 0x53, ptr + 16), NumPut('UInt', 0x20EC8348, ptr + 17), NumPut('UInt', 0xBACB8948, ptr + 21)
NumPut('UInt', Timeout, ptr + 25), NumPut('UShort', 0xB948, ptr + 29), NumPut('Ptr', Handle, ptr + 31)
NumPut('UShort', 0x15FF, ptr + 39), NumPut('UInt', -45, ptr + 41), NumPut('UShort', 0xB849, ptr + 45)
NumPut('Ptr', Handle, ptr + 47), NumPut('UChar', 0xBA, ptr + 55), NumPut('UInt', Msg, ptr + 56), NumPut('UShort', 0xB948, ptr + 60)
NumPut('Ptr', hWnd, ptr + 62), NumPut('UInt', 0xC18941, ptr + 70), NumPut('UShort', 0x15FF, ptr + 73)
NumPut('UInt', -71, ptr + 75), NumPut('UInt', 0x20C48348, ptr + 79), NumPut('UShort', 0xC35B, ptr + 83)
}
return ptr + A_PtrSize * 2
}
Clear() {
this.Thread.Wait(), OnMessage(this.WM_EVENTSIGNAL, this.OnEvent, 0), this.OnEvent := ''
DllCall('VirtualFree', 'Ptr', this.startAddress - A_PtrSize * 2, 'Ptr', A_PtrSize = 4 ? 49 : 85, 'UInt', MEM_DECOMMIT := 0x4000)
}
class _Thread {
__New(startAddress) {
if !(this.handle := DllCall('CreateThread', 'Ptr', 0, 'UInt', 0, 'Ptr', startAddress, 'Ptr', 0, 'UInt', 0, 'UInt', 0, 'Ptr'))
throw Exception('Failed to create thread.`nError code: ' . A_LastError)
}
Wait() => DllCall('WaitForSingleObject', 'Ptr', this.handle, 'Int', -1)
__Delete() => DllCall('CloseHandle', 'Ptr', this.handle)
}
}
class _ReadDirectoryChanges {
__New(dirPath, notifyFilter, watchSubtree, pBuffer, pOverlapped, hEvent) {
static OPEN_EXISTING := 3, access := (FILE_SHARE_READ := 1) | (FILE_SHARE_WRITE := 2), flags := (FILE_FLAG_OVERLAPPED := 0x40000000) | (FILE_FLAG_BACKUP_SEMANTICS := 0x2000000)
for v in ['notifyFilter', 'watchSubtree', 'pBuffer', 'pOverlapped', 'hEvent']
this.%v% := %v%
this.handle := DllCall('CreateFile', 'Str', dirPath, 'UInt', 1, 'UInt', access, 'Int', 0, 'UInt', OPEN_EXISTING, 'UInt', flags, 'Int', 0, 'Ptr')
}
Read() {
DllCall('RtlZeroMemory', 'Ptr', this.pOverlapped, 'Ptr', A_PtrSize * 3 + 8), NumPut('Ptr', this.hEvent, this.pOverlapped + A_PtrSize * 2 + 8)
return DllCall('ReadDirectoryChangesW', 'Ptr', this.handle, 'Ptr', this.pBuffer, 'UInt', 1024, 'UInt', this.watchSubtree, 'UInt', this.notifyFilter, 'Ptr', 0, 'Ptr', this.pOverlapped, 'Ptr', 0)
}
Clear() => DllCall('CloseHandle', 'Ptr', this.handle)
}
}
学习
V2??版本太多也不是什么好事,脚本不能共享,语法有差异