Jump to content
Yashied

RDC UDF (ReadDirectoryChanges Wrapper)

Recommended Posts

faustf

questions  , i have created this  script , but  why  if  i change  variable 

$iGResult = 0  , it  changes  in 1   autoamatically??

#include <APIConstants.au3>
#include <GDIPlus.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIFiles.au3>

#include "RDC.au3"

Opt('MustDeclareVars', 1)
Opt('TrayAutoPause', 0)

Global $hWnd = GUICreate(''), $aDir[3], $iGResult, $sGPath_Monitor
$sGPath_Monitor = StringReplace(@ScriptDir, "\INCLUDE", "") & (IniRead(@ScriptDir & "\presync_conf.ini", "Path_to_sync", "key1", "Error"))

_RDC_OpenDll()
If @error Then
    ConsoleWrite('Error: _RDC_OpenDll() - ' & @error & @CR)
    MsgBox(16, 'Error !!!', 'Error: _RDC_OpenDll() - ' & @error & @CR)
    Exit
EndIf

GUIRegisterMsg($WM_RDC, 'WM_RDC')

_RDC_Create($sGPath_Monitor, 1, BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, $FILE_NOTIFY_CHANGE_DIR_NAME, $FILE_NOTIFY_CHANGE_SIZE), 0, $hWnd)
If @error Then
    ConsoleWrite('Error: _RDC_Create() - ' & @error & ', ' & @extended & @CR)
    MsgBox(16, 'Error !!!', 'Error: _RDC_Create() - ' & @error & ' ' & @extended & @CR)
    ;Exit
EndIf


Func WM_RDC($hWnd, $iMsg, $wParam, $lParam)

    #forceref $hWnd, $iMsg, $wParam
    Local $aData = _RDC_GetData($lParam)

    If @error Then
        ; Do something because notifications will not come from this thread!
        ConsoleWrite('Error: _RDC_GetData() - ' & @error & ', ' & @extended & ', ' & _RDC_GetDirectory($lParam) & @CR)
        MsgBox(16, 'Error !!!', 'Error: _RDC_GetData() - ' & @error & ' ' & @extended & ' ' & _RDC_GetDirectory($lParam) & @CR)
        _RDC_Delete($lParam)
        Return 0
    EndIf
    For $i = 1 To $aData[0][0]
        $iGResult = $aData[$i][0]
    Next
    ;ConsoleWrite($iGResult)
    Return 0

EndFunc   ;==>WM_RDC

While 1

    Switch $iGResult
        Case $iGResult = 1 ; crea file
            MsgBox(0, '1', 'crea file')
            $iGResult = 0
        Case $iGResult = 2 ; cancella file
            MsgBox(0, '2', 'cancella file')
            $iGResult = 0
        Case $iGResult = 3 ; modifica file
            MsgBox(0, '3', 'modifica file')
            $iGResult = 0
        Case $iGResult = 4 ; nome vecchio
            MsgBox(0, '4', 'nome vecchio')
            $iGResult = 0
        Case $iGResult = 5 ; nome nuovo
            MsgBox(0, '5', 'nome nuovo')
            $iGResult = 0
    EndSwitch

WEnd

 

 

Share this post


Link to post
Share on other sites
Mbee
On 11/27/2016 at 9:51 AM, argumentum said:
Local $n
Local $t = @MIN&@SEC
For $n = 1 To 100
;~  Sleep($n * 10)
    FileWriteLine(@ScriptDir&'\~TEST~\testFastWrite'&$t&'_'&$n&'.txt',"delete, this just a test."&@CRLF)
Next

@Mbee , I've runned this and checked the original code's result. Could not find anything out of sequence.

Hello, @argumentum -- Sorry about the delay in responding.  I somehow missed the notification...

As for the code snippet you posted, I'm afraid I don't understand what you're testing -- at least in regards to my tiny change in the UDF.  The ONLY change I made was ONLY within the _RDC_GetData() function, which your snippet doesn't even call.  The documentation of the original version of that function claimed that the returned array from that call would hold the type of change in element [n][0] and the filename in element [n][1].  However, the original version (v1.0) actually returned the filename in element [n][0] and the type of change code in element [n][1], which was in error.  All I did was make the teeny tiny change so that the documentation would be correct!

So, since I don't see anywhere that you actually call _RDC_GetData(), my tiny change has had absolutely no effect on what you're trying to accomplish.

If I've misunderstood, please let me know.

Share this post


Link to post
Share on other sites
faustf

i try to modify  the script  with this  but put always up 100% cpu usage  :(

#include <APIConstants.au3>
#include <GDIPlus.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIFiles.au3>

#include "RDC.au3"

Opt('MustDeclareVars', 1)
Opt('TrayAutoPause', 0)

Global $hWnd = GUICreate(''), $aDir[3], $iGResult, $sGPath_Monitor, $de = 0

$sGPath_Monitor = StringReplace(@ScriptDir, "\INCLUDE", "") & (IniRead(@ScriptDir & "\presync_conf.ini", "Path_to_sync", "key1", "Error"))

_RDC_OpenDll()
If @error Then
    ConsoleWrite('Error: _RDC_OpenDll() - ' & @error & @CR)
    MsgBox(16, 'Error !!!', 'Error: _RDC_OpenDll() - ' & @error & @CR)
    Exit
EndIf

GUIRegisterMsg($WM_RDC, 'WM_RDC')

_RDC_Create($sGPath_Monitor, 1, BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, $FILE_NOTIFY_CHANGE_DIR_NAME, $FILE_NOTIFY_CHANGE_SIZE), 0, $hWnd)
If @error Then
    ConsoleWrite('Error: _RDC_Create() - ' & @error & ', ' & @extended & @CR)
    MsgBox(16, 'Error !!!', 'Error: _RDC_Create() - ' & @error & ' ' & @extended & @CR)
    ;Exit
EndIf


Func WM_RDC($hWnd, $iMsg, $wParam, $lParam)

    #forceref $hWnd, $iMsg, $wParam
    Local $aData = _RDC_GetData($lParam)

    If @error Then
        ; Do something because notifications will not come from this thread!
        ConsoleWrite('Error: _RDC_GetData() - ' & @error & ', ' & @extended & ', ' & _RDC_GetDirectory($lParam) & @CR)
        MsgBox(16, 'Error !!!', 'Error: _RDC_GetData() - ' & @error & ' ' & @extended & ' ' & _RDC_GetDirectory($lParam) & @CR)
        _RDC_Delete($lParam)
        Return 0
    EndIf
    For $i = 1 To $aData[0][0]
        $iGResult = $aData[$i][0]
        $de = 1
    Next

    ;ConsoleWrite($iGResult)
    Return 0

EndFunc   ;==>WM_RDC

While 1

    If $de = 1 Then
        Switch $iGResult
            Case $iGResult = 1 ; crea file
                MsgBox(0, '1', 'crea file')
                $de = 0
            Case $iGResult = 2 ; cancella file
                MsgBox(0, '2', 'cancella file')
                $de = 0
            Case $iGResult = 3 ; modifica file
                MsgBox(0, '3', 'modifica file')
                $de = 0
            Case $iGResult = 4 ; nome vecchio
                MsgBox(0, '4', 'nome vecchio')
                $de = 0
            Case $iGResult = 5 ; nome nuovo
                MsgBox(0, '5', 'nome nuovo')
                $de = 0
        EndSwitch
    EndIf


WEnd

but  how is  possible modify ???

 

Share this post


Link to post
Share on other sites
Mbee

@faustf, I haven't tried to analyze your code very much, but why the infinite loop?  In any case, there's a chance that your WM_RDC() handler is simply being invoked (via re-entrance) by the system more than once, so that the $iGResult variable is being reset each time.  As I noted at the end of my post on the first page ( here), you MUST expect to get each notification at least twice.

I would set a counter at the top of your WM_RDC() handler to record how many times it is being invoked.

 

Share this post


Link to post
Share on other sites
Mbee

@faustf, the %100 CPU usage might be due to your infinite loop, but the problem may lie elsewhere.  When I run the code you've posted on the previous page where you saw extreme CPU usage, I see at most %35 CPU usage...

Also, in your WM_RDC handler, you combine the data from multiple changes in a single variable! Huh??  And you set $de to 1 every pass through the loop, which also doesn't make sense.

Why don't you tell us exactly what you're trying to do/test in your code, please?

 

Edited by Mbee

Share this post


Link to post
Share on other sites
faustf

infinity loop because  , after intercept the  action inside the folder  by function Func WM_RDC , i must  show what i did do

 

Share this post


Link to post
Share on other sites
faustf

whit  the last script???  you see 35% ???

after start  yes ,  but if  you  try  to modify somthing inside the folder  start to up 100%

Edited by faustf

Share this post


Link to post
Share on other sites
Mbee

I made an edit you didn't see yet, so I'll repeat: Why don't you tell us precisely what you're trying to do or test?  I'll be happy to try to code an example up for you...

 

Share this post


Link to post
Share on other sites
Mbee

Also, please post a suitably simple copy of "presync_conf.ini"...

Share this post


Link to post
Share on other sites
faustf

[Path_to_sync]
key1=\WEB-SITE\eBay\PUBLICAZIONI\FOTO\

 

Share this post


Link to post
Share on other sites
faustf

i work  in  a virtualbox with windows 7 32bit   with 80 gb hdd  and 2.50 gb ram

Share this post


Link to post
Share on other sites
Mbee

@faustf, as promised, I've coded up an example test of the RDC functions as per what I understood about your needs.

You can download the attached source file and try it yourself, but I'll also post the code here.  Your attempts included a few serious mistakes, but the following works fine on my machine...

#include <APIConstants.au3>
#include <GDIPlus.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIFiles.au3>

#include "RDC.au3"

Opt('MustDeclareVars', 1)
Opt('GUICloseOnESC', 1)
Opt('GUIOnEventMode', 1)    ; Enable Event Mode
Opt('TrayAutoPause', 0)

Global $GiRDCid, $GhWnd, $GbActionsOccurred, $GsPath_Monitor, $GsEventDesc[50], $GiEventDescIndex = 0, $GiTotalRDCmsgCount = 0
Global Const $CsAppTitle = "RDC Test Script"

Local $iStat, $sPart1, $sPart2, $sOutMsg

$GbActionsOccurred = False

$sPart1 = StringReplace(@ScriptDir, "\INCLUDE", "")
$sPart2 = IniRead(@ScriptDir & "\presync_conf.ini", "Path_to_sync", "key1", "Error")
If $sPart2 = "Error" Then
    MsgBox($MB_ICONERROR, $CsAppTitle, "File 'presync_conf.ini' contains invalid data - Exiting")
    Exit
EndIf

$GsPath_Monitor = $sPart1 & $sPart2
If Not FileExists($GsPath_Monitor) Then
    MsgBox($MB_ICONERROR, $CsAppTitle, "Folder to be monitored does NOT exist! - Exiting")
    Exit
EndIf

_RDC_OpenDll()
If @error <> 0 Then
    MsgBox($MB_ICONERROR, $CsAppTitle, 'Error: _RDC_OpenDll() - ' & @error & ' - Exiting' & @CR)
    Exit
EndIf

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

$GhWnd = GUICreate($CsAppTitle)
If $GhWnd = 0 Then
    MsgBox($MB_ICONERROR, $CsAppTitle, 'Error: GUICreate() Failed! - Exiting')
    Exit
EndIf


$iStat = GUIRegisterMsg($WM_RDC, 'WM_RDC')
If $iStat <> 1 Then
    MsgBox($MB_ICONERROR, $CsAppTitle, "Error: GUIRegisterMsg() failed - Exiting")
    Exit
EndIf

$GiRDCid = _RDC_Create($GsPath_Monitor, True, _
    BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, $FILE_NOTIFY_CHANGE_DIR_NAME, $FILE_NOTIFY_CHANGE_SIZE), False, $GhWnd, 47)
If $GiRDCid  = -1 Then
    MsgBox($MB_ICONERROR, $CsAppTitle, 'Error: _RDC_Create() - @error = ' & @error & '  @extended = ' & @extended & ' -- Exiting' & @CR)
    Exit
EndIf


While True

    If $GbActionsOccurred Then
        $iStat = GUIRegisterMsg($WM_RDC, "")    ; Unregister this event handler to avoid being interrupted until done
        If $iStat <> 1 Then
            MsgBox($MB_ICONERROR, $CsAppTitle, "Error from GUIRegisterMsg() call to disable WM_RDC failed - Exiting")
            Exit
        EndIf

        $sOutMsg = ""

        For $i = 0 To $GiEventDescIndex -1
            $sOutMsg &= "Event # " & $i & " : " & $GsEventDesc[$i] & @CRLF
        Next

        MsgBox($MB_OK, $CsAppTitle, "Total number of WM_RDC invocations thus far = " & $GiTotalRDCmsgCount & @CRLF & @CRLF _
            & "Number of Action Events this pass = " & $GiEventDescIndex & "  -- Here's the list..." & @CRLF & $sOutMsg)

        $GbActionsOccurred = False              ; Reset this flag so we won't be triggered until there are more events
        $iStat = GUIRegisterMsg($WM_RDC, "WM_RDC") ; Re-register this event handler
        If $iStat <> 1 Then
            MsgBox($MB_ICONERROR, $CsAppTitle, "Error from GUIRegisterMsg() call to re-enable WM_RDC failed - Exiting")
            Exit
        EndIf

    Else

        Sleep(500)

    EndIf

WEnd


Func WM_RDC($hWnd, $iMsg, $wParam, $lParam)

    #forceref $hWnd, $iMsg, $wParam, $lParam

    Local $sName, $iActionCount, $iEventType


    $GiTotalRDCmsgCount += 1

    Local $aData = _RDC_GetData($GiRDCid)
    If @error <> 0 Then
        $sName = _RDC_GetDirectory($GiRDCid)
        If @error <> 0 Then
            MsgBox($MB_ICONERROR, $CsAppTitle, 'Error: _RDC_GetDirectory() failed. @error = ' & @error & ' @extended = ' _
                    & @extended & ' -- Exiting' & @CR)
            Exit
        EndIf
        MsgBox($MB_ICONERROR, $CsAppTitle, 'Error: _RDC_GetData() - @error = ' & @error & ' @extended = ' & @extended _
            & @CR & " Directory = '" & $sName & @CR & "... Exiting")
        _RDC_Delete($GiRDCid)
        Exit
    EndIf

    $iActionCount = $aData[0][0]
    If $iActionCount < 1 Then Return 0

    $GiEventDescIndex = 0
    For $i = 1 To $iActionCount
        $iEventType = $aData[$i][0]
        $sName = $aData[$i][1]

        Switch $iEventType
            Case $FILE_ACTION_ADDED
                $GsEventDesc[$GiEventDescIndex] = "Item Added = " & $sName
            Case $FILE_ACTION_REMOVED
                $GsEventDesc[$GiEventDescIndex] = "Item Removed = " & $sName
            Case $FILE_ACTION_MODIFIED
                $GsEventDesc[$GiEventDescIndex] = "Item Modified = " & $sName
            Case $FILE_ACTION_RENAMED_OLD_NAME
                $GsEventDesc[$GiEventDescIndex] = "Old item named " & $sName & " will be renamed"
            Case $FILE_ACTION_RENAMED_NEW_NAME
                $GsEventDesc[$GiEventDescIndex] = "Item renamed to " & $sName
            Case Else
                $GsEventDesc[$GiEventDescIndex] = "INVALID ACTION!"
        EndSwitch

        $GiEventDescIndex += 1
        If $GiEventDescIndex >= 50 Then
            MsgBox($MB_ICONERROR, $CsAppTitle, 'Error in WM_RDC: Too many events! - Exiting')
            Exit
        EndIf

    Next

    $GbActionsOccurred = True
    Return 0

EndFunc   ;==>WM_RDC


Func _ExitApp()
    Exit
EndFunc

 

 

 

 

RDC Test Script.au3

Edited by Mbee
typo & minor code change

Share this post


Link to post
Share on other sites
Mbee

Here is an explanation of the code I posted above, along with some comments (not in any particular order, but just as they occur to me)...

Note that you need to actually build this code and then run the resulting executable. It is not intended for running within SciTE.  Also, your code must NOT have the line: #include <RDC.au3>.  Instead, you need to have my version 1.1 of RDC.au3 in your development directory, because that's the correct code.  That might well be why others such as @argumentum have not seen the effects of my changes!  Replace #include <RDC.au3> with #include "RDC.au3" !

As others have quite correctly pointed out, one critical thing is that it's essential that the WM_RDC() event handler do it's job and return as quickly as possible (while still performing the necessary stuff).  Thus, in the code above, there are no time-consuming calls in the event handler except for the MsgBox() calls that will only be invoked upon an error and then will exit immediately anyway.

What I've done is to structure the main code so that it will do the time-consuming work such as issuing MsgBox calls (I stripped out the ConsoleWrite stuff since it was redundant and I don't like doing things that way anyway).  And it will only do that when there's something to report, as indicated by the "$GbActionsOccurred" flag.

Also, I enabled "On Event" mode, since your trials never even polled events anyway.  The original author of the examples did a bare minimum job and thus his/her examples are not a good basis to build on in the first place.  They appear to have been intended merely to show what the RDC calls looked like, rather than do anything rational.

The main part of your example code blindly fell right into the WM_RDC event handler, which was a mistake that was probably due to the poor example code provided.

Also, the earlier code's usage of the "$lParam" argument in the WM_RDC handler is very puzzling indeed (unless there's something I don't understand about the UDF)! The value of the parameter to be passed to functions such as "_RDC_GetData()" is the "RDC ID" (aka Thread ID) that was returned by the _RDC_Create() call. The UDF's documentation makes no mention that the $lParam value will contain that ID, but that could be a misunderstanding on my part...  In the case of multiple _RDC_Create() calls, each with different directories to be monitored, there might well need to be a way of allowing the WM_RDC handler to know which "RDC ID" the event came from, although getting the directory name might suffice...  If @Yashied coded the DLLs such as to provide that ID via either $lParam or in one of the words of the $wParam, that would do it.  I simply don't know if the DLLs are coded to do that or not...

I can't think of anything to add at the moment, so if you have any questions about the code I posted above, let me know!

 

Edited by Mbee
Added additional info

Share this post


Link to post
Share on other sites
Mbee

Changing topics, does anyone know how I can obtain @Yashied's source code for the DLLs? I'd like to take a look at it...  Is he still around these days?

Share this post


Link to post
Share on other sites
Mbee

Regarding the $lParam argument passed to the WM_RDC message handler, I've now more carefully reviewed the example script "RDC_Ex_Advanced.au3" and have seen the way the author (presumably Yashied) clearly assumed that it contained the RDC/Thread ID of the relevant directory.  I sure wish that had been documented!

But I also know that this was not strictly necessary.  In my code above, notice that the call to _RDC_Create() passed the "arbitrary" value of 47 (as a significant number of Americans -- either Ponoma College graduates or those who knew one (I had a friend who matriculated there), or just those who watched any number of Star Trek spin-off series' episodes -- understand as "the most common number in the universe"), a working alternative to using the $lParam value would be to pass a unique value for each separate call to _RDC_Create().  For instance...

Global $GaRDCID[2]

$GaRDCID[0] = _RDC_Create("C:\FolderA", True, _
    BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, $FILE_NOTIFY_CHANGE_DIR_NAME, $FILE_NOTIFY_CHANGE_SIZE), False, $GhWnd, 1)
If $GaRDCID[0]  = -1 Then
    MsgBox($MB_ICONERROR, $CsAppTitle, 'Error: _RDC_Create() - @error = ' & @error & '  @extended = ' & @extended & ' -- Exiting' & @CR)
    Exit
EndIf

$GaRDCID[1] = _RDC_Create("C:\FolderB", True, _
    BitOR($FILE_NOTIFY_CHANGE_FILE_NAME, $FILE_NOTIFY_CHANGE_DIR_NAME, $FILE_NOTIFY_CHANGE_SIZE), False, $GhWnd, 2)
If $GaRDCID[1]  = -1 Then
    MsgBox($MB_ICONERROR, $CsAppTitle, 'Error: _RDC_Create() - @error = ' & @error & '  @extended = ' & @extended & ' -- Exiting' & @CR)
    Exit
EndIf


;~ . . . .

Func WM_RDC($hWnd, $iMsg, $wParam, $lParam)

    #forceref $hWnd, $iMsg, $wParam, $lParam

    Local $iLowWord, $iRDCid, $sName, $iActionCount, $iEventType


    $iLowWord = BitAND($wParam, 0xFFFF) ; The low-order word contains the value of the final parameter to _RDC_Create()
    $iRDCid = $GaRDCID[$iLowWord -1]

    Local $aData = _RDC_GetData($iRDCid)


;~ . . . .

EndFunc

 

Granted, using $lParam is easier.  This is just FYI..

 

Share this post


Link to post
Share on other sites
Mbee

There were problems in the script I posted above for faustf, so I have posted the revised script below. I have also posted a better general example script with additional commentary for an event-mode GUI both in Post # 3 and below.  Enjoy.

 

RDC Test Script for faustf.au3

 

General RDC v1.1 Test Script with GUI.au3

Edited by Mbee

Share this post


Link to post
Share on other sites
argumentum

..so I was happily using this UDF/DLL and with a Edit control for debug in my project  ...
meanwhile downloading stuff with chrome browser ...
hey !, where is the new file?, it shows the "Unconfirmed 581257.crdownload", but, where is the newly renamed file ???, well, it does not know.
So use [NOW WORKING] a (broken) monitor file changes script which uses ReadDirectoryChangeW  , it does show every event.

Edit: Then again, I made a test writing 10000 files at 2 file per millisecond to a RAM disk and the above linked did not catch all the events but this UDF/DLL did.
...what to do, what to do. No clue yet.

Edited by argumentum

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

×