Jump to content
Sign in to follow this  
Zomp

[NOW WORKING] a (broken) monitor file changes script which uses ReadDirectoryChangeW

Recommended Posts

Good work on figuring it out guys. I have been playing around with the code as well, and have made a GUI for it. I simplified the different dll calls into some udfs so I thought I'd share it with anyone who might want it.

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.2.10.0
 Author:         zorphnog (M. Mims)

 Script Function:
    Monitors the user defined directories for file activity.

#ce ----------------------------------------------------------------------------


#include <Constants.au3>
#include <WinAPI.au3>
#include <Date.au3>
#include <GUIConstants.au3>
#include <GuiListBox.au3>
#include <GuiListView.au3>

Global Const _
        $FILE_FLAG_BACKUP_SEMANTICS = 0x02000000, _
        $FILE_FLAG_OVERLAPPED       = 0x40000000
Global Const _
        $FILE_NOTIFY_CHANGE_ALL         = 0x17F, _
        $FILE_NOTIFY_CHANGE_FILE_NAME   = 0x001, _
        $FILE_NOTIFY_CHANGE_DIR_NAME    = 0x002, _
        $FILE_NOTIFY_CHANGE_ATTRIBUTES  = 0x004, _
        $FILE_NOTIFY_CHANGE_SIZE        = 0x008, _
        $FILE_NOTIFY_CHANGE_LAST_WRITE  = 0x010, _
        $FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x020, _
        $FILE_NOTIFY_CHANGE_CREATION    = 0x040, _
        $FILE_NOTIFY_CHANGE_SECURITY    = 0x100
Global Const _
        $FILE_ACTION_ADDED            = 0x1, _
        $FILE_ACTION_REMOVED          = 0x2, _
        $FILE_ACTION_MODIFIED         = 0x3, _
        $FILE_ACTION_RENAMED_OLD_NAME = 0x4, _
        $FILE_ACTION_RENAMED_NEW_NAME = 0x5
Global Const _
        $MWMO_ALERTABLE      = 0x0002, _
        $MWMO_INPUTAVAILABLE = 0x0004, _
        $MWMO_WAITALL        = 0x0001
Global Const $FILE_LIST_DIRECTORY = 0x0001
Global Const $QS_ALLINPUT = 0x04FF
Global Const $INFINITE = 0xFFFF
Global Const $tagFNIIncomplete = "dword NextEntryOffset;dword Action;dword FileNameLength"
Global $bMonitorDone, $bSelected, $bMonitor
AutoItSetOption("GUIOnEventMode", 1)

$gFileMon = GUICreate("Directory Monitor", 731, 385, 194, 126)
GUISetOnEvent($GUI_EVENT_CLOSE, "_OnEvent_Close")
GUICtrlCreateGroup("Monitored Directories", 8, 0, 713, 105)
$btAdd = GUICtrlCreateButton("Add", 16, 24, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Add")
$btRemove = GUICtrlCreateButton("Remove", 16, 56, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Remove")
GUICtrlSetState(-1, $GUI_DISABLE)
$lbDirectories = GUICtrlCreateList("", 104, 16, 506, 71)
$btMonitor = GUICtrlCreateButton("Start Monitor", 632, 24, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Monitor")
GUICtrlSetState(-1, $GUI_DISABLE)
$btClear = GUICtrlCreateButton("Clear", 632, 56, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Clear")
GUICtrlCreateGroup("", -99, -99, 1, 1)
$lvNotifications = GUICtrlCreateListView("Action|Time|File", 8, 112, 714, 262)
GUICtrlSendMsg(-1, 0x101E, 0, Int(.1*710))
GUICtrlSendMsg(-1, 0x101E, 1, Int(.2*710))
GUICtrlSendMsg(-1, 0x101E, 2, Int(.7*710)-20)
GUISetState(@SW_SHOW)

_Main()

Func _DisplayFileMessages($hBuffer, $sDir)
    Local $hFileNameInfo, $pBuffer, $hTime
    Local $nFileNameInfoOffset = 12, $nOffset = 0, $nNext = 1
    $pBuffer = DllStructGetPtr($hBuffer)
    While $nNext <> 0
        $hFileNameInfo = DllStructCreate($tagFNIIncomplete, $pBuffer + $nOffset)
        $hFileName = DllStructCreate("wchar FileName[" & DllStructGetData($hFileNameInfo, "FileNameLength")/2 & "]", $pBuffer + $nOffset + $nFileNameInfoOffset)
        $hTime = _Date_Time_GetSystemTime()
        Switch DllStructGetData($hFileNameInfo, "Action")
            Case $FILE_ACTION_ADDED
                _GUICtrlListView_InsertItem($lvNotifications, "Created", 0)
            Case $FILE_ACTION_REMOVED
                _GUICtrlListView_InsertItem($lvNotifications, "Deleted", 0)
            Case $FILE_ACTION_MODIFIED
                _GUICtrlListView_InsertItem($lvNotifications, "Modified", 0)
            Case $FILE_ACTION_RENAMED_OLD_NAME
                _GUICtrlListView_InsertItem($lvNotifications, "Rename-", 0)
            Case $FILE_ACTION_RENAMED_NEW_NAME
                _GUICtrlListView_InsertItem($lvNotifications, "Rename+", 0)
            Case Else
                _GUICtrlListView_InsertItem($lvNotifications, "Unknown", 0)
        EndSwitch
        _GUICtrlListView_AddSubItem($lvNotifications, 0, _Date_Time_SystemTimeToDateTimeStr($hTime), 1)
        _GUICtrlListView_AddSubItem($lvNotifications, 0, $sDir & DllStructGetData($hFileName, "FileName"), 2)
        $nNext = DllStructGetData($hFileNameInfo, "NextEntryOffset")
        $nOffset += $nNext
    WEnd
EndFunc

Func _GetBufferHandle ()
    Return DllStructCreate("ubyte[2048]")
EndFunc

Func _GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs, $bAsync = Default, $nTimeout = Default)
    Local $aMsg, $i, $nBytes = 0
    If $nTimeout = -1 Or IsKeyword($nTimeout) Then $nTimeout = 250
    If Not $bAsync Then $nTimeout = $INFINITE
    $aMsg = DllCall("User32.dll", "dword", "MsgWaitForMultipleObjectsEx", _
        "dword", UBound($aOverlapped), _
        "ptr", DllStructGetPtr($hEvents), _
        "dword", $nTimeout, _
        "dword", 0, _
        "dword", 0x6)
    $i = $aMsg[0]
    Switch $i
        Case 0 To UBound($aDirHandles)-1
            If Not _WinAPI_GetOverlappedResult($aDirHandles[$i], DllStructGetPtr($aOverlapped[$i]), $nBytes, True) Then
                ConsoleWrite("!>  GetOverlappedResult Error(" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)
                Return 0
            EndIf
            DllCall("Kernel32.dll", "Uint", "ResetEvent", "uint", DllStructGetData($aOverlapped[$i], "hEvent"))
            _DisplayFileMessages($hBuffer, $aDirs[$i])
            _SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i],False,True)
            Return $nBytes
    EndSwitch
    Return 0
EndFunc

Func _GetDirHandle($sDir)
    Local $aResult
    $aResult = DllCall("Kernel32.dll", "hwnd", "CreateFile", _
        "str", $sDir, _
        "int", $FILE_LIST_DIRECTORY, _
        "int", BitOR($FILE_SHARE_DELETE,$FILE_SHARE_READ,$FILE_SHARE_WRITE), _
        "ptr", 0, _
        "int", $OPEN_EXISTING, _
        "int", BitOR($FILE_FLAG_BACKUP_SEMANTICS,$FILE_FLAG_OVERLAPPED), _
        "int", 0)
    If $aResult[0] = 0 Then
        ConsoleWrite("!>  CreateFile Error (" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)
        Exit
    EndIf
    Return $aResult[0]
EndFunc

Func _GetEventHandles ($aOverlapped)
    Local $i, $hEvents
    $hEvents = DllStructCreate("hwnd hEvent[" & UBound($aOverlapped) & "]")
    For $i=1 To UBound($aOverlapped)
        DllStructSetData($hEvents, "hEvent", DllStructGetData($aOverlapped[$i-1], "hEvent"), $i)
    Next
    Return $hEvents
EndFunc

Func _GetOverlappedHandle ()
    Local $hOverlapped = DllStructCreate($tagOVERLAPPED)
    For $i=1 To 5
        DllStructSetData($hOverlapped, $i, 0)
    Next
    Return $hOverlapped
EndFunc

Func _Main ()
    $bSelected = False
    $bMonitorDone = True
    $bMonitor = False
    While 1
        If Not $bMonitorDone Then _MonitorDirs()
        If $bMonitor And _GUICtrlListBox_GetCount($lbDirectories) = 0 Then
            $bMonitor = Not $bMonitor
            GUICtrlSetState($btMonitor, $GUI_DISABLE)
        ElseIf Not $bMonitor And _GUICtrlListBox_GetCount($lbDirectories) > 0 Then
            $bMonitor = Not $bMonitor
            GUICtrlSetState($btMonitor, $GUI_ENABLE)
        EndIf
        If $bSelected And _GUICtrlListBox_GetCurSel($lbDirectories) = -1 Then
            $bSelected = Not $bSelected
            GUICtrlSetState($btRemove, $GUI_DISABLE)
        ElseIf Not $bSelected And _GUICtrlListBox_GetCurSel($lbDirectories) <> -1 Then
            $bSelected = Not $bSelected
            GUICtrlSetState($btRemove, $GUI_ENABLE)
        EndIf
    WEnd    
EndFunc

Func _MonitorDirs ()
    Local $i, $nMax, $hBuffer, $hEvents
    $nMax = _GUICtrlListBox_GetCount($lbDirectories)
    Local $aDirHandles[$nMax], $aOverlapped[$nMax], $aDirs[$nMax]
    $hBuffer = _GetBufferHandle()
    For $i = 0 To $nMax-1
        $aDirs[$i] = _GUICtrlListBox_GetText($lbDirectories, $i)
        $aDirHandles[$i] = _GetDirHandle($aDirs[$i])
        $aOverlapped[$i] = _GetOverlappedHandle()
        _SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i], True, True)
    Next
    $hEvents = _GetEventHandles($aOverlapped)
    While Not $bMonitorDone
        _GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs)
    WEnd
EndFunc

Func _OnEvent_Add ()
    Local $sDir, $nMax, $i
    $sDir = FileSelectFolder("Select directory to monitor", "")
    If $sDir <> "" Then
        If StringRight($sDir, 1) <> "\" Then $sDir &= "\"
        $nMax = _GUICtrlListBox_GetCount($lbDirectories)-1
        For $i = 0 To $nMax
            If _GUICtrlListBox_GetText($lbDirectories, $i) = $sDir Then Return
        Next
        _GUICtrlListBox_AddString($lbDirectories, $sDir)
    EndIf
EndFunc

Func _OnEvent_Clear ()
    _GUICtrlListView_DeleteAllItems(GUICtrlGetHandle($lvNotifications))
EndFunc

Func _OnEvent_Close ()
    Exit
EndFunc

Func _OnEvent_Monitor ()
    If $bMonitorDone Then
        $bMonitorDone = False
        GUICtrlSetData($btMonitor, "Stop Monitor")
        GUICtrlSetState($btAdd, $GUI_DISABLE)
        GUICtrlSetState($btRemove, $GUI_DISABLE)
        GUICtrlSetState($lbDirectories, $GUI_DISABLE)
        $bSelected = False
    Else
        $bMonitorDone = True
        GUICtrlSetState($lbDirectories, $GUI_ENABLE)
        GUICtrlSetState($btAdd, $GUI_ENABLE)
        GUICtrlSetData($btMonitor, "Start Monitor")
    EndIf
EndFunc

Func _OnEvent_Remove ()
    _GUICtrlListBox_DeleteString($lbDirectories, _GUICtrlListBox_GetCurSel($lbDirectories))
EndFunc

Func _SetReadDirectory($hDir, $hBuffer, $hOverlapped, $bInitial = False, $bSubtree = False)
    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)
        If $hEvent[0] = 0 Then
            ConsoleWrite("!>  CreateEvent Failed (" & _WinAPI_GetLastError() & "): " & _WinAPI_GetLastErrorMessage() & @LF)
            Exit
        EndIf
        DllStructSetData($hOverlapped, "hEvent", $hEvent[0])
    EndIf
    $aResult = DllCall("Kernel32.dll", "int", "ReadDirectoryChangesW", _
        "hwnd", $hDir, _
        "ptr", $pBuffer, _
        "dword", $nBufferLength, _
        "int", $bSubtree, _
        "dword", BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, _
            $FILE_NOTIFY_CHANGE_SIZE,$FILE_NOTIFY_CHANGE_DIR_NAME), _
        "uint", 0, _
        "uint", $pOverlapped, _
        "uint", 0)
    If $aResult[0] = 0 Then
        ConsoleWrite("!>  ReadDirectoryChangesW Error(" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)
        Exit
    EndIf
    Return $aResult[0]
EndFunc

Share this post


Link to post
Share on other sites

Realy nice

good job all :P

I've been looking for a script like this for a while...

Would it be possible to see what program edits/deletes/moves a file?

Edited by Forsaken

Share this post


Link to post
Share on other sites

Hi together,

i stripped of "zorphnog's" GUI-Version and tried to install it as a service.....

I can make the service ( sc screate Monitor binPath= <path to exe> ) but i can't start the service.

Isn't it possible to make this as a service?

CODE
#cs ----------------------------------------------------------------------------

AutoIt Version: 3.2.10.0

Author: zorphnog (M. Mims)

Script Function:

Monitors the user defined directories for file activity.

To Do :

#ce ----------------------------------------------------------------------------

#include <Constants.au3>

#include <WinAPI.au3>

#include <Date.au3>

HotKeySet("{ESC}", "CLOSE")

$sDir = "C:\2\"

Global Const _

$FILE_FLAG_BACKUP_SEMANTICS = 0x02000000, _

$FILE_FLAG_OVERLAPPED = 0x40000000

Global Const _

$FILE_NOTIFY_CHANGE_ALL = 0x17F, _

$FILE_NOTIFY_CHANGE_FILE_NAME = 0x001, _

$FILE_NOTIFY_CHANGE_DIR_NAME = 0x002, _

$FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x004, _

$FILE_NOTIFY_CHANGE_SIZE = 0x008, _

$FILE_NOTIFY_CHANGE_LAST_WRITE = 0x010, _

$FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x020, _

$FILE_NOTIFY_CHANGE_CREATION = 0x040, _

$FILE_NOTIFY_CHANGE_SECURITY = 0x100

Global Const _

$FILE_ACTION_ADDED = 0x1, _

$FILE_ACTION_REMOVED = 0x2, _

$FILE_ACTION_MODIFIED = 0x3, _

$FILE_ACTION_RENAMED_OLD_NAME = 0x4, _

$FILE_ACTION_RENAMED_NEW_NAME = 0x5

Global Const _

$MWMO_ALERTABLE = 0x0002, _

$MWMO_INPUTAVAILABLE = 0x0004, _

$MWMO_WAITALL = 0x0001

Global Const $FILE_LIST_DIRECTORY = 0x0001

Global Const $QS_ALLINPUT = 0x04FF

Global Const $INFINITE = 0xFFFF

Global Const $tagFNIIncomplete = "dword NextEntryOffset;dword Action;dword FileNameLength"

Global $bMonitorDone, $bSelected, $bMonitor

AutoItSetOption("GUIOnEventMode", 1)

_Main()

Func _DisplayFileMessages($hBuffer, $sDir)

Local $hFileNameInfo, $pBuffer, $hTime

Local $nFileNameInfoOffset = 12, $nOffset = 0, $nNext = 1

$pBuffer = DllStructGetPtr($hBuffer)

While $nNext <> 0

$hFileNameInfo = DllStructCreate($tagFNIIncomplete, $pBuffer + $nOffset)

$hFileName = DllStructCreate("wchar FileName[" & DllStructGetData($hFileNameInfo, "FileNameLength")/2 & "]", $pBuffer + $nOffset + $nFileNameInfoOffset)

$hTime = _Date_Time_GetSystemTime()

Switch DllStructGetData($hFileNameInfo, "Action")

Case $FILE_ACTION_ADDED

ConsoleWrite(" Created " )

If DllStructGetData($hFileName, "FileName") = "neu.txt" Then

FileCopy($sDir & DllStructGetData($hFileName, "FileName"), $sdir & "gefunden.txt",1)

EndIf

Case $FILE_ACTION_REMOVED

ConsoleWrite( " Deleted " )

Case $FILE_ACTION_MODIFIED

ConsoleWrite(" Modified " )

Case $FILE_ACTION_RENAMED_OLD_NAME

ConsoleWrite(" Rename- " )

Case $FILE_ACTION_RENAMED_NEW_NAME

ConsoleWrite(" Rename+ " )

Case Else

ConsoleWrite(" Unknown" )

EndSwitch

ConsoleWrite(_Date_Time_SystemTimeToDateTimeStr($hTime))

ConsoleWrite(" : " & $sDir & DllStructGetData($hFileName, "FileName") & @crlf)

$nNext = DllStructGetData($hFileNameInfo, "NextEntryOffset")

$nOffset += $nNext

WEnd

EndFunc

Func _GetBufferHandle ()

Return DllStructCreate("ubyte[2048]")

EndFunc

Func _GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs, $bAsync = Default, $nTimeout = Default)

Local $aMsg, $i, $nBytes = 0

If $nTimeout = -1 Or IsKeyword($nTimeout) Then $nTimeout = 250

If Not $bAsync Then $nTimeout = $INFINITE

$aMsg = DllCall("User32.dll", "dword", "MsgWaitForMultipleObjectsEx", _

"dword", UBound($aOverlapped), _

"ptr", DllStructGetPtr($hEvents), _

"dword", $nTimeout, _

"dword", 0, _

"dword", 0x6)

$i = $aMsg[0]

Switch $i

Case 0 To UBound($aDirHandles)-1

If Not _WinAPI_GetOverlappedResult($aDirHandles[$i], DllStructGetPtr($aOverlapped[$i]), $nBytes, True) Then

ConsoleWrite("!> GetOverlappedResult Error(" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)

Return 0

EndIf

DllCall("Kernel32.dll", "Uint", "ResetEvent", "uint", DllStructGetData($aOverlapped[$i], "hEvent"))

_DisplayFileMessages($hBuffer, $aDirs[$i])

_SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i],False,True)

Return $nBytes

EndSwitch

Return 0

EndFunc

Func _GetDirHandle($sDir)

Local $aResult

$aResult = DllCall("Kernel32.dll", "hwnd", "CreateFile", _

"str", $sDir, _

"int", $FILE_LIST_DIRECTORY, _

"int", BitOR($FILE_SHARE_DELETE,$FILE_SHARE_READ,$FILE_SHARE_WRITE), _

"ptr", 0, _

"int", $OPEN_EXISTING, _

"int", BitOR($FILE_FLAG_BACKUP_SEMANTICS,$FILE_FLAG_OVERLAPPED), _

"int", 0)

If $aResult[0] = 0 Then

ConsoleWrite("!> CreateFile Error (" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)

Exit

EndIf

Return $aResult[0]

EndFunc

Func _GetEventHandles ($aOverlapped)

Local $i, $hEvents

$hEvents = DllStructCreate("hwnd hEvent[" & UBound($aOverlapped) & "]")

For $i=1 To UBound($aOverlapped)

DllStructSetData($hEvents, "hEvent", DllStructGetData($aOverlapped[$i-1], "hEvent"), $i)

Next

Return $hEvents

EndFunc

Func _GetOverlappedHandle ()

Local $hOverlapped = DllStructCreate($tagOVERLAPPED)

For $i=1 To 5

DllStructSetData($hOverlapped, $i, 0)

Next

Return $hOverlapped

EndFunc

Func _Main ()

$bSelected = True

$bMonitorDone = False

$bMonitor = True

While 1

If Not $bMonitorDone Then _MonitorDirs()

If $bMonitor Then

$bMonitor = Not $bMonitor

EndIf

If $bSelected Then

$bSelected = Not $bSelected

EndIf

WEnd

EndFunc

Func _MonitorDirs ()

Local $i, $nMax, $hBuffer, $hEvents

$nMax = 1

Local $aDirHandles[$nMax], $aOverlapped[$nMax], $aDirs[$nMax]

$hBuffer = _GetBufferHandle()

For $i = 0 To $nMax-1

$aDirs[$i] = $sDir

$aDirHandles[$i] = _GetDirHandle($aDirs[$i])

$aOverlapped[$i] = _GetOverlappedHandle()

_SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i], True, True)

Next

$hEvents = _GetEventHandles($aOverlapped)

While Not $bMonitorDone ; loop until "ESC"

_GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs)

WEnd

EndFunc

Func _SetReadDirectory($hDir, $hBuffer, $hOverlapped, $bInitial = False, $bSubtree = False)

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)

If $hEvent[0] = 0 Then

ConsoleWrite("!> CreateEvent Failed (" & _WinAPI_GetLastError() & "): " & _WinAPI_GetLastErrorMessage() & @LF)

Exit

EndIf

DllStructSetData($hOverlapped, "hEvent", $hEvent[0])

EndIf

$aResult = DllCall("Kernel32.dll", "int", "ReadDirectoryChangesW", _

"hwnd", $hDir, _

"ptr", $pBuffer, _

"dword", $nBufferLength, _

"int", $bSubtree, _

"dword", BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, _

$FILE_NOTIFY_CHANGE_SIZE,$FILE_NOTIFY_CHANGE_DIR_NAME), _

"uint", 0, _

"uint", $pOverlapped, _

"uint", 0)

If $aResult[0] = 0 Then

ConsoleWrite("!> ReadDirectoryChangesW Error(" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)

Exit

EndIf

Return $aResult[0]

EndFunc

Func CLOSE()

Exit

EndFunc

Greets

Dizzy

Share this post


Link to post
Share on other sites

I'm not sure what the requirements are to create a service application, but I would imagine the you would have to implement the correct hooks and handlers for the services API. I'm not sure that its possible to do with AutoIt.

P.S. ConsoleWrite is not going to display your messages if you're running as a service. You probably want to write to a log file or publish it as an application event.

edit - Actually, check out the FAQ sticky for information about creating service applications http://www.autoitscript.com/forum/index.php?showtopic=37289

Edited by zorphnog

Share this post


Link to post
Share on other sites

I'm not sure what the requirements are to create a service application, but I would imagine the you would have to implement the correct hooks and handlers for the services API. I'm not sure that its possible to do with AutoIt.

P.S. ConsoleWrite is not going to display your messages if you're running as a service. You probably want to write to a log file or publish it as an application event.

edit - Actually, check out the FAQ sticky for information about creating service applications http://www.autoitscript.com/forum/index.php?showtopic=37289

Hi zorphnog,

thanks for your reply.

Yes, i know that i don't see my console messages. This was just a first test to implement this as a service. Under "actions" you can see, that i look for a file neu.txt and if exist the program copies it to a new file. This is just a short function test. ;)

And thanks for the hint "creating service applications" - i'll have a look on it.

Dizzy

Share this post


Link to post
Share on other sites

this is pretty neat, exactly what i wanted, i didn't think monitoring something would be so hard, i spent a good day trying to figure out a way to monitor a file or dir, and spent a while searching the forums. after messing around with quite a few different things i finally came access this thread, but i think it needs a little bit more proper posting.

i take no credit for any work at all im just reposting the script, the following is a gui version of a program that will monitor what you select

this was posted on page 4 by zorphnog - #520303

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.2.10.0
 Author:         zorphnog (M. Mims)

 Script Function:
    Monitors the user defined directories for file activity.

#ce ----------------------------------------------------------------------------


#include <Constants.au3>
#include <WinAPI.au3>
#include <Date.au3>
#include <GUIConstants.au3>
#include <GuiListBox.au3>
#include <GuiListView.au3>

Global Const _
        $FILE_FLAG_BACKUP_SEMANTICS = 0x02000000, _
        $FILE_FLAG_OVERLAPPED       = 0x40000000
Global Const _
        $FILE_NOTIFY_CHANGE_ALL         = 0x17F, _
        $FILE_NOTIFY_CHANGE_FILE_NAME   = 0x001, _
        $FILE_NOTIFY_CHANGE_DIR_NAME    = 0x002, _
        $FILE_NOTIFY_CHANGE_ATTRIBUTES  = 0x004, _
        $FILE_NOTIFY_CHANGE_SIZE        = 0x008, _
        $FILE_NOTIFY_CHANGE_LAST_WRITE  = 0x010, _
        $FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x020, _
        $FILE_NOTIFY_CHANGE_CREATION    = 0x040, _
        $FILE_NOTIFY_CHANGE_SECURITY    = 0x100
Global Const _
        $FILE_ACTION_ADDED            = 0x1, _
        $FILE_ACTION_REMOVED          = 0x2, _
        $FILE_ACTION_MODIFIED         = 0x3, _
        $FILE_ACTION_RENAMED_OLD_NAME = 0x4, _
        $FILE_ACTION_RENAMED_NEW_NAME = 0x5
Global Const _
        $MWMO_ALERTABLE      = 0x0002, _
        $MWMO_INPUTAVAILABLE = 0x0004, _
        $MWMO_WAITALL        = 0x0001
Global Const $FILE_LIST_DIRECTORY = 0x0001
Global Const $QS_ALLINPUT = 0x04FF
Global Const $INFINITE = 0xFFFF
Global Const $tagFNIIncomplete = "dword NextEntryOffset;dword Action;dword FileNameLength"
Global $bMonitorDone, $bSelected, $bMonitor
AutoItSetOption("GUIOnEventMode", 1)

$gFileMon = GUICreate("Directory Monitor", 731, 385, 194, 126)
GUISetOnEvent($GUI_EVENT_CLOSE, "_OnEvent_Close")
GUICtrlCreateGroup("Monitored Directories", 8, 0, 713, 105)
$btAdd = GUICtrlCreateButton("Add", 16, 24, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Add")
$btRemove = GUICtrlCreateButton("Remove", 16, 56, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Remove")
GUICtrlSetState(-1, $GUI_DISABLE)
$lbDirectories = GUICtrlCreateList("", 104, 16, 506, 71)
$btMonitor = GUICtrlCreateButton("Start Monitor", 632, 24, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Monitor")
GUICtrlSetState(-1, $GUI_DISABLE)
$btClear = GUICtrlCreateButton("Clear", 632, 56, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Clear")
GUICtrlCreateGroup("", -99, -99, 1, 1)
$lvNotifications = GUICtrlCreateListView("Action|Time|File", 8, 112, 714, 262)
GUICtrlSendMsg(-1, 0x101E, 0, Int(.1*710))
GUICtrlSendMsg(-1, 0x101E, 1, Int(.2*710))
GUICtrlSendMsg(-1, 0x101E, 2, Int(.7*710)-20)
GUISetState(@SW_SHOW)

_Main()

Func _DisplayFileMessages($hBuffer, $sDir)
    Local $hFileNameInfo, $pBuffer, $hTime
    Local $nFileNameInfoOffset = 12, $nOffset = 0, $nNext = 1
    $pBuffer = DllStructGetPtr($hBuffer)
    While $nNext <> 0
        $hFileNameInfo = DllStructCreate($tagFNIIncomplete, $pBuffer + $nOffset)
        $hFileName = DllStructCreate("wchar FileName[" & DllStructGetData($hFileNameInfo, "FileNameLength")/2 & "]", $pBuffer + $nOffset + $nFileNameInfoOffset)
        $hTime = _Date_Time_GetSystemTime()
        Switch DllStructGetData($hFileNameInfo, "Action")
            Case $FILE_ACTION_ADDED
                _GUICtrlListView_InsertItem($lvNotifications, "Created", 0)
            Case $FILE_ACTION_REMOVED
                _GUICtrlListView_InsertItem($lvNotifications, "Deleted", 0)
            Case $FILE_ACTION_MODIFIED
                _GUICtrlListView_InsertItem($lvNotifications, "Modified", 0)
            Case $FILE_ACTION_RENAMED_OLD_NAME
                _GUICtrlListView_InsertItem($lvNotifications, "Rename-", 0)
            Case $FILE_ACTION_RENAMED_NEW_NAME
                _GUICtrlListView_InsertItem($lvNotifications, "Rename+", 0)
            Case Else
                _GUICtrlListView_InsertItem($lvNotifications, "Unknown", 0)
        EndSwitch
        _GUICtrlListView_AddSubItem($lvNotifications, 0, _Date_Time_SystemTimeToDateTimeStr($hTime), 1)
        _GUICtrlListView_AddSubItem($lvNotifications, 0, $sDir & DllStructGetData($hFileName, "FileName"), 2)
        $nNext = DllStructGetData($hFileNameInfo, "NextEntryOffset")
        $nOffset += $nNext
    WEnd
EndFunc

Func _GetBufferHandle ()
    Return DllStructCreate("ubyte[2048]")
EndFunc

Func _GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs, $bAsync = Default, $nTimeout = Default)
    Local $aMsg, $i, $nBytes = 0
    If $nTimeout = -1 Or IsKeyword($nTimeout) Then $nTimeout = 250
    If Not $bAsync Then $nTimeout = $INFINITE
    $aMsg = DllCall("User32.dll", "dword", "MsgWaitForMultipleObjectsEx", _
        "dword", UBound($aOverlapped), _
        "ptr", DllStructGetPtr($hEvents), _
        "dword", $nTimeout, _
        "dword", 0, _
        "dword", 0x6)
    $i = $aMsg[0]
    Switch $i
        Case 0 To UBound($aDirHandles)-1
            If Not _WinAPI_GetOverlappedResult($aDirHandles[$i], DllStructGetPtr($aOverlapped[$i]), $nBytes, True) Then
                ConsoleWrite("!>  GetOverlappedResult Error(" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)
                Return 0
            EndIf
            DllCall("Kernel32.dll", "Uint", "ResetEvent", "uint", DllStructGetData($aOverlapped[$i], "hEvent"))
            _DisplayFileMessages($hBuffer, $aDirs[$i])
            _SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i],False,True)
            Return $nBytes
    EndSwitch
    Return 0
EndFunc

Func _GetDirHandle($sDir)
    Local $aResult
    $aResult = DllCall("Kernel32.dll", "hwnd", "CreateFile", _
        "str", $sDir, _
        "int", $FILE_LIST_DIRECTORY, _
        "int", BitOR($FILE_SHARE_DELETE,$FILE_SHARE_READ,$FILE_SHARE_WRITE), _
        "ptr", 0, _
        "int", $OPEN_EXISTING, _
        "int", BitOR($FILE_FLAG_BACKUP_SEMANTICS,$FILE_FLAG_OVERLAPPED), _
        "int", 0)
    If $aResult[0] = 0 Then
        ConsoleWrite("!>  CreateFile Error (" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)
        Exit
    EndIf
    Return $aResult[0]
EndFunc

Func _GetEventHandles ($aOverlapped)
    Local $i, $hEvents
    $hEvents = DllStructCreate("hwnd hEvent[" & UBound($aOverlapped) & "]")
    For $i=1 To UBound($aOverlapped)
        DllStructSetData($hEvents, "hEvent", DllStructGetData($aOverlapped[$i-1], "hEvent"), $i)
    Next
    Return $hEvents
EndFunc

Func _GetOverlappedHandle ()
    Local $hOverlapped = DllStructCreate($tagOVERLAPPED)
    For $i=1 To 5
        DllStructSetData($hOverlapped, $i, 0)
    Next
    Return $hOverlapped
EndFunc

Func _Main ()
    $bSelected = False
    $bMonitorDone = True
    $bMonitor = False
    While 1
        If Not $bMonitorDone Then _MonitorDirs()
        If $bMonitor And _GUICtrlListBox_GetCount($lbDirectories) = 0 Then
            $bMonitor = Not $bMonitor
            GUICtrlSetState($btMonitor, $GUI_DISABLE)
        ElseIf Not $bMonitor And _GUICtrlListBox_GetCount($lbDirectories) > 0 Then
            $bMonitor = Not $bMonitor
            GUICtrlSetState($btMonitor, $GUI_ENABLE)
        EndIf
        If $bSelected And _GUICtrlListBox_GetCurSel($lbDirectories) = -1 Then
            $bSelected = Not $bSelected
            GUICtrlSetState($btRemove, $GUI_DISABLE)
        ElseIf Not $bSelected And _GUICtrlListBox_GetCurSel($lbDirectories) <> -1 Then
            $bSelected = Not $bSelected
            GUICtrlSetState($btRemove, $GUI_ENABLE)
        EndIf
    WEnd   
EndFunc

Func _MonitorDirs ()
    Local $i, $nMax, $hBuffer, $hEvents
    $nMax = _GUICtrlListBox_GetCount($lbDirectories)
    Local $aDirHandles[$nMax], $aOverlapped[$nMax], $aDirs[$nMax]
    $hBuffer = _GetBufferHandle()
    For $i = 0 To $nMax-1
        $aDirs[$i] = _GUICtrlListBox_GetText($lbDirectories, $i)
        $aDirHandles[$i] = _GetDirHandle($aDirs[$i])
        $aOverlapped[$i] = _GetOverlappedHandle()
        _SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i], True, True)
    Next
    $hEvents = _GetEventHandles($aOverlapped)
    While Not $bMonitorDone
        _GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs)
    WEnd
EndFunc

Func _OnEvent_Add ()
    Local $sDir, $nMax, $i
    $sDir = FileSelectFolder("Select directory to monitor", "")
    If $sDir <> "" Then
        If StringRight($sDir, 1) <> "\" Then $sDir &= "\"
        $nMax = _GUICtrlListBox_GetCount($lbDirectories)-1
        For $i = 0 To $nMax
            If _GUICtrlListBox_GetText($lbDirectories, $i) = $sDir Then Return
        Next
        _GUICtrlListBox_AddString($lbDirectories, $sDir)
    EndIf
EndFunc

Func _OnEvent_Clear ()
    _GUICtrlListView_DeleteAllItems(GUICtrlGetHandle($lvNotifications))
EndFunc

Func _OnEvent_Close ()
    Exit
EndFunc

Func _OnEvent_Monitor ()
    If $bMonitorDone Then
        $bMonitorDone = False
        GUICtrlSetData($btMonitor, "Stop Monitor")
        GUICtrlSetState($btAdd, $GUI_DISABLE)
        GUICtrlSetState($btRemove, $GUI_DISABLE)
        GUICtrlSetState($lbDirectories, $GUI_DISABLE)
        $bSelected = False
    Else
        $bMonitorDone = True
        GUICtrlSetState($lbDirectories, $GUI_ENABLE)
        GUICtrlSetState($btAdd, $GUI_ENABLE)
        GUICtrlSetData($btMonitor, "Start Monitor")
    EndIf
EndFunc

Func _OnEvent_Remove ()
    _GUICtrlListBox_DeleteString($lbDirectories, _GUICtrlListBox_GetCurSel($lbDirectories))
EndFunc

Func _SetReadDirectory($hDir, $hBuffer, $hOverlapped, $bInitial = False, $bSubtree = False)
    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)
        If $hEvent[0] = 0 Then
            ConsoleWrite("!>  CreateEvent Failed (" & _WinAPI_GetLastError() & "): " & _WinAPI_GetLastErrorMessage() & @LF)
            Exit
        EndIf
        DllStructSetData($hOverlapped, "hEvent", $hEvent[0])
    EndIf
    $aResult = DllCall("Kernel32.dll", "int", "ReadDirectoryChangesW", _
        "hwnd", $hDir, _
        "ptr", $pBuffer, _
        "dword", $nBufferLength, _
        "int", $bSubtree, _
        "dword", BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, _
            $FILE_NOTIFY_CHANGE_SIZE,$FILE_NOTIFY_CHANGE_DIR_NAME), _
        "uint", 0, _
        "uint", $pOverlapped, _
        "uint", 0)
    If $aResult[0] = 0 Then
        ConsoleWrite("!>  ReadDirectoryChangesW Error(" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)
        Exit
    EndIf
    Return $aResult[0]
EndFuncoÝ÷ Úz0¶¢YhÂ)à±Êâ¦×·¦{hÊ«£  ìr¸©µ»­ë-)ජ{(ì+×¥w¬¶!jܨ»§¶Ú!j^í«^½éíj¢+Zéèr·×è®Ø^±Êâ¦Ø¦ë-­êh²Ø§+m+/"¢x¬¶¬jg±·¢·ºÜ"¶èè¬r¸©µ¼

hopes this helps people out, its a great script:) thanks all!

cheers

seesoe

Share this post


Link to post
Share on other sites

@ seesoe

Why the GUI version always give me error when i trying to re monitor any location ?

is it a bug ?


73 108 111 118 101 65 117 116 111 105 116

Share this post


Link to post
Share on other sites

Thank you seesoe.

This is what I need also. :D

But how to add more files/folders?

I can see that it is this string:

$sDir = "C:\1\"

But how?

#cs ----------------------------------------------------------------------------

AutoIt Version: 3.2.10.0
Author: zorphnog (M. Mims)

Script Function:
Monitors the user defined directories for file activity.

To Do :

#ce ----------------------------------------------------------------------------


#include <Constants.au3>
#include <WinAPI.au3>
#include <Date.au3>


HotKeySet("{ESC}", "CLOSE")
$sDir = "C:\1\"

Global Const _
        $FILE_FLAG_BACKUP_SEMANTICS = 0x02000000, _
        $FILE_FLAG_OVERLAPPED       = 0x40000000
Global Const _
        $FILE_NOTIFY_CHANGE_ALL         = 0x17F, _
        $FILE_NOTIFY_CHANGE_FILE_NAME   = 0x001, _
        $FILE_NOTIFY_CHANGE_DIR_NAME    = 0x002, _
        $FILE_NOTIFY_CHANGE_ATTRIBUTES  = 0x004, _
        $FILE_NOTIFY_CHANGE_SIZE        = 0x008, _
        $FILE_NOTIFY_CHANGE_LAST_WRITE  = 0x010, _
        $FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x020, _
        $FILE_NOTIFY_CHANGE_CREATION    = 0x040, _
        $FILE_NOTIFY_CHANGE_SECURITY    = 0x100
Global Const _
        $FILE_ACTION_ADDED            = 0x1, _
        $FILE_ACTION_REMOVED          = 0x2, _
        $FILE_ACTION_MODIFIED         = 0x3, _
        $FILE_ACTION_RENAMED_OLD_NAME = 0x4, _
        $FILE_ACTION_RENAMED_NEW_NAME = 0x5
Global Const _
        $MWMO_ALERTABLE      = 0x0002, _
        $MWMO_INPUTAVAILABLE = 0x0004, _
        $MWMO_WAITALL        = 0x0001
Global Const $FILE_LIST_DIRECTORY = 0x0001
Global Const $QS_ALLINPUT = 0x04FF
Global Const $INFINITE = 0xFFFF
Global Const $tagFNIIncomplete = "dword NextEntryOffset;dword Action;dword FileNameLength"
Global $bMonitorDone, $bSelected, $bMonitor

AutoItSetOption("GUIOnEventMode", 1)

_Main()

Func _DisplayFileMessages($hBuffer, $sDir)
    Local $hFileNameInfo, $pBuffer, $hTime
    Local $nFileNameInfoOffset = 12, $nOffset = 0, $nNext = 1
    $pBuffer = DllStructGetPtr($hBuffer)
    While $nNext <> 0
        $hFileNameInfo = DllStructCreate($tagFNIIncomplete, $pBuffer + $nOffset)
        $hFileName = DllStructCreate("wchar FileName[" & DllStructGetData($hFileNameInfo, "FileNameLength")/2 & "]", $pBuffer + $nOffset + $nFileNameInfoOffset)
        $hTime = _Date_Time_GetSystemTime()
        Switch DllStructGetData($hFileNameInfo, "Action")
            Case $FILE_ACTION_ADDED
                ConsoleWrite(" Created " )
                If DllStructGetData($hFileName, "FileName") = "neu.txt" Then
                    FileCopy($sDir & DllStructGetData($hFileName, "FileName"), $sdir & "gefunden.txt",1)
                EndIf
            Case $FILE_ACTION_REMOVED
                MsgBox("","test","Deleted")
            ;   ConsoleWrite( " Deleted " )
        Case $FILE_ACTION_MODIFIED
                MsgBox('',"changed","something was changed in a file")
                ConsoleWrite(" Modified " )
            Case $FILE_ACTION_RENAMED_OLD_NAME
                ConsoleWrite(" Rename- " )
            Case $FILE_ACTION_RENAMED_NEW_NAME
                ConsoleWrite(" Rename+ " )
            Case Else
                ConsoleWrite(" Unknown" )
        EndSwitch

    ConsoleWrite(_Date_Time_SystemTimeToDateTimeStr($hTime))
    ConsoleWrite(" : " & $sDir & DllStructGetData($hFileName, "FileName") & @crlf)

    $nNext = DllStructGetData($hFileNameInfo, "NextEntryOffset")
    $nOffset += $nNext
    WEnd
EndFunc

Func _GetBufferHandle ()
    Return DllStructCreate("ubyte[2048]")
EndFunc

Func _GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs, $bAsync = Default, $nTimeout = Default)
    Local $aMsg, $i, $nBytes = 0
    If $nTimeout = -1 Or IsKeyword($nTimeout) Then $nTimeout = 250
        If Not $bAsync Then $nTimeout = $INFINITE
            $aMsg = DllCall("User32.dll", "dword", "MsgWaitForMultipleObjectsEx", _
            "dword", UBound($aOverlapped), _
            "ptr", DllStructGetPtr($hEvents), _
            "dword", $nTimeout, _
            "dword", 0, _
            "dword", 0x6)
            $i = $aMsg[0]
            Switch $i
                Case 0 To UBound($aDirHandles)-1
                    If Not _WinAPI_GetOverlappedResult($aDirHandles[$i], DllStructGetPtr($aOverlapped[$i]), $nBytes, True) Then
                        ConsoleWrite("!> GetOverlappedResult Error(" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)
                        Return 0
                    EndIf
                DllCall("Kernel32.dll", "Uint", "ResetEvent", "uint", DllStructGetData($aOverlapped[$i], "hEvent"))
                _DisplayFileMessages($hBuffer, $aDirs[$i])
                _SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i],False,True)
                Return $nBytes
            EndSwitch
    Return 0
EndFunc

Func _GetDirHandle($sDir)
    Local $aResult
    $aResult = DllCall("Kernel32.dll", "hwnd", "CreateFile", _
    "str", $sDir, _
    "int", $FILE_LIST_DIRECTORY, _
    "int", BitOR($FILE_SHARE_DELETE,$FILE_SHARE_READ,$FILE_SHARE_WRITE), _
    "ptr", 0, _
    "int", $OPEN_EXISTING, _
    "int", BitOR($FILE_FLAG_BACKUP_SEMANTICS,$FILE_FLAG_OVERLAPPED), _
    "int", 0)
    If $aResult[0] = 0 Then
        ConsoleWrite("!> CreateFile Error (" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)
        Exit
    EndIf
    Return $aResult[0]
EndFunc

Func _GetEventHandles ($aOverlapped)
    Local $i, $hEvents
    $hEvents = DllStructCreate("hwnd hEvent[" & UBound($aOverlapped) & "]")
    For $i=1 To UBound($aOverlapped)
        DllStructSetData($hEvents, "hEvent", DllStructGetData($aOverlapped[$i-1], "hEvent"), $i)
    Next
    Return $hEvents
EndFunc

Func _GetOverlappedHandle ()
    Local $hOverlapped = DllStructCreate($tagOVERLAPPED)
    For $i=1 To 5
        DllStructSetData($hOverlapped, $i, 0)
    Next
    Return $hOverlapped
EndFunc

Func _Main ()
    $bSelected = True
    $bMonitorDone = False
    $bMonitor = True
    While 1
        If Not $bMonitorDone Then _MonitorDirs()
            If $bMonitor Then
                $bMonitor = Not $bMonitor
            EndIf
            If $bSelected Then
                $bSelected = Not $bSelected
            EndIf
    WEnd
EndFunc

Func _MonitorDirs ()
    Local $i, $nMax, $hBuffer, $hEvents
    $nMax = 1
    Local $aDirHandles[$nMax], $aOverlapped[$nMax], $aDirs[$nMax]
    $hBuffer = _GetBufferHandle()
    For $i = 0 To $nMax-1
        $aDirs[$i] = $sDir
        $aDirHandles[$i] = _GetDirHandle($aDirs[$i])
        $aOverlapped[$i] = _GetOverlappedHandle()
        _SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i], True, True)
    Next
    $hEvents = _GetEventHandles($aOverlapped)
    While Not $bMonitorDone ; loop until "ESC"
        _GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs)
    WEnd
EndFunc

Func _SetReadDirectory($hDir, $hBuffer, $hOverlapped, $bInitial = False, $bSubtree = False)
    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)
        If $hEvent[0] = 0 Then
            ConsoleWrite("!> CreateEvent Failed (" & _WinAPI_GetLastError() & "): " & _WinAPI_GetLastErrorMessage() & @LF)
            Exit
        EndIf
        DllStructSetData($hOverlapped, "hEvent", $hEvent[0])
    EndIf
    $aResult = DllCall("Kernel32.dll", "int", "ReadDirectoryChangesW", _
    "hwnd", $hDir, _
    "ptr", $pBuffer, _
    "dword", $nBufferLength, _
    "int", $bSubtree, _
    "dword", BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, _
    $FILE_NOTIFY_CHANGE_SIZE,$FILE_NOTIFY_CHANGE_DIR_NAME), _
    "uint", 0, _
    "uint", $pOverlapped, _
    "uint", 0)
    If $aResult[0] = 0 Then
        ConsoleWrite("!> ReadDirectoryChangesW Error(" & @error & "): " & _WinAPI_GetLastErrorMessage() & @LF)
        Exit
    EndIf
    Return $aResult[0]
EndFunc

Func CLOSE()
    Exit
EndFunc

Share this post


Link to post
Share on other sites

Thank you seesoe.

This is what I need also. ^_^

But how to add more files/folders?

I can see that it is this string:

$sDir = "C:\1\"

But how?

Your answer is here "Just remember to set the $dirs variable to how many your going to watch, and then fill in the array from 0 to $dirs - 1 with the names of the directories (ending with a \ I believe)." Edited by dmob

Share this post


Link to post
Share on other sites

@all, Works great!

I'm monitoring the c:\ drive with 'zorphnog' version and it seems to be catching everything without noticeable issues..

You should submit this to the Example Scripts forum so this can get more attention. (I only found this from KaFus signature. :) )

Edited by Kastout

Don't bother, It's inside your monitor!------GUISetOnEvent should behave more like HotKeySet()

Share this post


Link to post
Share on other sites

Extremely nice script, works very well for me. I needed to monitor a network UNC path to figure out when new builds were pushed, and take certain actions based on file updates - this works brilliantly.

Thanks to all the guys who worked on it!

Kp.

Share this post


Link to post
Share on other sites

Hi there,

thanks for all who worked on this script to get it working. I was looking for something like this and could very well use it (be it that I broke it down to handle just one folder). One thing noted: when stopping and resuming the script, often it will crash. I tried to cleanup the event and struct variables but that didn't help. Finally I found that calling WinAPI CloseHandle() for the directory- and eventhandler did the job. Now monitoring can be stopped and resumed as much as you like.

Just wanted to share this with you.

- Heron -

Share this post


Link to post
Share on other sites

Hi there,

thanks for all who worked on this script to get it working. I was looking for something like this and could very well use it (be it that I broke it down to handle just one folder). One thing noted: when stopping and resuming the script, often it will crash. I tried to cleanup the event and struct variables but that didn't help. Finally I found that calling WinAPI CloseHandle() for the directory- and eventhandler did the job. Now monitoring can be stopped and resumed as much as you like.

Just wanted to share this with you.

- Heron -

I too have been checking out this au3 app and have been having a lot of fun with it. I was wondering if anyone knew how to modify a few things. I was attempting to accomplish the following:

Pop-up window when an item entered into a certain folder (as a notifier)

Minimize the application so it runs as a little icon by the icon tray next to the clock (and keeps running/monitoring the predetermined folder).

Has the ability to be brought back into "normal" view if you right click the icon and select "maximize" or some such word.

I have found stand alone "popup" and "minimize" au3 doc's on the forums but I don't know how to work them into this one. I've been linking them by inserting run("popup.exe", "", @SW_SHOW) but there is lag time when I do that. I would like to have it all run together.

The purpose behind all of this:

If you set your printer (on Windows XP) to "Print to Text" the only option it gives you is to print as the same file ex. DOC.txt

I am acting as the router for our office and all of the printed documents DO NOT need to be printed and they come in at times in rapid succession and when my program is hanging up the newest print document writes over the last one and I completely miss a document!

I'm trying to get it so that when the DOC.txt arrives in the predesignated folder my program automatically time/date stamps it with a unique number, sends me audio noises and visual notification that I have a new DOC.txt that has been received (and renamed) for me in the print folder I'm monitoring.

Also, the "ZMV Monitor.au3" will not run unless you have "C:\print\INCOMING\" because it is set to monitor that location. When it finds that location does not exist it stops trying and closes out.

I hope this makes sense. I'll attach all of the different coding I've been working on and if anyone could help me that would be wonderful!!

Thank you so much in advance!

Matt

ZMV Monitor.au3

rename.au3

popup.au3

Share this post


Link to post
Share on other sites

I forgot to add one other thing I was trying to do. I was also trying to see just the file name not the "C:\print\INCOMING\" (or the directory). This because I have the file being changed to a date/time stamp and scrolling over to see which is which is cumbersome.

I also failed to attach this other one as well; sorry mates.

Matt

MINIMIZE TEST.au3

Share this post


Link to post
Share on other sites

Good work on figuring it out guys. I have been playing around with the code as well, and have made a GUI for it. I simplified the different dll calls into some udfs so I thought I'd share it with anyone who might want it.

This script drives my CPU up to 100%.I do need this functionality, so I tried to modify those scripts myself.

According to http://msdn.microsoft.com/en-us/library/ms684245%28VS.85%29.aspx,if change these lines:

$aMsg = DllCall("User32.dll", "dword", "MsgWaitForMultipleObjectsEx", _

"dword", UBound($aOverlapped), _

"ptr", DllStructGetPtr($hEvents), _

"dword", $nTimeout, _

"dword", 0, _

"dword", 0x6)

to:

$aMsg = DllCall("User32.dll", "dword", "MsgWaitForMultipleObjectsEx", _

"dword", UBound($aOverlapped), _

"ptr", DllStructGetPtr($hEvents), _

"dword", $nTimeout, _

"dword", 0x4FF, _

"dword", 0x6)

The script will not be resource-consuming.

And we should do some cleaning and close handles when stopping monitoring, thus the monitor can stop and restart without crash.

I've developed a UDF _MonitorDirectory() for filesystem monitoring, the function with an example as below:

;~ Example
OnAutoItExitRegister("_Exit")
Global $aDirs[2]
$aDirs[0] = @ScriptDir
$aDirs[1] = "C:\"
_MonitorDirectory($aDirs, True, 100, "_ReportFileChanges")
While 1
    Sleep(20)
WEnd

;~ This function will be called when changes are registered
Func _ReportFileChanges($Action, $FilePath)
    ;~ Your own script here ...
    ;~ ...
    ConsoleWrite($Action & ": " & $FilePath & @CRLF)
    TrayTip("MonitorDirectory", $Action & ": " & $FilePath, 5, 1)
EndFunc   ;==>_ReportFileChanges

;~ Stop monitoring before exiting at least
Func _Exit()
    _MonitorDirectory()
    Exit
EndFunc   ;==>_Quit



;~ =========================== FUNCTION _MonitorDirectory() ==============================
#cs
    Description:     Monitors the user defined directories for file activity.
    Original:        http://www.autoitscript.com/forum/index.php?showtopic=69044&hl=folderspy&st=0
    Modified:        Jack Chen
    Syntax:         _MonitorDirectory($Dirs = "", $Subtree = True, $TimerMs = 250, $Function = "_ReportChanges")
    Parameters:
                    $Dirs          - Optional: Zero-based array of valid directories to be monitored.
                    $Subtree       - Optional: Subtrees will be monitored if $Subtree = True.
                    $TimerMs       - Optional: Timer to register changes in milliseconds.
                    $Function      - Optional: Function to launch when changes are registered. e.g. _ReportChanges
                    Syntax of your function must be e.g._ReportChanges($Action, $FilePath)
                    Possible actions: Created, Deleted, Modified, Rename-, Rename+, Unknown
    Remarks:        Call _MonitorDirectory() without parameters to stop monitoring all directories.
                    THIS SHOULD BE DONE BEFORE EXITING SCRIPT AT LEAST.
#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)
    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 = "Created"
            Case 0x2 ; $FILE_ACTION_REMOVED
                $Action = "Deleted"
            Case 0x3 ; $FILE_ACTION_MODIFIED
                $Action = "Modified"
            Case 0x4 ; $FILE_ACTION_RENAMED_OLD_NAME
                $Action = "Rename-"
            Case 0x5 ; $FILE_ACTION_RENAMED_NEW_NAME
                $Action = "Rename+"
            Case Else
                $Action = "Unknown"
        EndSwitch

        $FilePath = $sDir & DllStructGetData($hFileName, "FileName")
        Call($sFunction, $Action, $FilePath) ; Launch the specified function
        $nNext = DllStructGetData($hFileNameInfo, "NextEntryOffset")
        $nOffset += $nNext
    WEnd
EndFunc   ;==>_ParseFileMessages
;~ ===========================End of FUNCTION _MonitorDirectory() ==============================

I have modified zorphnog's FolderSpy with this function _MonitorDirectory().Now it's light and reliable.

Code:

#cs ----------------------------------------------------------------------------

    AutoIt Version: 3.3.6.1
    Author:         zorphnog (M. Mims)
    Modified:       Jackchen

    Script Function:
    Monitors the user defined directories for file activity.

#ce ----------------------------------------------------------------------------

#include <Constants.au3>
#include <WinAPI.au3>
#include <Date.au3>
#include <GUIConstants.au3>
#include <GuiListBox.au3>
#include <GuiListView.au3>
#include <Array.au3>

Global $bMonitoring = False
AutoItSetOption("GUIOnEventMode", 1)

$gFileMon = GUICreate("Directory Monitor", 731, 385, 194, 126)
GUISetOnEvent($GUI_EVENT_CLOSE, "_OnEvent_Close")
GUICtrlCreateGroup("Monitored Directories", 8, 0, 713, 105)
$btAdd = GUICtrlCreateButton("Add", 16, 24, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Add")
$btRemove = GUICtrlCreateButton("Remove", 16, 56, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Remove")
GUICtrlSetState(-1, $GUI_DISABLE)
$lbDirectories = GUICtrlCreateList("", 104, 16, 506, 71)
$btMonitor = GUICtrlCreateButton("Start Monitor", 632, 24, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Monitor")
GUICtrlSetState(-1, $GUI_DISABLE)
$btClear = GUICtrlCreateButton("Clear", 632, 56, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Clear")
GUICtrlCreateGroup("", -99, -99, 1, 1)
$lvNotifications = GUICtrlCreateListView("Action|Time|File", 8, 112, 714, 262)
GUICtrlSendMsg(-1, 0x101E, 0, Int(.1 * 710))
GUICtrlSendMsg(-1, 0x101E, 1, Int(.2 * 710))
GUICtrlSendMsg(-1, 0x101E, 2, Int(.7 * 710) - 20)
GUISetState(@SW_SHOW)

While 1
    If Not $bMonitoring And _GUICtrlListBox_GetCurSel($lbDirectories) <> -1 And GUICtrlGetState($btRemove) = $GUI_SHOW + $GUI_DISABLE Then
        GUICtrlSetState($btRemove, $GUI_ENABLE)
    EndIf
    Sleep(20)
WEnd

Func _ReportChanges($Action, $FilePath)
    Local $hTime
    $hTime = _Date_Time_GetSystemTime()
    _GUICtrlListView_InsertItem($lvNotifications, $Action, 0)
    _GUICtrlListView_AddSubItem($lvNotifications, 0, _Date_Time_SystemTimeToDateTimeStr($hTime), 1)
    _GUICtrlListView_AddSubItem($lvNotifications, 0, $FilePath, 2)
EndFunc   ;==>_ReportChanges

Func _OnEvent_Add()
    Local $sDir, $nMax, $i
    $sDir = FileSelectFolder("Select directory to monitor", "")
    If $sDir <> "" Then
        If StringRight($sDir, 1) <> "\" Then $sDir &= "\"
        $nMax = _GUICtrlListBox_GetCount($lbDirectories) - 1
        For $i = 0 To $nMax
            If _GUICtrlListBox_GetText($lbDirectories, $i) = $sDir Then Return
        Next
        _GUICtrlListBox_AddString($lbDirectories, $sDir)

        GUICtrlSetState($btMonitor, $GUI_ENABLE)

    EndIf
EndFunc   ;==>_OnEvent_Add

Func _OnEvent_Clear()
    _GUICtrlListView_DeleteAllItems(GUICtrlGetHandle($lvNotifications))
EndFunc   ;==>_OnEvent_Clear

Func _OnEvent_Close()
    If $bMonitoring Then _MonitorDirectory()
    Exit
EndFunc   ;==>_OnEvent_Close

Func _OnEvent_Monitor()
    If Not $bMonitoring Then
        $bMonitoring = True
        GUICtrlSetData($btMonitor, "Stop Monitor")
        GUICtrlSetState($btAdd, $GUI_DISABLE)
        GUICtrlSetState($btRemove, $GUI_DISABLE)
        GUICtrlSetState($lbDirectories, $GUI_DISABLE)
        $n = _GUICtrlListBox_GetCount($lbDirectories)
        Local $Dirs[$n]
        For $i = 0 To $n - 1
            $Dirs[$i] = _GUICtrlListBox_GetText($lbDirectories, $i)
        Next
        _MonitorDirectory($Dirs)
    Else
        $bMonitoring = False
        GUICtrlSetState($lbDirectories, $GUI_ENABLE)
        GUICtrlSetState($btAdd, $GUI_ENABLE)
        GUICtrlSetData($btMonitor, "Start Monitor")
        _MonitorDirectory()
    EndIf
EndFunc   ;==>_OnEvent_Monitor

Func _OnEvent_Remove()
    _GUICtrlListBox_DeleteString($lbDirectories, _GUICtrlListBox_GetCurSel($lbDirectories))
    If _GUICtrlListBox_GetCount($lbDirectories) = 0 Then
        GUICtrlSetState($btMonitor, $GUI_DISABLE)
    EndIf
EndFunc   ;==>_OnEvent_Remove



;~ =========================== FUNCTION _MonitorDirectory() ==============================
#cs
    Description:     Monitors the user defined directories for file activity.
    Original:        http://www.autoitscript.com/forum/index.php?showtopic=69044&hl=folderspy&st=0
    Modified:        Jack Chen
    Syntax:         _MonitorDirectory($Dirs = "", $Subtree = True, $TimerMs = 250, $Function = "_ReportChanges")
    Parameters:
                    $Dirs          - Optional: Zero-based array of valid directories to be monitored.
                    $Subtree       - Optional: Subtrees will be monitored if $Subtree = True.
                    $TimerMs       - Optional: Timer to register changes in milliseconds.
                    $Function      - Optional: Function to launch when changes are registered. e.g. _ReportChanges
                    Syntax of your function must be e.g._ReportChanges($Action, $FilePath)
                    Possible actions: Created, Deleted, Modified, Rename-, Rename+, Unknown
    Remarks:        Call _MonitorDirectory() without parameters to stop monitoring all directories.
                    THIS SHOULD BE DONE BEFORE EXITING SCRIPT AT LEAST.
#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)
    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 = "Created"
            Case 0x2 ; $FILE_ACTION_REMOVED
                $Action = "Deleted"
            Case 0x3 ; $FILE_ACTION_MODIFIED
                $Action = "Modified"
            Case 0x4 ; $FILE_ACTION_RENAMED_OLD_NAME
                $Action = "Rename-"
            Case 0x5 ; $FILE_ACTION_RENAMED_NEW_NAME
                $Action = "Rename+"
            Case Else
                $Action = "Unknown"
        EndSwitch

        $FilePath = $sDir & DllStructGetData($hFileName, "FileName")
        Call($sFunction, $Action, $FilePath) ; Launch the specified function
        $nNext = DllStructGetData($hFileNameInfo, "NextEntryOffset")
        $nOffset += $nNext
    WEnd
EndFunc   ;==>_ParseFileMessages
;~ ===========================End of FUNCTION _MonitorDirectory() ==============================
Edited by jackchen

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...