dmp() - Advanced debug function for AutoHotKey

Post your working scripts, libraries and tools for AHK v1.1 and older
0biWanKenobi

dmp() - Advanced debug function for AutoHotKey

02 May 2015, 10:50

I wrote this debug function for AutoHotKey to have a better handling with my AutoHotKey debugging workflow.

It depends on AutoHotKey_L.

Usage: dmp(yourVar)

Result:
http://guresicpark.de/sites/default/fil ... es/dmp.png

Features:
- multidimensioal arrays are displayed serialized
- dumped lines can be copied & directly pasted in your AutoHotKey script
- ability to cancel dmp-loop (via Button Cancel or via ESC-Key)
- continue dmp-loop via Button Continue or via Enter-Key



How to install:

In your main script directory create a folder \lib and place dmp.ahk there.

Example:
C:\myscript\lib\dmp.ahk

After you have finished this you can use dmp() anywhere in your script.

Example code:

Code: Select all

car1 := {model: "Toyota", color:"red", speed:100}
car2 := {model: "Chrysler", color:"white", speed:200}
car3 := {model: "BMW", color:"Black", speed:180}

driver1 := {name: "Peter", age:"31", salary:1800, car:car3}
driver2 := {name: "Jeff", age:"38", salary:2200, car:car1}
driver3 := {name: "Jim", age:"40", salary:1950, car:nil}
driver4 := {name: "Frank", age:"22", salary:1650, car:car2}

drivers := [driver1, driver2, driver3, driver4]

for deltaDriver, driverItem in drivers
{
    dmp(driverItem)
}

dmp(drivers)
Download: dmp.ahk

Homepage: http://guresicpark.de/autohotkey/dmp
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: dmp() - Advanced debug function for AutoHotKey

02 May 2015, 11:35

I'm interested in you _dmpListLines() func

It looks like you are overwriting the memory addresses so SetForegroundWindow and ShowWindow won't be called, so the end user doesn't see the ListLines window.

But what are those values that you are using? Where did you get them and what do they represent?

Code: Select all

; Overwrite SetForegroundWindow() and ShowWindow() temporarily:
    NumPut(0x0004C200000001B8, pSFW+0, 0, "int64")  ; return TRUE
    NumPut(0x0008C200000001B8, pSW+0, 0, "int64")   ; return TRUE
edit/
whoops further searching reveals that Lexikos originally wrote this function, maybe he can chime in

vasili111
Posts: 747
Joined: 21 Jan 2014, 02:04
Location: Georgia

Re: dmp() - Advanced debug function for AutoHotKey

03 May 2015, 01:25

Thank you for script. Useful in debugging!
DRAKON-AutoHotkey: Visual programming for AutoHotkey.
Guest

Re: dmp() - Advanced debug function for AutoHotKey

03 May 2015, 08:46

dmp 1.2

- bugfixes
- output improved
- new feature: now you can output multiple variables with one dmp call, example:

Code: Select all

aNames := ["Jeff", "Peter", "Jim"]
sText := " Lorem ipusm "

dmp(aNames, sText, Trim(sText))
Result: http://guresicpark.de/sites/default/fil ... s/dmp2.png

Download: dmp.ahk
Homepage: http://guresicpark.de/autohotkey/dmp
User avatar
joedf
Posts: 8953
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: dmp() - Advanced debug function for AutoHotKey

04 May 2015, 07:36

Cool, sorta like PHP's vardump
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: dmp() - Advanced debug function for AutoHotKey

04 May 2015, 08:34

@guest3456
Better ask Lexikos about 0x0004C200000001B8
ref: ListVars
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
toralf
Posts: 868
Joined: 27 Apr 2014, 21:08
Location: Germany

Re: dmp() - Advanced debug function for AutoHotKey

04 May 2015, 11:18

Could you imagine a way to show if a var contains also space characters? E.g. Add >< around the content of var when any amount of white space exists at the start or end of the content.
ciao
toralf
0biWanKenobi

Re: dmp() - Advanced debug function for AutoHotKey

04 May 2015, 11:58

dmp 1.21
- nicer output
- performance tweaks
- small code clean up

Download: dmp.ahk
Homepage: http://guresicpark.de/autohotkey/dmp
0biWanKenobi

Re: dmp() - Advanced debug function for AutoHotKey

04 May 2015, 12:10

Hello toralf,
it is already implented with quotes -> "
Try this:

Code: Select all

sText1 := "Lorem ipsum dolor sit amet"

sText2 := "    Lorem ipsum dolor sit amet"

sText3 := "Lorem ipsum dolor sit amet    "

sText4 := "    Lorem ipsum dolor sit amet    "

sText5=
(join`r`n

	Lorem ipsum dolor sit amet,
	consetetur sadipscing elitr,
	sed diam nonumy eirmod tempor.
)

dmp(sText1, sText2, sText3, sText4, sText5)
And dmp should show you this result:

Code: Select all

>>>>> sText1

    sText1 := "Lorem ipsum dolor sit amet"

<<<<<



>>>>> sText2

    sText2 := "    Lorem ipsum dolor sit amet"

<<<<<



>>>>> sText3

    sText3 := "Lorem ipsum dolor sit amet    "

<<<<<



>>>>> sText4

    sText4 := "    Lorem ipsum dolor sit amet    "

<<<<<



>>>>> sText5

    sText5 :=
"
	Lorem ipsum dolor sit amet,
	consetetur sadipscing elitr,
	sed diam nonumy eirmod tempor."

<<<<<
You can even copy dmp result and copy it in your AutoHotKey script.
0biWanKenobi

Re: dmp() - Advanced debug function for AutoHotKey

05 May 2015, 12:38

dmp 1.23
- code cleanup
- New feature: alphabetically sorted output, example:

>>>>> drivers

drivers[1]["age"] := "31"
drivers[1]["car"]["color"] := "Black"
drivers[1]["car"]["model"] := "BMW"
drivers[1]["car"]["speed"] := 180
drivers[1]["name"] := "Peter"
drivers[1]["salary"] := 1800

6 elements for drivers <<<<<

Download: dmp.ahk

Homepage: http://guresicpark.de/autohotkey/dmp
0biWanKenobi

Re: dmp() - Advanced debug function for AutoHotKey

17 May 2015, 06:02

dmp 1.25
- window is now resizeable
- added button "Reload scirpt" for restarting debugged script after modifying script file

Download: dmp.ahk
Homepage: http://guresicpark.de/autohotkey/dmp
pmobin
Posts: 17
Joined: 14 Apr 2016, 12:50

Re: dmp() - Advanced debug function for AutoHotKey

19 Aug 2020, 22:33

Hi all,

Does dmp.ahk exist anywhere? The .de site is down.

Thanks,
FM
User avatar
joedf
Posts: 8953
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: dmp() - Advanced debug function for AutoHotKey

21 Aug 2020, 07:34

From: https://web.archive.org/web/20160121062531/http://guresicpark.de/autohotkey/dmp
but the download link was not archived... :(

EDIT: I found a copy here:
https://github.com/Ixiko/AHK-libs-and-classes-collection/blob/eef70b9dc1a5a712c41f2d218dd625de93dc67fc/lib-a_to_h/dmp.ahk
Included as a code in the bottom for archival purposes.

function dmp() 1.25 for AutoHotKey

Usage: dmp(yourVar)

Result:
dmp.png
dmp.png (10.02 KiB) Viewed 3327 times


Features:
  • multidimensioal arrays are displayed serialized
  • dumped lines can be copied & directly pasted in your AutoHotKey script
  • ability to cancel dmp-loop (via Button Cancel or via ESC-Key)
  • continue dmp-loop via Button Continue or via Enter-Key
How to install:

In your main script directory create a folder \lib and place dmp.ahk there.

Example:

C:\myscript\lib\dmp.ahk

After you have finished this you can use dmp() anywhere in your script.

Example code:

Code: Select all

car1 := {model: "Toyota", color:"red", speed:100}
car2 := {model: "Chrysler", color:"white", speed:200}
car3 := {model: "BMW", color:"Black", speed:180}

driver1 := {name: "Peter", age:"31", salary:1800, car:car3}
driver2 := {name: "Jeff", age:"38", salary:2200, car:car1}
driver3 := {name: "Jim", age:"40", salary:1950, car:nil}
driver4 := {name: "Frank", age:"22", salary:1650, car:car2}

drivers := [driver1, driver2, driver3, driver4]

for deltaDriver, driverItem in drivers
{
    dmp(driverItem)
}

dmp(drivers)
Download dmp.ahk

Code: Select all

; http://the-automator.com/download/dmp.ahk
; dmp Version 1.25
; By ObiWanKenobi
; Visit guresicpark.de for dmp updates
; May 8, 2015
;~ http://guresicpark.de/autohotkey/dmp

dmp(pVar*) {
    static _iCallCount := 0

    ; set x as basic variable name
    aVarnames := ["x"]

    ; now search variable name
	sLines := _dmpListLines()
    aLines := StrSplit(sLines, "`n", "`r")
    iLinesLength := aLines.Length()
    for deltaLines, LinesItem in aLines
    {
        sCurrentLine := aLines[(aLines.Length()+1)-deltaLines]
        if RegExMatch(sCurrentLine, "i)dmp\s*\(.*\)", match)
        {
            RegExMatch(sCurrentLine, "^(\d+)\:", match)
            iLineNumber := match1 + 0
            aVarnames := _dmpGetVarnames(sCurrentLine)
            break
        }
    }

    ; start dump
    _iCallCount++
    for deltaVar, VarItem in pVar
    {
        global gliRowCount := 0
        global glsRet=
        _dmp(VarItem, aVarnames[deltaVar])
        glsRet := LTrim(glsRet, "`r`n")
        glsRet := StrReplace(glsRet, "%", "``%")
        if (sDmpOutput!="")
            sDmpOutput .= "`r`n`r`n`r`n`r`n"
        sDmpOutput .= ">>>>> " . aVarnames[deltaVar]
        sDmpOutput .= "`r`n`r`n"
        sDmpOutput .= glsRet
        sDmpOutput .= "`r`n`r`n"
        if (gliRowCount > 1)
            sDmpOutput .= gliRowCount . " elements for " . aVarnames[deltaVar] . " "
        sDmpOutput .= "<<<<<"
    }

    pidCurrent := DllCall("GetCurrentProcessId")

    sScriptPopup =
    (ltrim join`r`n
        #NoEnv

        sDmpOutput=
        `(join``r``n
            %sDmpOutput%
        `)

        OnMessage(0x0111, "On_EN_SETFOCUS")
        OnMessage(0x100, "OnKeyDown")

        Gui +AlwaysOnTop +ToolWindow +Resize +MinSize400x300
        Gui, Add, Edit, +Readonly w780 h570 vedit, `% sDmpOutput
        Gui, Add, Button, xm w100 y+10 gButtonContinue vButtonContinue, Continue
        Gui, Add, Button, xp+120 yp+0 w100 gButtonReload vButtonReload, Reload script
        Gui, Add, Button, xp+120 yp+0 w100 gButtonKill vButtonKill, Kill script

        gosub Guisize

        Gui, Show, Center w800 h600, call #%_iCallCount% in line %iLineNumber% - dmp 1.25
        Return

        Guisize:
            glsEditWidth := "w" . A_GuiWidth - 20
            glsEditHeight := "h" . A_GuiHeight - 50
            GuiControl, Move, edit, `% glsEditWidth . " " . glsEditHeight
            GuiControl, Move, ButtonContinue, `%  "y" . (A_GuiHeight - 30)
            GuiControl, Move, ButtonReload, `%  "y" . (A_GuiHeight - 30)
            GuiControl, Move, ButtonKill, `%  "y" . (A_GuiHeight - 30)
        return

        ButtonReload:
            process, close, `% %pidCurrent%
            Sleep, 120
            Run, %A_ScriptFullPath%
            ExitApp
        return

        ButtonKill:
            process, close, `% %pidCurrent%
        GUIEscape:
        GuiClose:
        ButtonContinue:
        ExitApp

        On_EN_SETFOCUS(wParam, lParam) {
           Static EM_SETSEL   := 0x00B1
           Static EN_SETFOCUS := 0x0100
           Critical
           If ((wParam >> 16) = EN_SETFOCUS) {
              DllCall("User32.dll\HideCaret", "Ptr", lParam)
              PostMessage, `%EM_SETSEL`%, -1, 0, , ahk_id `%lParam`%
           }
        }

        OnKeyDown(wParam)
        {
            if (wParam = 13)
                ExitApp
        }
    )

    pidScriptPopup := _dmpDynaRun(sScriptPopup)
    Process, WaitClose, %pidScriptPopup%
}

_dmp(pVar, _psPrefix, _piLevel:=0) {
    global gliRowCount
    global glsRet

    if (IsObject(pVar))
    {
        if (_dmpArrayEmpty(pVar))
        {
            gliRowCount++
            glsRet .= "`r`n" . _psPrefix . " := []"
        }
        else
        {
            for deltaVar, VarItem in pVar
            {
                _dmp(VarItem, _psPrefix . "[" . _dmpGetQuotes(deltaVar) . "]", _piLevel + 1)
            }
        }
    }
    else
    {
        gliRowCount++
        glsRet .= "`r`n" . _psPrefix . " := " . _dmpGetQuotes(pVar)
    }
}

_dmpArrayEmpty(paArray) {
    for deltaArray, ArrayItem in paArray
        return false
    return true
}

_dmpGetQuotes(pVar) {
    sRet=
    if !IsObject(pVar)
    {
        if (ObjGetCapacity([pVar], 1) != "")
        {
            if (RegExMatch(pVar, "^\d+\.\d+$"))
                sRet := pVar
            else
            {
                if (StrSplit(pVar, "`n", "`r").Length() > 1)
                    sRet := "`n"
                sRet .= """" . pVar . """"
            }
        }
        else
        {
            if !pVar
                sRet := "0"
            else
                sRet := pVar
        }
    }
    return sRet
}

_dmpRecursiveBracketNeutralizer(ByRef psText, paBracket, piStartLevel:=0, piStartPos:=1, _piLevel:=0) {
	iPos := piStartPos
	while (iPos <= StrLen(psText))
	{
		if (SubStr(psText, iPos, StrLen(paBracket[1]))==paBracket[1])
		{
			iPos := _dmpRecursiveBracketNeutralizer(psText, paBracket, piStartLevel, iPos+1, _piLevel+1)
		}
		else if (SubStr(psText, iPos, StrLen(paBracket[2]))==paBracket[2])
		{
			if (piStartLevel<_piLevel)
			{
				; do replacement
				iDiff:=iPos+StrLen(paBracket[2])-piStartPos
				sReplacement=
				loop, % (iDiff+1)
					sReplacement .= "*"
				psText:=_dmpReplaceSE(psText, piStartPos-1, (iPos-1)+StrLen(paBracket[2]), sReplacement)

				; calculate difference between old found string and replacement for iPos reset
				iPos+=(StrLen(sReplacement)-iDiff)
			}
			return iPos++
		}
		else
			iPos++
	}
}

; *** string functions

_dmpStringSplitPositions(psText, psNeedle, piStartPos:=1) {
	aRet := []
	if (psText != "")
	{
		iStartPos := piStartPos
		while (iPos := InStr(psText, psNeedle, false, iStartPos))
		{
			aEl := []
			aEl["iStartPos"] := iStartPos
			aEl["iEndPos"] := iPos-1
			aRet.Push(aEl)
			iStartPos := iPos + StrLen(psNeedle)
		}
		aEl := []
		aEl["iStartPos"] := iStartPos
		aEl["iEndPos"] := StrLen(psText)
		aRet.Push(aEl)
	}
	return aRet
}

_dmpReplaceSE(psText, piPosStart, piPosEnd:="", psReplacement:="") {
	if (psText!="")
	{
		piPosEnd := piPosEnd != "" ? piPosEnd : StrLen(psText)
		sBefore := SubStr(psText, 1, piPosStart-1)
		sAfter := SubStr(psText, piPosEnd+1, StrLen(psText))
		return sBefore . psReplacement . sAfter
	}
	else
	{
		return psReplacement
	}
}

_dmpExtractSE(psText, piPosStart, piPosEnd:="") {
	if (psText != "")
	{
		piPosEnd := piPosEnd != "" ? piPosEnd : StrLen(psText)
		return SubStr(psText, piPosStart, piPosEnd-(piPosStart-1))
	}
}

_dmpGetVarContent(psText) {
	sRet=
	if RegExMatch(psText, "i)dmp\s*\((.*)\)", match)
	{
		sRet := match1
	}
	return sRet
}

_dmpGetVarnames(psText) {
	aRet := []
	if (psText!="")
	{
		sTextSaved := psText

		_dmpRecursiveBracketNeutralizer(psText, ["{", "}"])
		_dmpRecursiveBracketNeutralizer(psText, ["[", "]"])
		_dmpRecursiveBracketNeutralizer(psText, ["(", ")"], 1)

		sVarContent := _dmpGetVarContent(psText)
		aVarContentPositions := _dmpStringSplitPositions(sVarContent, ",")
		sVarContentSaved := _dmpGetVarContent(sTextSaved)
		for deltaVarContentPositions, VarContentPositionsItem in aVarContentPositions
		{
			sFound := _dmpExtractSE(sVarContentSaved, VarContentPositionsItem["iStartPos"], VarContentPositionsItem["iEndPos"])
			sFound=%sFound%
			aRet.Push(sFound)
		}
	}
	return aRet
}

; *** external functions

_dmpDynaRun(s, pn:="", pr:=""){ ; s=Script,pn=PipeName,n:=,pr=Parameters,p1+p2=hPipes,P=PID
   static AhkPath:="""" A_AhkPath """" (A_IsCompiled||(A_IsDll&&DllCall(A_AhkPath "\ahkgetvar","Str","A_IsCompiled"))?" /E":"") " """
   if (-1=p1 := DllCall("CreateNamedPipe","str",pf:="\\.\pipe\" (pn!=""?pn:"AHK" A_TickCount),"uint",2,"uint",0,"uint",255,"uint",0,"uint",0,"Ptr",0,"Ptr",0))
      || (-1=p2 := DllCall("CreateNamedPipe","str",pf,"uint",2,"uint",0,"uint",255,"uint",0,"uint",0,"Ptr",0,"Ptr",0))
      Return 0
   ; allow compiled executable to execute dynamic scripts. Requires AHK_H
   Run, % AhkPath pf """ " pr,,UseErrorLevel HIDE, P
   If ErrorLevel
      return 0,DllCall("CloseHandle","Ptr",p1),DllCall("CloseHandle","Ptr",p2)
   DllCall("ConnectNamedPipe","Ptr",p1,"Ptr",0),DllCall("CloseHandle","Ptr",p1),DllCall("ConnectNamedPipe","Ptr",p2,"Ptr",0)
   if !DllCall("WriteFile","Ptr",p2,"Wstr",s:=(A_IsUnicode?chr(0xfeff):"") s,"UInt",StrLen(s)*(A_IsUnicode ? 2 : 1)+(A_IsUnicode?4:6),"uint*",0,"Ptr",0)
      P:=0
   DllCall("CloseHandle","Ptr",p2)
   Return P
}

_dmpListLines() {
    static hwndEdit, pSFW, pSW, bkpSFW, bkpSW
    ListLines Off

    if !hwndEdit
    {
        ; Retrieve the handle of our main window's Edit control:
        dhw := A_DetectHiddenWindows
        DetectHiddenWindows, On
        Process, Exist
        ControlGet, hwndEdit, Hwnd,, Edit1, ahk_class AutoHotkey ahk_pid %ErrorLevel%
        DetectHiddenWindows, %dhw%

        astr := A_IsUnicode ? "astr" : "str"
        hmod := DllCall("GetModuleHandle", "str", "user32.dll")
        ; Get addresses of these two functions:
        pSFW := DllCall("GetProcAddress", "uint", hmod, astr, "SetForegroundWindow")
        pSW := DllCall("GetProcAddress", "uint", hmod, astr, "ShowWindow")
        ; Make them writable:
        DllCall("VirtualProtect", "uint", pSFW, "uint", 8, "uint", 0x40, "uint*", 0)
        DllCall("VirtualProtect", "uint", pSW, "uint", 8, "uint", 0x40, "uint*", 0)
        ; Save initial values of the first 8 bytes:
        bkpSFW := NumGet(pSFW+0, 0, "int64")
        bkpSW := NumGet(pSW+0, 0, "int64")
    }

    ; Overwrite SetForegroundWindow() and ShowWindow() temporarily:
    NumPut(0x0004C200000001B8, pSFW+0, 0, "int64")  ; return TRUE
    NumPut(0x0008C200000001B8, pSW+0, 0, "int64")   ; return TRUE

    ; Dump ListLines into hidden AutoHotkey main window:
    ListLines

    ; Restore SetForegroundWindow() and ShowWindow():
    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.
}
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
gregster
Posts: 9001
Joined: 30 Sep 2013, 06:48

Re: dmp() - Advanced debug function for AutoHotKey

21 Aug 2020, 07:45

Joe Glines has a copy of it: https://www.the-automator.com/download/dmp.ahk
Edit: Oh, I see you already found it :thumbup:

Code: Select all

; http://the-automator.com/download/dmp.ahk
; dmp Version 1.25
; By ObiWanKenobi
; Visit guresicpark.de for dmp updates 
; May 8, 2015  
;~ http://guresicpark.de/autohotkey/dmp

dmp(pVar*)
{
    static _iCallCount := 0
    
    ; set x as basic variable name
    aVarnames := ["x"]
    
    ; now search variable name
	sLines := _dmpListLines()
    aLines := StrSplit(sLines, "`n", "`r")
    iLinesLength := aLines.Length()
    for deltaLines, LinesItem in aLines
    {
        sCurrentLine := aLines[(aLines.Length()+1)-deltaLines]
        if RegExMatch(sCurrentLine, "i)dmp\s*\(.*\)", match)
        {
            RegExMatch(sCurrentLine, "^(\d+)\:", match)
            iLineNumber := match1 + 0
            aVarnames := _dmpGetVarnames(sCurrentLine)
            break
        }
    }
    
    ; start dump
    _iCallCount++
    for deltaVar, VarItem in pVar
    {
        global gliRowCount := 0
        global glsRet=
        _dmp(VarItem, aVarnames[deltaVar])
        glsRet := LTrim(glsRet, "`r`n")
        glsRet := StrReplace(glsRet, "%", "``%")
        if (sDmpOutput!="")
            sDmpOutput .= "`r`n`r`n`r`n`r`n"
        sDmpOutput .= ">>>>> " . aVarnames[deltaVar]
        sDmpOutput .= "`r`n`r`n"
        sDmpOutput .= glsRet
        sDmpOutput .= "`r`n`r`n"
        if (gliRowCount > 1)
            sDmpOutput .= gliRowCount . " elements for " . aVarnames[deltaVar] . " "
        sDmpOutput .= "<<<<<"
    }
    
    pidCurrent := DllCall("GetCurrentProcessId")
    
    sScriptPopup =
    (ltrim join`r`n
        #NoEnv
        
        sDmpOutput=
        `(join``r``n
            %sDmpOutput%
        `)

        OnMessage(0x0111, "On_EN_SETFOCUS")
        OnMessage(0x100, "OnKeyDown")
        
        Gui +AlwaysOnTop +ToolWindow +Resize +MinSize400x300
        Gui, Add, Edit, +Readonly w780 h570 vedit, `% sDmpOutput
        Gui, Add, Button, xm w100 y+10 gButtonContinue vButtonContinue, Continue
        Gui, Add, Button, xp+120 yp+0 w100 gButtonReload vButtonReload, Reload script
        Gui, Add, Button, xp+120 yp+0 w100 gButtonKill vButtonKill, Kill script
        
        gosub Guisize
        
        Gui, Show, Center w800 h600, call #%_iCallCount% in line %iLineNumber% - dmp 1.25
        Return
        
        Guisize:
            glsEditWidth := "w" . A_GuiWidth - 20
            glsEditHeight := "h" . A_GuiHeight - 50
            GuiControl, Move, edit, `% glsEditWidth . " " . glsEditHeight
            GuiControl, Move, ButtonContinue, `%  "y" . (A_GuiHeight - 30)	
            GuiControl, Move, ButtonReload, `%  "y" . (A_GuiHeight - 30)	
            GuiControl, Move, ButtonKill, `%  "y" . (A_GuiHeight - 30)	
        return
        
        ButtonReload:
            process, close, `% %pidCurrent%
            Sleep, 120
            Run, %A_ScriptFullPath%
            ExitApp
        return
        
        ButtonKill:
            process, close, `% %pidCurrent%
        GUIEscape:
        GuiClose:
        ButtonContinue:
        ExitApp
        
        On_EN_SETFOCUS(wParam, lParam) {
           Static EM_SETSEL   := 0x00B1
           Static EN_SETFOCUS := 0x0100
           Critical
           If ((wParam >> 16) = EN_SETFOCUS) {
              DllCall("User32.dll\HideCaret", "Ptr", lParam)
              PostMessage, `%EM_SETSEL`%, -1, 0, , ahk_id `%lParam`%
           }
        }
        
        OnKeyDown(wParam)
        {
            if (wParam = 13)
                ExitApp
        }
    )
    
    pidScriptPopup := _dmpDynaRun(sScriptPopup)
    Process, WaitClose, %pidScriptPopup%
}

_dmp(pVar, _psPrefix, _piLevel:=0)
{
    global gliRowCount
    global glsRet
    
    if (IsObject(pVar))
    {
        if (_dmpArrayEmpty(pVar))
        {
            gliRowCount++
            glsRet .= "`r`n" . _psPrefix . " := []"
        }
        else
        {
            for deltaVar, VarItem in pVar
            {
                _dmp(VarItem, _psPrefix . "[" . _dmpGetQuotes(deltaVar) . "]", _piLevel + 1)
            }
        }
    }
    else
    {
        gliRowCount++
        glsRet .= "`r`n" . _psPrefix . " := " . _dmpGetQuotes(pVar)
    }
}

_dmpArrayEmpty(paArray)
{
    for deltaArray, ArrayItem in paArray
        return false
    return true
}

_dmpGetQuotes(pVar)
{
    sRet=
    if !IsObject(pVar)
    {
        if (ObjGetCapacity([pVar], 1) != "")
        {
            if (RegExMatch(pVar, "^\d+\.\d+$"))
                sRet := pVar
            else
            {
                if (StrSplit(pVar, "`n", "`r").Length() > 1)
                    sRet := "`n"
                sRet .= """" . pVar . """"
            }
        }
        else
        {
            if !pVar
                sRet := "0"
            else
                sRet := pVar
        }
    }
    return sRet
}

_dmpRecursiveBracketNeutralizer(ByRef psText, paBracket, piStartLevel:=0, piStartPos:=1, _piLevel:=0)
{
	iPos := piStartPos
	while (iPos <= StrLen(psText))
	{
		if (SubStr(psText, iPos, StrLen(paBracket[1]))==paBracket[1])
		{
			iPos := _dmpRecursiveBracketNeutralizer(psText, paBracket, piStartLevel, iPos+1, _piLevel+1)
		}
		else if (SubStr(psText, iPos, StrLen(paBracket[2]))==paBracket[2])
		{
			if (piStartLevel<_piLevel)
			{
				; do replacement
				iDiff:=iPos+StrLen(paBracket[2])-piStartPos
				sReplacement=
				loop, % (iDiff+1)
					sReplacement .= "*"
				psText:=_dmpReplaceSE(psText, piStartPos-1, (iPos-1)+StrLen(paBracket[2]), sReplacement)
				
				; calculate difference between old found string and replacement for iPos reset
				iPos+=(StrLen(sReplacement)-iDiff)
			}
			return iPos++
		}
		else
			iPos++
	}
}

; *** string functions

_dmpStringSplitPositions(psText, psNeedle, piStartPos:=1)
{
	aRet := []
	if (psText != "")
	{
		iStartPos := piStartPos
		while (iPos := InStr(psText, psNeedle, false, iStartPos))
		{
			aEl := []
			aEl["iStartPos"] := iStartPos
			aEl["iEndPos"] := iPos-1
			aRet.Push(aEl)
			iStartPos := iPos + StrLen(psNeedle)
		}
		aEl := []
		aEl["iStartPos"] := iStartPos
		aEl["iEndPos"] := StrLen(psText)
		aRet.Push(aEl)
	}
	return aRet
}

_dmpReplaceSE(psText, piPosStart, piPosEnd:="", psReplacement:="")
{
	if (psText!="")
	{
		piPosEnd := piPosEnd != "" ? piPosEnd : StrLen(psText)
		sBefore := SubStr(psText, 1, piPosStart-1)
		sAfter := SubStr(psText, piPosEnd+1, StrLen(psText))
		return sBefore . psReplacement . sAfter
	}
	else
	{
		return psReplacement
	}	
}

_dmpExtractSE(psText, piPosStart, piPosEnd:="")
{
	if (psText != "")
	{
		piPosEnd := piPosEnd != "" ? piPosEnd : StrLen(psText)
		return SubStr(psText, piPosStart, piPosEnd-(piPosStart-1))
	}
}

_dmpGetVarContent(psText)
{
	sRet=	
	if RegExMatch(psText, "i)dmp\s*\((.*)\)", match)
	{
		sRet := match1
	}
	return sRet
}

_dmpGetVarnames(psText)
{
	aRet := []
	if (psText!="")
	{
		sTextSaved := psText
		
		_dmpRecursiveBracketNeutralizer(psText, ["{", "}"])
		_dmpRecursiveBracketNeutralizer(psText, ["[", "]"])
		_dmpRecursiveBracketNeutralizer(psText, ["(", ")"], 1)

		sVarContent := _dmpGetVarContent(psText)
		aVarContentPositions := _dmpStringSplitPositions(sVarContent, ",")
		sVarContentSaved := _dmpGetVarContent(sTextSaved)
		for deltaVarContentPositions, VarContentPositionsItem in aVarContentPositions
		{
			sFound := _dmpExtractSE(sVarContentSaved, VarContentPositionsItem["iStartPos"], VarContentPositionsItem["iEndPos"])
			sFound=%sFound%
			aRet.Push(sFound)
		}
	}
	return aRet
}

; *** external functions

_dmpDynaRun(s, pn:="", pr:=""){ ; s=Script,pn=PipeName,n:=,pr=Parameters,p1+p2=hPipes,P=PID
   static AhkPath:="""" A_AhkPath """" (A_IsCompiled||(A_IsDll&&DllCall(A_AhkPath "\ahkgetvar","Str","A_IsCompiled"))?" /E":"") " """
   if (-1=p1 := DllCall("CreateNamedPipe","str",pf:="\\.\pipe\" (pn!=""?pn:"AHK" A_TickCount),"uint",2,"uint",0,"uint",255,"uint",0,"uint",0,"Ptr",0,"Ptr",0))
      || (-1=p2 := DllCall("CreateNamedPipe","str",pf,"uint",2,"uint",0,"uint",255,"uint",0,"uint",0,"Ptr",0,"Ptr",0))
      Return 0
   ; allow compiled executable to execute dynamic scripts. Requires AHK_H
   Run, % AhkPath pf """ " pr,,UseErrorLevel HIDE, P
   If ErrorLevel
      return 0,DllCall("CloseHandle","Ptr",p1),DllCall("CloseHandle","Ptr",p2)
   DllCall("ConnectNamedPipe","Ptr",p1,"Ptr",0),DllCall("CloseHandle","Ptr",p1),DllCall("ConnectNamedPipe","Ptr",p2,"Ptr",0)
   if !DllCall("WriteFile","Ptr",p2,"Wstr",s:=(A_IsUnicode?chr(0xfeff):"") s,"UInt",StrLen(s)*(A_IsUnicode ? 2 : 1)+(A_IsUnicode?4:6),"uint*",0,"Ptr",0)
      P:=0
   DllCall("CloseHandle","Ptr",p2)
   Return P
}

_dmpListLines()
{
    static hwndEdit, pSFW, pSW, bkpSFW, bkpSW
    ListLines Off
    
    if !hwndEdit
    {
        ; Retrieve the handle of our main window's Edit control:
        dhw := A_DetectHiddenWindows
        DetectHiddenWindows, On
        Process, Exist
        ControlGet, hwndEdit, Hwnd,, Edit1, ahk_class AutoHotkey ahk_pid %ErrorLevel%
        DetectHiddenWindows, %dhw%
        
        astr := A_IsUnicode ? "astr" : "str"
        hmod := DllCall("GetModuleHandle", "str", "user32.dll")
        ; Get addresses of these two functions:
        pSFW := DllCall("GetProcAddress", "uint", hmod, astr, "SetForegroundWindow")
        pSW := DllCall("GetProcAddress", "uint", hmod, astr, "ShowWindow")
        ; Make them writable:
        DllCall("VirtualProtect", "uint", pSFW, "uint", 8, "uint", 0x40, "uint*", 0)
        DllCall("VirtualProtect", "uint", pSW, "uint", 8, "uint", 0x40, "uint*", 0)
        ; Save initial values of the first 8 bytes:
        bkpSFW := NumGet(pSFW+0, 0, "int64")
        bkpSW := NumGet(pSW+0, 0, "int64")
    }
    
    ; Overwrite SetForegroundWindow() and ShowWindow() temporarily:
    NumPut(0x0004C200000001B8, pSFW+0, 0, "int64")  ; return TRUE
    NumPut(0x0008C200000001B8, pSW+0, 0, "int64")   ; return TRUE
    
    ; Dump ListLines into hidden AutoHotkey main window:
    ListLines
    
    ; Restore SetForegroundWindow() and ShowWindow():
    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.
}
mstrauss2021
Posts: 30
Joined: 13 Feb 2021, 10:34

Re: dmp() - Advanced debug function for AutoHotKey

14 Feb 2021, 17:45

I like the idea of dmp.ahk.

However, when I put it just before the last return of my macro and run my macro, I can't find where the dmp file is saved. I examined dmp.ahk but still cant find where the output is saved.

Anyone know?
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: dmp() - Advanced debug function for AutoHotKey

15 Feb 2021, 09:52

thats because nothing is being saved anywhere, it just displays information in an edit-control.
if u want to save something, look at sDmpOutput inside dmp() and FileOpen(..., "w").Write(...) it to a file or something
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: dmp() - Advanced debug function for AutoHotKey

16 May 2021, 07:54

guest3456 wrote:
02 May 2015, 11:35
It looks like you are overwriting the memory addresses so SetForegroundWindow and ShowWindow won't be called, so the end user doesn't see the ListLines window.

But what are those values that you are using? Where did you get them and what do they represent?

Code: Select all

; Overwrite SetForegroundWindow() and ShowWindow() temporarily:
    NumPut(0x0004C200000001B8, pSFW+0, 0, "int64")  ; return TRUE
    NumPut(0x0008C200000001B8, pSW+0, 0, "int64")   ; return TRUE
edit/
whoops further searching reveals that Lexikos originally wrote this function, maybe he can chime in
no, the functions are still called - theyre just stubbed to return true and do nothing else(which is why u dont end up seeing their actual effects, ie a window showing up)
the numbers are what u get when u compile:

Code: Select all

BOOL SetForegroundWindow(HWND hWnd) { return TRUE; }
BOOL ShowWindow(HWND hWnd, int  nCmdShow) { return TRUE; }
to bytecode

but u probably knew all that by now, other ppl might not
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: dmp() - Advanced debug function for AutoHotKey

17 May 2021, 02:05

swagfag wrote:
16 May 2021, 07:54
no, the functions are still called - theyre just stubbed to return true and do nothing else(which is why u dont end up seeing their actual effects, ie a window showing up)
the numbers are what u get when u compile:

Code: Select all

BOOL SetForegroundWindow(HWND hWnd) { return TRUE; }
BOOL ShowWindow(HWND hWnd, int  nCmdShow) { return TRUE; }
to bytecode

but u probably knew all that by now, other ppl might not
i did not know that, thanks, very interesting. does that overwrite the calls to those functions only within the script itself? or also for all external windows too? i'm guessing its only the ahk script because i thought you needed to hook a dll to accomplish the latter


Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 215 guests