Sign in to follow this  
Followers 0
MaximusNeo701

Nested looping bug

12 posts in this topic

Been using autoit here for for about 6 months. I am a software dev, and it is very useful to help automate tasks for work so I can spend my time accomplishing other goals but I believe I have come across a pretty serious bug in the way Autoit executes scripts.

This in my experience has applied to while and for loops but I believe it extends to any loops inside of loops. The easiest example of this bug I can explain is on for loops

For $i = 1 To 8

Local $oInputs = _IETagNameGetCollection($oIE, "input")

For $oInput In $oInputs

if $oInput.value = "SOMEVALUE" Then

$ButtonObject = $oInput

EndIf

Next

MyFunction( $oInput)

Next

this is actual code I have been working on but I changed a few names of things to make it very generic. So we would expect the initial For loop to execute 8 times now, and inside each of those 8 runs to find the object on the webpage I am looking for. But the issue is that my loop only runs 4 times? So I jumped it up 1 to 16 on my bounds on the outermost For loop and it runs 8 times. Great so it works right? Well it seems to me that at some point when the token "Next" is encountered that it must also for some reason be increasing my outermost For loop counter when it should not. But I know for a fact that isn't really the case since it would have to step through the innermost loop about 30 times (lots of elements on the IE page,) so it only seems to be increasing the outermost For loop counter upon exiting the the innermost loop. Sounds like something with the looping stack isn't working correctly.

Here is the example of the while loops that didn't work correctly, now I will say this isn't copied and pasted from my code as I undid the work since it didn't work and I had a theory loops had an issue but wasn't able to observe it correctly until now. The code will be very very psuedo code to make reading easier

setupProgramData()

while(1)

sleepUntilProgramStartTime($startTime) <-- this was initially a while loop also but would stay inside the loop until I made it a method

dostuff()

$rs = getSomeSQLRecords()

While $rs.EOF = False

doStuffWithSQLData($rs)

WEnd

cleanup()

WEnd

Now what happened here if I remember correctly, whenever the WEnd was encountered leaving the innermost While Loop the software would break. I cannot recall exactly what happened, but with msgbox outputs and spitting out values I could see then things went south. It ran perfectly before I tried to implement this idea of never stop running and just begin again when it was the proper time by using the outermost while loop. I did test just getting a message box at the right time and it also did work; so I know by itself the outermost loop did also work. Just when nesting loops Autoit becomes not very happy.

This issue doesn't seem to arise when I have a loop inside of a function/method and call said function/method inside of that loop. It just seems to be an issue when loops are nested within the same function/method. If anyone has any input or feedback for me I would greatly appreciate it, or to at least know if this is a known issue.

Share this post


Link to post
Share on other sites

#2 ·  Posted (edited)

This issue doesn't seem to arise when I have a loop inside of a function/method and call said function/method inside of that loop.

Here may be a clue. I suspect that you may be altering the iteratioon count $i in the function called within the loop. If you put your nested For loops inside another function, chances are it will be fixed. If $i is a global variable, it can potentially be altered by any function called on within your loop.

Edited by czardas

Share this post


Link to post
Share on other sites

I have checked on this, $i is a local variable. Also in the example above $i is used on the outermost loop and $oInput In $oInputs on the innermost loop; so that should not be an issue, that section was copy and pasted and I just changed a variable name to SOMEVALUE. A quick ctrl+f on the software to be sure there were no more uses of the variable $i, but I do appreciate the feedback.

Also that still leaves the while loop issue unresolved; as I am getting ready for a major updated with new functionality I would like to be able to go into it without fearing this problem again.

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

All the variables in the code you posted are global variables. They are not assigned locally within a function, but rather local to the global scope (outside of any function). If this is not the case in your original script, then there is most likely a bug you created somewhere else in your code.

Local $i
Local $iLoopCount = 0
For $i = 0 To 9
    $iLoopCount += 1
    _Interference() ; This introduces a bug.
Next
MsgBox(0, "Loop Count", $iLoopCount)

Func _Interference()
    $i = 10
EndFunc

If you really think you have found a bug in AutoIt, post code that demonstrates this. The code you posted does not demonstrate what you claim to be a bug.

Edited by czardas

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

_Interference() ; This introduces a bug.

By default when variables are declared using Dim or assigned in a function they have Local scope unless there is a global variable of the same name (in which case the global variable is reused). This can be altered by using the Local and Global keywords to declare variables and force the scope you want.

Local $i
Local $iLoopCount = 0
For $i = 0 To 9
$iLoopCount += 1
_Interference()
Next
MsgBox(0, "Loop Count", $iLoopCount)
Func _Interference()
Local $i = 10
EndFunc

I'm guessing 'global' is relative...the local for the scrip is a higher level than the variable set in the function (which is why it overrides the 'global' (actually local $i, line 1)), unless specifically defined as local (in the function), like above...i've always found it much easier to append a small string after variables, to ensure I don't over-ride my variables...like $i_FuncName

Edited by jdelaney

IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

I understand how that works. I'm not so sure that the OP knows this though. Dim is meant to be depreciated. There must be some reason why the OP's code is not working as expected. We would have to see more of the code to figure that out.

Edited by czardas

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Yep, it all depends on what he is doing in MyFunction( $oInput)

Which, it shouldn't be 100% doing what he wants either...the sudo code should look like this:

For $i = 1 To 8
 Local $oInputs = _IETagNameGetCollection($oIE, "input")
 For $oInput In $oInputs
  If $oInput.value = "SOMEVALUE" Then
   $ButtonObject = $oInput
   ExitLoop
  EndIf
 Next
 MyFunction($ButtonObject)
Next

or this

For $i = 1 To 8
 Local $oInputs = _IETagNameGetCollection($oIE, "input")
 For $oInput In $oInputs
  If $oInput.value = "SOMEVALUE" Then
   MyFunction($oInput)
   ExitLoop
  EndIf
 Next
Next
Edited by jdelaney
1 person likes this

IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Thanks for the feedback, I do not use dim as I am aware of the issue of local vs global variables and reusing a global could cause an issue.

MyFunction was just stubbed in; and still an empty method when I posted it. The entire method I am having this issue with is now posted.

if Not($imagedir = "none") Then
  local $FileList = _FileListToArray($imagedir)
  if @error = 0 Then
    local $FileList = _ArrayShuffle($FileList,1,$FileList[0])

    For $i = 1 To 16
      Local $oInputs = _IETagNameGetCollection($oIE, "input")
      For $oInput In $oInputs
        if $oInput.value = "add image" Then
          local $uploadButtonObject = $oInput
        EndIf
      Next
      _IEAction ($uploadButtonObject, "click")
      ControlClick("[CLASS:IEFrame]", "", "[CLASS:Internet Explorer_Server; INSTANCE:1]", "Left", 1, 350, 270)

      Sleep($SLEEPTIMER)
      ControlSetText("Choose File to Upload","", "[CLASS:Edit; INSTANCE:1]", $imagedir & $FileList[$i])
      sleep(1000)
      ControlClick("Choose File to Upload", "","[CLASS:Button; INSTANCE:1]")
      sleep($SLEEPTIMER + 10000)
    Next
  EndIf
EndIf

$i used in the FileList[] is so that I can access the filename stored in that array, and I would like it to loop 8 times. This is the entire method after some refactoring. I ran a test by removing the inner most loop and the issue went away. I appreciate the feedback, the reason MyFunction()'s code was not posted was because it was just stubbed, I don't make a habit of asking for help without providing all the pertinent info though. I also tested just calling this Method alone and I am still seeing the same issue with no other code being executed.

Also I meant no offense to anyone who helps work on Autoit, I most likely should have put a ? on the end as I haven't been able to solve this solution.

Edited by MaximusNeo701

Share this post


Link to post
Share on other sites

MaximusNeo701,

I don't see anything in your code that shows the number of iterations for any for...to loops. How do you know how many time they are iterating?

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

For $i = 1 To 16

6th line the first loop, it may not have shown up well I was editing to fix the indentations which did not copy over

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

No, that means nothing...$i can be altered.

I suggest a consolewrite in every supect loop to verify this.

kylomas

edit: additional info

Run this

for $i = 1 to 5
 ConsoleWrite($i & @LF)
 for $j = 1 to 5
  ConsoleWrite(@tab & $j & @LF)
 Next
next

Your problem lies elsewhere.

Edited by kylomas

Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

No, that means nothing...$i can be altered.

I suggest a consolewrite in every supect loop to verify this.

kylomas

edit: additional info

Run this

for $i = 1 to 5
ConsoleWrite($i & @LF)
for $j = 1 to 5
ConsoleWrite(@tab & $j & @LF)
Next
next

Your problem lies elsewhere.

Was actually already contemplating doing this since I started the thread but haven't had time. Though from that code I do not see $i being edited so still stumped.

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  
Followers 0