2

Say I call a function that uses a byref modifier. Once in the function, I want to fetch the string value of the passed variable.

myvar := "george"
passit(myvar)

passit(byref whatvar){
    msgbox % %whatvar%    ;I should see a messagebox reporting the string "myvar"
}

Getting the string value of the variable works fine if I'm not passing the variable byref.

Maybe I'm going about this the wrong way. I want the function to know the string name for the variable being referenced.

bgmCoder
  • 6,205
  • 8
  • 58
  • 105

2 Answers2

2

This approch uses the buildin ListLines-Command to access the needed metadata.

The command ListLines opens the main window of the current script and displays the last executed script lines. Content looks like this:

Script lines most recently executed (oldest first).  Press [F5] to refresh.  The seconds elapsed between a line and the one after it is in parentheses to the right (if not 0).  The bottommost line's elapsed time is the number of seconds since it executed.

---- D:\Eigene_Dateien\ahk scripts\test3.ahk
002: myvar := "george"
003: passit(myvar)  
007: MsgBox,GetOriginalVariableNameForSingleArgumentOfCurrentCall(A_ThisFunc)
012: lines := ListLines()

Press [F5] to refresh.

This data can be parsed to extract the wanted information (what is passed to 'passit'). One problem here is, that there is no buildin programmatically way of access this info. The function ListLines overrides temporary User32.ShowWindow and User32.SetForgroundWindow to return simply true, so the buildin command ListLines can be used without displaying its window (Might produce problems with multithreaded scripts). From this 'hidden' window its text is received and cleaned up. Function is written by Lexikos (http://www.autohotkey.com/board/topic/20925-listvars/#entry156570 http://www.autohotkey.com/board/topic/58110-printing-listlines-into-a-file/#entry365156).

GetOriginalVariableNameForSingleArgumentOfCurrentCall extracts the variable name with a regular expression, which searches the first call to the passed function above the current call (call to GetOriginalVariableNameForSingleArgumentOfCurrentCall).

  myvar := "george"
  passit(myvar)
return

passit(whatvar){
  msgbox % GetOriginalVariableNameForSingleArgumentOfCurrentCall(A_ThisFunc)
}

GetOriginalVariableNameForSingleArgumentOfCurrentCall(callerFuncName)
  {
  lines := ListLines()
  pattern = O)%callerFuncName%\((.*?)\).*?%A_ThisFunc%\(.*?\)
  RegExMatch(lines, pattern, match)
  return match[1]
  }

; Originally written by Lexikos / Copy of ListGlobalVars http://www.autohotkey.com/board/topic/20925-listvars/#entry156570
; with modifications from here http://www.autohotkey.com/board/topic/58110-printing-listlines-into-a-file/#entry365156
; Tested/Modified for AHK Unicode 64bit v1.1.14.03
ListLines()
{
    static hwndEdit, pSFW, pSW, bkpSFW, bkpSW
    ListLines Off

    if !hwndEdit
    {
        dhw := A_DetectHiddenWindows
        DetectHiddenWindows, On
        Process, Exist
        ControlGet, hwndEdit, Hwnd,, Edit1, ahk_class AutoHotkey ahk_pid %ErrorLevel%
        DetectHiddenWindows, %dhw%

        astr := A_IsUnicode ? "astr":"str"
        ptr := A_PtrSize=8 ? "ptr":"uint"
        hmod := DllCall("GetModuleHandle", "str", "user32.dll")
        pSFW := DllCall("GetProcAddress", ptr, hmod, astr, "SetForegroundWindow")
        pSW := DllCall("GetProcAddress", ptr, hmod, astr, "ShowWindow")
        DllCall("VirtualProtect", ptr, pSFW, ptr, 8, "uint", 0x40, "uint*", 0)
        DllCall("VirtualProtect", ptr, pSW, ptr, 8, "uint", 0x40, "uint*", 0)
        bkpSFW := NumGet(pSFW+0, 0, "int64")
        bkpSW := NumGet(pSW+0, 0, "int64")
    }

    if (A_PtrSize=8) {
        NumPut(0x0000C300000001B8, pSFW+0, 0, "int64")  ; return TRUE
        NumPut(0x0000C300000001B8, pSW+0, 0, "int64")   ; return TRUE
    } else {
        NumPut(0x0004C200000001B8, pSFW+0, 0, "int64")  ; return TRUE
        NumPut(0x0008C200000001B8, pSW+0, 0, "int64")   ; return TRUE
    }

    ListLines

    NumPut(bkpSFW, pSFW+0, 0, "int64")
    NumPut(bkpSW, pSW+0, 0, "int64")

    ; Retrieve ListLines text and strip out some unnecessary stuff:
    ControlGetText, ListLinesText,, ahk_id %hwndEdit%
    RegExMatch(ListLinesText, ".*`r`n`r`n\K[\s\S]*(?=`r`n`r`n.*$)", ListLinesText)
    StringReplace, ListLinesText, ListLinesText, `r`n, `n, All

    ListLines On
    return ListLinesText  ; This line appears in ListLines if we're called more than once.
}
hippibruder
  • 168
  • 4
  • Say, that seems to work. Thank you! There is a lot going on there, can you explain what is happening? Just to make it even more interesting, I did this: `global myvar msgbox % GetOriginalVariableNameForSingleArgumentOfCurrentCall(A_ThisFunc) . "=" . myvar` to get the messagebox to say : `myvar=george` – bgmCoder Jun 04 '14 at 18:50
  • 1
    @BGM I have added explanation – hippibruder Jun 05 '14 at 09:09
  • Excellent! Thank you very much - I understand and that to me is worth as much as the snippet. – bgmCoder Jun 05 '14 at 13:31
1

The closest to what you would want...? This reminds of a question I had.
See http://ahkscript.org/boards/viewtopic.php?f=14&t=3651

myvar:="test"
passit("myvar") ; display value, and change it

msgbox % "myvar = " myvar

passit(byref whatvar){ ; no more need for byref here...
    msgbox % whatvar " = " (%whatvar%)
    %whatvar%:="blah" ; edit globalvar "hack"
}
Joe DF
  • 5,438
  • 6
  • 41
  • 63
  • JoeDF - that is close. Problem is I want to pass the variable as a variable, not as a string. Then I want the function to be able to know the string name of the passed variable. – bgmCoder Jun 02 '14 at 13:39
  • @BGM Hmm I don't know if it's possible... How are the variables actually created? – Joe DF Jun 02 '14 at 22:28
  • @BGM ok, i see... if it absolutely can not be passed as a string then, I really don't know if it's possible... – Joe DF Jun 03 '14 at 01:39
  • I think he needed the `byref` so that `passit` could modify the specified variable.               I agree that it would be convenient if there were some construct for getting the name of a variable as a string, but that’s for the *Wish List* section of the forum… if it hasn’t already been suggested—I can’t determine if it has or not. – Synetech Apr 09 '16 at 00:26