This code is able to analyze existing compiled GUIs and "disassemble" them to functional PB code. It once helped me recover some GUI code for a lost project source.
Note that this is a quick and dirty demo and definitely flaky and incomplete. It was fun to play with, but I have no plans to further develop it at this stage - consider it a starting point. Enjoy!
edit: replaced with the example in the next post
Gui disassembling
Gui disassembling
Last edited by firace on Wed Jun 16, 2021 5:03 pm, edited 1 time in total.
Re: Gui disassembling
Demo below. Again, expect bugs, but should be fun to play with nonetheless.
Note: works best with PB programs.
Note: works best with PB programs.
Code: Select all
;; note: windows only.
Global winleft
Global wintop
Global reconstructedGUIcode$
Debug "--- ---"
Procedure EnumChildWindowsProcedure(hwnd, lparam)
gadgetnum = GetDlgCtrlID_(hwnd)
Protected Classname$ = Space(#MAX_PATH)
Protected parentclassname$ = Space(#MAX_PATH)
Protected Textname$ = Space(#MAX_PATH)
parentHandle = GetParent_(hwnd)
SendMessage_(hwnd,#WM_GETTEXT,128,@Textname$)
GetClassName_(hwnd, @Classname$, #MAX_PATH-1)
GetClassName_(parentHandle , @parentclassname$, #MAX_PATH-1)
rc.rect
GetWindowRect_(hwnd,rc)
XXX = rc\left - winleft
YYY = rc\top - wintop - GetSystemMetrics_(#SM_CYCAPTION)
If Classname$ = "Button"
If gadgetnum > 13000 And gadgetnum < 13100
CheckBoxGadget(#PB_Any, XXX, YYY, rc\right - rc\left, rc\bottom - rc\top , Left(Textname$,60))
Else
ButtonGadget(#PB_Any, XXX, YYY , rc\right - rc\left, rc\bottom - rc\top , Left(Textname$,60))
reconstructedGUIcode$ + #CRLF$ + "ButtonGadget(#PB_Any, " + XXX + "," + YYY + "," + Str(rc\right - rc\left) + "," + Str(rc\bottom - rc\top) + "," + #DQUOTE$ + Left(Textname$,60) + #DQUOTE$ + ")"
EndIf
ElseIf Classname$ = "Static"
TextGadget(#PB_Any, XXX, YYY, rc\right - rc\left, rc\bottom - rc\top , Left(Textname$,60))
reconstructedGUIcode$ + #CRLF$ + "TextGadget(#PB_Any, " + XXX + "," + YYY + "," + Str(rc\right - rc\left) + "," + Str(rc\bottom - rc\top) + "," + #DQUOTE$ + Left(Textname$,60) + #DQUOTE$ + ")"
ElseIf Classname$ = "Scintilla"
EG = EditorGadget(#PB_Any, XXX, YYY, rc\right - rc\left, rc\bottom - rc\top ) : SetGadgetText(EG, Classname$)
reconstructedGUIcode$ + #CRLF$ + "ScintillaGadget(#PB_Any, " + XXX + "," + YYY + "," + Str(rc\right - rc\left) + "," + Str(rc\bottom - rc\top) + ")"
ElseIf Classname$ = "ListBox"
ListViewGadget(#PB_Any, XXX, YYY, rc\right - rc\left, rc\bottom - rc\top)
reconstructedGUIcode$ + #CRLF$ + "ListIconGadget(#PB_Any, " + XXX + "," + YYY + "," + Str(rc\right - rc\left) + "," + Str(rc\bottom - rc\top) + "," + ")"
ElseIf Classname$ = "SysListView32"
ListViewGadget(#PB_Any, XXX, YYY, rc\right - rc\left, rc\bottom - rc\top)
reconstructedGUIcode$ + #CRLF$ + "ListViewGadget(#PB_Any, " + XXX + "," + YYY + "," + Str(rc\right - rc\left) + "," + Str(rc\bottom - rc\top) + "," + ")"
ElseIf Classname$ = "Edit" And parentclassname$ <> "ComboBox"
StringGadget(#PB_Any, XXX, YYY, rc\right - rc\left, rc\bottom - rc\top , Left(Textname$,60))
ElseIf Classname$ = "ComboBox"
ComboBoxGadget(#PB_Any, XXX, YYY, rc\right - rc\left, rc\bottom - rc\top, #PB_ComboBox_Editable )
reconstructedGUIcode$ + #CRLF$ + "ComboBoxGadget(#PB_Any, " + XXX + "," + YYY + "," + Str(rc\right - rc\left) + "," + Str(rc\bottom - rc\top) + ", #PB_ComboBox_Editable) "
ElseIf Classname$ = "RichEdit20W"
EG = EditorGadget(#PB_Any, XXX, YYY, rc\right - rc\left, rc\bottom - rc\top ) : SetGadgetText(EG, Classname$)
reconstructedGUIcode$ + #CRLF$ + "EditorGadget(#PB_Any, " + XXX + "," + YYY + "," + Str(rc\right - rc\left) + "," + Str(rc\bottom - rc\top) + ") "
EndIf
ProcedureReturn #True
EndProcedure
Procedure Deconstruct(targetWindowHandle)
Debug targetWindowHandle
rc.rect
Textname$ = Space(128)
SendMessage_(targetWindowHandle,#WM_GETTEXT,128,@Textname$)
GetWindowRect_(targetWindowHandle,rc)
winleft = rc\left
wintop = rc\top
WW = rc\right - rc\left - GetSystemMetrics_(#SM_CYFIXEDFRAME) *2
HH = rc\bottom - rc\top - GetSystemMetrics_(#SM_CYCAPTION) - GetSystemMetrics_(#SM_CYFIXEDFRAME)* 2
OpenWindow(123, 100, 100, WW, HH, "[ReconstructedGUI]", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_MaximizeGadget | #PB_Window_Invisible) : StickyWindow(123, 1)
reconstructedGUIcode$ = "; Automatically generated code! " + #CRLF$
reconstructedGUIcode$ + ~"OpenWindow(#PB_Any, 100, 100, " + WW + "," + HH + ~", \"\", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)" + #CRLF$ + #CRLF$
EnumChildWindows_(targetWindowHandle, @EnumChildWindowsProcedure(), 0)
reconstructedGUIcode$ + #CRLF$ + #CRLF$ + "Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow "
SetGadgetText(6, reconstructedGUIcode$)
EndProcedure
Procedure.l enumWins(hwnd.l, lParam.l)
If hwnd
If IsWindowVisible_(hwnd) And Not IsIconic_(hwnd) ;... Only looking for visible windows
pText.s = Space(256)
SendMessage_(hwnd, #WM_GETTEXT, 256, @pText)
If Len(pText) > 0 ;... Skip windows with empty title
AddGadgetItem(52, 0, Str(hwnd) + " - " + Left(pText,48) )
EndIf
EndIf
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
OpenWindow(0,30,30,540,700,"GUI Reverser", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget)
TextGadget(50, 10, 15, 100, 22, "Analyze window -->")
ComboBoxGadget(52, 120, 10, 345, 20)
ButtonGadget(20,10,620,140,20,"Test code") : DisableGadget(20, 1)
EditorGadget(6, 10, 100, 460, 500, #PB_Editor_ReadOnly) : LoadFont(10, "Consolas", 12) : SetGadgetFont(6, FontID(10))
Classname$ = Space(#MAX_PATH)
parentHandleClassname$ = Space(#MAX_PATH)
Textname$ = Space(#MAX_PATH)
EnumWindows_(@enumWins(), 0)
Repeat
Event = WaitWindowEvent()
If event = #PB_Event_Gadget
If EventGadget() = 52
handle = Val(StringField(GetGadgetText(52), 1, " "))
Deconstruct(handle) : DisableGadget(20, 0)
EndIf
If EventGadget() = 20
HideWindow(123, 0)
EndIf
EndIf
Until Event = #PB_Event_CloseWindow
Last edited by firace on Thu Jun 17, 2021 7:51 am, edited 1 time in total.
Re: Gui disassembling
I like the idea and this kind of tools
I tried it on itself, I only have the window!
A refresh button would be good to refresh the "Analyze window" combobox, if an app is launched after.
Good continuation
I tried it on itself, I only have the window!
Code: Select all
; Automatically generated code!
OpenWindow(123, 100, 100, 1544,809, "", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Good continuation
- Kwai chang caine
- Always Here
- Posts: 5345
- Joined: Sun Nov 05, 2006 11:42 pm
- Location: Lyon - France
Re: Gui disassembling
Yes very good idea, practice when you have lost the source code of a complex GUI or recreate a fake of another
I believe CodeCaddy have this function in the old time
Thanks for sharing
I believe CodeCaddy have this function in the old time
Thanks for sharing
The happiness is a road...
Not a destination
Not a destination
Re: Gui disassembling
Interesthing