Jump to content

How to define a common set of variables and functions for multiple scripts ?


Recommended Posts

Q. HOW TO DEFINE A COMMON SET OF VARIABLES AND FUNCTIONS FOR MULTIPLE SCRIPTS ?

I have been coding AutoIt for almost an year now. This is my first post in forum, i will be as specific as possible.

Here is my project and the issues I am facing (alongside with steps i have tried to resolve them but couldn't, due to reasons stated)

AIM OF MY PROJECT: To manage my daily tasks

  • Design : I have a Master Script (Controller.au3) which contains a GUI to determine which TASK to execute based on various factors.
  • Each TASK has a separate Script which is executed or terminated via the Controller.au3 GUI.
  • Picture 1.1 - ProjectOutline

ProjectOutline.thumb.png.1ca432fc59390d63ef17385553188d66.png

 

  • Under each TASK Script, there are basically 3 Regions
    • #Region SCRIPT REGION  : contains the TASK code
    • #Region COMMON INITIAL VARIABLES  : contains few variables that all of my TASK(s) will require. They are basically stored INI values which are master controlled by Controller.au3 GUI (code attached}
    •  
      #Region ;;COMMON INITIAL VARIABLES
       
      ;;;AUTOIT OPTIONS
          #NoTrayIcon
          Opt("PixelCoordMode"0;1=absolute, 0=relative, 2=client
       
      ;;;INI VARS
          Global $ScriptName = StringTrimRight(@ScriptName, 4)
       
          ;parent directories
          Global $Dir_Task=StringTrimRight(@ScriptDir,StringLen('\scripts\' & $ScriptName))
          Global $Dir_config = $Dir_Task & '\config'
       
          ;parent INIs
          Global $settingsINI=$Dir_config & '\settings.ini'
          Global $operational=$Dir_config & '\operational.ini'
       
          Global $Dir_Root = StringTrimRight($Dir_Task,StringLen(IniRead($settingsINI,'ActiveWindow','WindowTitle',0))
          Global $Dir_assets = $Dir_Root & '\assets'
          Global $Dir_DLL = $Dir_Root & '\DLLs'
          
      ;;; WINDOW VARIABLES
          Global $WinTitle=IniRead($settingsINI,'Emulator','WindowTitle','error')
          Global $WinHandle = WinGetHandle($WinTitle,'')
          If @error Then                                              ;WinHandle error handler
              ER('WinHandle does not exist',2)
              _EndProgram('WinHandle not found')
          Else
              Global $WinPos = WinGetPos($WinHandle)
          EndIf
       
          Global $Win_Static_X=IniRead($settingsINI,'Window','StaticX',640)
          Global $Win_Static_Y=IniRead($settingsINI,'Window','StaticX',369)
          WinMove($WinHandle,'',$WinPos[0],$WinPos[1],$Win_Static_X$Win_Static_Y)
       
      ;;; TIMER VARS
          Global $LastRuntime=IniRead($settingsINI,$ScriptName,'LastRuntime',0)
          Global $TimeGap=IniRead($settingsINI,$ScriptName,'TimeGap',0)
       
      ;;; MISC VARS
          Global $RequestCounter = IniRead($settingsINI,$ScriptName,'RequestCounter','0')
       
      ;;; ACCOUNT VARS
          Global $username = IniRead($settingsINI,'Account','Username',0)
       
      ;;; IMAGE-DEBUG VARS
          Global $xcoord = 0
          Global $ycoord = 0
          Global $ImageDebugMode = IniRead($settingsINI,$ScriptName'ImageDebugMode'0)
          Global $ImageDebugger
       
      ;;; LOGGING
          Global $LogPath = @ScriptDir & '\' & $ScriptName & '.log'
          FileDelete($LogPath)
          Global $MainErrorLog = $Dir_Bot & '\Logs\Errors.log'
       
          Global $ImageLog = IniRead($settingsINI,$ScriptName,'ImageLog',1)
          Global $ChatAnnounce = IniRead($settingsINI,$ScriptName,'ChatAnnounce',1)
       
      #EndRegion
       
    • #Region COMMON UDFs : Contains a lot of functions that are again going to be used by all of my TASK scripts during their execution. {example code attached of a very simple function}
    •  
          Func ER($msg,$code)
              $year = @YEAR
              $month = @MON
              $date = @MDAY
              $hour = @HOUR
              $minute = @MIN
              $minute = @SEC
       
              FileWrite($MainErrorLog,$year & '-' & $month  & '-' & $date & @TAB & $hour & '-' & $minute & '-' & $minute &  @TAB & 'Error (' & $code & ')' & @TAB & '{' & $ScriptName & '}' & @TAB & $msg & @CRLF)
              Switch $code
                  Case 1      ;MINOR ERROR - LOG WRITE
                      CR('!Error : ' & $msg)
                  Case 2      ;MAJOR ERROR - LOG WRITE + TOOLTIP
                      ToolTip($msg,$WinPos[0-20 + ($WinPos[2])/2 ,$WinPos[1-20 + ($WinPos[3])/2 ,$username & '-' & $ScriptName,2)
                      CR('!Error : ' & $msg)
                      Sleep(5000)
                      ToolTip('')
              EndSwitch
       
              ;;PRINT ERROR WINDOW
              PrintScreen('Logs\ImageLogs\Errors\' & $year & '-' & $month  & '-' & $date,$hour'-' & $minute & '-' & $minute & ' ' & $msg)
       
          EndFunc
    •  

 

  • So the workflow is Controller.au3 >> (starts a script and writes INI) >> Common Variables Loaded from INI >> Script Running

PROBLEM FACED: How to pass the common variables to each script ?

  • I want to declare those list of variables for each and every script that runs. Currently i am copy and pasting the entire region in all the scripts.
  • But the issue comes, when i have to make some changes to any variable in #Region COMMON INITIAL VARIABLES or any function in #Region COMMON UDF , then i have to copy and paste those regions in all the scripts (which can go upto 30+ scripts in future)
  • I need a better way to define those common variables and functions for all the scripts.

TRIED METHODS - FAILED

I have tried the following methods but failed to achieve anything more productive then copy pasting the regions.

  • Declaring those variables from the Controller.au3  : if i declare them from Controller.au3 then i have to pass them via ShellExecute or as parameters of a Function Call, which is quiet tedious in my case as Common Variable are more than 30+. {I have reduced 50% of the variables to avoid the bloat in the above example code}
  • Adding all the scripts to the Controller.au3 : Makes the GUI unresponsive because of many internal loops in each TASK which waits for user input or waits for process completion.
  • Tried using Loop interruptions : (as mentioned in Wiki) , works fine for a few scripts, but for 30-50+ TASKS, become cumbersome.
  • From Forums : Tried MailSlot, but the idea remains same, i have to checkmailslotmessage in every script again to define and use the variables there.

BACKUP

If everything fails, then i will make a script to read all the TASK scripts and identify a particular marker "Keywork" for starting of each region and then From Line A to Line B, delete everything and insert a new code. Repeat this in a loop for all the TASK scripts.

Then Batch-Complile them all.

But this is a very crude method. I am reserving it for the last attempt.

Link to comment
Share on other sites

Make only one big .exe

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

I don't know if I understand exactly the need, however it is worth taking a look at this interesting post by @LarsJ (https://www.autoitscript.com/forum/topic/202618-implementing-irunningobjecttable-interface) which can probably be useful for your purpose.
For example, you can declare a single array and use the individual elements of the array instead of many different variables. This array (and its content) can therefore be shared among all the different scripts that can read and/or modify its content independently. This way changes made by one script can be read by another script.

 

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

@devilspride, welcome to the AutoIt forum.

notice that when you #include some external file, that file which you create yourself (often known as UDF) does not have to include functions only - it can include whatever code you choose, be it variables or constants declarations, option statements, function calls, etc. so you can put all the region of the COMMON INITIAL VARIABLES into a dedicated file, and #include it in all your scripts.

or am i missing something?

Signature - my forum contributions:

Spoiler

UDF:

LFN - support for long file names (over 260 characters)

InputImpose - impose valid characters in an input control

TimeConvert - convert UTC to/from local time and/or reformat the string representation

AMF - accept multiple files from Windows Explorer context menu

DateDuration -  literal description of the difference between given dates

Apps:

Touch - set the "modified" timestamp of a file to current time

Show For Files - tray menu to show/hide files extensions, hidden & system files, and selection checkboxes

SPDiff - Single-Pane Text Diff

 

Link to comment
Share on other sites

14 hours ago, jchd said:

big .exe

XD will do that if no option left.

8 hours ago, Chimp said:

I don't know if I understand exactly the need, however it is worth taking a look at this interesting post by @LarsJ (https://www.autoitscript.com/forum/topic/202618-implementing-irunningobjecttable-interface) which can probably be useful for your purpose.
For example, you can declare a single array and use the individual elements of the array instead of many different variables. This array (and its content) can therefore be shared among all the different scripts that can read and/or modify its content independently. This way changes made by one script can be read by another script.

 

I will give this is a go. But there is high chance it will have the same issues, because i am calling some variables and then i have to again recall those variables in the child scripts, just the method is different.

What i want is a solution that i dont want to edit my child scripts again and again to add the common variables or functions.

Using ROT i am basically calling their handles rather than declaring them explicitly.

1 hour ago, orbs said:

@devilspride, welcome to the AutoIt forum.

notice that when you #include some external file, that file which you create yourself (often known as UDF) does not have to include functions only - it can include whatever code you choose, be it variables or constants declarations, option statements, function calls, etc. so you can put all the region of the COMMON INITIAL VARIABLES into a dedicated file, and #include it in all your scripts.

or am i missing something?

Exactly thats what i thought when i started the project. But it gives the error that the variables are undeclared. i will write and example and post it. Maybe i missed something there.

That would be the easiest thing if i can do that. Then i will just have to place one au3 file in the root directory and everything is fine.

Link to comment
Share on other sites

16 hours ago, devilspride said:

PROBLEM FACED: How to pass the common variables to each script ?

  • I want to declare those list of variables for each and every script that runs. Currently i am copy and pasting the entire region in all the scripts.
  • But the issue comes, when i have to make some changes to any variable in #Region COMMON INITIAL VARIABLES or any function in #Region COMMON UDF , then i have to copy and paste those regions in all the scripts (which can go upto 30+ scripts in future)
  • I need a better way to define those common variables and functions for all the scripts.

It sounds like you need data that can be accessed by any of your task-related scripts.  You also need to be able to easily make changes to that data and for those task-related scripts to be able to pick up those changes without a huge amount of maintenance to each script.  What you are describing sounds like a central repository for data/settings/configuration information, in other words a database. The database could be a flat file like an INI file, or a relational database like SQLite. So the scripts just query the database for the common information.  Am I missing something in your requirements? 🤔:huh2:  Of course I'm talking about the data not the functions.

 

Edit:

I see that your issue was with how to properly include .au3 files into your scripts.  I guess you can disregard my post.  :)  However, if you are compiling your scripts to executable files, using includes will require you to recompile if changes are made to them.

Edited by TheXman
Link to comment
Share on other sites

Thanks to @orbs

I made a test script to include all my COMMON VARIABLES and COMMON FUNCTIONS in the root and it worked with my TEST scripts.

But i get it now why i was having problems.

Maybe i am wrong but i think it was due to a extra "." in the help file that was throwing errors.

This works :

#include "..\includes\common.au3"

But this doesn't :

#include "...\includes\common.au3"

 

The helpfile tells us to use the latter one. Maybe i missed something in how to use the helpfile for #include

P.S. : it was actually my typo that i used ".." instead of "..." 😆😆

Link to comment
Share on other sites

3 minutes ago, TheXman said:

It sounds like you need data that can be accessed by any of your task-related scripts.  You also need to be able to easily make changes to that data and for those task-related scripts to be able to pick up those changes without a huge amount of maintenance to each script.  What you are describing sounds like a central repository for data/settings/configuration information, in other words a database. The database could be a flat file like an INI file, or a relational database like SQLite. So the scripts just query the database for the common information.  Am I missing something in your requirements? 🤔:huh2:

Yes @TheXman

absolutely correct. For the most parts i was using the INIs as my central repository.

The only issue was the polling and requesting data from each task script required the variables and functions to be declared inside them. which i was trying to reduce by a better way.

Finally got the answer.

Thank you everyone for a quick solution to my issue.

*P.S. Is the helpfile information on relative paths for #include correct ?

Because i was using that format in my previous attempts to solve my issues, but got errors of "path not found" and "variables not declared" if i used the AutoIt helpfile format.

Luckily / unluckily i was sleepy and just used two ".." instead of three "..." and it worked like charm.

Link to comment
Share on other sites

6 minutes ago, devilspride said:

*P.S. Is the helpfile information on relative paths for #include correct ?

Yes

Link to comment
Share on other sites

Haven't searched the forums for it but during my testing found an interesting thing. Maybe helpful for others who are using Relative paths for #includes

 

Example 1 - common file is in same folder

Script Path : W:\AutoIt\Testing\main\main.au3

Include Path W:\AutoIt\Testing\main\common.au3

To include common.au3 in main.au3 use the following code

#include "common.au3"

Example 2 - common file is in Sub-Folder

Script Path : W:\AutoIt\Testing\main\main.au3

Include Path W:\AutoIt\Testing\main\includes\common.au3

#include ".\includes\common.au3"

Here "." represents one level up of directory

. = Path to "main" directory 

Example 3 - common file is in parent folder

Script Path : W:\AutoIt\Testing\main\main.au3

Include Path W:\AutoIt\Testing\includes\common.au3

#include "..\includes\common.au3"

".." represents two level up i.e. Path to "Testing" directory

 

** Unfortunately "..." does not work if i want to place an #include file in directory 3 levels up i.e. in "AutoIt" folder.

 

This is just for reference for others if they stumble upon the same topic. I do not mean to start another discussion / thread.

I have already got the answer. Thank you all for the support and other ideas.

Link to comment
Share on other sites

2 levels up would be "..\..\includes\common.au3", 3 levels "..\..\..\Includes\common.au3" and so on.

In DOS/CMD, there is no such syntax as "...\"

.\ = current directory

..\ = parent directory

so ..\..\ = parent of parent directory

 

"..." as it relates to the help file for the INCLUDE directive, is an ellipsis meaning "whatever is necessary to complete this part" goes here.  :doh:😄

Edited by TheXman
Link to comment
Share on other sites

4 hours ago, TheXman said:

2 levels up would be "..\..\includes\common.au3", 3 levels "..\..\..\Includes\common.au3" and so on.

In DOS/CMD, there is no such syntax as "...\"

.\ = current directory

..\ = parent directory

so ..\..\ = parent of parent directory

 

"..." as it relates to the help file for the INCLUDE directive, is an ellipsis meaning "whatever is necessary to complete this part" goes here.  :doh:😄

Thank you for the reply :)

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...