Adaptable functions

Get help with using AutoHotkey and its commands and hotkeys
AviationGuy
Posts: 185
Joined: 17 Jan 2019, 10:13

Adaptable functions

22 Mar 2019, 04:09

Hi there,

Currently, I'm working on a project to make functions easy adaptable. The idea is that multiple scripts use the same functions but different versions of these functions. The reason for is explained below.

*Problem statement*
Company A & B are using the same function. When for example company A updates Chrome, they still want to use the same function as company B but with the new Chrome version. However, in the updated Chrome the search button moved to another position on the page so the function needs to be updated. Because of this, I want to be able to select a version of the same function both companies are using.

All the functions are stored in their own file with the name of the function as the file name (did this with the help of AHK Studio).
My idea was to put the version of the function each script needs to use at the top of the script. Then the script uses the function version based on that selected version. I posted an example below.
(For clarity I've put the function below the function call)

Code: Select all

; ISF version
version:="v2"															; select function version that script needs to use here
; ISF call
ImageSearchFun(version,,,,,"S:\...\Image.png")									; call the function
; IFS function
ImageSearchFun(version, x1:=0, y1:=0, x2:=0, y2:=0, ImageFile:="S:\...\Image.png"){		; function
	if (version="v1"){													; if version=v1 do this
		ImageSearch, FoundX, FoundY, x1, y1, x2, y2, %ImageFile%
		if (ErrorLevel = 2) {
			Msgbox ok
		}
		else if (ErrorLevel = 1) {
			Sleep 10
			Return 0
		}
		else {
			Sleep 10
			Return 1
		}
	}
	if (version="v2"){													; if version=v2 do this
		ImageSearch, FoundX, FoundY, x1, y1, x2, y2, %ImageFile%
		if (ErrorLevel = 2) {
			Msgbox ok
		}
		else if (ErrorLevel = 1) {
			Sleep 10
			Return 0
		}
		else {
			Sleep 10
			Return 1
		}
	}
}
It does the trick but I tested it on small scripts. I'm wondering if all these if-commands will slow the script down. The scripts that I want to use this method on have about 20 functions and each function is called about 5 times, so that are a lot of 'ifs'...
I want to know if this is the best way of doing it. I also thought about saving the different function scripts at GitHub and call them from there but I don't know to what extent that is possible.

Would like to hear you guys thoughts about this!
User avatar
Cerberus
Posts: 126
Joined: 12 Jan 2016, 15:46

Re: Adaptable functions

22 Mar 2019, 10:49

Using If statements in functions the way you do is a normal way to approach the issue. The Ifs will have a negligible effect on performance, unless you're adding millions of them. Based on my testing, it takes about 1 millisecond to do maybe three thousand If tests against a simple variable, on my new, mid-range computer, using the test code below. You can run it on your own computer to see how long it takes for you.


Code: Select all

;ahk
x = 1

Speed1()
Loop 1000000
{
	y = a
}
Speed2Msgbox("Just assigning a value to a variable 1 million times took ")

Speed1()
Loop 1000000
{
	If (x = 1)
		y = a
}
Speed2Msgbox("Testing a variable against a value and then assigning a value, each 1 million times, took ")

Speed1()
Loop 1000000
{
	If (x = 2)
		Msgbox X is two.
	If (x = 1)
		y = a
}
Speed2Msgbox("Testing against a value twice and then assigning a value, each 1 million times, took ")

Return

;*** ;----Functions to measure performance/speed----
Speed1() {
global
  DllCall("QueryPerformanceCounter", "Int64*", CounterBefore)
  ; Msgbox Before.
  }
  
Speed2() {
global  
  DllCall("QueryPerformanceCounter", "Int64*", CounterAfter)
}

Speed2Msgbox(MessageBegin = "The operation took ") {
global
  DllCall("QueryPerformanceCounter", "Int64*", CounterAfter)
  DllCall("QueryPerformanceFrequency", "Int64*", Frequency)
  TimeMS := (CounterAfter - CounterBefore) / (Frequency / 1000)
  ; MsgBox % "Elapsed QPC time is " . CounterAfter - CounterBefore ", frequency is " Frequency ", ms is " (CounterAfter - CounterBefore) / (Frequency / 1000) ", TimeMS is " TimeMS "; CounterAfter is " . CounterAfter "; CounterBefore is " . CounterBefore . "."
  Msgbox % MessageBegin TimeMS " ms on this computer."
}
AviationGuy
Posts: 185
Joined: 17 Jan 2019, 10:13

Re: Adaptable functions

22 Mar 2019, 11:04

Ok, so the if's aren't any problem then, thanks for the info. Don't really understand your code but I trust you :)
But is there a better way of doing this?
gregster
Posts: 2493
Joined: 30 Sep 2013, 06:48

Re: Adaptable functions

22 Mar 2019, 11:15

Well, in the case of Chrome, I prefer automating webpages via their DOM structure (like with the COM interface and Internet Explorer) and even injecting javascript etc., even with a hidden browser, independent of the actual screen coordinates of a specific button or other page elements.

There is the Chrome.ahk library and the Selenium webdriver approach (I personally have only experience with the former), but I think both approaches require to start Chrome in debugging mode (not sure if this could be a security concern in a company, since you mentioned this setting).
A_AhkUser
Posts: 1074
Joined: 06 Mar 2017, 16:18
GitHub: AAhkUser
Location: France

Re: Adaptable functions

22 Mar 2019, 14:43

Here's another way to achieve this (I will not speculate on whether it is a better way of doing this) by redirecting the function call using a static function reference:

Code: Select all

#NoEnv
#SingleInstance force
#Warn


ImageSearchFun(_p1, p2) {
static _imageSearchFun := Func("imageSearch" . APP_VERSION:=2)
return _imageSearchFun.call(_p1, p2)
}

ImageSearchFun(1, 2)

imageSearch(p1, p2) {
return "common core imageSearch stuff... - params: " . p1 . "," . p2
}
imageSearch1(p1, p2) {
MsgBox % r := imageSearch(p1, p2)
MsgBox % A_ThisFunc . " stuff... - params: " . p1 . "," . p2
}
imageSearch2(p1, p2) {
MsgBox % r := imageSearch(p1, p2)
MsgBox % A_ThisFunc . " stuff... - params: " . p1 . "," . p2
}
AviationGuy
Posts: 185
Joined: 17 Jan 2019, 10:13

Re: Adaptable functions

25 Mar 2019, 03:10

Thanks for the replies! Unfortunately, I didn't have any time this weekend so I couldn't get back on this earlier.
gregster wrote:
22 Mar 2019, 11:15
Well, in the case of Chrome, I prefer automating webpages via their DOM structure (like with the COM interface and Internet Explorer) and even injecting javascript etc., even with a hidden browser, independent of the actual screen coordinates of a specific button or other page elements.

There is the Chrome.ahk library and the Selenium webdriver approach (I personally have only experience with the former), but I think both approaches require to start Chrome in debugging mode (not sure if this could be a security concern in a company, since you mentioned this setting).
The script is for operating the interface of a program I use at work (just a program I use, nothing related to the internet so I don't think things like COM are an option here). It clicks buttons with the help of ImageSearch based on specific circumstances.
Atm, I have a set of functions which ensure the right buttons get pressed. But as I mentioned, I want to make them adaptable so when the program gets an update I just have to change 'v1' to 'v2' in my example above and the script will run the other function versions (and thus I'm able to easily switch between function versions).
AviationGuy
Posts: 185
Joined: 17 Jan 2019, 10:13

Re: Adaptable functions

25 Mar 2019, 03:27

Thank you also for your reply!
Also, very creative name, I like it :D
A_AhkUser wrote:
22 Mar 2019, 14:43
Here's another way to achieve this (I will not speculate on whether it is a better way of doing this) by redirecting the function call using a static function reference:

Code: Select all

#NoEnv
#SingleInstance force
#Warn


ImageSearchFun(_p1, p2) {
static _imageSearchFun := Func("imageSearch" . APP_VERSION:=2)
return _imageSearchFun.call(_p1, p2)
}

ImageSearchFun(1, 2)

imageSearch(p1, p2) {
return "common core imageSearch stuff... - params: " . p1 . "," . p2
}
imageSearch1(p1, p2) {
MsgBox % r := imageSearch(p1, p2)
MsgBox % A_ThisFunc . " stuff... - params: " . p1 . "," . p2
}
imageSearch2(p1, p2) {
MsgBox % r := imageSearch(p1, p2)
MsgBox % A_ThisFunc . " stuff... - params: " . p1 . "," . p2
}
If I'm understanding this correctly you are changing the function name based on the version?
If this is the case then it's not what I'm looking for. I have multiple scripts with lots of functions and it will take hours to change all the function names when I need to update a function. (If this isn't what you mean I'm sorry)
Also, I found this on the page you mentioned:
However, this requires the function name to be resolved each time, which is inefficient if the function is called more than once.
And as I said above, I have multiple function calls so that wouldn't be clever to do I think.
User avatar
nnnik
Posts: 4187
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Adaptable functions

25 Mar 2019, 05:28

The function name does not need to be resolved each time - it is resolved once at the script startup when func("imageSearch" . APP_VERSION:=2) is ran once.
Recommends AHK Studio

Return to “Ask For Help”

Who is online

Users browsing this forum: Bad husband, boiler, Google [Bot] and 152 guests