ListBuffer() : Buffer object viewer

Post your working scripts, libraries and tools.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

ListBuffer() : Buffer object viewer

03 Mar 2022, 12:23

ListBuffer(Bin, Title)

Usage examples:
 
Example 1:
 
Convert a pointer to buffer and view it :
 

Code: Select all

BufGet(Ptr, Bytes)
{
    Local Buf :=  Buffer(Bytes, 0)
    Try DllCall("Kernel32\RtlMoveMemory", "ptr",Buf, "ptr",Ptr, "ptr",Bytes)
    Return Buf
}

#Requires AutoHotkey v2.0
#SingleInstance
Bin  :=  BufGet( StrPtr("The Quick Brown Fox"), 40 )
ListBuffer(Bin)
 
Image
 
 
Example 2:
 
View file contents:
 

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance

Bin := FileRead(A_AhkPath, "RAW")
ListBuffer(Bin, A_AhkPath)
 
Image
 
 
Example 3:
 
View a structure:
 

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance

WINDOWINFO := Buffer(60, 0)
NumPut("uint", 60, WINDOWINFO)
DllCall("User32\GetWindowInfo",  "ptr",A_ScriptHwnd, "ptr",WINDOWINFO)
ListBuffer(WINDOWINFO, "WINDOWINFO Structure")
 
Image
 
 
Example 4:
 
8 bytes double values example. Search for float:3.48225:
 

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance

Doub := Buffer(8, 0)
NumPut("Double", 123.456, Doub)
ListBuffer(Doub)
 
Image
 
 
Navigation:
 
  • Navigate through the bytes by using Mouse ScrollWheel over Offset edit control,
    or use Up/Down arrow keys when Offset has focus.
  • When Hex control is in focus:
    Use keys 1-8 (not numpad keys) to jump offsets forward by as many bytes,
    or combine any number (1-8) with shift to jump offsets backward.
  • Use Search edit control to jump to an offset by specifying a Type and Value separated by a colon,
    and press enter key to execute the search.
    Type can be any NumPut() supported type. eg Type:Value ushort:0xFFFF (Try this in example 2)
    or StrPut() supported encoding. eg. Type:Value utf-16:Fox (Try this in example 1).
    Type can be ignored if you want search in Hex for eg. :FF FF 00 00 (Spacing optional).
    Type can be odd byte search [1 thru 8], for example 40 bit/5 byte search: 5:515403350086 or 5:0x78006F0046 (Try this in example 1).
  • Accelerator keys for quick focus, toggling check boxes etc., are all provided thru GUI menu bar.
 
 
Source for Machine code:
 
Spoiler
 
 
The function:
 

Code: Select all

ListBuffer(Bin, Title := "", *)                           ;  v0.49 by SKAN  for ah2 on D52L/D66U @ autohotkey.com/r?t=101121
{
    If Type(Bin) != "Buffer"
    {
       MsgBox("Not a buffer", "ListBuffer", "T3 Icon? 0x1000")
       Return 0
    }
                    QPC(R := 0)                           ;  By SKAN  for ah2 on CT91/D497 @ goo.gl/nf7O4G
                    {
                        Static   P := 0,  F := 0, Q := DllCall("Kernel32\QueryPerformanceFrequency", "int64p",&F)
                        Return ( DllCall("Kernel32\QueryPerformanceCounter","int64p",&Q) * 0 + (R ? (P:=Q)*0 : (Q-P)/F) )
                    }

    Local  TickCount      :=  QPC(1)
        ,  Loading        :=  True                        ;  Disallow GuiClose() until GUI fully loaded
        ,  hMod1          :=  DllCall("Kernel32\LoadLibrary", "str","RichEd20.dll", "ptr")
        ,  hMod2          :=  DllCall("Kernel32\LoadLibrary", "str","Crypt32.dll",  "ptr")

        ,  HexL           :=  Bin.Size * 3                ;  Hex buffer len at 3x size of original
        ,  Hex                                            ;  Hex buffer
        ,  CRLF           :=  "`r`n"
        ,  LF             :=  "`n"
        ,  Err

    Local  MyGui
        ,  ChkB1,  ChkB2                                  ;  Reverse, BigEndian
        ,  Edit1,  Edit2,  Edit3                          ;  Values, Offset, Search
        ,  UpDn1                                          ;  Attached to Offset
        ,  Text1,  Text2,  Text3                          ;  Bin size, PtrSize @ Ptr, Bin to Text
        ,  Rich1                                          ;  Hex
        ,  MySB                                           ;  StatusBar
        ,  SB_Text := ""

        ;  Variables for CtrlSetTip()
    Local  TOOLINFO                                       ;  TOOLINFO structure
        ,  hToolTip       :=  0                           ;  Created by CtrlSetTip() and  destroyed at GuiClose()
        ,  Tool                                           ;  GuiControlObj, CtrlSetTip(Tool)
        ,  Size           :=  24 + (A_PtrSize * 6)        ;  TOOLINFO size
        ,  Tip  :=  Tips()                                ;  passed to CtrlSetTip()

                    Tips()
                    {
                        Local Pipe := "|"
                        Return StrSplit( "Use Mouse wheel or Up/Down arrow" LF "to Scroll between Offset 0 to "
                                                                            Bin.Size-1 LF LF "Quick focus:  CTRL+O"     Pipe
                                         "For Search-types, Press ALT+S" LF  "For searching, CLICK here, or press ENTER"
                                                                                       LF LF "Quick focus:  CTRL+S"     Pipe
                                         "Search in Reverse" LF  "(When checked, make sure Offset is at end of data)" 
                                                                     LF "Press ALT+H"  LF LF "Quick Toggle: CTRL+R"     Pipe
                                         "Hex-goto:" LF "First: CTRL+F   Last: CTRL+L" LF LF "Quick focus:  CTRL+H"     Pipe
                                         "Pointer type" LF "and" LF "Pointer"                                           Pipe
                                         "Maximum Text display of 192 bytes," LF "starting from current Offset"         Pipe
                                         "Values"                                      LF LF "Quick focus:  CTRL+U"     Pipe
                                         "Toggle values between Little/Big Endian"     LF LF "Quick Toggle: CTRL+B"     Pipe
                                       , Pipe )
                    }

    MyGui   :=   Gui("+DpiScale +AlwaysOnTop", "ListBuffer" . (Strlen(Title) ? " - " : "") . Title)
                 MyGui.MarginX  :=  20
                 MyGui.MarginY  :=  16

                    GetSysColor(n)
                    {
                        Return  Format( "{5:}{6:}{3:}{4:}{1:}{2:}", StrSplit(Format("{:06X}"
                                      , DllCall("User32\GetSysColor", "int",n)))* )
                    }

    ;  Edit1 (Values Edit Control) will be flagged 'Readonly' and loses its default color.
    ;  So, find/appy default foreground/background color. (COLOR_WINDOWTEXT := 8, COLOR_WINDOW := 5)

    Local  ColorOption := "c" GetSysColor(8) " Background" GetSysColor(5)
        ,  BigE           :=  0                           ;  Default Checkbox value (BigEndian)
        ,  ReverseSearch  :=  0                           ;  Default Checkbox value
        ,  Bytes          :=  0
        ,  W                                              ;  Width of Edit1

                 MyGui.SetFont("s11", "Courier New")
    Edit1   :=   MyGui.AddEdit("xm ym R5 +ReadOnly -Tabstop " ColorOption, Format("{:48}",""))         ; Values Edit Control
                 Edit1.GetPos(,,&W)                       ;  To apply same width (48 characters) to RichEdit control
                 Edit1.OnEvent("Focus", (*) => MySB_Tip("[Focused Edit] : Values", 2000))

                 MyGui.SetFont("s10", "Segoe UI")
    Tool    :=   MyGui.AddText("xm y8 0x100", "Offset")                                    ;  SS_NOTIFY := 0x100
                 CtrlSetTip(Tool, Tip[1])

    Tool    :=   MyGui.AddText("x160 yp w80 0x100", "Search")                              ;  SS_NOTIFY := 0x100
                 Tool.OnEvent("Click", TrySearch)
                 CtrlSetTip(Tool, Tip[2])

    ChkB1   :=   MyGui.AddCheckbox("x240 yp -Tabstop Right w" w-240+MyGui.MarginX " Checked" ReverseSearch, "Reverse")
                 CtrlSetTip(ChkB1, Tip[3])

                 MyGui.SetFont("s11", "Consolas")
    Edit2   :=   MyGui.AddEdit("xm y+4 w124 Number Right", 0)         ;  Offset Edit Control
                 Edit2.OnEvent("Change", SelectByte)      ;  Selects appropriate Hex, 3 times the value of Offset
                 Edit2.OnEvent("Focus", (*) => MySB_Tip("[Focused Edit] : Offset", 2000), 0)

    Bytes   :=   Bin.Size>0 ? Bin.Size-1 : 0              ;  To handle empty buffer like:     B := Buffer(0),  ListBuffer(B)
    UpDn1   :=   MyGui.AddUpDown("Left Wrap 0x80 Range" Bytes "-0")
    Edit3   :=   MyGui.AddEdit("x160 yp vSearch w" w-160+MyGui.MarginX)                               ;  Search Edit Control
                 Edit3.OnEvent("Focus", (*) => MySB_Tip("[Focused Edit] : Search", 2000))

                 MyGui.SetFont("s10", "Segoe UI")
    Text1   :=   MyGui.AddText("xm y+12 0x100", "Hex data of " Bin.Size " bytes")    ;  SS_NOTIFY := 0x100
                 CtrlSetTip(Text1, Tip[4])

    Text2   :=   MyGui.AddText("x360 yp 0x100 Right w" w-360+MyGui.MarginX, (A_PtrSize=8 ? "x64" : "x86") " @ " Bin.Ptr)
                 CtrlSetTip(Text2, Tip[5])

    Local  CHARRANGE     :=  Buffer(8)                                                       ;  for TrySearch()
        ,  Selection     :=  0
        ,  SelBytes      :=  0
        ,  pCHARRANGE                                                                        ;  for EN_SELCHANGE()
        ,  Rich1_Min     :=  0                                                               ;  for EN_SELCHANGE()
        ,  Rich1_Max     :=  0                                                               ;  for EN_SELCHANGE()
        ,  Rich1_Options :=  ( 0x200000    ;  WS_VSCROLL
                             | 0x000100    ;  ES_NOHIDESEL
                             | 0x000800    ;  ES_READONLY
                             | 0x008000 )  ;  ES_SAVESEL
                          .  " E0x20000 "  ;  WS_EX_STATICEDGE

                 MyGui.SetFont("s11", "Courier New")
    Rich1   :=   MyGui.AddCustom("ClassRichEdit20A xm y+4 R8  w" W " " Rich1_Options)        ;  Same width as Edit1 (Values)
                 DllCall("Uxtheme\SetWindowTheme", "ptr",Rich1.Hwnd, "str","Explorer", "ptr",0)

                    RichEdit_SetPropertyBits(hRich)  ;               How to eliminate MessageBeep from the RICHEDIT control?
                    {                                ;                                            autohotkey.com/r/?t=091105

                        Local  OnTxPropertyBitsChange  :=  19               ; <= Thanks swagfag @ autohotkey.com/r/?p=402594
                            ,  Unknown
                            ,  pUnknown
                            ,  TxtSrv
                            ,  IID_ITextServices       :=  "{8D33F740-CF58-11CE-A89D-00AA006CADC5}"

                        SendMessage(0x43C, 0, Unknown  :=  Buffer(8), hRich)               ;  EM_GETOLEINTERFACE := 0x43C
                        pUnknown  :=  NumGet(Unknown, "ptr")
                        TxtSrv    :=  ComObjQuery(pUnknown, IID_ITextServices)
                        ObjRelease(pUnknown)

                        If  A_Ptrsize = 8
                        {
                            ComCall(OnTxPropertyBitsChange, TxtSrv, "int",0x802, "int",0x2) ; tiny.cc/OnTxPropertyBitsChange
                            TxtSrv :=  ""
                            Return
                        }
                                                                            ;    Thanks lexikos @ autohotkey.com/r/?p=402798

                        Local  vtbl                    :=  NumGet(TxtSrv.Ptr, "ptr")
                            ,  pOnTxPropertyBitsChange :=  NumGet(vtbl + (19 * A_PtrSize), "ptr")
                            ,  thiscall_thunk          :=  Buffer(8)

                        NumPut("int64", 0xE2FF50595A58, thiscall_thunk)
                        DllCall("Kernel32\VirtualProtect", "ptr",thiscall_thunk, "ptr",8, "int",0x40, "uint*",0)
                        DllCall(thiscall_thunk, "ptr",pOnTxPropertyBitsChange, "ptr",TxtSrv, "int",0x802, "int",0x2)
                        TxtSrv  :=  ""
                    }

                 RichEdit_SetPropertyBits(Rich1.Hwnd)
                 DllCall("User32\ShowScrollBar", "ptr",Rich1.Hwnd, "int",1, "int",True)    ;  SB_VERT := 1

                 MyGui.SetFont("s10", "Segoe UI")
    Tool    :=   MyGui.AddText("xm y+12 0x100", "Text")                                    ;  SS_NOTIFY := 0x100
                 CtrlSetTip(Tool, Tip[6])

                 MyGui.SetFont("s11", "Courier New")
                 MyGui.AddText("r5 y+4 Center E0x20000 w" W)
    Text3   :=   MyGui.AddText("xp+16 yp+8 r4 w" W-20)                                     ;  Display Bin converted to Text

    Local  EditMargins  :=  Format("0x{1:04X}{1:04X}", 8*(A_ScreenDPI/96))

                 SendMessage(0xD3, 0x3, EditMargins, Edit1.Hwnd)                           ;  EM_SETMARGINS := 0xD3
                 SendMessage(0xD3, 0x3, EditMargins, Edit2.Hwnd)                           ;   ( EC_LEFTMARGIN |
                 SendMessage(0xD3, 0x3, EditMargins, Edit3.Hwnd)                           ;     EC_RIGHTMARGIN ) := 0x3
                 SendMessage(0xD3, 0x3, EditMargins, Rich1.Hwnd)

                 MyGui.SetFont("s10", "Segoe UI")
    Tool    :=   MyGui.AddText("xm y+20 0x100", "Unsigned/signed values")                  ;  SS_NOTIFY := 0x100
                 CtrlSetTip(Tool, Tip[7])

    ChkB2   :=   MyGui.AddCheckbox("x200 yp -Tabstop Right w" w-200+MyGui.MarginX " Checked" BigE, "Convert to BigEndian")
                 CtrlSetTip(ChkB2, Tip[8])

                    ToggleEndian(*)                       ;  Toggles value between Little Endian and Big Endian
                    {
                        BigE   :=  ChkB2.Value
                        NumValues(Bin, UpDn1.Value, Bytes)                         ;  Update Values
                    }

                 ChkB2.OnEvent("Click", ToggleEndian)

    Local  X, Y
    MyGui.AddText("xm y+4 w0 h0").GetPos(&X, &Y)          ;  Dummy text control for place holder
    Edit1.Move(X, Y)                                      ;  Move Edit1 (Values Edit Control) to place holder

    X       :=   MyGui.MarginX
    MySB    :=   MyGui.AddStatusBar()
                 MySB.SetParts(X, W, X)                   ;  Set active status bar centered to Edit1 (Value Edit Control)

    Local  FileMenu    :=  Menu()                         ;           ----------------   Gui MenuBar for Accelerators ------
        ,  FocusMenu   :=  Menu()
        ,  HexMenu     :=  Menu()
        ,  ToggleMenu  :=  Menu()
        ,  SearchFill  :=  Menu()
        ,  Menus       :=  MenuBar()

                    OpenTextInNotepad(Filename)
                    {
                        TickCount   :=  QPC(1)
                        Local  Text :=  BinToTxt(Bin.Ptr, Bin.Size)
                        TickCount   :=  QPC(0)

                        Try    FileDelete(Filename)
                        Try    FileAppend(Text, Filename, "RAW")
                          ,    MySB_Tip("Text conversion in " Round(TickCount*1000, 1) "ms.  Opening text in Notepad", 3000)
                          ,    Run("Notepad.exe /A '" Filename "'",, "Max")
                        Catch
                               MySB_Tip("[File creation/open failed] : " Filename, 3000)
                    }

    FileMenu.Add("Open text in &Notepad    " A_Tab "Alt+N",  (*) => OpenTextInNotepad(A_Temp "\ListBuffer.txt"))
    FileMenu.Add("Always on &Top           " A_Tab "Alt+T",  (*) => WinSetAlwaysOnTop(-1, MyGui.Hwnd))
    FileMenu.Add("Search                   " A_Tab "Enter",  (*) => TrySearch())
    FileMenu.Add()
    FileMenu.Add("E&xit                    " A_Tab "Alt+X",  (*) => ExitApp())

    FocusMenu.Add("&Offset" A_Tab "Ctrl+O",(*) => Edit2.Focus())
    FocusMenu.Add("&Search" A_Tab "Ctrl+S",(*) => Edit3.Focus())
    FocusMenu.Add("&Hex   " A_Tab "Ctrl+H",(*) => Rich1.Focus())
    FocusMenu.Add("Val&ues" A_Tab "Ctrl+U",(*) => Edit1.Focus())

    ToggleMenu.Add("&Reverse search      " A_Tab "Ctrl+R", (*) =>  ChkB1.Value := !ChkB1.Value)
    ToggleMenu.Add("Convert to &BigEndian" A_Tab "Ctrl+B", (*) => (ChkB2.Value := !ChkB2.Value, ToggleEndian()))

                    SearchItemFill(ItemName, ItemPos, MyMenu)
                    { ; Uncommon Menu ItemName like Int32, Int24 etc., will be translated by Search()
                        Local Len  :=  StrLen(ItemName) + 1
                        Edit3.Text :=  ItemName ":<value>"
                        Edit3.Focus()
                        SendMessage(0xB1, Len, Len+8, Edit3.Hwnd)                          ;  EM_SETSEL := 0xB1
                    }

    Loop Parse "hex||char|short|int24|int32|int64|float|double||cp0|utf-8|utf-16|cp936||1|2|3|4|5|6|7|8", "|"
          If  A_LoopField
              SearchFill.Add( A_LoopField, SearchItemFill)
        Else  SearchFill.Add()

                    CopyToClipboard(Ctrl)
                    {
                        NumPut("int64", 0, CHARRANGE)

                          If  Ctrl.Type = "Custom"
                              SendMessage(0x434, 0, CHARRANGE, Ctrl.Hwnd)                  ;  EM_EXGETSEL := 0x434
                        Else  SendMessage(0xB0, CHARRANGE.Ptr, CHARRANGE.Ptr+4, Ctrl.Hwnd) ;  EM_GETSEL   := 0xB0

                        Selection := NumGet(CHARRANGE, 4, "uint") - NumGet(CHARRANGE, 0, "uint")

                        If Selection < 1
                           Return MySB_Tip("[Nothing to copy]")

                        SendMessage(0x301, 0,0, Ctrl.Hwnd)                                 ;  WM_COPY     := 0x301

                        Local  Length := StrLen(A_Clipboard)
                        MySB_Tip("[Copied " Length " chars] : " SubStr(A_Clipboard, 1,47), 0)
                    }


                    CopyAsInteger(Ctrl)
                    {
                        Local  Buf  :=  Buffer(8, 0)
                            ,  Val  :=  0

                        If SelBytes > 8
                           Return MySB_Tip("[Not copied] : Selected bytes more than 8")

                        DllCall("Kernel32\RtlMoveMemory", "ptr",Buf, "ptr",Bin.Ptr+Rich1_Min, "ptr",SelBytes)
                        Val  :=  NumGet(Buf,"Int64")

                          If  GetKeyState("Control", "P")
                              Val  :=  Format("0x{:0"  (SelBytes*2) "X}", Val)
                        Else  Val  :=  Format("0x{:X}", Val)

                        A_Clipboard  :=  Val
                        MySB_Tip("[Copied " SelBytes " byte integer] : " Val, 0)
                    }


                    CopyAsBase64(Rich1)
                    {
                        Local  Offset  :=  Edit2.Value
                            ,  Base64  :=  ""
                            ,  Reqd    :=  0

                        DllCall("Crypt32\CryptBinaryToString"
                              , "ptr",Bin.Ptr+Offset, "int",SelBytes, "int",0x40000001, "ptr",0, "intp",&Reqd)

                        VarSetStrCapacity(&Base64, Reqd * 2)

                        DllCall("Crypt32\CryptBinaryToString"
                              , "ptr",Bin.Ptr+Offset, "int",Selbytes, "int",0x40000001, "str",Base64, "intp",&Reqd)

                        A_Clipboard  :=  Base64
                        MySB_Tip("[Copied " Selbytes " bytes] : " SubStr(Base64, 1,47), 0)
                    }


                    CopyAsText(Encoding)
                    {
                        If Not SubStr(Edit1.Text, 16, 2)
                           Return MySB_Tip("[Copy failed] : Begin byte cannot be null", 3000)

                        Local  Offset  :=  Edit2.Value
                            ,  Length  :=  (Bin.Size - Offset) // (Encoding="UTF-16" ? 2 : 1)

                        A_Clipboard  :=  StrGet(Bin.Ptr+Offset, Length, Encoding)
                        Length       :=  StrLen(A_Clipboard)

                        MySB_Tip("[Copied " Length " chars] : " SubStr(A_Clipboard, 1,47), 0)
                    }

    HexMenu.Add("&Copy to clipboard  "  A_Tab "Ctrl+C", (*) => CopyToClipboard(MyGui.FocusedCtrl))
    HexMenu.Add("Copy as &Integer    "  A_Tab "Ctrl+I", (*) => CopyAsInteger(Rich1))
    HexMenu.Add("Co&py as Base64     "  A_Tab "Ctrl+P", (*) => CopyAsBase64(Rich1))
    HexMenu.Add()
    HexMenu.Add("Copy &Text (unicode)"  A_Tab "Ctrl+T", (*) => CopyAsText("UTF-16"))
    HexMenu.Add("Cop&y Text (utf-8)  "  A_Tab "Ctrl+Y", (*) => CopyAsText("UTF-8"))
    HexMenu.Add()

                    HexDataGoTo(Pos)
                    {
                        If  Pos = -1
                            Return ControlSetText(UpDn1.Value, Edit2.Hwnd)

                        PostMessage(0xB1, Pos, Pos, Rich1.Hwnd)                               ;  EM_SETSEL := 0xB1
                        MySB_Tip("[Hex data] : Moved to " (Pos=0 ? "first" : "last") " offset " , 2000)
                    }

    HexMenu.Add("Goto &First offset"   A_Tab "Ctrl+F",(*) => HexDataGoTo(   0))
    HexMenu.Add("Goto &Last offset "   A_Tab "Ctrl+L",(*) => HexDataGoTo(HexL))
    HexMenu.Add("Goto Curre&nt offset" A_Tab "Ctrl+N",(*) => HexDataGoTo(  -1))

    Menus.Add("&File",         FileMenu)
    Menus.Add("&Quick-focus",  FocusMenu)
    Menus.Add("Quick-to&ggle", ToggleMenu)
    Menus.Add("&Search-types", SearchFill)
    Menus.Add("&Hex-data",     HexMenu)
    MyGui.MenuBar := Menus                                ;           ----------------   Gui MenuBar End -------------------

                    GuiClose(*)
                    {
                        If  Loading
                            Return 0

                        MySB_Tip("", 0)                                            ;  Clear any pending timers

                        If  GetKeyState("Control", "P")
                            ExitApp

                        DllCall("User32\DestroyWindow", "ptr",hTooltip)
                        MyGui.Destroy()

                        DllCall("Kernel32\FreeLibrary", "ptr",hMod1)               ;  RichEd20.dll
                        DllCall("Kernel32\FreeLibrary", "ptr",hMod2)               ;  Crypt32.dll

                        Return
                    }

    MyGui.OnEvent("Close",  GuiClose)
    MyGui.OnEvent("Escape", GuiClose)

                    GuiContextMenu(GuiObj, GuiCtrlObj, Item, IsRightClick, X, Y)
                    {
                        If    Not IsRightClick
                              Return

                        If    Type(GuiCtrlObj)    =  "String"
                              Return FileMenu.Show()

                        If    GuiCtrlObj.ClassNN  =  "RichEdit20A1"
                              Return HexMenu.Show()

                        If    GuiCtrlObj.ClassNN  =  "Static2"
                              Return SearchFill.Show()

                        FileMenu.Show()
                    }

    MyGui.OnEvent("ContextMenu", GuiContextMenu)
    MyGui.Show("AutoSize Hide")                           ;  Resize to accomodate moved Edit1 Value control
    MyGui.Show()                                          ;  Show the resized GUI

                                                          ;           -------   Rich control settings/routines  begin  -----

                    EN_SETFOCUS(*)                                                 ;  EN_SETFOCUS  := 0x100
                    {
                        If  Not SelBytes > 1
                            MySB_Tip("[Focused Edit] : Hex data", 2000)
                    }


                    EN_KILLFOCUS(*)                                                ;  EN_KILLFOCUS := 0x200
                    {
                        UpDn1.Value  :=  Rich1_Max
                        UpDn1.Value  :=  Rich1_Min
                    }

    Rich1.OnCommand(0x100, EN_SETFOCUS)
    Rich1.OnCommand(0x200, EN_KILLFOCUS)

                    EN_MSGFILTER(GuiControl, Param)                                ;  EN_MSGFILTER    := 0x700
                    {
                    ;   Triggered when Number keys are pressed when Rich1 control has focus. Pressing number keys 1 thru 8,
                    ;   (not NumPad) jumps offsets forward by as many bytes.   Combine with shift to jump offsets backward.

                        Local  Offset  :=  Param+(A_PtrSize*3)
                            ,  Key                                     
                            ,  Msg     :=  NumGet(Offset, "uint")
                            ,  wParam  :=  NumGet(Offset+4, A_PtrSize*0, "ptr")

                         If  Msg = 0x101   ;  WM_KEYUP := 0x101                    ;  When pressed key is released
                        and  IsNumber( Key := Chr(wparam) )                        ;  and the released key is a number
                        and  Key>0 and Key<9                                       ;  and number is in range of 1-8, then
                             UpDn1.Value  +=  GetKeyState("Shift", "P")            ;  If shift key is detected
                                           ?  0 - Integer(Key)                     ;  shift as many bytes backward, else
                                           :  Integer(Key)                         ;  shift as many bytes forward
                    }


                    EN_SELCHANGE(GuiControl, lParam)                               ;  EN_SELCHANGE  := 0x702
                    {
                        pCHARRANGE  :=  lParam+(A_PtrSize*3)                       ;  Called whenever Rich1,
                        Rich1_Min   :=  NumGet(pCHARRANGE, 0, "uint") // 3         ;  (Hex data) selection changes
                        Rich1_Max   :=  NumGet(pCHARRANGE, 4, "uint") // 3

                        If Rich1_Max  =  Bin.Size
                           Rich1_Max -=  1

                        SelBytes  :=  Rich1_Max - Rich1_Min + 1

                        If   UpDn1.Value != Rich1_Min
                             Edit2.OnEvent("Change", SelectByte, 0)                ;  Turn off to avoid recursive triggering
                         ,   UpDn1.Value := Rich1_Min                              ;  Update offset.    (Without SelectByte)
                         ,   Edit2.OnEvent("Change", SelectByte, 1)                ;  Turn back on event change

                        Bytes  :=  Bin.Size - UpDn1.Value
                        Bytes  :=  Bytes > 192 ? 192 : Bytes

                        Text3.Text  :=  BinToTxt192(Bin.Ptr + UpDn1.Value, Bytes)  ;  Update Text
                        NumValues(Bin, UpDn1.Value, Bytes)                         ;  Update Values

                          If  SelBytes > 1
                              MySB_Tip("[Selected bytes] : " SelBytes, 0)
                        Else
                          If  SubStr(SB_Text, 1, 19) = "[Selected bytes] : "
                              MySB_Tip("", 0)
                    }


                    SelectByte(*)  ;  Called when Edit2 (Offset) changes with Mouse wheel / Up Down arrow keys.
                    {              ;  Selects appropriate Hex, 3 times the value of Offset.
                        PostMessage(0xB1, UpDn1.Value*3, UpDn1.Value*3+2, Rich1.Hwnd) ;  EM_SETSEL := 0xB1
                    }

 ;  EM_SETEVENTMASK := 0x445,  ENM_SELCHANGE := 0x80000,  ENM_KEYEVENTS := 0x10000
 ;  EN_MSGFILTER    := 0x700,  EN_SELCHANGE  := 0x702,    EN_SETFOCUS   := 0x100.    EN_KILLFOCUS := 0x200

    SendMessage(0x445, 0, 0x80000|0x10000, Rich1.Hwnd)                             ;  Set Event Mask

    Rich1.OnNotify(0x700, EN_MSGFILTER, 1)                                         ;  Monitor number key press in Hex data
    Rich1.OnNotify(0x702, EN_SELCHANGE, 1)                                         ;  Monitor selection change in Hex data

                                                          ;           -------   Rich control settings/routines  end  -------
                    MySB_Tip(Text, TimeOut := 3000)
                    {
                        Static  Address :=  0

                        Timeout :=  Abs(TimeOut)
                        SB_Text :=  Text
                        Text    :=  RTrim(A_Space Text, A_Space)
                        MySB.SetText(Text, 2)

                        If  Address
                            DllCall("User32\KillTimer", "ptr",MyGui.Hwnd, "int",1234)
                         ,  CallbackFree(Address)
                         ,  Address := 0

                        If  TimeOut = 0
                            Return

                        Address :=  CallbackCreate( MySB_Tip.Bind("", 0), "Fast" )
                        DllCall("User32\SetTimer", "ptr",MyGui.Hwnd, "uint",1234, "uint",TimeOut, "ptr",Address)
                    }

    MySB_Tip("[Loading] ...", 0)

    Hex      :=  BufferToSHex(Bin)                                                 ;  Convert buffer to 'Spaced Hex' buffer
    DllCall("User32\SetWindowTextA", "ptr",Rich1.Hwnd, "ptr",Hex)                  ;  and apply 'Spaced Hex' into RichEdit
    Hex.Size := 0                                                                  ;  and save memory

;   Trigger offset selection in Hex data via SelectByte()

;   ControlSetText(Bin.Size-1, Edit2.Hwnd)                ;  Move to Hex last offset to fully account loading time
    ControlSetText(0, Edit2.Hwnd)                         ;  Move to Hex first offset

    TickCount  :=  Round(QPC(), 3)                        ;  End of Loading time.
    Loading    :=  False                                  ;  Mark Loading completed to allow GuiClose() to work.

    MySB_Tip("[Loading] Completed in " TickCount "s", 3000)
    Edit2.OnEvent("Focus", (*) => MySB_Tip("[Focused Edit] : Offset", 2000), 1)

    WinWaitClose(MyGui.Hwnd)
    Return 1
    ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


                    NumValues(Source, Offset, Bytes)      ;  Formats and Updates Values edit control
                    {
                        If Bytes < 1                      ;  To handle empty buffer like:     B := Buffer(0),  ListBuffer(B)
                           Return            

                        Static Buf     :=  Buffer(8)
                        Local  Num
                            ,  Double_ :=  ""
                            ,  Float_  :=  ""
                            ,  NumType :=  Bytes>7 ? "uint64" : Bytes>2 ? "uint" : Bytes>1 ? "ushort" : "uchar"
                            ,  Val     :=  0

                        If   Bytes != 3
                             Val       :=  NumGet(Source, Offset,    NumType)
                        Else           ;   read uint24
                             Val       :=  NumGet(Source, Offset,   "ushort")
                                       | ( NumGet(Source, Offset+2, "uchar" ) << 16 )

                        Num  :=  Format("{:016X}", Val)
                     ,  Num  :=  BigE

                             ?  Format( "0x{15:}{16:}"
                                     . "|0x{15:}{16:}{13:}{14:}"
                                     . "|0x{15:}{16:}{13:}{14:}{11:}{12:}"
                                     . "|0x{15:}{16:}{13:}{14:}{11:}{12:}{09:}{10:}"
                                     . "|0x{15:}{16:}{13:}{14:}{11:}{12:}{09:}{10:}{07:}{08:}{05:}{06:}{03:}{04:}{01:}{02:}"
                                     ,  StrSplit(Num)* )

                             :  Format( "0x{15:}{16:}"
                                     . "|0x{13:}{14:}{15:}{16:}"
                                     . "|0x{11:}{12:}{13:}{14:}{15:}{16:}"
                                     . "|0x{09:}{10:}{11:}{12:}{13:}{14:}{15:}{16:}"
                                     . "|0x{01:}{02:}{03:}{04:}{05:}{06:}{07:}{08:}{09:}{10:}{11:}{12:}{13:}{14:}{15:}{16:}"
                                     ,  StrSplit(Num)* )

                     ,  Num  :=  StrSplit(Num, "|")
                     ,  Num[5] += 0,  Num[4] += 0,  Num[3] += 0,  Num[2] += 0,  Num[1] += 0 ; Convert Hex to Decimal numbers

                        If Bytes > 7
                           Double_  :=  NumGet(NumPut("int64", Num[5], Buf) - 8, "double")
                        ,  Double_  :=  Format("{:.15g}", Double_)
                        ,  Double_  :=  StrLen(Double_) > 16 ? "" : Double_

                        If Bytes > 3
                           Float_   :=  NumGet(NumPut("uint",  Num[4], Buf) - 4, "float")
                        ,  Float_   :=  Format("{:.7g}", Float_)
                        ,  Float_   :=  StrLen(Float_)  >  9 ? "" : Float_

                        If Bytes < 8                                               ;  Blank out redundant zeroes
                        {
                              Num[5] := ""
                           If Bytes < 4
                              Num[4] := ""
                           If Bytes < 3
                              Num[3] := ""
                           If Bytes < 2
                              Num[2] := ""
                        }

                        Edit1.Text := Format( "Char  {1:11} {2:11}             Float"   CRLF
                                            . "Short {3:11} {4:11}  {5:16}"             CRLF
                                            . "Int24 {6:11} {7:11}                  "   CRLF
                                            . "Int32 {8:11} {9:11}            Double"   CRLF
                                            . "Int64 {10:23}  {11:16}"
                                            , Num[1]
                                            , Num[1]<0x80                     ? Num[1] : (Num[1] & 0x7F      )  - 0x80
                                            , Num[2]
                                            , Not Num[2] || Num[2]<0x8000     ? Num[2] : (Num[2] & 0x7FFF    )  - 0x8000
                                            , Float_
                                            , Num[3]
                                            , Not Num[3] || Num[3]<0x800000   ? Num[3] : (Num[3] & 0x7FFFFF  )  - 0x800000
                                            , Num[4]
                                            , Not Num[4] || Num[4]<0x80000000 ? Num[4] : (Num[4] & 0x7FFFFFFF)  - 0x80000000
                                            , Num[5]
                                            , Double_
                                            )
                    }


                    BufferToSHex(Buf)                     ;  Converts buffer content to 'Spaced Hex', much faster than 
                    {                                     ;  Crypt32.dll.  Every byte is converted in to 
                        Static mCode                      ;  2 hex Chars + 1 space = 3 Chars.   So, 1.0 MB of Buffer will
                        Local  mSz, Hex                   ;  consume 3.0 MB ANSI text (+ Null Terminator) in
                                                          ;  Rich1 (RichEdit20A) control.
                        If  not IsSet(mCode)
                            mSz := A_PtrSize=8 ? 128 : 105
                         ,  mcode := Buffer(mSz)
                         ,  DllCall("Kernel32\VirtualProtect", "ptr",mcode, "ptr",mSz, "int",0x40, "int*",0)
                         ,  DllCall("Crypt32\CryptStringToBinary"
                                  , "str",A_PtrSize=8

                                  ? "U1ZFhcB2djHARTHJDx9AAEGJwkYPthQRRYnTQcHrBESI20GD+wlAD5fWQPbeQIDmB0CAxjBAAPNEic6IHDJFid"
                                  . "NBg+MPRYjaQYP7CUEPl9NB9ttBgOMHQYDDMEUA2mdFjVkBRogUGmdFjVECQsYEEiBBg8EDg8ABRDnAcpNeW8M="

                                  : "VYnlg+wEU1ZXi30Mg30QAHZQMfYx24tNCA+2DDGJTfzB6QSIyoP5CQ+X0PbYJAcEMADCiBQfi1X8idGD4Q+Iyo"
                                  . "P5CQ+X0fbZgOEHgMEwAMqIVB8BxkQfAiCDwwNGO3UQcrRfXluJ7F3D"

                                  , "int",A_PtrSize=8 ? 172 : 140, "int",0x1, "ptr",mCode, "int*",mSz, "int",0, "int",0)

                        Hex := Buffer((Buf.Size*3) + 1)                            ;  bytes extra for null terminator
                        DllCall(mCode, "ptr",Buf, "ptr",Hex, "int",Buf.Size, "cdecl")
                        NumPut("ushort", 0, Hex, Hex.Size - 2)                      ;  put a trailing null terminator

                        Return Hex                        ;  Return 'Spaced Hex' as buffer
                    }


                    BinToTxt192(pBin, Bytes:=192)         ;  Converts binary content to printable/readable text.
                    {
                        Local  Txt  :=  BinToTxt(pBin, Bytes)
                               Txt  :=  StrGet(Txt, "cp0")

                        Return  SubStr(Txt,  1,48)  LF  SubStr(Txt,  49,48)  LF
                             .  SubStr(Txt, 97,48)  LF  SubStr(Txt, 145,48)
                    }


                    BinToTxt(pBin, Bytes)                 ;  Converts binary content to printable/readable text.
                    {                                     ;  Chrs in range of 0-32, 126-161 and 173 
                        Static mCode                      ;  are converted to Chr(46), a period '.'
                        Local  mSz, Txt

                        If  not IsSet(mCode)
                            mSz := A_PtrSize=8 ? 100 : 86
                         ,  mcode := Buffer(mSz)
                         ,  DllCall("Kernel32\VirtualProtect", "ptr",mcode, "ptr",mSz, "int",0x40, "int*",0)
                         ,  DllCall("Crypt32\CryptStringToBinary"
                                  , "str",A_PtrSize=8

                                  ? "U1ZFhcB2WjHARTHJQYnCRg+2HBFBg/sgcwe7LgAAAOsqQbouAAAAQYH7rQAAAEEPRfNBD0TyQbouAAAAQYPrf0"
                                  . "GD+yFBD0baD0feRYnKQYjbRogcEkGDwQGDwAFEOcByq15bww=="

                                  : "U1ZXg3wkGAB2SDHAMdKLTCQQD7YMAYP5IHMHvi4AAADrH78uAAAAgfmtAAAAD0X5uy4AAACD6X+D+SEPRvMPR/"
                                  . "eLTCQUifOIHBFCQDtEJBhyvF9eW8M="

                                  , "int",A_PtrSize=8 ? 136 : 116, "int",0x1, "ptr",mCode, "int*",mSz, "int",0, "int",0)

                        Txt := Buffer(Bytes)
                        DllCall(mCode, "ptr",pBin, "ptr",Txt, "int",Bytes, "cdecl")

                        Return Txt
                    }


                    TrySearch(*)                     ;  Attempt search
                    {
                        Local  Val           :=  Edit3.Text
                             , Pos           :=  0
                             , ReverseSearch :=  ChkB1.Value

                        If  not StrLen(Val)
                            Return

                        If  not InStr(Val, ":")
                            Return MySB_Tip("[Search Error] : Invalid search.  Enter 'Type:Value'")

                        If  ReverseSearch = 1  and  UpDn1.Value = 0
                            Return MySB_Tip("[Note] : Cannot search backward at first offset. Try at Offset " Bin.Size-1)

                        If  ReverseSearch = 0  and  UpDn1.Value = Bin.Size-1
                            Return MySB_Tip("[Note] : Cannot search forward at last offset. Try at Offset 0")

                        QPC(1)

                        Try Pos := Search(Bin, Val)
                        Catch as Err
                        {
                              MySB_Tip("[Search Error] : " Err.Message ".", 7000)
                              Return QPC(0)
                        }

                        SendMessage(0x434, 0, CHARRANGE, Rich1.Hwnd)                       ;  EM_EXGETSEL := 0x434
                        Selection := NumGet(CHARRANGE, 4, "uint") - NumGet(CHARRANGE, 0, "uint")

                        If  Selection  and  UpDn1.Value = Pos-1
                            Try   UpDn1.Value +=           ReverseSearch ? -1 :  1
                              ,   Pos  :=  Search(Bin, Val)
                              ,   UpDn1.Value += Pos ? 0 : ReverseSearch ?  1 : -1

                        TickCount  :=  QPC()

                        If  Pos
                        {
                            MySB_Tip("[Search] : Found at offset " Pos-1 " in " Round(TickCount*1000, 1) "ms", 10000)
                            Return ControlSetText(Pos-1, Edit2.Hwnd)
                        }

                        Local Loc := Not Selection ? "from" : ReverseSearch ? "before" : "after"
                        MySB_Tip("[Search] : Not found " Loc " offset " UpDn1.Value, 10000)
                    }


                    Search(HayBuffer, Val)                     ;  Formats user's 'search input' into proper Needle, based on
                    {                                          ;  Type and Value (Type:Value)...       Examples:
                        Val  :=  StrSplit(Val, ":",, 2)        ;  
                                                               ;  6 bytes x 8 bits = 48 bit search: '6:0x987654321000'
                        Local  valtype      :=  Trim( Val[1] ) ;                                 or '6:167633986129920'
                             , value        :=  Val[2]         ;                                 or '6:-113840990580736'
                             , Needle                          ;
                             , Len                             ;  Hex search unicode text '.ahk': ':2E 00 61 00 68 00 6B 00'
                             , Bytes        :=  0              ;  
                             , Unicode      :=  0              ;  Numput based search: 'int:-1', 'uint:1024', 'float:1.234'
                             , StartingPos                     ;  
                             , Buf          :=  Buffer(8, 0)   ;  StrPut based search: 'cp0:Fox', 'utf-8:Fox', 'utf-16:Fox'

                             , vals         :=  { int32:"int", int24:3, u:"utf-16", a:"cp0", hex:""}

                             , NumTypes     :=  { double:8, float:4, uint64:8, int64:8,  uint:4,  int:4
                                                , ushort:2, short:2,   uptr:8,   ptr:8, uchar:1, char:1 }

                        If Not StrLen(value)
                               Throw ValueError("Value empty", 0)

                        If  HasProp(vals, valtype)             ;  Translation available
                            valtype := vals.%valtype%          ;  so, translate

                          If  IsNumber(valtype)                                    ;  example 40 bit/5 byte search: '5:-255'
                          {
                              If  valtype>0 and valtype<9
                              {
                                   Try    NumPut("uint64", value, Buf)
                                     ,    Needle := Buffer(valtype)
                                     ,    DllCall("Kernel32\RtlMoveMemory", "ptr",Needle, "ptr",Buf, "ptr",valtype)
                                   Catch
                                          Throw ValueError("Invalid numerical value", -1)
                              }
                              Else Throw ValueError("Invalid bytes of " valtype " as type. Use 1 to 8", -1)
                          }

                        Else  ;  Hex based search

                          If  valtype  =   ""                                        ;  example hex search: ':FF 00 FF 00'
                          {
                              value    :=  StrReplace(value, A_Space)
                           ,  Len      :=  StrLen(value)
                           ,  Bytes    :=  Ceil(Len/2)
                           ,  Needle   :=  Buffer(Bytes)

                              If  Not DllCall("Crypt32\CryptStringToBinary", "str",value
                                                                           , "int",Len
                                                                           , "int",0xC   ;  CRYPT_STRING_HEXRAW := 0xC
                                                                           , "ptr",Needle
                                                                           , "uintp",Bytes
                                                                           , "int",0
                                                                           , "int",0)
                                      Throw ValueError("Invalid hex value" , -2)
                          }

                        Else  ; Numput based search

                          If  HasProp(NumTypes, valtype)                             ;  example num search: 'uint:1024'
                          {
                              Try     Needle   :=  Buffer(NumTypes.%valtype%)
                                   ,  NumPut(valtype, value, Needle)
                              Catch
                                     Throw ValueError("Invalid numerical value", -3)
                          }

                        Else  ; StrPut based text search

                          {
                              Try    Needle    :=  Buffer(StrPut(Value,valtype))     ;  example unicode search: 'utf-16:Fox'
                                  ,  Bytes     :=  StrPut(Value, Needle, valtype)
                                  ,  Unicode   :=  NumGet(Needle, Needle.Size-2, "ushort") = 0
                                  ,  Needle    :=  Buffer(Bytes-1-Unicode)
                                  ,  StrPut(Value, Needle, valtype)
                              Catch
                                     Throw ValueError("Invalid text search", -4)

                          }

                        Local ReverseSearch := ChkB1.Value
                        StartingPos     :=  ReverseSearch = 0 ? UpDn1.Value + 1 : UpDn1.Value - HayBuffer.Size + Needle.Size

                        If  ReverseSearch and StartingPos > 0
                            StartingPos :=  0

                        Return InBuffer(HayBuffer, Needle, StartingPos)
                    }


                    InBuffer(HayBuffer, NeedleBuffer, StartingPos)       ;  Modified/Simplified version of
                    {                                                    ;  InBin v0.60 by SKAN on D456/D459 @ tiny.cc/inbin
                        Static mCode
                        Local  mSz, Hex, Pos := 0

                        If  not IsSet(mCode)
                            mSz    :=  A_PtrSize=8 ? 183 : 180
                         ,  mcode  :=  Buffer(mSz)
                         ,  DllCall("Kernel32\VirtualProtect", "ptr",mcode, "ptr",mSz, "int",0x40, "int*",0)
                         ,  DllCall("Crypt32\CryptStringToBinary"
                                  , "str",A_PtrSize=8

                                  ? "U1ZXQVSLRCRIRItcJFCJ00Qpy4XAvgEAAABBuv////9BD07yhcB+B2dEjVD/6wgBwkGJ0kUpykSJ0kGD6QE52n"
                                  . "dnMcBBidJBijhCODwRdU9FicpHihQQZ0KNPApEOBQ5dT1Bg/kCci9BugEAAABBg/kBdh5EiddBijw4Z0aNJBJF"
                                  . "ieRCODwhdQlBg8IBRTnKcuJFOcp1A4PAAUQ52HQOAfKF0nIEOdp2mzHA6wRnjUIBQVxfXlvD"

                                  : "VYnlg+wMU1ZXi1UUi0UMKdCJRfQxwIN9GAAPntD32IPg/kCJRfiDfRgAfgmLRRhIiUX86wuLRQwDRRgp0IlF/I"
                                  . "tF/InBSjtN9HdbMcCLdQiKHA6LdRA6HnVAjTQRi30Iihw3i3UQOhwWdS+D+gJyJL4BAAAAg/oBdhaNPDGLXQiK"
                                  . "HDuLfRA6HDd1BUY51nLqOdZ1AUA7RRx0EANN+IXJcgU7TfR2pzHA6wONQQFfXluJ7F3D"

                                  , "int",A_PtrSize=8 ? 244 : 240, "int",0x1, "ptr",mCode, "int*",mSz, "int",0, "int",0)

                        Try  Pos := DllCall(mCode, "ptr",HayBuffer,      "int",HayBuffer.Size
                                                 , "ptr",NeedleBuffer, "short",NeedleBuffer.Size
                                                 , "int",StartingPos,    "int",1
                                                 , "cdecl uint")
                        Return Pos
                    }


                    CtrlSetTip(GuiCtrl, TipText, *)              ;  Original by 'just me'.
                    {                                            ;  GuiCtrlSetTip() - Add tooltips to your Gui.Controls
                         TOOLINFO  :=  Buffer(Size, 0)           ;  https://www.autohotkey.com/boards/viewtopic.php?t=116218
                                                                 ;  I've simplified it for ListBuffer().

                      ;  TTF_SUBCLASS | TTF_IDISHWND := 0x11  (TTF_SUBCLASS := 0x10, TTF_IDISHWND := 0x1)
                         NumPut("uint",Size, "uint",0x11, "uptr",MyGui.Hwnd, "uptr", MyGui.Hwnd, TOOLINFO)

                         If  Not hToolTip
                             CreateToolTip()

                                        CreateToolTip()
                                        {
                                            hToolTip := DllCall("User32\CreateWindowEx", "uint",0
                                                              , "str","tooltips_class32", "ptr",0, "uint",0x80000003
                                                              , "int",0x80000000, "int",0x80000000, "int",0x80000000
                                                              , "int",0x80000000, "ptr",MyGui.Hwnd, "ptr",0
                                                              , "ptr",0, "ptr",0, "uptr")

                                            SendMessage(0x418, 0, 480,  hToolTip)          ;  TTM_SETMAXTIPWIDTH := 0x418
                                            SendMessage(0x403, 0, 1000, hToolTip)          ;  TTM_SETDELAYTIME   := 0x403
                                                                                           ;    , TTDT_AUTOMATIC := 0

                                            DllCall("Uxtheme\SetWindowTheme", "ptr",hToolTip, "ptr",0, "ptr",0)
                                        }

                        NumPut("uptr", GuiCtrl.Hwnd, TOOLINFO, 8 + A_PtrSize)
                        SendMessage(0x0432, 0, TOOLINFO.Ptr, hToolTip)                     ;  TTM_ADDTOOLW       := 0x432

                        NumPut("uptr", StrPtr(TipText), TOOLINFO, 24 + (A_PtrSize * 3))    ;  lpszText
                      	SendMessage(0x0439, 0, TOOLINFO.Ptr, hToolTip)                     ;  TTM_UPDATETIPTEXTW := 0x439
                    }
} ; ________________________________________________________________________________________________________________________
My Scripts and Functions: V1  V2
iseahound
Posts: 1451
Joined: 13 Aug 2016, 21:04
Contact:

Re: ListBuffer() : Buffer object viewer

03 Mar 2022, 19:59

Excellent. Viewing structures has always been a wish of mine :dance:
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: ListBuffer() : Buffer object viewer

07 Mar 2022, 21:18

@iseahound :thumbup:

Trivial update:
Following added to force an always present vertical scrollbar in RichEdit control

Code: Select all

DllCall("User32\ShowScrollBar", "ptr",Rich1.Hwnd, "int",1, "int",True) ; SB_VERT 1
hasantr
Posts: 933
Joined: 05 Apr 2016, 14:18
Location: İstanbul

Re: ListBuffer() : Buffer object viewer

23 Mar 2022, 17:48

In the end, with this tool, the things that I have trouble understanding will be simpler. :)
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: ListBuffer() : Buffer object viewer

24 Mar 2022, 05:49

Excellent as always from you.
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

ListBuffer() v0.30

09 May 2023, 18:19

Updated : v0.30

A couple of silly typos fixed.
Added 24-bit value (thanks to onlinetoolz.net for Convert between unsigned and signed tool)
Using mouse-wheel scroll on Offset control was scrolling Hex content in opposite direction. Fix was as easy as reversing range option in up-down control.
For example (from docs):

Code: Select all

MyGui.AddEdit()
MyGui.AddUpDown("vMyUpDown Range1-10", 5)
should be changed to

Code: Select all

MyGui.AddEdit()
MyGui.AddUpDown("vMyUpDown Range10-1", 5)
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

ListBuffer() v0.39

15 May 2023, 16:00

Updated : v0.39

Breaking change: Bin parameter previously required VarRef, now expects a buffer.
The change doesn't seem to affect loading speed. 31 MiB "C:\Windows\System32\WindowsCodecsRaw.dll" takes only a second to fully load.

Gui.MenuBar has been included for the sake of accelerator keys.
All text labels now show a *tooltip about associated accelerator keys for the control under it.
*GuiCtrlSetTip() - Add tooltips to your Gui.Controls by @just me

Values: 24-Bit has been renamed to Int24 and Int has been renamed to Int32

The following auto-clearing Status bar text doesn't work properly when triggered from WM_COMMAND>EN_SETFOCUS() notification.

Code: Select all

MySB_Tip(Text, TimeOut := 2000)
{
    MySB.SetText(RTrim( A_Space Text, A_Space), 2)
    SetTimer((*) => MySB_Tip("", 0), 0 - Abs(Timeout))
}
This has been replaced with DllCall() based SetTimer():

Code: Select all

                    
                    MySB_Tip(Text, TimeOut := 2000)
                    {
                        Static  Address :=  0

                        Timeout :=  Abs(TimeOut)
                        Text    :=  RTrim(A_Space Text, A_Space)
                        MySB.SetText(Text, 2)

                        If  Address
                            DllCall("User32.dll\KillTimer", "ptr",MyGui.Hwnd, "int",1234)
                         ,  CallbackFree(Address)
                         ,  Address := 0

                        If  TimeOut = 0
                            Return

                        Address :=  CallbackCreate( MySB_Tip.Bind("", 0), "Fast" )
                        DllCall("User32.dll\SetTimer", "ptr",MyGui.Hwnd, "uint",1234, "uint",TimeOut, "ptr",Address)
                    }
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

ListBuffer() v0.40

16 May 2023, 12:18

Updated : v0.40

Previously

Code: Select all

                    NumValues(Source, Offset, Bytes)
                    {
                    ...
                            ,  NumType :=  Bytes>7 ? "uint64" : Bytes>2 ? "uint" : Bytes>1 ? "ushort" : "uchar"
                    ...
                        Num  :=  Format("{:016X}", NumGet(Source.Ptr+Offset, NumType))
was reading past buffer 1 byte when reading uint for the sake of int24. (When data was last 3 bytes)
Now corrected to use a legal way.

Code: Select all

                    NumValues(Source, Offset, Bytes) ; Formats and Updates Values edit control
                    {
                       ...
                            ,  NumType :=  Bytes>7 ? "uint64" : Bytes>2 ? "uint" : Bytes>1 ? "ushort" : "uchar"
                            ,  Val     :=  0

                        If   Bytes != 3
                             Val       :=  NumGet(Source, Offset,    NumType)
                        Else           ;   read uint24
                             Val       :=  NumGet(Source, Offset,   "ushort")
                                        |  NumGet(Source, Offset+2, "uchar" ) << 16

                        Num  :=  Format("{:016X}", Val)
 
 
Spoiler
 
 
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

ListBuffer() v0.42

19 May 2023, 01:41

Updated : v0.42

Code has been enhanced, many glitches fixed and code commenting has been improved.
 
 
I previously wrote: Updated : v0.39

Breaking change: Bin parameter previously required VarRef, now expects a buffer.
The change doesn't seem to affect loading speed. 31 MiB "C:\Windows\System32\WindowsCodecsRaw.dll" takes only a second to fully load.
I checked to confirm. The pointer is same for a buffer outside and inside a function.
However, The 31 MiB file takes above 5 seconds to load fully in the RichEdit control.
Find and remove comment for the line *ControlSetText(Bin.Size-1, Edit2.Hwnd) to know the full loading time.
(*That is equivalent of pressing Ctrl+End in RichEdit control).
 

Code: Select all

;   Trigger offset selection in Hex data via SelectByte()

;   ControlSetText(Bin.Size-1, Edit2.Hwnd)                ;  Move to Hex last offset to fully account loading time
    ControlSetText(0, Edit2.Hwnd)                         ;  Move to Hex first offset
Note: This would make the GUI un-moveable during full load time.
 
 
Spoiler
 
 
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

ListBuffer() v0.46

22 May 2023, 12:51

Updated : v0.46
 
Code has been enhanced, user-friendliness improved.
Few glitches fixed and code re-organised.
 
 
Spoiler
 
 
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

ListBuffer() v0.47

24 May 2023, 20:08

Updated : v0.47

Code has doubled the size in last 10 days. Final update for now.
Have included ListBuffer() in my Lib.
 
 
Spoiler
 
 
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

ListBuffer() v0.48

14 Jun 2023, 00:23

Updated : v0.48
 
Added text copying feature from current offset (both utf-16 and utf-8).
 
 
Spoiler
 
Attachments
Mixed.txt
(289 Bytes) Downloaded 97 times
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

ListBuffer() v0.49

30 Jun 2023, 11:24

Updated : v0.49

Added Copy as Base64 option for selected bytes.
This enables me to pull mcode directly from a .obj file.

For Pelles-C created .obj file,
code length is an int @offset:36
code starting pos is an int @offset:40
 
 
CopyAsBase64.png
CopyAsBase64.png (41.82 KiB) Viewed 1949 times
 
 
Attachments
ToGrayscale_64.zip
(690 Bytes) Downloaded 67 times
hasantr
Posts: 933
Joined: 05 Apr 2016, 14:18
Location: İstanbul

Re: ListBuffer() v0.49

04 Jul 2023, 13:40

SKAN wrote:
30 Jun 2023, 11:24
Updated : v0.49

Added Copy as Base64 option for selected bytes.
This enables me to pull mcode directly from a .obj file.

For Pelles-C created .obj file,
code length is an int @offset:36
code starting pos is an int @offset:40
 
 
CopyAsBase64.png
 
 

Thanks skan. I'm not as involved with AHK as I used to be, but I'm so glad to see you're okay and back. You are a very helpful and wonderful person. May everything be fine for you.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

ListBuffer()

05 Jul 2023, 01:08

Hi @hasantr
Thanks for cheering me on!
:) :thumbup:
hugojans
Posts: 1
Joined: 08 Mar 2024, 09:36

Re: ListBuffer() : Buffer object viewer

08 Mar 2024, 09:40

VERY useful! Thanks!

Return to “Scripts and Functions (v2)”

Who is online

Users browsing this forum: No registered users and 27 guests