Jump to content

Generate Function at Runtime using IRunningObjectTable / AutoItObject


Recommended Posts

Posted (edited)

Hi Folks,

this is a simple example of how to generate a function with and call it during runtime (+ pass data from/to it). It is accomplished by using AutoItObject and inspired by Access AutoIt

#include <AutoItGenFuncEx.au3>

$iSleepTime = 500

$oFunction = _AutoItGenFuncEx_CreateFunction("$iTreshold", _;           <------ What are the Parameters?
        '' _;                                                           <------ What is the Sourcecode?
         & @LF & 'For $i = 1 to 100' _
         & @LF & '  IF $i <= $iTreshold then ' _
         & @LF & '    Sleep(10)' _
         & @LF & '  Else' _
         & @LF & '    Sleep($iSleepTime) ; slower at the end.' _
         & @LF & '  EndIf' _
         & @LF & '' _
         & @LF & '  ToolTip("Counter:" & $i)' _
         & @LF & 'Next', _
        "") ;                                                   <------ What should be returned?

If IsObj($oFunction) Then
    $oFunction.Call(Random(90, 95, 1))
EndIf

There are many discussions about running "dynamic" autoit code on the internet - and there are a lot of alternatives for this. And almost always, it is absolutely not necessary to do such a thing as generating function code at runtime, because you're better off with a different program design choice. My need for this came from a very special use case.

People have tried to approach this problem in several ways each with it's own set of advantages and limitations - very simple tasks can be accomplished with Execute(), Call(), Eval(), Assign(), or running source with /AutoItScriptExecuteLine or /AutoItScriptExecute, more advanced tasks can usually be tackled with multiple scripts communicating with each other via files, console streams, windows messages, tcp, dllcallbacks, etc.

The most advanced discussions I've found on this included to get 'autoit function pointers', adding threads to the autoit script or copying the function into a new process, which, to my knowledge, have never been really successful, stable, or easy to use. - and this UDF is no exception because it still comes with it's limitations: For example you can't use ByRef parameters at all and global variables from the main program are just copies - but not actual references.

Threads / Alternatives: 

Dynamic functions

Is it possible to find out the memory address of a internal function and retreive the struct of it?

_DllCall.au3 Callback - no external library (dll) required

DotNet.au3 DotNet.au3 UDF to access .NET Framework from AutoIt

Lua.au3 Embedding Lua scripts in AutoIt

AssembleIt _AssembleIt() for FASM.au3 now with "Debugger"

Standalone Example

The goal of the standalone script is to showcase the idea & inspire people to explore AutoItObjects and the RoT.

Spoiler

generate function.zip

How it works: Basically quite simple (not in this order:)

Spoiler
  • The generated Function Code - plus some additional lines of code - are written into a seperate file (in this example it's the File 'autoitselfmody.au3' in the @ScriptDir) and launched using @AutoItExe
  • Data is passed from the main script to the generated file (and vice versa) using a simple Container. This container can also contain callbacks for the generated function. In this example, there is a MessageBox Method showing the Callback capabilities.
  • A second Container is created from the generated file to pass back the generated function and the main script is notified. (in this example, the Property "ready" is changed to True)
  • The main script can now call the generated function, pass parameters, receive Returns, etc.

How it's done: Technically this is just..

Spoiler
  1. Creating a simple AutoItObjects Object "$Object_In" in the main script using _AutoItObject_Create() to pass data or functions "to" the generated script
  2. Adding a simple "ready" property to the Object.
  3. (In this example: Adding a Callback Method "MessageBox" to the object.)
  4. Registering the Object using _AutoItObjects_RegisterObject()
  5. Writing the generated File, which will be..:
    1.  Getting the Container created at 1) using ObjGet()
    2.  Creating a simple AutoItObjects Object "$Object_Out" using _AutoItObject_Create() to pass back the function reference
    3.  Adding the generated Method to the just created Object using _AutoItObject_AddMethod()
    4.  Registering the Object using _AutoItObjects_RegisterObject()
    5.   (In this example: Calling the Callback of object)
    6.   setting the "ready" property created at 2) to True
    7.   Idling around
  6. 6) Starting the generated File
  7. 7) Waiting for the "ready" property created at 2) to be changed to True
  8. 8.) Getting the Object created at 5.2) using ObjGet
  9. 9) Calling the Function via the object method created at 5.3)

Example Script

Spoiler
#include <AutoItObject.au3>
_AutoItObject_Startup()

; Container for passing data, callbacks, etc.
$oObject_In = _AutoItObject_Create()
_AutoItObject_RegisterObject($oObject_In, 'AutoItTest.SelfMody.In')
_AutoItObject_AddProperty($oObject_In, 'ready')

; Example: Callback-Method
_AutoItObject_AddMethod($oObject_In,"MessageBox", "MessageBox")

; Example: Call function in main script in main script (nothing special yet)
$oObject_In.MessageBox("1) Regular call of function from within the same script")

; generate external function
Make_external_function()

; call external function:
Do
    Sleep(100)
Until $oObject_In.ready

$oObject_Out = ObjGet("AutoItTest.SelfMody.Out")
$oObject_Out.some_external_function("3) call of function in external (generated) Script")

Func MessageBox($oSelf, $sText)
    MsgBox(0,"",$sText)
EndFunc



Func Make_external_function()
    $sSourceCode = ''  _
        &@LF&   '#include <AutoItObject.au3>' _
        &@LF&   '_AutoItObject_StartUp()' _
        &@LF&   '$oObject_In  = ObjGet("AutoItTest.SelfMody.In")' _
        &@LF&   '' _
        &@LF&   '$oObject_Out = _AutoItObject_Create()' _
        &@LF&   '_AutoItObject_AddMethod($oObject_Out,"some_external_function", "some_external_function")' _
        &@LF&   '_AutoItObject_RegisterObject($oObject_Out, "AutoItTest.SelfMody.Out")' _
        &@LF&   '' _
        &@LF&   '$oObject_In.MessageBox("2) Callback of Function from external script")' _
        &@LF&   '$oObject_In.ready = True' _
        &@LF&   '' _
        &@LF&   'While Sleep(100)' _
        &@LF&   'WEnd' _
        &@LF&   '' _
        &@LF&   'Func some_external_function($oSelf, $vParam)' _
        &@LF&   '   MsgBox(0,"some_external_function",$vParam)' _
        &@LF&   '   Exit' _
        &@LF&   'EndFunc'

    FileDelete(@ScriptDir & '\autoitselfmody.au3')
    FileWrite(@ScriptDir & '\autoitselfmody.au3', $sSourceCode)
    Run(StringFormat('%s /AutoIt3ExecuteScript "%s"', @AutoItExe, @ScriptDir & '\autoitselfmody.au3'),@ScriptDir)
EndFunc

Output: 1422310107_GIF15_02.202102-51-49.gif.7dc8118a4eb0a385aad52e1503e17b2a.gif

FYI : the "generated" File looks like this - the generated part would be     'MsgBox(0,"some_external_function",$vParam)'. The rest is just loading the objects in & out.

Spoiler
#include <AutoItObject.au3>
_AutoItObject_StartUp()
$oObject_In  = ObjGet("AutoItTest.SelfMody.In")

$oObject_Out = _AutoItObject_Create()
_AutoItObject_AddMethod($oObject_Out,"some_external_function", "some_external_function")
_AutoItObject_RegisterObject($oObject_Out, "AutoItTest.SelfMody.Out")

$oObject_In.MessageBox("2) Callback of Function from external script")
$oObject_In.ready = True

While Sleep(100)
WEnd

Func some_external_function($oSelf, $vParam)
    MsgBox(0,"some_external_function",$vParam)
    Exit
EndFunc

 

 

 

Simple UDF "AutoItGenFunc"

The goal of the UDF is to have an easy way for beginners and lazy people to use way to allow "complex" AutoIt Coding to be executed during Runtime.

Spoiler

/Edit: I've created a ready-to use UDF to generate functions. Maybe you want to use that instead. See the AutoItGenFunc.au3 Archive attached

 AutoItGenFunc.zip

AutoItGenFunc.au3 - the simple UDF

Spoiler
#include-once
#include <File.au3>
#include <AutoItObject.au3>



Func _AutoItGenFunc_CreateFunction($sParameters, $sCoding, $sReturn = "")
    Local Static $fInitialized = False
    If Not $fInitialized Then
        _AutoItObject_Startup()
        $fInitialized = True
    EndIf

    Local $sUniqueID = StringMid(_TempFile(@ScriptDir, "", "", 9), StringLen(@ScriptDir) + 2, -2)
    If $sParameters <> '' Then $sParameters = ', ' & $sParameters
    $sSourceCode = '' _
             & @LF & '#include <AutoItObject.au3>' _
             & @LF & '_AutoItObject_StartUp()' _
             & @LF & '$oObject_Main  = ObjGet("_AutoItGenFunc.' & $sUniqueID & '.Main")' _
             & @LF & '' _
             & @LF & '$oObject_Sub = _AutoItObject_Create()' _
             & @LF & '_AutoItObject_AddProperty($oObject_Sub,"done", "")' _
             & @LF & '_AutoItObject_AddMethod($oObject_Sub,"call", "_AutoItGenFunc__DynamicFunction")' _
             & @LF & '_AutoItObject_RegisterObject($oObject_Sub, "_AutoItGenFunc.' & $sUniqueID & '.Sub")' _
             & @LF & '' _
             & @LF & '$oObject_Main.ready = True' _
             & @LF & 'Do ' _
             & @LF & '  Sleep(100)' _
             & @LF & 'Until $oObject_Sub.done Or Not ProcessExists(' & @AutoItPID & ')' _
             & @LF & '' _
             & @LF & 'Func _AutoItGenFunc__DynamicFunction($oSelf' & $sParameters & ')' _
             & @LF & $sCoding _
             & @LF & '  $oSelf.done = True' _
             & @LF & '   Return ' & $sReturn _
             & @LF & 'EndFunc' _
             & @LF & ''

    $oObject_Main = _AutoItObject_Create()
    _AutoItObject_AddProperty($oObject_Main, 'ready')
    _AutoItObject_RegisterObject($oObject_Main, "_AutoItGenFunc." & $sUniqueID & ".Main")

    FileWrite(@ScriptDir & '\' & $sUniqueID, $sSourceCode)
    $iPID = Run(StringFormat('%s /AutoIt3ExecuteScript "%s"', @AutoItExe, @ScriptDir & '\' & $sUniqueID), @ScriptDir)

    Do
        Sleep(100)
    Until $oObject_Main.ready; OR not ProcessExists($iPID)

    $oObject_Sub = ObjGet("_AutoItGenFunc." & $sUniqueID & ".Sub")
    If Not IsObj($oObject_Sub) Then Return SetError(@error, @extended, Null)
    Return $oObject_Sub
EndFunc   ;==>_AutoItGenFunc_CreateFunction

 

You 1)Create a function using $oFunction = _AutoItGenFunc_CreateFunction($parameters, $coding, $returnstatement), then call the "call(...)" method of your function object. 

The call()-method of the returned Function Object will have the parameters you defined when calling _AutoItGenFunc_CreateFunction.

Usage Example #1 of AutoItGenFunc:

Spoiler
#include <AutoItGenFunc.au3>

$oFunction = _AutoItGenFunc_CreateFunction( _
        "$iMsgBoxFlag, $sTitle, $sText", _          ;                   <------ What are the Parameters?
        "MsgBox($iMsgBoxFlag, $sTitle, $sText)", _  ;                   <------ What is the Sourcecode?
        "")                                         ;                   <------ What should be returned?

If IsObj($oFunction) Then
    MsgBox(0, '', 'Example 1 returned: ' & $oFunction.Call(64, 'Some great title', 'Some philosophical text') & '... because it doesnt have a return')
EndIf

Output: 642676297_GIF15_02.202102-54-07.gif.80e74b31a2dca846624036dcd7792bd7.gif

Usage Example #2 of AutoItGenFunc:

Spoiler
#include <AutoItGenFunc.au3>
$oFunction = _AutoItGenFunc_CreateFunction("$sSendText", _  ;           <------ What are the Parameters?
        'Run("notepad.exe")' _ ;                                        <------ What is the Sourcecode?
         & @LF & 'Local $hWnd = WinWait("[CLASS:Notepad]", "", 10)' _
         & @LF & 'Send("Todays time/date is {F5}{ENTER}")' _
         & @LF & '' _
         & @LF & 'Send("Parameter $sSendText = " & $sSendText)' _ ; <- fyi: parameter used here
         & @LF & '$vRandom = Random(1,100,1)' _ ;                   <- fyi: return value set here
         & @LF & '' _
         & @LF & 'WinClose($hWnd)' _
         & @LF & 'WinWaitActive("[CLASS:#32770]")' _
         & @LF & 'Sleep(500)' _
         & @LF & 'Send("{TAB}")', _
        "$vRandom") ;                                                   <------ What should be returned?

If IsObj($oFunction) Then
    MsgBox(0, '', 'Example 2 returned a random number: ' & $oFunction.Call("This is written to Notepad"))
EndIf

Output: 1484621440_GIF15_02.202112-36-02.gif.4558074e749e648e18e25c6598fb5ea1.gif

 

 

 

Extended UDF "AutoItGenFuncEx"

The goal of the extended UDF is to have an easy to use way for beginners and lazy people to allow even more "complex" AutoIt Coding (callbacks) to be executed during Runtime.

Spoiler

 

AutoItGenFuncEx_v3.zip

I've also created AutoItGenFuncEx.au3, which allows direct 'access' to global variables and functions (see below) in the main script.
Direct access to global variables means: the values of used global variables are copied into the object before the function is executed. Please see Example #3.
Global variables can be changed inside the function and are copied back before return.
Note: Changes to global variables may not be reflected in Callback Functions called from your generated function (as of now). This behaviour is subject to change.

AutoItGenFuncEx allows callbacks to the main script. Please see Example #4. 
Functions are therefore wrapped into a Custom function __AutoItGenFuncExWrapped__YOUFUNCTIONNAMEHERE that have an additional parameter $__oSelf.

Note: To enable callbacks a line "#AutoItGenFunc_AllowCallbacks=true" somewhere in your script is required.
This will make the UDF look for certain #include- and #AutoIt3Wrapper_Res_File_Add-Directives in your main script file.
It will add your function definitions (names & parameters) to your program resources, plus include a wrapper file to which adds an additional parameter for the AutoItObject-Reference to the callback-functions. Include files are resolved automatically but can be Excluded by adding a line #AutoItGenFunc_SkipInclude=true in the respective include file.

 

AutoItGenFuncEx - Example 1 - Simple Messagebox:

Spoiler
#include <AutoItGenFuncEx.au3>

; Step 1) Create a Function:
$oFunction = _AutoItGenFuncEx_CreateFunction( _
        "$iMsgBoxFlag, $sTitle, $sText", _          ;                   <------ What are the Parameters?
        "MsgBox($iMsgBoxFlag, $sTitle, $sText)", _  ;                   <------ What is the Sourcecode?
        "")                                         ;                   <------ What should be returned?

; Step 2) Check, if the function was created:
If IsObj($oFunction) Then

    ; Step 3) Call the function. (-> Parameters of call() are defined in line 5)
    $vReturnValue = $oFunction.Call(64, 'Some great title', 'Some philosophical text')

    ; Step 4) Display the return value. (-> Which is defined in line 7)
    MsgBox(0, '', 'Example 1 returned: ' & $vReturnValue & '... because it doesnt have a return')
EndIf

1422310107_GIF15_02.202102-51-49.gif.7dc8118a4eb0a385aad52e1503e17b2a.gif

AutoItGenFuncEx - Example 2 - Write Text in Notepad:

Spoiler
#include <AutoItGenFuncEx.au3>

; Step 1) Create a Function:
$oFunction = _AutoItGenFuncEx_CreateFunction( _
        "$sSendText", _ ;                                                       <------ What are the Parameters?
         & '' _
         & @LF & 'Run("notepad.exe")' _ ;                                       <------ What is the Sourcecode?
         & @LF & 'Local $hWnd = WinWait("[CLASS:Notepad]", "", 10)' _
         & @LF & 'Send("Todays time/date is {F5}{ENTER}")' _
         & @LF & '' _
         & @LF & 'Send("Parameter $sSendText = " & $sSendText)' _ ; <- fyi: parameter used here
         & @LF & '$vRandom = Random(1,100,1)' _ ;                   <- fyi: return value set here
         & @LF & '' _
         & @LF & 'WinClose($hWnd)' _
         & @LF & 'WinWaitActive("[CLASS:#32770]")' _
         & @LF & 'Sleep(500)' _
         & @LF & 'Send("{TAB}")', _
        "$vRandom") ;                                                           <------ What should be returned?


; Step 2) Check, if the function was created:
If IsObj($oFunction) Then

    ; Step 3) Call the function. (-> Parameters of call() are defined in line 5)
    $vReturnValue = $oFunction.Call("This is written to Notepad")

    ; Step 4) Display the return value. (-> Which is defined in line 18, and set in line 12)
    MsgBox(0, '', 'Example 2 returned a random number: ' & $vReturnValue)
EndIf

1484621440_GIF15_02.202112-36-02.gif.4558074e749e648e18e25c6598fb5ea1.gif

AutoItGenFuncEx - Example 3 - Share global variables:

Spoiler
#include 'AutoItGenFuncEx.au3'
$hGUI = GUICreate("Example 3")
$hButton  = GUICtrlCreateButton("Click me",0,0,400, 400)
GUICtrlSetFont(-1, 36)
GUISetState()


$Global_variable_in_main = "not a parameter, but global variable"


While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case -3
            Exit
        Case $hButton

            ; Step 1) Create a Function:

                $oRandom = _AutoItGenFuncEx_CreateFunction( _
                    '' & _ ; ----- Parameters:
                    "$iFrom = 0, $iTo = 100", _
                    '' _ ; ----- Sourcecode:
                    & @LF & "MsgBox(0,'','$Global_variable_in_main is: ' & @LF & @LF & $Global_variable_in_main)" _
                    & @LF & "If $hGUI <> '' Then "  _
                    & @LF & "   MsgBox(0,'','and $hGUI is: ' & $hGUI)" _
                    & @LF & 'EndIf' _
                    & @LF & 'WinMove($hGUI, "", Random(0, @DesktopWidth - 300, 1), Random(0, @DesktopHeight - 300, 1))' _
                    & @LF & 'Sleep(10)', _
                    '' & _ ; ----- Return:
                    "Random($iFrom, $iTo, 1)")

                ; Step 2) Check, if the function was created:
                If IsObj($oRandom) Then

                    ; Step 3) Call the function. (-> Parameters of call() are defined in line 22)
                    $iRandomValue = $oRandom.call(1, 100)

                    ; Step 4) Display the return value. (-> Which is defined in line 30)
                    GUICtrlSetData($hButton, $iRandomValue)
                EndIf
    EndSwitch
WEnd

1803156796_GIF15_02.202102-57-42.gif.f913a93ec5aba3653e841ad149c32d9b.gif

AutoItGenFuncEx - Example 4 - Callbacks into main script:

Spoiler
#include <AutoItGenFuncEx.au3>
#include <MsgBoxConstants.au3>
#AutoItGenFunc_AllowCallbacks=yes ;  <----- this enables callbacks. script will add compiler-directives and restart on first launch. Make sure to launch script at least once uncompiled to allow those source code updates.

Global $hGUI, $say_hi = 'hello'

; Step 1) Create a Function:
$oFunction = _AutoItGenFuncEx_CreateFunction( "$sTitle", _ ; Parameters
        "" _
        &@LF& "$iMsgBox = MsgBox(4, $sTitle, 'very callback.')   " _    ; parameter $sTitle defined in line 8
        &@LF& "                                                  " _
        &@LF& "If $iMsgBox = 6 Then                              " _
        &@LF& "  _some_callback('wow', $say_hi & ' this is doge')" _    ; _some_callback() is defined in line 41
        &@LF& "  $say_hi = 'oh, hi doge'                         " _    ; variable $say_hi is defined as Global in line 5
        &@LF& "Else                                              " _
        &@LF& "  $say_hi = 'sad'                                 " _
        &@LF& "EndIf                                             " _
        ) ;


; Step 2) Check, if the function was created:
If IsObj($oFunction) Then

    ; Step 3) Call the function. (-> Parameters of call() are defined in line 9)
    $oFunction.Call('much function')
EndIf

; This variable $say_hi is changed inside the generated function
MsgBox(0,"", $say_hi)


; This handle "$hGUI" is set in line 42, by a function "_some_callback" which is called from the generated function (line 12)
If IsHWnd($hGUI) Then
    Do
        Sleep(10)
    Until GUIGetMsg() = -3
    GUIDelete($hGUI)
EndIf


Func _some_callback($sGUITitle, $sGUIText)
    $hGUI = GUICreate($sGUITitle, 400, 100, 100, 300)
    GUICtrlCreateLabel($sGUIText, 0, 0, 400, 100)
    GUICtrlSetFont(-1, 36)
    GUISetState()

    WinSetOnTop($hGUI, '', 1)
EndFunc   ;==>_some_callback

Output: 1726484130_GIF17_02.202112-06-18.gif.49d2c625592d221509c8ec736e460478.gif

 

AutoItGenFuncEx - Example 5 - Keeping functions alive for performance:

Spoiler
#include <AutoItGenFuncEx.au3>
#include <Date.au3>
#include <MsgBoxConstants.au3>

Global $sToolTip

; Step 1) Create a Function:
$oFunction = _AutoItGenFuncEx_CreateFunction( _
        "$iFrom = -999, $iTo = 999", _
        "ToolTip('Generated function says: ' & $sToolTip)", _
        "Random($iFrom, $iTo , 1)")

For $i = 1 To 100
    $sToolTip = _NowTime() & "." & @MSEC
    $iReturn = $oFunction.Call(1, 100, True) ; all functions have an additional option parameter $fKeepAlive at the end; if set to True, function will not self-release after first call.

;~  ConsoleWrite("Random value: " & $iReturn & @CRLF)
    ToolTip("Random value: " & $iReturn , 400, 400)
Next


$oFunction.done = True ; release function

MsgBox(0, "", "The function will be released now.")

; dont try this:
$oFunction.Call()

 

 

 

Download within the corresponding Spoilers, or find version history below:

Update 17.02.2021:

- added parameter to keep functions alive, see Example #5
- Global Variables are now changeable and copied back into the main script, see Updated Example #4.
- added $oFunction.Source which stores the AutoIt-Source of the generated file for debugging purposes.
- better handling of global vars and funcs
- added logic for also resolving global vars and functions in included files.
- added #AutoItGenFuncEx_SkipInclude directive to indicate that a include should not be "wrapped", thus not being callable from a generated function.

AutoItGenFuncEx_v3.zip

 

Update 15.02.2021:

- access global variables (read-only) and callback functions from main program.
- added #AutoItGenFuncEx_AllowCallbacks directive to indicate that functions in the main script should be wrapped into callback-enabled functions. See Example #4.

AutoItGenFuncEx_v2.zip

Initial Post:

generate function.zip

AutoItGenFunc.zip

I did not find any easier solution for sharing data and functions between scripts yet, so this is my dirty hack. Maybe it's useful for someone with the same problem.

I would also be happy if someone would point out alternatives or improvements. I feel like there is potential.

GIF 15.02.2021 02-59-04.gif

Edited by SEuBo
v3, Example 4 updated, Example 5 added
Posted

I am missing the why I would do it this way and not compile directly your code with everything in it.

anyway check the eval, execute, assign, call in the helpfile

Example of usage besides the help example it interprets a simple multiline string as a micro language (no loop constructs supported)

#include <MsgBoxConstants.au3>

func moreDynamic($str)
   consolewrite($str)
EndFunc

;Assign function to variable
$f=MsgBox
$f($MB_SYSTEMMODAL, "Title","dynamic function")
$f=moreDynamic
$f("just some text")

;Call function
$strMultiLine = "msgbox 0 title fromstring'"  & @Crlf
$strMultiLine &= "moredynamic texttoshowdynamic" & @Crlf
$strMultiLine &= "consolewrite texttoshowdynamic2console" & @Crlf


$arrLines=stringsplit($strMultiLine, @crlf)
dim $i
for $i=0 to ubound($arrLines)-1
   $fArray=stringsplit($arrLines[$i], " ")
   $parCount=ubound($farray)-1
consolewrite($fArray[1] & $parcount & @crlf)

   if $parCount = 0 then call($fArray[1])
   if $parCount = 1 then call($fArray[1],$fArray[2],$fArray[3])
   if $parCount = 2 then call($fArray[1],$fArray[2])
   if $parCount = 3 then call($fArray[1],$fArray[2],$fArray[3])
   if $parCount = 4 then call($fArray[1],$fArray[2],$fArray[3],$fArray[4])
Next

 

Posted (edited)

Hi,

Because your Example wouldn't allow Variable assignments, Loops, If-Statements, etc.

#include <AutoItGenFunc.au3>
$oFunction = _AutoItGenFunc_CreateFunction("", _  ;             <------ What are the Parameters?
        '' _ ;                                                  <------ What is the Sourcecode?
         & @LF & 'For $i = 1 to 100' _
         & @LF & '  IF $i < 50 then ' _
         & @LF & '    Sleep(100)' _
         & @LF & '  Else' _
         & @LF & '    Sleep(10) ; faster at the end.' _
         & @LF & '  EndIf' _
         & @LF & '' _
         & @LF & '  ToolTip("Counter:" & $i)' _
         & @LF & 'Next', _
        "") ;                                                   <------ What should be returned?

If IsObj($oFunction) Then
    $oFunction.Call()
EndIf

oh and the "why" is: I have a Complex application and users are supposed to create business objects and corresponding logic by themselfes supported by GUI easy AutoItObjects based Scripting. Logic is supposed to be entered and executed during runtime. This is my workaround until I can understand how to hook into IDispatch deep enough to dynamically load the coding directly into an AutoItObject-Object or something. This is nothing I intend to use on daily basis, but I still found it interesting enough to share, since most discussions about dynamic functions in Autoit end up with Execute(), Assign(), Eval() and it's limitations.

Cheers,

Edited by SEuBo
Posted

My point was more that you still need the AutoIt compiler to run the script thats outside on the filesystem.

The examples I gave are able to run without compiler and yes biggest missing things are loops, if statements.

But anyway #pragma compile(AutoItExecuteAllowed, true) would allow me to run any non compiled AutoIt file.

Your example looks fine but just trying to understand when to use it 

 

 

Posted (edited)

Hey!

As I said, it's a very very special usage scenario and I never had to use such a thing within the all my autoit life - up until now.

5 hours ago, junkew said:

My point was more that you still need the AutoIt compiler to run the script thats outside on the filesystem.

https://www.autoitscript.com/autoit3/docs/intro/running.htm

Run a script using another compiled script:

Compiled.exe [/ErrorStdOut] /AutoIt3ExecuteScript file [params ...]
                Execute another AutoIt script file from a compiled AutoIt3 executable. 

Compiled.exe [/ErrorStdOut] /AutoIt3ExecuteLine "command line"
                Execute one line of code as with AutoIt3.exe above. 

This means that there is no need to have a copy of AutoIt3.exe in addition to the compiled file - the interpreter stub of the compiled file will replace it.  So as long as there is at least one compiled script available, other AutoIt scripts can be run without the need to have AutoIt3.exe on the machine., either pre-installed or added via FileInstall.

that is, if the script is compiled with #pragma compile(AutoItExecuteAllowed, true) as you stated, yes. but that's the default.

Edited by SEuBo
  • Moderators
Posted

SEuBo,

Quote

if the script is compiled with #pragma compile(AutoItExecuteAllowed, true) as you stated, yes. but that's the default.

No, the default is NOT to allow compiled scripts to run other scripts - from the Help file:

Quote

However, the executable must have been compiled with the #pragma compile(AutoItExecuteAllowed, True) directive as the default setting does not permit use of the /AutoItExecuteScript or /AutoItExecuteLine parameters.

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

 

Posted (edited)
On 2/11/2021 at 8:09 PM, junkew said:

Your example looks fine but just trying to understand when to use it 

/Edit: I've updated the first post in regard to this.

The usage scenario is create & call a function which parameters and behaviour is unkown during compile time (or startup) and can also not be determined by algorithms, because it is supposed to be programmed while the application is running. I am developing an AutoIt based ERP system together with a small local business as a prototype/first customer help them reduce costs. The entire application, and all data / functions are encapsulated in Objects (- from here on I use the word "objects" equivalent to "classes". ). There are

- System objects (e.g. "Application", "Database", "ObjectBuilder", "Printer", "Mail", etc.) and
- Business objects (e.g. "Material", "Materialprice", "Customer", "Salesorder", "Material Text", "Contract", "Invoice", "ContractReleaseOrder", etc.).

The system objects are fixed and encapsulate everything that runs "in the background" and some very generic functionality. 

There will be a standard set of business objects and templates, but in general, business objects, their relations and their logics are to be created during runtime - by the user. This will be a heavily UI-guided process. Also, users are supposed to write Scripts "just-in-time", while there are looking at some data inside the application. Those Scripts shall have access to the whole Application: the screens, the data, the other objects, AutoIt Functions, the neat and the ugly bits. There is nothing worse than having a functionality somewhere that is doing exactly what you need, but you can't call it.

At the moment, the Business Objects are created manually (XML files with their definition and au3 files with method coding). After those files are added (and an #include-statement was added to a collective include), I have to restart my application. Otherwise I can not access the just created include.

And this is where my problem comes from: The Function sourcecode is entered by the user and it can only be called in the current application after restart (which is bad, when you already entered data on the screen, but also want a new script to run).

There are a lot of workarounds for stuff like this - exposing data & functions via API and defined interfaces, etc., - NOT letting users enter code and mess with stuff, - using languages that are better suited.. But I chose AutoIt because it is amazing and I want it to be the scripting language inside my AutoIt Application. 

As I said: very special use-case. Just for clarification :)

Edited by SEuBo

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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...