Jump to content

odd CallArgArray flaw


Linguist
 Share

Recommended Posts

Hallo dear buffs,

by scripting a data driven KodaForm (.kxf) compiler with and for AutoIt, I stumbled across an unexplained problem with the special CallArgArray option of the AutoIt Call function that needs a short explanation. As the documentation says, "This array must have its first element set to "CallArgArray" and elements 1 - n will be passed as separate arguments to the function.", it causes an odd inconvenience if the array (according to to the called function) has no further arguments exept the keyword "CallArgArray". Is this intended, or grounded in the inner workings of AutoIt? For me it's an extra step in the loop to check such situation and reduces the performance unnecessarily. Any savvy would be appriciated, as well as an advice to open a bug report or a feature request.

Link to comment
Share on other sites

  • Developers

Not sure what the issue is and why use call() at all?

Can you show a snippet showing your issue?

Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Link to comment
Share on other sites

Hey Jos,

that was quick. Thanx! Here's a short snippet:

local $aCallArg1[]=["CallArgArray",10,8],$aCallArg2[]=["CallArgArray"]
 
MsgBox(default,"Probe 1","0x"&Call("Hex",$aCallArg1)&@LF&Hex(@error,4)&" "&Hex(@extended,4))
exit MsgBox(default,"Probe 2",Call("_ReturnIt",$aCallArg2)&@LF&Hex(@error,4)&" "&Hex(@extended,4))

func _ReturnIt()
    return 100
endfunc
 

Link to comment
Share on other sites

  • Developers

What about something like this:

Global $aCallArg1[] = ["CallArgArray", 10, 8]
Global $aCallArg2[] = ["CallArgArray"]

ConsoleWrite("Probe 1 0x" & Call("_ReturnIt", $aCallArg1) & @CRLF & @error & " " & @extended & @CRLF)
ConsoleWrite("Probe 2 " & Call("_ReturnIt", $aCallArg2) & @CRLF & @error & " " & @extended & @CRLF)

Func _ReturnIt($Param1 = 1, $Param2 = 1)
    Return $Param1 * $Param2
EndFunc   ;==>_ReturnIt

Jos

Edited by Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Link to comment
Share on other sites

Thanks for your suggestion, but my problem is more general. The used Hex function is just an example, as well as the _returnIt UDF.

By scripting a data driven program code the Call function is the only point of intersection between DATA and CODE and acts as my 'von Neumann Gate' :graduated:, cos no other function is able to take an ASCII string and make it a function call. If the loop has to decide (on the data given) which AutoIt function (or UDF) is to be used to prosess them, its next task is to assemble an CallArgArray. But if the loop decides to call a function w/o an argument, it stucks. This is the reason why it has to switch to another Call function call with no arguments at all. That comes undhandy! If I could use an 'empty' CallArgArray in the same way Call is processed w/o arguments, things would be a bit easier.

Link to comment
Share on other sites

  • Moderators

Linguist,

I have been thinking about this problem and, while you have highlighted the case where the function takes no parameters, it also arises when you do not pass sufficient parameters to a function where the parameters have no default value set:

#include <MsgBoxConstants.au3>

Local $aCallArg2[] = ["CallArgArray", 10, 8], $aCallArg1[] = ["CallArgArray", 10], $aCallArg0[] = ["CallArgArray"]

MsgBox($MB_SYSTEMMODAL, "2/2 Params", Call("_ReturnIt_2", $aCallArg2) & @LF & Hex(@error, 4) & " " & Hex(@extended, 4))
MsgBox($MB_SYSTEMMODAL, "1/2 Params", Call("_ReturnIt_2", $aCallArg1) & @LF & Hex(@error, 4) & " " & Hex(@extended, 4))
MsgBox($MB_SYSTEMMODAL, "0/2 Params", Call("_ReturnIt_2", $aCallArg0) & @LF & Hex(@error, 4) & " " & Hex(@extended, 4))

MsgBox($MB_SYSTEMMODAL, "2/0 Params", Call("_ReturnIt_0", $aCallArg2) & @LF & Hex(@error, 4) & " " & Hex(@extended, 4))
MsgBox($MB_SYSTEMMODAL, "1/0 Params", Call("_ReturnIt_0", $aCallArg1) & @LF & Hex(@error, 4) & " " & Hex(@extended, 4))
MsgBox($MB_SYSTEMMODAL, "0/0 Params", Call("_ReturnIt_0", $aCallArg0) & @LF & Hex(@error, 4) & " " & Hex(@extended, 4))

Func _ReturnIt_2($vParam1, $vParam2)
    Return "Any problem with 2 params?"
EndFunc   ;==>_ReturnIt

Func _ReturnIt_0()
    Return "Any problem with no params?"
EndFunc   ;==>_ReturnIt
So the problem is not really AutoIt failing to deal with an "empty" CallArgArray array, but that any such array which does not correctly match its elements to the function's obligatory parameters will fail. This I see more as a restriction on the coder than an AutoIt problem per se. AutoIt cannot read your mind and it is the coder's responsibility to provide the correct parameters for any function they use. ;)

I fear that you may well have to store a value for each of the functions that could be called giving the number of obligatory parameters needed. Then you can correctly size your CallArgArray array for that particular function. If you store these functions names in an array, could you not add another column to hold such a value? :huh:

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png 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 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

 

Link to comment
Share on other sites

Melba23,

thanx a lot for your thoughts and your explanation. I have to agree that this is not realy an AutoIt failure, as the Call documentation states in particular "elements 1 - n will be passed" and no argument would be a zero. You are also right about the fact that the scribe is responsible for the number of arguments within the array. Never the less, if the called function intakes no arrguments at all, an 'empty' CallArgArray reflects the correct number. Since the only AutoIt function (as far as I know) w/o an argument is SplashOff() this problem concerns first and foremost an UDF call. In the end it's probably just a question of symetry, to treat an 'empty' CallArgArray like a Call function call w/o arguments.

To circumvent this obstacle, is of course just a tenary operation like:
$var=(Ubound($aCallArg)>1 ? Call("func",$aCallArg) : Call("func"))

Link to comment
Share on other sites

  • Moderators

Ternary is certainly an option, or you could wrap your Call function in a custom function that validates what you need it too without changing the style of your code/coding.

Something like this maybe:

Func _myCustomCall($s_func, $v_p1 = "", $v_p2 = "", _
        $v_p3 = "", $v_p4 = "", $v_p5 = "", $v_p6 = "", _
        $v_p7 = "", $v_p8 = "", $v_p9 = "", $v_p10 = "", _
        $v_p11 = "", $v_p12 = "", $v_p13 = "", $v_p14 = "", _
        $v_p15 = "", $v_p16 = "", $v_p17 = "", $v_p18 = "", _
        $v_p19 = "", $v_p20 = "")
        ; obviously could add more, but 21 params is crazy anyway

    Local $v_ret = 0, $a_callargs = $v_p1
    If Not IsArray($a_callargs) Then
        Dim $a_callargs[@NumParams]
        $a_callargs[0] = "CallArgArray"
        For $i = 1 To UBound($a_callargs) - 1
            $a_callargs[$i] &= Eval("v_p" & $i)
        Next
    EndIf

    Switch UBound($a_callargs)
        Case 1
            $v_ret = Call($s_func)
        Case Else
            $v_ret = Call($s_func, $a_callargs)
    EndSwitch

    Return SetError(@error, @extended, $v_ret)
EndFunc

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

SmOke_N,

good thinking and there are at least 'fifty ways to love your liver' :shifty: but my main concern (as mentioned above) is the lack of performance. Coding a script language means @1st 'cause to make' not doing scripting epics. On the other hand, if coding a data driven script I have to consider every called function as a blackbox with none of my hands inside. So I leave it up to you (as 'guardians of the AutoIt galaxy') to make the posed oddity a feature request for isometry, or let the sufficient afflicted scribe deal with it. Anyway... Thanx for your attention.

Link to comment
Share on other sites

  • Moderators

I didn't disagree with your first post.  I was merely offering an alternative to the issue at hand.

I think the melodramatics are a bit much when referring to "every called function".

You're playing with dynamic structuring, with one of the only few functions that will allow it.

If you did have to consider it, it would be with your design and with only those functions that allow dynamic data implementation.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

maybe a "safe" way to use the Call() function with the "CallArgArray" special array is like this:

1) prepare an array with as many parameters as you like to pass (also arrays within array, or just an empty variable as well)
2 call your function by passing your parameters contained in the above array in this way;  $aSendArguments[2] = ["CallArgArray", $aMy_Args]

perhaps in this way the call() function should never fail

Local $aMy_Args[] = [1, 2, 3, "four"] ; pass 4 arguments for example (or more...)
Local $aSendArguments[2] = ["CallArgArray", $aMy_Args] ; prepare the Packet containing arguments
Call("MyBlackBoxFunction", $aSendArguments)

Local $aMy_Args = "" ; pass nothing
Local $aSendArguments[2] = ["CallArgArray", $aMy_Args] ; prepare the Packet containing arguments
Call("MyBlackBoxFunction", $aSendArguments)

Func MyBlackBoxFunction($aArguments)
    MsgBox(0, "", "Received " & UBound($aArguments) & " arguments")
    ; manage the arguments received within the $aArguments array
EndFunc   ;==>MyBlackBoxFunction

 

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

SmOke_N,

I didn't ment to be melodramtic nor rude and I really do appreciate your help, honestly. For me 'Scripting epics' is a more general tern and wasn't refering to your helping code example at all, which is of course a possible solution. Sorry it came over this way! My hope is, that a tiny improvement within the AutoIt Call function would improve the core loop performance of my DATA-CODE intersection.

Link to comment
Share on other sites

  • Moderators

SmOke_N,

I didn't ment to be melodramtic nor rude and I really do appreciate your help, honestly. For me 'Scripting epics' is a more general tern and wasn't refering to your helping code example at all, which is of course a possible solution. Sorry it came over this way! My hope is, that a tiny improvement within the AutoIt Call function would improve the core loop performance of my DATA-CODE intersection.

Understood, I wasn't referring to my code either.

I understand your wish for it to be improved upon, and have to agree.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

Thanx SmOke_N and Chimp,

I know, I'm a strange guy with silly problems... Why would anyone being so eager with one of the most unused AutoIt features?

So please allow me to give a more sprawling tour and turn from abstract to concrete, beginning with the key question: An own KodaForm (.kxf) compiler, really?! By this time I'm scripting nearly 5 years with AutoIt and I love it, cos it's one of the fastest and most versatile scripting engines for Windows. Since then I coded lots of applications for several social constitutions and for companies and out of a simple automation & admin-tool coding, things are grown up to full blown custom projects, usually done with C++ before. One of my everyday problems (besides keeping OCX modules on the hop) is to tailor GUI scripts and meanwhile this task is getting real ugly if you have to design an application with hundreds of GUI controls. Therefore I decided fiddle a completely new approach (avoiding WPF) and started to compile KXF files into a SQLite database. Although this compiler prototype is coded in AutoIt by now, it will be done with C++ later on (or even with FASM if it fits my needs), but when it comes to the AutoIt application, I have to stick with the scripting engine.

Key element of the AutoIt source include for my applications is a tiny wrapper as a resource loader, based on a SQL COM object and has to deliver (among icons, pics and other GUI control data) my so called 'FormCode' records. Their simple SQL table format looks like:

                            [FormName, SegmentName, OrdinalNum, ObjectName, ObjectTag, FormCode]

The FormCode itself is a pipe delimited ASCII String and starts with a function name (AutoIt function, or UDF) followed by a bunch of pre-evaluated data and/or 'EvalClauses'. Such an EvalClause is an unevaluated param and itself a function, too, preceded with a suitable PrefixToken (§Function, @Macro, or $Variant). This funny FormCode string looks like e.g.: "GUICtrlSetBkColor|$MyControlID|§_WinAPI_GetSysColor;15"

If the runtime UDF is going to open a new Form (actual with _GUICreate("FormName") ) it simply issues a SQL statemant and gets back a statement object with all FormCode records of the given FormName. Than it has to step thru this object taking one FormCode after the other (sorted by their OrdinalNum) and has to evaluate all its given EvalClauses. This is the first time the AutoIt Call function come into play (or the Execute function, if an @ or $ token is indicated). This has to be done once for every given GUI function param (with its own temporary CallArgArray). In the end it returns a ready-made GUI function CallArgArray, which is used by the final Call function call.

Lets say a GUI function Call has to be evaluated with 3 EvalClauses per Call (on average) and a complete GUI form has e.g. 40 FormCode records (building steps), it has to process 120 Call function calls all in all. That's where my life comes to 'zen of code optimiziation' and my part of the job, is to reduce every loop to its absolut minimum to make this tricky concept work on a scripting engine.

I hope this could somehow clarify my hardships at least a bit and I'd be pleased if ever anyone was following my tour up to this point.
 

Link to comment
Share on other sites

  • Moderators

Linguist,

Interesting concept - delighted you are coding it and not I ! :D

The use of a prefix character to identify the use of the following string reminds me of an old DOS menu app that I wrote some 25 years back which read lines from inifiles and used similar prefix characters to determine whether the line was for display or what to do once a selection was made. But as you already use these prefixes to distinguish between using Call / Execute on the string, can you not simply add another prefix to make a similar distinction between Call / Call /w CallArgArray? You must already do a test on the string to differentiate the leading character so you would not be further slowing the overall process, just adding another Case to whatever decision structure you use. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png 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 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

 

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