Jump to content

About detecting changes to files?


youtuber
 Share

Recommended Posts

why are you defining func _WinAPI_ReadDirectoryChanges?? start with the working sample

 

#include <APIFilesConstants.au3>
#include <Array.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIError.au3>
#include <WinAPIFiles.au3>
#include <WinAPIMem.au3>

Global $g_sPath = @TempDir & '\~TEST~'

DirCreate($g_sPath)
If Not FileExists($g_sPath) Then
    MsgBox(BitOR($MB_ICONERROR, $MB_SYSTEMMODAL), 'Error', 'Unable to create folder.')
    Exit
EndIf

OnAutoItExitRegister('OnAutoItExit')

Local $hDirectory = _WinAPI_CreateFileEx($g_sPath, $OPEN_EXISTING, $FILE_LIST_DIRECTORY, BitOR($FILE_SHARE_READ, $FILE_SHARE_WRITE), $FILE_FLAG_BACKUP_SEMANTICS)
If @error Then
    _WinAPI_ShowLastError('', 1)
EndIf

Local $pBuffer = _WinAPI_CreateBuffer(8388608)

Local $aData
While 1
    $aData = _WinAPI_ReadDirectoryChanges($hDirectory, BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, $FILE_NOTIFY_CHANGE_DIR_NAME), $pBuffer, 8388608, 1)
    If Not @error Then
        _ArrayDisplay($aData, '_WinAPI_ReadDirectoryChanges')
    Else
        _WinAPI_ShowLastError('', 1)
    EndIf
WEnd

Func OnAutoItExit()
    DirRemove($g_sPath, 1)
EndFunc   ;==>OnAutoItExit

then make your other script to actuate it.

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Link to comment
Share on other sites

@Earthshine yes, but the gui doesn't respond and doesn't detect changes to the text document :(

Spoiler

bV8Jj8.png

#include <APIFilesConstants.au3>
#include <Array.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIError.au3>
#include <WinAPIFiles.au3>
#include <WinAPIMem.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <File.au3>

Global $g_sPath = @DesktopDir & '\Changing folder'
DirCreate($g_sPath)
If Not FileExists($g_sPath) Then
    MsgBox(BitOR($MB_ICONERROR, $MB_SYSTEMMODAL), 'Error', 'Unable to create folder.')
    Exit
EndIf
Global $pBuffer = _WinAPI_CreateBuffer(8388608)
Global $aData
OnAutoItExitRegister('OnAutoItExit')
Global $hDirectory = _WinAPI_CreateFileEx($g_sPath, $OPEN_EXISTING, $FILE_LIST_DIRECTORY, BitOR($FILE_SHARE_READ, $FILE_SHARE_WRITE), $FILE_FLAG_BACKUP_SEMANTICS)
If @error Then
    _WinAPI_ShowLastError('', 1)
EndIf

$Form1 = GUICreate("Form1", 493, 263)
$Edit1 = GUICtrlCreateEdit("" & @CRLF, 16, 24, 457, 193, BitOR($ES_MULTILINE, $ES_AUTOVSCROLL, $WS_VSCROLL))
GUISetState(@SW_SHOW, $Form1)
While 1
    $aData = _WinAPI_ReadDirectoryChanges($hDirectory, BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, $FILE_NOTIFY_CHANGE_DIR_NAME), $pBuffer, 8388608, 1)
    If Not @error Then
        GUICtrlSetData($Edit1, @MIN & " : " & @SEC & " File has changed " & $aData & @CRLF, 1)
    Else
        _WinAPI_ShowLastError('', 1)
    EndIf
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit

    EndSwitch
WEnd

Func OnAutoItExit()
    DirRemove($g_sPath, 1)
EndFunc   ;==>OnAutoItExit

 

Edited by youtuber
Link to comment
Share on other sites

  • Developers

OK... this is my last contribution to this thread in an effort to make you realize what I have been telling you all the time!
Copy it into SciTE. set the directory correct and press f5. Then watch the Console... and think about what you see. Then make some changes in the directory and look again to the Console and also the gui this time. :)

#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <APIFilesConstants.au3>
#include <Array.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIError.au3>
#include <WinAPIFiles.au3>
#include <WinAPIMem.au3>
Opt("GUIOnEventMode", 1)

Global $ChangingFolder = @DesktopDir & "\Changing folder"
Global $pBuffer = _WinAPI_CreateBuffer(8388608)
Global $aData

Global $hDirectory = _WinAPI_CreateFileEx($ChangingFolder, $OPEN_EXISTING, $FILE_LIST_DIRECTORY, BitOR($FILE_SHARE_READ, $FILE_SHARE_WRITE), $FILE_FLAG_BACKUP_SEMANTICS)
If @error Then
    _WinAPI_ShowLastError('', 1)
EndIf


$Form1 = GUICreate("Form1", 493, 263)
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEButton")
$Edit1 = GUICtrlCreateEdit("" & @CRLF, 16, 24, 457, 193, BitOR($ES_MULTILINE, $ES_AUTOVSCROLL, $WS_VSCROLL))
GUISetState(@SW_SHOW, $Form1)

While 1
    ConsoleWrite(" Wait for changes..")
    $aData = _WinAPI_ReadDirectoryChanges($hDirectory, BitOR($FILE_NOTIFY_CHANGE_DIR_NAME, $FILE_NOTIFY_CHANGE_LAST_WRITE, $FILE_NOTIFY_CHANGE_CREATION), $pBuffer, 8388608, 1)
    ConsoleWrite(" Something changed?")
    If Not @error and IsArray($aData) Then
        $curcontent=GUICtrlRead($Edit1)
        For $x = 1 to $aData[0][0]
            $curcontent &= @CRLF & $aData[$x][0] & " -> " & $aData[$x][1]
        Next
        GUICtrlSetData($Edit1, $curcontent, 1)
    Else
        _WinAPI_ShowLastError('', 1)
    EndIf
WEnd

Func CLOSEButton()
    ; Note: At this point @GUI_CtrlId would equal $GUI_EVENT_CLOSE,
    ; and @GUI_WinHandle would equal $hMainGUI
    Exit
EndFunc   ;==>CLOSEButton

Jos

Edited by Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Link to comment
Share on other sites

34 minutes ago, youtuber said:

yes but still not responding to close gui

  Reveal hidden contents

TAkAe.png

 

Hey, I'll try to explain in the simplest terms the issue you're facing.

Jos's sample here loops to detect file changes. Something you are overlooking, is that "_WinAPI_ReadDirectoryChanges" will ONLY return after a change is made. That means when you put _WinAPI_ReadDirectoryChanges in your code, your script will WAIT until it returns before continuing. The only way it returns is if a file is changed. No file change? No script. 

That's fine, but with how this sample is written, once the _WinAPI_ReadDirectoryChanges call returns, we loop again due to "While 1" and it blocks once more, over and over again, no matter how many changes you make, until you manually queue the exit.

Here is the workflow of the code you are sampling:
Initiate GUI -> Wait for change in directory so _WinAPI_ReadDirectoryChanges can return -> Update GUI -> Repeat. 

Nothing in your script can run until _WinAPI_ReadDirectoryChanges returns. For this reason, the script will stop responding! That's what's giving you your error. Your script doesn't care about anything anymore EXCEPT waiting on _WinAPI_ReadDirectoryChanges!

The way to get out of that, without editing Jos's sample is: After you try to exit the script, make one more change to the directory. This allowed _WinAPI_ReadDirectoryChanges to return and then lets your Exit code run right after, instead of looping again. 

This turns the execution to:
Queue exit -> Wait for _WinAPI_ReadDirectoryChanges -> Run queued code directly after, which is exit

If you just want to see Jos's example work, when you finish changing your files, try to close the GUI. Now you will see "Not Responding". Don't fret though, to get it to truly close, you need to make one more change in your directory. Once you save the change to the directory, the script will exit right away without any errors. 

What Jos is trying to tell you is that if you are making one script use _WinAPI_ReadDirectoryChanges, it will constantly block without having a good way to exit. The solution to this is to have another script that can act as a "controller" of sorts and use that to close the script running _WinAPI_ReadDirectoryChanges whenever you want, instead of getting stuck. 

@Jos if I have misinterpreted please let me know :)

Edited by Zein
Link to comment
Share on other sites

_WinAPI_ReadDirectoryChanges,My fault is not my fault @AdamUL my script is still in the first message and still haven't changed :(

actually I had a good working example.

#include <Array.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

Local $ChangingFolder = @DesktopDir & "\Changing folder"
Global $sFileToCheck = $ChangingFolder & "\file.txt"
Global $bFileChanged = False
Global $sFileDateTime = _ArrayToString(FileGetTime($sFileToCheck))
AdlibRegister("_CheckFile", 250)
$Form1 = GUICreate("Form1", 493, 263)
$Edit1 = GUICtrlCreateEdit("" & @CRLF, 16, 24, 457, 193, BitOR($ES_MULTILINE, $ES_AUTOVSCROLL, $WS_VSCROLL))
GUISetState(@SW_SHOW, $Form1)
While 1
    If $bFileChanged Then
        GUICtrlSetData($Edit1, @MIN & " : " & @SEC & " File has changed " & $sFileToCheck & @CRLF, 1)
        $sFileDateTime = _ArrayToString(FileGetTime($sFileToCheck))
        $bFileChanged = False
    EndIf
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit

    EndSwitch
WEnd

Func _CheckFile()
    If $sFileDateTime <> _ArrayToString(FileGetTime($sFileToCheck)) Then $bFileChanged = True
EndFunc   ;==>_CheckFile


but

But I wanted for all txt files in a folder.

And I'm still waiting for a solution, just for all txt files in a single folder.

Edited by youtuber
Link to comment
Share on other sites

  • Developers
1 hour ago, youtuber said:

yes but still not responding to close gui

Correct... and what where you conclusions at each step I told you to do or do you want me to just burb up the working code for you? 

Quote

And I'm still waiting for a solution, just for all txt files in a single folder.

fuck it... you were told what the solution is but seem to refuse to follow all advice and pointers given...   i am really done here now.

Edited by Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Link to comment
Share on other sites

the example code works GREAT, returns ALL changes regardless. if you run the sample and dump files into that temp dir, they show up in the array just fine. lol. Jos' code works great too.

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Link to comment
Share on other sites

  • Developers
18 minutes ago, Earthshine said:

Jos' code works great too.

It works sort-of as it returns all changes to the GUI but the GUI is unresponsive. I actually have the proper working code prepared but simply refuse to provide code to people unwilling to make any progress themselves first and make this a learning experience.

Jos

Edited by Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Link to comment
Share on other sites

On 11/13/2018 at 10:20 PM, Jos said:

Ah.. that's a good approach to life...  when confused simply ignore it and it for sure will go away. ;) 

@Jos , you on a roll today... :P:thumbsup:

Kind Regards
Skeletor

"Coffee: my defense against going postal."

Microsoft Office Splash Screen | Basic Notepad Program (Beginner) | Transparent Splash Screen | Full Screen UI

Link to comment
Share on other sites

Quote

@Zein Here is the workflow of the code you are sampling:
Initiate GUI -> Wait for change in directory so _WinAPI_ReadDirectoryChanges can return -> Update GUI -> Repeat. 

yes but i dont know how to disable _WinAPI_ReadDirectoryChanges and update gui

function _WinAPI_ReadDirectoryChanges form1 gui for freezing GUIDelete or GUIRegisterMsg,give me a hint that I'm going to use something like that, very complicated for me, I am very confused.:(

Edited by youtuber
Link to comment
Share on other sites

1 hour ago, youtuber said:

yes but i dont know how to disable _WinAPI_ReadDirectoryChanges and update gui

function _WinAPI_ReadDirectoryChanges form1 gui for freezing GUIDelete or GUIRegisterMsg,give me a hint that I'm going to use something like that, very complicated for me, I am very confused.:(

You disable it by finding a way to queue other code, and then forcing _WinAPI_ReadDirectoryChanges  to return.

One potential way to do this is by writing your script in two functions
One function has the _WinAPI_ReadDirectoryChanges call, and the other function has the rest of your code.
You could then bind that second function to a hotkey, and when you're done with _WinAPI_ReadDirectoryChanges  you press the hotkey. 

Once you press the hotkey, force _WinAPI_ReadDirectoryChanges  to return by making another change to the folder. Once the change is made, the function you bound to the hotkey will be called and your code will continue without losing responsiveness, all while being able to extract the results of _WinAPI_ReadDirectoryChanges

Of course, this is less than ideal for an automated program, but you can work off of this to find an automated approach. 

Link to comment
Share on other sites

@youtuber,

you seemed to be confused. You HAVE TO SPLIT that problem into 2 DIFFERENT SCRIPTS. Script 1 only looks for directory changes and stucks as long as there is no change and reports if there is a change.

Script 2 is holding the responsive gui and waiting for a message that there is a change in the directory. If there is a change it has to inspect the directory and write the changes into the gui.

The messages between both scripts are delivered by registry entries for lack of a better idea.

At the end if you want to exit script 2 (and script 1 should exit too) you have to set the kill switch and then create a temp file in the directory with script 2 so that script 1 is able to react.

Here is some pseudo code:

#Region - Script 1 - Read Directory Changes
#include <APIFilesConstants.au3>
#include <FileConstants.au3>
#include <GUIConstantsEx.au3>
#include <WinAPIDiag.au3>
#include <WinAPIFiles.au3>
#include <WinAPISys.au3>

Global $g_sPathRegistry = ; same as in Script 2
Global $g_sPath = ; same as in Script 2

Local $hDirectory = _WinAPI_CreateFileEx($g_sPath, $OPEN_EXISTING, $FILE_LIST_DIRECTORY, BitOR($FILE_SHARE_READ, $FILE_SHARE_WRITE), $FILE_FLAG_BACKUP_SEMANTICS)
If @error Then
    _WinAPI_ShowLastError('', 1)
EndIf

Local $pBuffer = _WinAPI_CreateBuffer(8388608)

Local $aData
While 1
    ;                                                        !! Look exactly below if these are the parameters you want
    $aData = _WinAPI_ReadDirectoryChanges($hDirectory, BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, $FILE_NOTIFY_CHANGE_DIR_NAME), $pBuffer, 8388608, 1) ; it will "loop" inside this function as long as there is no change!!!
    ; That part below will only be executed if there is any change in the directory regarding the parameters you defined above
    If Not @error Then
        _LookForKillSwitch()
        _SayScript2_ThatThereIsAChange()
    Else
        _WinAPI_ShowLastError('', 1)
    EndIf
WEnd

Func _SayScript2_ThatThereIsAChange()
    ; for lack of a better solution:
    RegWrite($g_sPathRegistry, "DirectoryChange", "REG_DWORD", 1)
EndFunc

Func _LookForKillSwitch()
    Local $bKillSwitch = RegRead($g_sPathRegistry, "KillSwitch")
    If $bKillSwitch Then Exit
EndFunc
#EndRegion

#Region - Script 2 - React To Directory Changes
Global $g_sPathRegistry = ; same as in Script 1
Global $g_sPath = ; same as in Script 1
RegWrite($g_sPathRegistry, "KillSwitch", "REG_DWORD", 0) ; reset
RegWrite($g_sPathRegistry, "DirectoryChange", "REG_DWORD", 0) ; reset

_ReadYourFilesHere()
; Create your GUI here
_UpdateGUI()

While 1
    _IsThereAChangeInDirectory()
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _KillScript1()
            Exit
    EndSwitch
    Sleep(1000) ; to not read the registry permanently
WEnd

Func _ReadYourFilesHere()
    ; make a list of all files in the directory
EndFunc

Func _UpdateGUI()
    ; Update the list to your GUI or what ever is needed
EndFunc

Func _IsThereAChangeInDirectory()
    Local $bChange = RegRead($g_sPathRegistry, "DirectoryChange")
    If $bChange Then
        _ReadYourFilesHere()
        _UpdateGUI()
    EndIf
EndFunc

Func _KillScript1()
    RegWrite($g_sPathRegistry, "KillSwitch", "REG_DWORD", 1) ; set kill switch
    FileWrite($g_sPath & "/temp.txt", "Write some random stuff") ; Creates a file in $g_sPath, so that script 1 can react and can find kill switch
    While ProcessExists("Script1.exe")
        ; wait a bit
    WEnd
    FileDelete($g_sPath & "/temp.txt")
EndFunc
#EndRegion

Regards, Simpel

SciTE4AutoIt = 3.7.3.0   AutoIt = 3.3.14.2   AutoItX64 = 0   OS = Win_10   Build = 19044   OSArch = X64   Language = 0407/german
H:\...\AutoIt3\SciTE     H:\...\AutoIt3      H:\...\AutoIt3\Include     (H:\ = Network Drive)

   88x31.png  Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind.

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...