;~ 示例
OnAutoItExitRegister("_Exit")
Global $aDirs[2]
$aDirs[0] = @SystemDir
$aDirs[1] = "D:\mydata\desktop"
_MonitorDirectory($aDirs, True, 100, "_ReportFileChanges")
While 1
Sleep(20)
WEnd
;~ 检测到文件系统变化时将执行此函数
Func _ReportFileChanges($Action, $FilePath)
;~ 你自己的脚本代码 ...
;MsgBox(0,"",$FilePath)
;~ ...
ConsoleWrite($Action & ": " & $FilePath & @CRLF)
TrayTip("发现文件系统变化", $Action & ": " & $FilePath, 5, 1)
EndFunc ;==>_ReportFileChanges
;~ 退出脚本前必须停止所有监视
Func _Exit()
_MonitorDirectory()
Exit
EndFunc ;==>_Exit
;~ =========================== 函数 _MonitorDirectory() ==============================
#cs
说明: 监视自定义的文件夹中的文件变化(文件或文件夹的新建、修改、删除等)。
参考: http://www.autoitscript.com/forum/index.php?showtopic=69044&hl=folderspy&st=0
修改: Jack Chen
语法: _MonitorDirectory($Dirs = "", $Subtree = True, $TimerMs = 250, $Function = "_ReportChanges")
参数:
$Dirs - 要监视的文件夹(数组)
$Subtree - 若 $Subtree = True 则监视子文件夹
$TimerMs - 检查文件系统变化的时间间隔(毫秒)
$Function - 当发现文件系统变化时执行的函数,又如:_ReportChanges
函数语法须如: _ReportChanges($Action, $FilePath)
$Action可能的值: 新建, 删除, 修改, 重命名-, 重命名+, 未知
注: 不带任何参数调用_MonitorDirectory() 则可停止监视所有文件夹,在退出脚本前必须停止所有监视。
#ce
Func _MonitorDirectory($Dirs = "", $Subtree = True, $TimerMs = 250, $Function = "_ReportChanges")
Local Static $nMax, $hBuffer, $hEvents, $aSubtree, $sFunction
If IsArray($Dirs) Then
$nMax = UBound($Dirs)
ElseIf $nMax < 1 Then
Return
EndIf
Local Static $aDirHandles[$nMax], $aOverlapped[$nMax], $aDirs[$nMax]
If IsArray($Dirs) Then
$aDirs = $Dirs
$aSubtree = $Subtree
$sFunction = $Function
;~ $hBuffer = DllStructCreate("byte[4096]")
$hBuffer = DllStructCreate("byte[65536]")
For $i = 0 To $nMax - 1
If StringRight($aDirs[$i], 1) <> "" Then $aDirs[$i] &= ""
;~ http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx
$aResult = DllCall("kernel32.dll", "hwnd", "CreateFile", "Str", $aDirs[$i], "Int", 0x1, "Int", BitOR(0x1, 0x4, 0x2), "ptr", 0, "int", 0x3, "int", BitOR(0x2000000, 0x40000000), "int", 0)
$aDirHandles[$i] = $aResult[0]
$aOverlapped[$i] = DllStructCreate("ulong_ptr Internal;ulong_ptr InternalHigh;dword Offset;dword OffsetHigh;handle hEvent")
For $j = 1 To 5
DllStructSetData($aOverlapped, $j, 0)
Next
_SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i], True, $aSubtree)
Next
$hEvents = DllStructCreate("hwnd hEvent[" & UBound($aOverlapped) & "]")
For $j = 1 To UBound($aOverlapped)
DllStructSetData($hEvents, "hEvent", DllStructGetData($aOverlapped[$j - 1], "hEvent"), $j)
Next
AdlibRegister("_GetChanges", $TimerMs)
ElseIf $Dirs = "ReadDirChanges" Then
_GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs, $aSubtree, $sFunction)
ElseIf $Dirs = "" Then
AdlibUnRegister("_GetChanges")
;~ Close Handle
For $i = 0 To $nMax - 1
DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $aDirHandles[$i])
DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $aOverlapped[$i])
Next
DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hEvents)
$nMax = 0
$hBuffer = ""
$hEvents = ""
$aDirHandles = ""
$aOverlapped = ""
$aDirs = ""
$aSubtree = ""
$sFunction = ""
EndIf
EndFunc ;==>_MonitorDirectory
Func _SetReadDirectory($hDir, $hBuffer, $hOverlapped, $bInitial, $bSubtree)
Local $hEvent, $pBuffer, $nBufferLength, $pOverlapped
$pBuffer = DllStructGetPtr($hBuffer)
$nBufferLength = DllStructGetSize($hBuffer)
$pOverlapped = DllStructGetPtr($hOverlapped)
If $bInitial Then
$hEvent = DllCall("kernel32.dll", "hwnd", "CreateEvent", "UInt", 0, "Int", True, "Int", False, "UInt", 0)
DllStructSetData($hOverlapped, "hEvent", $hEvent[0])
EndIf
;~ http://msdn.microsoft.com/en-us/library/aa365465%28VS.85%29.aspx
$aResult = DllCall("kernel32.dll", "Int", "ReadDirectoryChangesW", "hwnd", $hDir, "ptr", $pBuffer, "dword", $nBufferLength, "int", $bSubtree, "dword", BitOR(0x1, 0x2, 0x4, 0x8, 0x10, 0x40, 0x100), "Uint", 0, "Uint", $pOverlapped, "Uint", 0)
;~ BitOR(0x1, 0x2, 0x4, 0x8, 0x10, 0x40, 0x100) 的说明:
;~ 0x1 - 监视文件新建/删除/重命名, 0x2 - 监视文件夹新建/删除, 0x4 - 监视属性, 0x8 - 监视文件大小变化,
;~ 0x10 - 监视文件最后修改时间, 0x40 - 监视文件创建时间, 0x100 - 监视安全描述
;~ 若只要监视文件名、文件夹名变化(不监视修改),可改成 BitOR(0x1, 0x2),
;~ 若只要监视文件名变化(忽略文件夹),则可直接改成0x1(不用BitOR了)
Return $aResult[0]
EndFunc ;==>_SetReadDirectory
Func _GetChanges()
_MonitorDirectory("ReadDirChanges")
EndFunc ;==>_GetChanges
Func _GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs, $aSubtree, $sFunction)
Local $aMsg, $i, $nBytes = 0
$aMsg = DllCall("User32.dll", "dword", "MsgWaitForMultipleObjectsEx", "dword", UBound($aOverlapped), "ptr", DllStructGetPtr($hEvents), "dword", -1, "dword", 0x4FF, "dword", 0x6)
$i = $aMsg[0]
Switch $i
Case 0 To UBound($aDirHandles) - 1
DllCall("Kernel32.dll", "Uint", "ResetEvent", "uint", DllStructGetData($aOverlapped[$i], "hEvent"))
_ParseFileMessages($hBuffer, $aDirs[$i], $sFunction)
_SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i], False, $aSubtree)
Return $nBytes
EndSwitch
Return 0
EndFunc ;==>_GetDirectoryChanges
Func _ParseFileMessages($hBuffer, $sDir, $sFunction)
Local $hFileNameInfo, $pBuffer, $FilePath
Local $nFileNameInfoOffset = 12, $nOffset = 0, $nNext = 1
$pBuffer = DllStructGetPtr($hBuffer)
While $nNext <> 0
$hFileNameInfo = DllStructCreate("dword NextEntryOffset;dword Action;dword FileNameLength", $pBuffer + $nOffset)
$hFileName = DllStructCreate("wchar FileName[" & DllStructGetData($hFileNameInfo, "FileNameLength") / 2 & "]", $pBuffer + $nOffset + $nFileNameInfoOffset)
Switch DllStructGetData($hFileNameInfo, "Action")
Case 0x1 ; $FILE_ACTION_ADDED
$Action = "新建"
Case 0x2 ; $FILE_ACTION_REMOVED
$Action = "删除"
Case 0x3 ; $FILE_ACTION_MODIFIED
$Action = "修改"
Case 0x4 ; $FILE_ACTION_RENAMED_OLD_NAME
$Action = "重命名-"
Case 0x5 ; $FILE_ACTION_RENAMED_NEW_NAME
$Action = "重命名+"
Case Else
$Action = "未知"
EndSwitch
$FilePath = $sDir & DllStructGetData($hFileName, "FileName")
Call($sFunction, $Action, $FilePath) ; Launch the specified function
$nNext = DllStructGetData($hFileNameInfo, "NextEntryOffset")
$nOffset += $nNext
WEnd
EndFunc ;==>_ParseFileMessages
;~ ===========================以上为函数_MonitorDirectory() ==============================