Jump to content
water

Get the name of the last called function

Recommended Posts

In my UDF I store the name of the running function in a Global variable:

Global $__sFunctionName
_Function1()
ConsoleWrite($__sFunctionName & @CRLF)
_Function2()
ConsoleWrite($__sFunctionName & @CRLF)
Exit

Func _Function1()
    $__sFunctionName = "_Function1"
    _Function2()
EndFunc

Func _Function2()
    $__sFunctionName = "_Function2"
    ; ...
EndFunc

What I get from this script is two times "_Function2".

I would like to get the name of the function I called from the main script. Means: "_Function1" and "_Function2" from the example above.
Is  this possible with AutoIt?


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2019-10-24 - Version 1.4.14.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2019-11-30 - Version 1.4.0.0) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki
Task Scheduler (NEW 2019-12-03 - Version 1.5.1.0) - Download - General Help & Support - Wiki

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

water,

Something like this will give you the whole function chain:

Global $__sFunctionName
_Function1()
ConsoleWrite($__sFunctionName & @CRLF)
$__sFunctionName = ""
_Function2()
ConsoleWrite($__sFunctionName & @CRLF)
$__sFunctionName = ""
Exit

Func _Function1()
    $__sFunctionName &= ":+_Function1"
    _Function2()
    $__sFunctionName &= ":-_Function1"
EndFunc

Func _Function2()
    $__sFunctionName &= ":+_Function2"
    ; ...
    $__sFunctionName &= ":-_Function2"
EndFunc

Any 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

 

Share this post


Link to post
Share on other sites

My 2 cts... and all those parentheses in ternary function, why did you disappear... again :P

Global $__sFN
_Function1()
_CW()

_Function2()
_CW()
Exit

Func _Function1()
    $__sFN = ($__sFN = "" ? "_Function1" : $__sFN)
    _Function2()
EndFunc

Func _Function2()
    $__sFN = ($__sFN = "" ? "_Function2" : $__sFN)
    ; ...
EndFunc

Func _CW()
    ConsoleWrite($__sFN & @CRLF)
    $__sFN = ""
EndFunc

Though it looks simpler without ternary :

Global $__sFN
_Function1()
_CW()

_Function2()
_CW()
Exit

Func _Function1()
    If $__sFN = "" Then $__sFN = "_Function1"
    _Function2()
EndFunc

Func _Function2()
    If $__sFN = "" Then $__sFN = "_Function2"
    ; ...
EndFunc

Func _CW()
    ConsoleWrite($__sFN & @CRLF)
    $__sFN = ""
EndFunc

 

Edited by pixelsearch

Share this post


Link to post
Share on other sites
Just now, Nine said:

Or place your $__sFunctionName = "..." as the last statement of the function, instead as the first ?

Not sure he can do that. What about one or several Returns within the functions ?
It seems better to place it at line #1 of each function, kind of... "Water was there" :)

Edit : this answer wasn't supposed to be placed here but in the last part of the previous post... anyway, it's done now.

Edited by pixelsearch

Share this post


Link to post
Share on other sites
24 minutes ago, pixelsearch said:

Not sure he can do that. What about one or several Returns within the functions ?

If you read his post, he wants  "_Function1" and "_Function2"  only, not more...unless I didn't understand him correctly.  Known to have done that before :)

Share this post


Link to post
Share on other sites

Generally speaking:

I want every function (e.g. Func1) that is called from the main script to set $__sFN. If this function calls another function (e.g Func2) I do not want to modify $__sFN.
But: If Func2 is called from the mains cript I want to set $__sFN to Func2.
I just want the first level of the function chain.

What is it for?
When a function returns an error to the main script I want to call another function that translates @error to the full error message. As the error codes start with 1 for every function I need the name of the function. Either in a global variable or provided by the user.
You will find a stripped down example

If the global variable needs a lot of coding in the main script, I just could use unique error numbers (then no function name would be needed)

Spoiler
#include <MsgBoxConstants.au3>

Global $__oTS_Error
Global $__sTS_FunctionName = ""

Global $oService = _TS_Open()
If @error <> 0 Then Exit MsgBox($MB_ICONERROR, "Task Scheduler UDF", "Error connecting to the Task Scheduler Service. @error = " & @error & ", @extended = " & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
Exit

Func _TS_Open($sComputer = Default, $sUser = Default, $sDomain = Default, $sPassword = Default)
    $__sTS_FunctionName = "_TS_Open"
    Local $oTS_Service
    _TS_ErrorNotify(4)
    If @error Then Return SetError(1, @error, 0)
    $oTS_Service = ObjCreate("Schedule.Service")
    If @error Then Return SetError(2, @error, 0)
    $oTS_Service.Connect($sComputer, $sUser, $sDomain, $sPassword)
    If @error Then Return SetError(3, @error, 0)
    Return $oTS_Service
EndFunc   ;==>_TS_Open

Func _TS_ErrorNotify($iDebug, $sDebugFile = "")
    If Not IsInt($iDebug) Or $iDebug < -1 Or $iDebug > 4 Then Return SetError(1, 0, 0)
    $__iTS_Debug = $iDebug
    ; A COM error handler will be initialized only if one does not exist
    If ObjEvent("AutoIt.Error") = "" Then
        $__oTS_Error = ObjEvent("AutoIt.Error", "__TS_ErrorHandler")         ; Creates a custom error handler
        If @error <> 0 Then Return SetError(2, @error, 0)
        Return SetError(0, 1, 1)
    ElseIf ObjEvent("AutoIt.Error") = "__TS_ErrorHandler" Then
        Return SetError(0, 0, 1)         ; COM error handler already set by a call to this function
    Else
        Return SetError(3, 0, 0)         ; COM error handler already set to another function
    EndIf
    Return 1
EndFunc   ;==>_TS_ErrorNotify

; #FUNCTION# ====================================================================================================================
; Name ..........: _TS_ErrorText
; Description ...: Returns the full error message text for a function and error number.
; Syntax.........: _TS_ErrorText($iErrorNumber[, $sErrorFunction = $__sTS_FunctionName])
; Parameters ....: $iErrorNumber   - Integer of the error returned by a function call of this UDF
;                  $sErrorFunction - Name of the function to retrieve the error message from.
;                    Default is the function name which is set by the function istself
; Return values .: Success - Error text for the error number
;                  Failure - Returns $sErrorFunction and sets @error:
;                  |1 - Specified function could not be found. The return value is set to $sErrorFunction
;                  |2 - Specified error number could not be found for the specified function
; Author ........: water
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _TS_ErrorText($iErrorNumber, $sErrorFunction = $__sTS_FunctionName)
    Local $bFunctionFound = False
    Local $aErrorMessages[][] = [ _
            ["_TS_Open", 1, "Error creating the COM error handler. @extended is set to the error code returned by _TS_ErrorNotify"], _
            ["_TS_Open", 2, "Error creating the Task Scheduler Service. @extended is set to the COM error code"]]
    For $i = 0 To UBound($aErrorMessages, 1) - 1
        If $aErrorMessages[$i][0] = $sErrorFunction Then
            $bFunctionFound = True
            If $aErrorMessages[$i][1] = $iErrorNumber Then Return $aErrorMessages[$i][2]
        EndIf
    Next
    If $bFunctionFound = False Then Return SetError(1, 0, $sErrorFunction) ; Function not found
    Return SetError(2, 0, $sErrorFunction) ; Error message not found
EndFunc   ;==>_TS_ErrorText

 

 


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2019-10-24 - Version 1.4.14.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2019-11-30 - Version 1.4.0.0) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki
Task Scheduler (NEW 2019-12-03 - Version 1.5.1.0) - Download - General Help & Support - Wiki

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites
3 minutes ago, water said:

I want every function (e.g. Func1) that is called from the main script to set $__sFN. If this function calls another function (e.g Func2) I do not want to modify $__sFN.
But: If Func2 is called from the mains cript I want to set $__sFN to Func2.
I just want the first level of the function chain.

Then my solution should work :)

Share this post


Link to post
Share on other sites
1 hour ago, pixelsearch said:

Not sure he can do that. What about one or several Returns within the functions ?
It seems better to place it at line #1 of each function, kind of... "Water was there" :)

Exact :) As you can see from the example script I posted above.

Your solution works as expected. Downside is that I have to reset $__sFN after each function call in the main script.
Will need to think about the way to go 🤔


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2019-10-24 - Version 1.4.14.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2019-11-30 - Version 1.4.0.0) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki
Task Scheduler (NEW 2019-12-03 - Version 1.5.1.0) - Download - General Help & Support - Wiki

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

You could use @extended as the function name and reason. Then have the user pass @extended to your error function helper?

Func _TS_Open()
    
    ; <Checking stuff>
    If @error Then Return SetError(1, "_TS_Open - Application doesn't exist", False)
    
    ; Internal Function error
    Local $ret = _TS_Internals()
    If @error Then Return SetError(@error, @extended, $ret)
    
EndFunc

Func _TS_Internals()
    
    ; Some COM thing
    Return SetError(2, "_TS_Internals - COM Error -2146424242", False)
    
EndFunc

All my code provided is Public Domain... but it may not work. ;) Use it, change it, break it, whatever you want.

Share this post


Link to post
Share on other sites

@Nine: now that water explained that it was "Generally speaking" (which seemed obvious to me) and there could be dozen of functions involved, do you see "_Function 1" written in the console, if he does it your way, i.e. placing $__sFunctionName = "..." as the last statement of the function, for example :

Global $__sFunctionName, $x = 1
_Function1()
ConsoleWrite($__sFunctionName & @CRLF)

Func _Function1()
    If $x <> 0 Then
        Return SetError(1, 0, "someone ruined my code !")
    EndIf
    $__sFunctionName = "_Function1"
EndFunc

 

Just now, water said:

If the global variable needs a lot of coding in the main script...

Global $__sFN
_Function1()
$__sFN = ""

_Function2()
$__sFN = ""

Func _Function1()
    If $__sFN = "" Then $__sFN = "_Function1"
    ; ...
EndFunc

Func _Function2()
    If $__sFN = "" Then $__sFN = "_Function2"
    ; ...
EndFunc

imho that's not a lot of coding, if you really need it. Anyway Water, you'll choose the best way... as usual :)

Edit: your alternative to "use unique error numbers (then no function name would be needed)" should certainly work too, though one can easily mix error numbers ranges assigned to each function, especially if there are plenty.

Edited by pixelsearch

Share this post


Link to post
Share on other sites

the need to report the function name is something i encountered many times, mainly for debugging purposes. the solution has always been to set the function name as a string to a variable, where the obvious downside is that it has to be in each and every function, which is tedious and could be easily missed thus altogether crippled. a better solution would be in the hands of the AutoIt core developers - to add a macro similar to @ScriptLineNumber that would store the function name.

Share this post


Link to post
Share on other sites

I hope this isn't complete nonsense. I've been sitting on the PC since the early morning and I'm pretty done 😴.

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7
#include <Array.au3>

Global $__aFunctionName[0]

_Function1()
_ArrayDisplay($__aFunctionName, "_Function1 - Stack") ; *** just for display
ConsoleWrite("> FunctionName = " & _GetFunctionName() & @CRLF) ; *** just for display

_Function2()
_ArrayDisplay($__aFunctionName, "_Function2 - Stack") ; *** just for display
ConsoleWrite("> FunctionName = " & _GetFunctionName() & @CRLF) ; *** just for display

_Function3()
_ArrayDisplay($__aFunctionName, "_Function3 - Stack") ; *** just for display
ConsoleWrite("> FunctionName = " & _GetFunctionName() & @CRLF) ; *** just for display

Exit

Func _Function1()
    _ArrayAdd($__aFunctionName, "_Function1")
    _Function2()
EndFunc

Func _Function2()
    _ArrayAdd($__aFunctionName, "_Function2")
EndFunc

Func _Function3()
    _ArrayAdd($__aFunctionName, "_Function3")
    _Function1()
    _Function2()
EndFunc

Func _GetFunctionName()
    Local $sFuncName = $__aFunctionName[0]
    For $i = UBound($__aFunctionName)-1 To 0 Step -1
        _ArrayDelete($__aFunctionName, $i)
    Next
    Return $sFuncName
EndFunc

 


Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Share this post


Link to post
Share on other sites
16 hours ago, orbs said:

a better solution would be in the hands of the AutoIt core developers - to add a macro similar to @ScriptLineNumber that would store the function name.

I would love to see that before dying - a macro whose return value doesn't change when reassigned  :)

Share this post


Link to post
Share on other sites
On 10/31/2019 at 7:05 PM, water said:

I just want the first level of the function chain.

maybe by using a static variable within a dedicated function instead of a global variable?

; Global $__sFunctionName
_Function1()
ConsoleWrite(_FunctionName() & @CRLF) ; $__sFunctionName & @CRLF)
_Function2()
ConsoleWrite(_FunctionName() & @CRLF) ; $__sFunctionName & @CRLF)
Exit

Func _Function1()
    _FunctionName("_Function1") ; $__sFunctionName = "_Function1"
    _Function2()
EndFunc   ;==>_Function1

Func _Function2()
    _FunctionName("_Function2") ; $__sFunctionName = "_Function2"
    ; ...
EndFunc   ;==>_Function2

; stores a function name only if there is not already one stored
; Call this function without parameter to get stored value and free the 'stack'
Func _FunctionName($sFuntionName = '')
    Static Local $sStack = ''
    Local $sFirstLevelFunctionName = ''
    If $sFuntionName = '' Then ; get stored function name
        $sFirstLevelFunctionName = $sStack
        $sStack = '' ; and free stack
        Return $sFirstLevelFunctionName
    Else ; store function name (only if $sStack is empty)
        If $sStack = '' Then $sStack = $sFuntionName
    EndIf
EndFunc   ;==>_FunctionName

 

Edited by Chimp
simplified the function _FunctionName() a bit

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

Share this post


Link to post
Share on other sites

Thanks for your efforts! Looks good!
I can't test at the moment, so I only could read and try to understand your code.
Am I right that if I do not call _FunctionName() no new function name will be set?
I modified your example so that after calling _Function1 I call _Function2 from the main script without calling _FunctionName() between this two calls.
So I think _Function2 wont't be set.

_Function1()
_Function2()
ConsoleWrite(_FunctionName() & @CRLF) ; $__sFunctionName & @CRLF) ; <== I think this line will now return "_Function1"
Exit

Func _Function1()
    _FunctionName("_Function1")
    _Function2()
EndFunc   ;==>_Function1

Func _Function2()
    _FunctionName("_Function2")
    ; ...
EndFunc   ;==>_Function2

; Stores a function name only if there is not already one stored
; Call this function without parameter to get stored value and free the 'stack'
Func _FunctionName($sFuntionName = '')
    Static Local $sStack = ''
    Local $sFirstLevelFunctionName = ''
    If $sFuntionName = '' Then ; get stored function name
        $sFirstLevelFunctionName = $sStack
        $sStack = '' ; and free stack
        Return $sFirstLevelFunctionName
    Else ; Store function name (only if $sStack is empty)
        If $sStack = '' Then $sStack = $sFuntionName
    EndIf
EndFunc   ;==>_FunctionName

 


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2019-10-24 - Version 1.4.14.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2019-11-30 - Version 1.4.0.0) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki
Task Scheduler (NEW 2019-12-03 - Version 1.5.1.0) - Download - General Help & Support - Wiki

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Thanks everyone for your efforts!
After playing with all the different approaches I still have the impression that it is some overhead (in coding and during run time) just to get the name of the currently running function. Pitty there is no macro for this.

I have played with a very simple solution: The error number needs to be unique in the scope of the UDF.
Now the error numbers are created like this nnmm: nn is the number assigned to a function, mm is the existing error number. So @error = 5 in the 15th function of the UDF becomes @error = 1505 (the limitation of 99 errors shouldn't be a problem).
I have already updated the TaskScheduler UDF and all example scripts now provide @error and @extended and the full error text.

Hope to soon release the new version for you to play with!

Thanks for taking the time to find  a solution :thumbsup:


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2019-10-24 - Version 1.4.14.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2019-11-30 - Version 1.4.0.0) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki
Task Scheduler (NEW 2019-12-03 - Version 1.5.1.0) - Download - General Help & Support - Wiki

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

yes, right
first function call "freeze" the "first level" function name until you will 'free' it by calling the _functionname() function (without parameters)
P.S.
I don't know if I understood myself ...  :lol:

 

p.p.s

opsss, @water posted the above post just a bit before mine (I hadn't time to read it)

Edited by Chimp
added p.p.s. comment

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

Share this post


Link to post
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

×
×
  • Create New...