Usage examples:
Example 1:
Convert a pointer to buffer and view it :
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)
Example 2:
View file contents:
View file contents:
Code: Select all
#Requires AutoHotkey v2.0
#SingleInstance
Bin := FileRead(A_AhkPath, "RAW")
ListBuffer(Bin, A_AhkPath)
Example 3:
View a structure:
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")
Example 4:
8 bytes double values example. Search for float:3.48225:
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)
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
}
} ; ________________________________________________________________________________________________________________________