Jump to content

Function reflection


Recommended Posts

Hi,

What I want to do is define the hotkeys for my program within an ini file, so the ini file would look something like:

[functions]

function1=alt+control+shift+a

function2=ctrl+b

A problem arises if the ini file defines a function that does not exist within the script. In this case the script stops with "Unknown function name.: " I have tried AutoItSetOption("RunErrorsFatal", 0), but this does not help. Ideally one would fill an array with all of the function names within my compiled script and then check that function name before setting it with HotKeySet(...). I believe this ability is called reflection.

I guess I could read in the script.au3 file and write all of the function names to the ini file before hand, but I am looking for something a little more elegant and robust. Anyone have some ideas?

Thank you.

Link to comment
Share on other sites

make an array with all the function names and say something like

#include <array.au3>
$AllFuncs = _ArrayCreate( 'Play', 'Pause', 'Stop', 'Exit', 'Test' ) ;An array containing all your function names
$FuncFromINI = 'Play' ;the func the user is trying to call from the INI
$OK = 0 ; this var is to say if the func was found or not
If IsArray($AllFuncs) Then
For $i=0 to Ubound($allFuncs)-1 step 1
If $FuncFromINI = $AllFuncs[$i] Then $Ok = 1
Next
If $ok = 1 Then
MsgBox(64,'','Function is in your script')
Else
MsgBox(64,'','Function is not in your script')
Endif
Endif

Tested and works....

Edited by DBak

[center][/center]

Link to comment
Share on other sites

Yes, that method would work, but we will be adding and removing functions rather regularly. I do not want to have to modify a list somewhere in the source... just have the code detect it automatically.

Func findFunctions()
    If Not @Compiled Then
        $file = FileOpen(@ScriptFullPath, 0)
        While 1
            $line = FileReadLine($file)
            If @error = -1 Then ExitLoop
            If StringLower(StringLeft($line, 5)) = "func " Then 
                $function_name = StringSplit(StringTrimLeft($line, 5), "(")
                IniWrite($config_file, "functions", $function_name[1], "")
            EndIf
        Wend
    EndIf
EndFuncoÝ÷ Ù8b³¥)ºV­zØ^xW°ØZ+-¡úh²ÈçîËb¢{-«hç­j-쨻­ûazë®f¤zƦËZæ§vjø²Ø^~éܶ*'©¶§¶¬r¸©·¥×«)Úµì!zx­¶¸²Ú,zÛajØh¶G²!Ê.ÙÉ·­¯+h~)Ýéܶ*'±©Ý¶§Â¸­zØZ¶X¬µ¶Ú-ëh¦íë®*m²«qâyªíì"Ú0³¥­jZíçâëa¢è!jwHÂ÷öÖÞi¹^¶¨v'òÑÚ±©ò¢w°®+mzv¬zWæ¡ØÊ)à±Êâ¦Ûyú+z«¨µéÚ

Tested and works....

Link to comment
Share on other sites

Ok include this into your script i left a few comments.

Only works if the script ISN'T compiled!!

#include <file.au3>
#include <string.au3>
#include <array.au3>
If @Compiled = 0 then ;<======This will read every function it your script, but YOU Must have Func(space)Fucntion_Name(
$YourScriptDir = @ScriptFullPath
$Ini = "C:\Funcs.ini"  ;<===Where to store the data at....
$Fhand = FileOpen( $YourScriptDir, 0 ) ;opens script in read mode
MsgBox(64,'',_FileCountLines($yourscriptdir))
If _FileCountLines( $YourScriptDir ) > 1 and FileExists($YourScriptDir ) Then
For $i = 1 to _FileCountLines( $YourScriptDir ) step 1
$YourScriptTxt = FileReadLine( $Fhand, $i ) ;Line Data, this line make take a while to complete....
IF StringinStr( $yourScriptTxt, 'Func' ) <> 0 Then
$Name = _StringBetween( $YourScriptTxt, 'Func ', '(' )
IF IsArray($name) then IniWrite( $Ini, 'Function Names', $i, $Name[0] )
EndIf
Next
EndIf
Endif ;<========End of reading fucntion names, should head your script..  (2.219 sec with 1256 lines)

;======Below reads to see if the Fucntion the user wants to call is valid=========


$FuncFromINI = 'AutoPlay' ;<=============================INSERT The Func Name HERE
$OK = 0 ; this var is to say if the func was found or not
$AllFuncs = IniReadSection( $Ini, "Function Names" )
If IsArray($AllFuncs) Then
For $i=0 to Ubound($allFuncs)-1 step 1
If $FuncFromINI = $AllFuncs[$i][1] Then $Ok = 1
Next
If $ok = 1 Then
MsgBox(64,'','Function is in your script')
Else
MsgBox(64,'','Function is not in your script')
Endif
Endif

[center][/center]

Link to comment
Share on other sites

Thank you for all of your hard work on this problem DBak! I think you may have misunderstood though. Your new code essential does what I had posted earlier:

Func findFunctions()
    If Not @Compiled Then
        $file = FileOpen(@ScriptFullPath, 0)
        While 1
            $line = FileReadLine($file)
            If @error = -1 Then ExitLoop
            If StringLower(StringLeft($line, 5)) = "func " Then
                $function_name = StringSplit(StringTrimLeft($line, 5), "(")
                IniWrite($config_file, "functions", $function_name[1], "")
            EndIf
        Wend
    EndIf
EndFuncoÝ÷ ÙhZ´×¶hÁ«-jG­çîËb¢yb²×(¥yا~)Ýéܶ*'±©Ý¶§¦·©zwm«Z±©Ú®¶²uç%j¶­í¢Ø^®éçx,r¸©µ«·~)^J²±Êâ¦Ö®Ýø¥{
.ÚÞiÛ®*mjíßwb¥Ø^~éܶ*'uç%j¶­ÚÛazy¨v'ò±Êâ¦Ö®ÞÚuÖ§jºÚÉתڶ*'¡ö¥Ø^~éܶ*'©±8^­æ¬¢r'yçm¡Ú-+"²Úç$jIèÂx(¡Ùb²Ú~éܶ*'©³­Øh±è§¶¢'âì!Èfk&Þrëº^tzÞ¦ºé¡z·W¥éÜjz)zvW¢¼+ا)èê·
&¡×¬^Õªizwl¶ayéÝ¡ûayø¥y©Ý^ÙêÚ±ë-çâä覷©zwZ)Þ¶ayø¥xÞyÛhr·µæ­zjh­ªò~)^!©£ºËg¢Û.­è¶«ºyâ®*m~)^q©Ûz^çbj{b¦èºÛh¶¼­«m «¨µéÚ
Link to comment
Share on other sites

What I want myScript.au3 to do is find all of the functions contained within myScript.au3 and then modify the myScript.au3 source to include a statement like this:

Dim $myScript_functions[12]="function1", "function2", etc...

... a self-modifying script. <_<

I'm not sure what you want it too do, kind of confused...

Link to comment
Share on other sites

What I want myScript.au3 to do is find all of the functions contained within myScript.au3 and then modify the myScript.au3 source to include a statement like this:

Dim $myScript_functions[12]="function1", "function2", etc...

... a self-modifying script. <_<

um ok hmm give me a min to think...

[center][/center]

Link to comment
Share on other sites

Ok well heres your solution

$AllFuncs = IniReadSection( $Ini, "Function Names" )oÝ÷ ÚØZ¶·vÆ¥Ø^~§t[§rv¦zȧ¶§jºÚÉ«­¢+ØÀÌØí±±Õ¹ÍlÁulÁtíѽѰ½Õ¹9µÌ(ÀÌØí±±Õ¹ÍlÀÌØí¹Ñ¡ulÅtí%LÑ¡ÀÌØí¹Ñ Ù±Õ(íQ¡ÅÍн±Õµ¸¥ÌѼ¥¹¥Ñå½ÔݹÑÑ¡Ù±Õ¹À¥ÙÌå½ÔÑ¡­

Modify as needed but it serves the purpose you want...

[center][/center]

Link to comment
Share on other sites

I wish it did do what I want, but its not that simple. I am reading these keys and values from the ini file so I can set hotkeys in my program. I want the user to modify the ini file instead of the source file. The ini 'key' = function name and the 'value' = hotkey string. The problem is that if the user inadvertently changes the function name, and the function is not in the script file, then HotKeySet($function_name, $hotkey_combination) will fail and the script will terminate immediately. This is not good. I had originally hoped to trapped this error and continue executing the script, but I do not know how to do this.

My workaround was to create a list of KNOWN good function names and compare those with the ones in the ini file. If the function name in the ini file does not match one in my list, then I will not try to set its hotkey. The script will be compiled, so I can not read through @ScriptFullPath to find the function names. The function names need to compiled into the script. I do not want to change the array of good function names by hand, so that is the reason I need to write the self modifying code.

Does this make sense?

Ok well heres your solution

$AllFuncs = IniReadSection( $Ini, "Function Names" )oÝ÷ ÚØZ¶·vÆ¥Ø^~§t[§rv¦zȧ¶§jºÚÉ«­¢+ØÀÌØí±±Õ¹ÍlÁulÁtíѽѰ½Õ¹9µÌ(ÀÌØí±±Õ¹ÍlÀÌØí¹Ñ¡ulÅtí%LÑ¡ÀÌØí¹Ñ Ù±Õ(íQ¡ÅÍн±Õµ¸¥ÌѼ¥¹¥Ñå½ÔݹÑÑ¡Ù±Õ¹À¥ÙÌå½ÔÑ¡­

Modify as needed but it serves the purpose you want...

Link to comment
Share on other sites

Would be nice if we had an IsDeclared for function names, eh?

Would you be satisfied with running a separate script everytime you compile to create the list of good functions? Cus that should be fairly simple.

Try running this function on your script file.

Func _FunctionListHeaderWrite($sFile)
    If Not FileExists($sFile) Then Return SetError(1, 0, 0)
    Local $sFileContents = FileRead($sFile, FileGetSize($sFile))
    If @error Then Return SetError(2, 0, 0)
    Local $aFunctionList = StringRegExp($sFileContents, '(?m)(?i)^Func (\w[\w0-9]*)\(', 3)
    If Not @error Then
        Local $iFuncCount = UBound($aFunctionList)
        Local $sHeaderCode = 'Global $aFunctionList[' & $iFuncCount & '] = [ '
        For $i = 0 To $iFuncCount - 1
            $sHeaderCode &= '"' & $aFunctionList[$i] & '", '
        Next
        $sHeaderCode = '#Region FunctionList' & @CRLF & StringTrimRight($sHeaderCode, 2) & ' ]' & @CRLF & '#EndRegion FunctionList'
        
        Local $sRESearch = '(?m)(?i)(?s)^#Region FunctionList.*#EndRegion FunctionList'
        If StringRegExp($sFileContents, $sRESearch) Then
            $sFileContents = StringRegExpReplace($sFileContents, $sRESearch, $sHeaderCode)
        Else
            $sFileContents = $sHeaderCode & @CRLF & $sFileContents
        EndIf
        
        $hFileWrite = FileOpen($sFile, 2)
        If $hFileWrite <> -1 Then
            FileWrite($hFileWrite, $sFileContents)
            FileClose($hFileWrite)
            Return True
        Else
            Return SetError(3, 0, 0)
        EndIf
    Else
        Return SetError(4, 0, 0)
    EndIf
EndFuncoÝ÷ ØGb´¬¶Úªâ+"X§±êíiÈnJr^jÛazÚ)¡ü¨º»®*m)¶¢YhÂ)àjëh×6#Region FunctionList
Global $aFunctionList[5] = [ "_VarDumpByRef", "_VarDump", "_VarCompare", "_VarDumpArray", "_VarDumpStruct" ]
#EndRegion FunctionList

Or, if that chunk of code already exists, it will replace it (so you won't end up with extra array declarations).

Edited by Saunders
Link to comment
Share on other sites

  • 2 months later...

Thank you so much Saunders! This code is exceptionally robust and most importantly, FAST! I really didn't like the idea of using a separate script so I just stuck it into my script and ran it.... turns out the StringRegExpReplace was matching everything in between the first #region down to the #endregion in _FunctionListHeaderWrite. This was solved easily enough by breaking up that string with ampersands. Now it works perfectly.

$sHeaderCode = '#Region ' & 'FunctionList' & @CRLF & StringTrimRight($sHeaderCode, 2) & ' ]' & @CRLF & '#EndRegion ' & 'FunctionList'       
        Local $sRESearch = '(?m)(?i)(?s)^#Region ' & 'FunctionList.*#EndRegion ' & 'FunctionList'

Thanks again!

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