ViciousXUSMC Posted September 21, 2015 Share Posted September 21, 2015 (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 #22.) 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") EndFuncThe actual code was a bit different, I had to strip the colon out of the time and such. Edited September 21, 2015 by ViciousXUSMC Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted September 21, 2015 Moderators Share Posted September 21, 2015 ViciousXUSMC,Bad practice to use Global Variables in a functionIt 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 Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
ViciousXUSMC Posted September 21, 2015 Author Share Posted September 21, 2015 (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 September 21, 2015 by ViciousXUSMC Link to comment Share on other sites More sharing options...
TheDcoder Posted September 21, 2015 Share Posted September 21, 2015 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 #2Why not to this: ?Global $vStartTime, $vEndTime Func YourFunction() ; Code... $vStartTime = ; <value> $vEndTime = ; <value> EndFunc EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time) DcodingTheWeb Forum - Follow for updates and Join for discussion Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted September 21, 2015 Moderators Share Posted September 21, 2015 want to update them with a new value, so I assume that is still considered declaring themNo, 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?expandcollapse popup#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 EndFuncM23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
ViciousXUSMC Posted September 21, 2015 Author Share Posted September 21, 2015 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. Link to comment Share on other sites More sharing options...
JohnOne Posted September 21, 2015 Share Posted September 21, 2015 it started to give me some crazy results.Can you expand on this. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
ViciousXUSMC Posted September 21, 2015 Author Share Posted September 21, 2015 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. Link to comment Share on other sites More sharing options...
BrewManNH Posted September 21, 2015 Share Posted September 21, 2015 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 GudeHow 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 Link to comment Share on other sites More sharing options...
JohnOne Posted September 21, 2015 Share Posted September 21, 2015 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 ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
JohnOne Posted September 21, 2015 Share Posted September 21, 2015 (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 September 21, 2015 by JohnOne ViciousXUSMC 1 AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
ViciousXUSMC Posted September 21, 2015 Author Share Posted September 21, 2015 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. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now