ViciousXUSMC

Function with ByRef Variables using AdlibRegister

12 posts in this topic

#1 ·  Posted (edited)

I was working on a good way to run a script after x amount of time without needing to run it as a scheduled task so that it can be run from any computer.  I have used AdlibRegister() before with good success for small periods of time but never larges ones (like an hour).  So I tried it out and it looks like it actually works very well.

One thing that sort of annoyed me though was walking up to the computer and not knowing when it was going to run next, so I tried to plug in a little time check function and it appeared to work on my little test but in production it started to give me some crazy results.

Breaking it down, I figured most of the issue had to do with two things.

1.) Bad practice to use Global Variables in a function.  I never understood why, so I try not to do it.  In this example I would need MyFunc() to update $vEndTime and $vStartTime globally so I believe the right way to do this would be to pass the variables to the function ByRef.  But that leads to problem #2

2.) You can not pass any variables to a function called with AdlibRegister()

So that leads me to create this topic so that I can learn some new best practices.

Why exactly is using Global in the function a bad idea on a simple script like this?  How can I pass these to/from the function using AdlibRegister() and if it can't really be done, what is the best way to do this?  

For now I have my script working without the "check time" feature and I could update/return multiple values from the function with Global scope but I create this thread in hopes to learn more of why/how things can and should not be done.  Also maybe a good tip on how to run a function on a repeat basis with accurate time without AdlibRegister() 

Regards,

Edit: Just realized I did not post the example code.

;Just a concept this is not my actual script where things were a bit different
#Include <Date.au3>
Global $iWaitTime = 60000*60
Global $vStartTime = _NowTime(4)

HotKeySet("^!t", "CheckTime")
AdlibRegister("MyFunc", $iWaitTime)

MyFunc()

While 1
    Sleep(10)
WEnd

Func MyFunc()
    $vEndTime = $vStartTime
    $vStartTime = _NowTime(4)
    ;do stuff
    ;do stuff
EndFunc

Func CheckTime()
    MsgBox(0, "", "Current Cycle is set for " & $iWaitTime/60000 & " Minutes" & @CRLF & @CRLF & _
    "There is " &  ($iWaitTime/60000)-(_NowTime(4)-$vStartTime) & " Minutes Left Until Next Cycle")
EndFunc

The actual code was a bit different, I had to strip the colon out of the time and such.

Edited by ViciousXUSMC

Share this post


Link to post
Share on other sites



ViciousXUSMC,

Bad practice to use Global Variables in a function

It is bad practice to declare them inside functions, but there should be no problem in using them. Perhaps posting some code might be a good idea - otherwise it is a bit difficult to suggest why updating Global variables from within a function does not seem to work as it should.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Yeah, well I declare them first outside of the function, but basically want to update them with a new value, so I assume that is still considered declaring them.  I read our help files and it says the right way to do this is to pass the variable to the function ByRef, so that the function not only see's the varible but can update it.  But again if I am using adliberegister() to start my function I cant use that feature.

As for the script I wrote it over the weekend while practicing code, so I will not have access to it until I get home, that is why I put together a close resemblance example out of memory above.  When I get home later I can post the code but I already stripped out most of the time check stuff since it was not working correctly for me.

In testing it worked, on my actual script it was like the $vStartTime was not gettng updated or something, as after a loop or two passed the time left until next run started going negative.

Edited by ViciousXUSMC

Share this post


Link to post
Share on other sites

1.) Bad practice to use Global Variables in a function.  I never understood why, so I try not to do it.  In this example I would need MyFunc() to update $vEndTime and $vStartTime globally so I believe the right way to do this would be to pass the variables to the function ByRef.  But that leads to problem #2

Why not to this: :huh:?

Global $vStartTime, $vEndTime

Func YourFunction()
    ; Code...
    $vStartTime = ; <value>
    $vEndTime = ; <value>
EndFunc

Spoiler

My contributions to the AutoIt Community

Some messages & Apologizes:

If I hurt you, Please accept my apologies, I never (regardless of the situation) mean to hurt anybody!!!

Also, I am very busy with my project so I will appear in the last row of the online list, if you want to contact me: Email@TheDcoder.xyz

Or you can have a nice chat with me in freenode, I use the same nick on freenode too!

3fHNZJ.gif

PLEASE JOIN ##AutoIt AND HELP THE IRC AUTOIT COMMUNITY!

Share this post


Link to post
Share on other sites

 

want to update them with a new value, so I assume that is still considered declaring them

No, that is assignation, not declaration.

Passing a variable ByRef is not necessary for the function to "see and update", if it is Global in scope any function can see and change it - one of the reasons you should limit the number of such variables to prevent inadvertent changes. Passing ByRef is normally used to prevent the function making a copy of the variable passed as a parameter and so saving memory - it will act directly on the original variable. Does this make it clearer?

#include <MsgBoxConstants.au3>

Global $vVar = 10
MsgBox($MB_SYSTEMMODAL, "Value", $vVar)

_Func_1($vVar)
MsgBox($MB_SYSTEMMODAL, "Value", $vVar)

$vVar = _Func_2($vVar)
MsgBox($MB_SYSTEMMODAL, "Value", $vVar)

_Func_3($vVar)
MsgBox($MB_SYSTEMMODAL, "Value", $vVar)

_Func_4($vVar)
MsgBox($MB_SYSTEMMODAL, "Value", $vVar)


Func _Func_1($vVar)

    ; The function uses a Local variable $vVar to work on
    $vVar = 20
    ; Which is destroyed when the function ends

EndFunc



Func _Func_2($vVar)

    ; The function still uses a Local variable $vVar to work on
    $vVar = 20
    ; Which is now returned
    Return $vVar



EndFunc



Func _Func_3(ByRef $vVar)

    ; The function now uses the Global variable $vVar directly
    $vVar = 30

EndFunc



Func _Func_4($vVar2)

    ; The function again uses a Local variable to work on, but with a differnt name
    $vVar2 = 40
    ; Now reassign the Global variable
    $vVar = $vVar2

EndFunc

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

Share this post


Link to post
Share on other sites

Yes, clear now.  

Its a performance best practice so that you only keep the original variable in memory, but you can updated the varible with a new value if it is in the global scope, however it adds shadow copy of it rather than updating the original variable in memory.

Also I see I did not post the code in the first post for some reason so I just edited that. 

So it seems I just must have had something wrong with my code, as my test example worked and you guys said what I was trying to do is ok from a coding standpoint. 

Share this post


Link to post
Share on other sites

Yeah, sure.

If I just ran the script, the function runs once and then AdlibRegister() took over.

Run the TimeCheck function and all looked normal.  It would tell me the last time the function ran, and then subtract that time from _NowTime() to get the number of minutes that have passed since it ran.

Then that value would get subtracted from the time designated for the full wait period.  Thus the result would be minutes left until it runs again.

In my test just using a msgbox and some smaller time frames it worked perfectly.  On the actual production script that only ran about once an hour.  The first loop (before Adlibregister) seemed to return the proper time.

After the function ran a few times automatically I would start getting results like:

"Script last run at 17:00, current wait set for 60 minutes.  Current time is 17:35 -3 minutes remaining."

Not real numbers but I would have 20+ minutes left until it would run again yet I was getting negative time remaining until it would run again.  I am not sure if its just a loss of sync due to things not timing out properly (I always have this issue when I try to use TimerInit() TimerDiff()) or something in my code was not updating properly so I was getting bad results.

Share this post


Link to post
Share on other sites

Instead of Global, as long as the variable is used only in the function called by the AdLib, you could use Static declaration of the variable inside the function. That won't work if you are using the variable in more than one function though.


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

What about something like this, set for thirty seconds for brevity...

;Just a concept this is not my actual script where things were a bit different
#Include <Date.au3>
Global $Seconds = 30
Global $iWaitTime = 1000 * $Seconds ; 1 minutet
Global $vStartTime = _NowCalc()

HotKeySet("^!t", "CheckTime")
AdlibRegister("MyFunc", $iWaitTime)

MyFunc()

While 1
    Sleep(10)
WEnd

Func MyFunc()
    $vEndTime = $vStartTime
    $vStartTime = _NowCalc()
    ConsoleWrite("MyFunc Adlib" & @LF)
EndFunc

Func CheckTime()
    ConsoleWrite(@LF & "Current Cycle is set for " & $iWaitTime/1000 & " Seconds" & @LF & _
    "There is " &  ($Seconds - _DateDiff("s", $vStartTime, _NowCalc())) & " Seconds Left Until Next Cycle" & @LF)
EndFunc

 


AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Genericized.

#include <Date.au3>

Global $aSeconds[3] = [" Seconds ", 1000, "s"]
Global $aMinutes[3] = [" Minutes ", 1000 * 60, "n"]
Global $aHours[3] = [" Hours ", (1000 * 60) * 60, "h"]

Global $aUnits = $aMinutes ; This can be $aSeconds, $aMinutes or $aHours
Global $iUnits = 3

HotKeySet("^!t", "CheckTime")

Global $iWaitTime = $iUnits * $aUnits[1]
Global $vStartTime = _NowCalc()

AdlibRegister("MyFunc", $iWaitTime)

While 1
    Sleep(10)
WEnd

Func MyFunc()
    $vStartTime = _NowCalc()
    ConsoleWrite("MyFunc Adlib: " & $vStartTime & @LF)
EndFunc   ;==>MyFunc

Func CheckTime()
    ConsoleWrite(@LF & "Current Cycle is set for " & $iWaitTime / $aUnits[1] & $aUnits[0] & @LF & _
            "There is " & ($iUnits - _DateDiff($aUnits[2], $vStartTime, _NowCalc())) & $aUnits[0] & "Left Until Next Cycle" & @LF)
EndFunc   ;==>CheckTime

 

Edited by JohnOne
1 person likes this

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites

Thanks for the time John that looks like a good approach and has a few extra nuggets of knowledge in there that I can learn from. 

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

  • Similar Content

    • FMS
      By FMS
      Hello,

      I've an error and don't know why and hope somebody can help me..
      I think maybe i din't include somethin for the "ByRef" function, but i could be wrong :S
      Anyway here is what i included ...
      #include <ButtonConstants.au3> #include <ComboConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <File.au3> ; for _FileCreate ed. #Include <GuiComboBoxEx.au3> ; for _GUICtrlComboBoxEx_ResetContent #include "EzMySql.au3" #include <Array.au3> This is what i do before the error starts ... (everything else is running properly)
      $query = "SELECT * FROM `users` ;" $hostname = Read_from_ini("app","server","ip","no_server_ip") $dbname = "blokkerreferencedata" $usrname = Read_from_ini("app","server","username","no_server_usr") $Pass = Read_from_ini("app","server","pass","no_server_pass") $SQLport = Read_from_ini("app","server","sql_port","no_server_port") $iresult_rows = "" $iresult_colums = "" $iresult = get_result($query,$hostname,$dbname,$usrname,$Pass,$SQLport,ByRef $iresult_rows,ByRef $iresult_colums) _ArrayDisplay($iresult,"result") Here is the error i get...
      ==> Error in expression.: $iresult = get_result($query,$hostname,$dbname,$usrname,$Pass,$SQLport,ByRef $iresult_rows,ByRef $iresult_colums) $iresult = get_result($query,$hostname,$dbname,$usrname,$Pass,$SQLport,^ ERROR does somebody see what i do wrong here???
      thanks in advanced.

      ps. if it isn't a forgotten "include" --> how does somebody know whish include to use???
       
    • ur
      By ur
      I have function which needs 3 parameters and the last one is passed ByReference.
       
      ReadFunction($strFunctionName,ByRef $countArgts)
       
      But can I make the reference parameter as optional.i.e., $countArgts as optional or to keep a default value as below.
       
      ReadFunction($strFunctionName,ByRef $countArgts=1560)
      This is giving a compilation error, or any method overloading approach like in Programming languages Java,etc.
       
    • rudi
      By rudi
      Hi.

      Reading the help file I noticed the directive "#forceref" in sereral sample codes, e.g. for "ByRef" in this line:


      #forceref $v1, $v2, $v3, $v4, $v5, $v6, $v7, $v8, $v9, $v10, $v11, $v12, $v13, $v14, $v15, $v16, $v17, $v18, $v19
      What is it's effect? searching the help file, I can find it "outside" of sample code just for this entry:

      Au3check syntax tool

      #forceref $varname [, ...] can be used for inside functions, like the following: Func Test_Numparams($v1 = 0, $v2 = 0, $v3 = 0, $v4 = 0, $v5 = 0, $v6 = 0, $v7 = 0, $v8 = 0, $v9 = 0) #forceref $v1, $v2, $v3, $v4, $v5, $v6, $v7, $v8, $v9

      Same question for #forcedef

      From this postings here I don't get the exact effect either:
      (#forceref)


      (#forcedef)

      Regards, Rudi.
      Regards, Rudi.