Jump to content

Help with best way to do this function


Go to solution Solved by Andreik,

Recommended Posts

@Andreik I tried some asm these last days :)

1) First of all, I downloaded the last stable version 2.16.01 of nasm (netwide assembler) which is free, from the original nasm website and simply placed nasm.exe in a new folder C:\nasm

The goal was to be able to "quickly" compile an .asm program and grab its corresponding .obj file, to use automatically its inner binary code with AutoIt DllCallAddress function, as you did in your 1st post. Then we can modify the asm code directly from the AutoIt Edit control, compile and test again etc... all this without leaving the script, while using 2 buttons named "Compile" and "Test code"

2) To do that, I scripted a basic pattern (reusable when needed), a sort of "quick nasm compiler/tester with AutoIt" :
#include <Array.au3> ; during tests
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <SendMessage.au3>
#include <WindowsConstants.au3>

Opt("MustDeclareVars", 1) ;0=no (default), 1=require pre-declaration
Opt("GUICloseOnESC", 0) ;1=ESC closes (default), 0=ESC won't close

Global $g_Nasm_Path = "C:\nasm\", $g_Nasm_Exe = $g_Nasm_Path & "nasm.exe", $g_File_Err = $g_Nasm_Path & "nasmerr.err"
Global $g_File_Asm = $g_Nasm_Path & "test.asm", $g_File_Obj = $g_Nasm_Path & "test.obj", $g_File_Lst = $g_Nasm_Path & "test.lst"

Global $g_iGui_W = 900, $g_iGui_H = 600
Global $g_hGui = 0, $g_idEdit, $g_sAsmJustCompiled, $g_bJustCompiled, $g_sHexCode

; In case of global variables, add them here
; ...

Main()

;============================================
Func Main()

    If Not FileExists($g_Nasm_Exe) Then Exit MsgBox($MB_TOPMOST, "File doesn't exist", $g_Nasm_Exe)

    $g_hGui = GUICreate("Nasm test (v1)", $g_iGui_W, $g_iGui_H, -1, -1, _
        BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX), _
        $WS_EX_ACCEPTFILES) ; accept to maximize & resize the GUI, also accept drag & drop

    $g_idEdit = GUICtrlCreateEdit("", 1, 1, _
        $g_iGui_W - 2, $g_iGui_H - 100, _
        BitOR($ES_WANTRETURN, $WS_VSCROLL, $ES_AUTOVSCROLL)) ; no hozizontal scrollbar
        ; or if we want horizontal scrollbar : BitOR($GUI_SS_DEFAULT_EDIT))
    GUICtrlSetFont(-1, 11, 400, 0, "Lucida Console")
    GUICtrlSetState(-1, $GUI_DROPACCEPTED) ; drag & drop accepted in the edit control (it will accept .asm file content)
    GUICtrlSendMsg($g_idEdit, $EM_LIMITTEXT, -1, 0) ; added to allow unlimited text size in edit control
    _SetTabStops($g_idEdit, 14) ; 14 corresponds approx. to 4 characters width (as my Scite) in this Standard Edit control with this font

    Local $idCompile = GUICtrlCreateButton("Compile", 100, $g_iGui_H - 70 , 80, 30)

    Local $idTest = GUICtrlCreateButton("Test code", 250, $g_iGui_H - 70 , 80, 30)
    GUICtrlSetState($idTest, $GUI_DISABLE)

    GUISetState(@SW_SHOW, $g_hGui)

    ; Reload eventual .asm test file
    If FileExists($g_File_Asm) Then
        GUICtrlSetData($g_idEdit, FileRead($g_File_Asm))
    EndIf

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                If MsgBox(BitOr($MB_YESNO, $MB_TOPMOST, $MB_ICONQUESTION, $MB_DEFBUTTON2), _
                    "Attention", "Quit the script ?", 0, $g_hGui) = $IDYES Then
                        If FileExists($g_File_Asm) Then ; keep a backup, who knows...
                            FileMove($g_File_Asm, $g_File_Asm & "_bak", 1) ; $FC_OVERWRITE (1) = overwrite existing files.
                        EndIf
                        _Write_Asm()
                        ExitLoop ; While 1
                EndIf

            Case $idCompile
                GUICtrlSetState($idCompile, $GUI_DISABLE) ; prevent accidental double click on the button
                GUICtrlSetState($idTest, $GUI_DISABLE)
                $g_bJustCompiled = False
                _Compile()
                If $g_bJustCompiled Then GUICtrlSetState($idTest, $GUI_ENABLE)
                GUICtrlSetState($idCompile, $GUI_ENABLE)

            Case $idTest
                GUICtrlSetState($idTest, $GUI_DISABLE) ; prevent accidental double click on the button
                GUICtrlSetState($idCompile, $GUI_DISABLE)
                If $g_sAsmJustCompiled <> StringStripWS(GUICtrlRead($g_idEdit), 1 + 2) Then ; 1=strip leading white space, 2=strip trailing white space
                    MsgBox($MB_TOPMOST, "Watch out", "Asm code has changed, please compile", 0, $g_hGui)
                Else
                    _Test()
                EndIf
                GUICtrlSetState($idCompile, $GUI_ENABLE)
                GUICtrlSetState($idTest, $GUI_ENABLE)

            Case $GUI_EVENT_DROPPED
                If @GUI_DragId = -1 Then ; -1 means dragged from a file (only alternative is to drag from... Listview item : help file)
                    ; If StringRight(@GUI_DragFile, 4) <> ".asm" Or StringRight(@GUI_DragFile, 4) <> ".txt" Then
                    If StringRight(@GUI_DragFile, 4) <> ".asm" Then
                        ; GuiCtrlSendMsg($g_idEdit, $EM_SETREADONLY, 1, 0) ; read-only (too late, name of bad file extension already pasted in edit control)
                        MsgBox($MB_TOPMOST, "Drag & Drop", _
                            @GUI_DragFile & " does not have an .asm extension", 0, $g_hGui)
                        ; GuiCtrlSendMsg($g_idEdit, $EM_SETREADONLY, 0, 0) ; not read-only
                    Else
                        GUICtrlSetData(@GUI_DropId, FileRead(@GUI_DragFile))
                    EndIf
                EndIf
        EndSwitch
    WEnd

    ; in case of global structures in the script, release them here (not mandatory but why not)
    ; ...
    GUIDelete($g_hGui)
EndFunc   ;==>Main()

;============================================
Func _Compile()

    _Write_Asm()
    If @error Then Return

    ; Local $sCommand = " /c C:\nasm\nasm.exe -Z C:\nasm\nasmerr.err -l C:\nasm\test.lst -f win32 C:\nasm\test.asm"
    Local $sCommand = " /c " & $g_Nasm_Exe & " -Z " & $g_File_Err & " -l " & $g_File_Lst & " -f win32 " & $g_File_Asm

    Local $iRet = RunWait(@ComSpec & $sCommand, $g_Nasm_Path, @SW_HIDE)
    ; Help file RunWait : runs an external program and pauses script execution until the program finishes.
    ; Return Value :
    ; Success: the exit code of the program that was run.
    ; Failure: sets the @error flag to non-zero.

    Select
        Case @error
            MsgBox($MB_TOPMOST, "RunWait", "AutoIt error, please check AutoIt code", 0, $g_hGui)
            Return
        Case $iRet
            MsgBox($MB_TOPMOST, "Nasm compile : ERROR", FileRead($g_File_Err), 0, $g_hGui)
            Return
        Case Else
            ; get binary code from nasm list file
            Local $sFile_Lst = FileRead($g_File_Lst)
            Local $aArray = StringRegExp($sFile_Lst, '(?m)^.{16}([[:xdigit:]]{2,})', 3) ; according to $g_File_Lst format
            If @error Then
                MsgBox($MB_TOPMOST, '$aArray - StringRegExp', _
                    'error = ' & @error & (@error = 1 ? ' (no matches)' : ' (bad pattern)'), 0, $g_hGui)
                Return
            EndIf

            ; get binary code from nasm obj file (preparing a double check)
            Local $hFile_Obj = FileOpen($g_File_Obj, 0 + 16) ; $FO_READ = 0 , $FO_BINARY = 16
            If $hFile_Obj = -1 Then
                MsgBox($MB_TOPMOST, "FileOpen error", $g_File_Obj & " could not be opened", 0, $g_hGui)
                Return
            EndIf
            Local $aArray2 = StringRegExp(FileRead($hFile_Obj), '000020005060(.+)2E66696C6500', 3) ; according to $g_File_Obj format
            If @error Then
                MsgBox(0, '$aArray2 - StringRegExp', _
                    'error = ' & @error & (@error = 1 ? ' (no matches)' : ' (bad pattern)'), 0, $g_hGui)
                FileClose($hFile_Obj)
                Return
            EndIf
            FileClose($hFile_Obj)

            ; double check binary code extracted from nasm list file with binary code found in nasm obj file
            $g_sHexCode = ""
            For $i = 0 To Ubound($aArray) - 1
                $g_sHexCode &= $aArray[$i]
            Next
            If $g_sHexCode <> $aArray2[0] Then
                MsgBox($MB_TOPMOST, "Double check error", "Binary code is different between these 2 files :" & @crlf & _
                    $g_File_Lst & @crlf & _
                    $g_File_Obj, 0, $g_hGui)
                $g_sHexCode = ""
                Return
            Else
                MsgBox($MB_TOPMOST, "Nasm compile : done", $sFile_Lst, 0, $g_hGui)
                ; _ArrayDisplay($aArray)
            EndIf
    EndSelect

    $g_sAsmJustCompiled = StringStripWS(GUICtrlRead($g_idEdit), 1 + 2) ; 1=strip leading white space, 2=strip trailing white space
    $g_bJustCompiled = True
EndFunc   ;==>_Compile

;============================================
Func _Write_Asm()

    Local $hFile_Asm = FileOpen($g_File_Asm, 2) ; 2 = Write mode (erase previous contents)
    If $hFile_Asm = -1 Then
        ClipPut(GUICtrlRead($g_idEdit))
        MsgBox($MB_TOPMOST, "FileOpen error", _
            $g_File_Asm & " could not be opened" & @crlf & _
            "(Asm code has been copied to the Clipboard)" , 0, $g_hGui)
        Return SetError(1, 0, 0)
    Else
        FileWrite($hFile_Asm, GUICtrlRead($g_idEdit))
        FileClose($hFile_Asm)
    EndIf
EndFunc   ;==>_Write_Asm

;============================================
Func _SetTabStops($hWnd, $iTabStops)

    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)

    ; Next line _SendMessage based on _GUICtrlEdit_SetTabStops / _GUICtrlRichEdit_SetTabStops, with "uint*" instead of "struct*" of course.
    _SendMessage($hWnd, $EM_SETTABSTOPS, 1, $iTabStops, 0, "wparam", "uint*")
EndFunc   ;==>_SetTabStops

;============================================
Func _Test()
    If $g_bJustCompiled Then ; only once after each successful compile.
        ; set/reset functions here.
        ; ...
        $g_bJustCompiled = False
    EndIf

    ; launch function tests then display results here.
    ; ...
    MsgBox($MB_TOPMOST, "Test", "Done", 0, $g_hGui)
EndFunc   ;==>_Test

3) Now we can add some code to the pattern, for example :
; 1) if you got Global variables, place them at the beginning of program, before Main()
; =====================================================================================
Global $g_tData = DllStructCreate('int Data[100000]'), $g_NbElem

...

; 2) replace the _Test() function of the pattern with your own _Test() function
; =============================================================================
Func _Test()
    If $g_bJustCompiled Then ; only once after each successful compile.
        ; set/reset functions here.
        FillStruct($g_tData) ; fill it with 0xFFFFFFFF everywhere
        LoadSomeTestNumbers2($g_tData) ; this will also reset $g_NbElem (+++)
        $g_bJustCompiled = False
    EndIf

    ; launch function tests then display results here.
    Local $Minimum = GetMinimum($g_tData)
    WriteNumber($g_tData, $Minimum)
    MsgBox($MB_TOPMOST, "Minimum", $Minimum, 0, $g_hGui)
EndFunc   ;==>_Test

...

; 3) place your own functions at the end of the script
; ====================================================
Func FillStruct(ByRef $tStruct)
    Local $Code = Binary('0x8B7424048B4C2408C706FFFFFFFF83C604E2F5C20800') ; Andreik's original
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4)
EndFunc

Func LoadSomeTestNumbers2(ByRef $tStruct)
    $g_NbElem = 10000
    Local $aNumbers[$g_NbElem]
    For $Index = 10 To ($g_NbElem - 1) + 10 ; 10000 times (from 10 To 10009)
        WriteNumber($tStruct, $Index)
    Next
EndFunc

Func GetMinimum(ByRef $tStruct)
    Local $Code = Binary('0x' & $g_sHexCode)
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
;~  Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4)

    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', $g_NbElem) ; ok too here...
    $g_NbElem += 1 ; ...but then, don't forget to increment $g_NbElem !

    Return $aCall[0]
EndFunc

Func WriteNumber(ByRef $tStruct, $Minimum)
    Local $Code = Binary('0x8B7424048B4C24088B54240CAD83F8FF7409E2F8B8FFFFFFFFEB088956FCB800000000C20C00') ; Andreik's original
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4, 'int', $Minimum)
    Return $aCall[0]
EndFunc

Here is a display of the minimalist GUI :

QPx9cRlj_o.png

Here are some basic .asm codes I tested, trying to get correct results when dealing with signed integers > 7FFFFFFF
;============================================
; https://www.autoitscript.com/forum/topic/210242-help-with-best-way-to-do-this-function/?do=findComment&comment=1518466
; original andreik asm code starting search from 0 (will return a minimum = 0 which is correct...
;  as elements of structure go from 10 to 10009)
mov esi, [esp + 4]
mov ecx, [esp + 8] ; counter for LOOP/LOOPcc
xor edx, edx ; blanks edx (same as mov edx, 0)
next:
lodsd
cmp eax, edx
je increase
loop next
jmp exit
increase:
mov esi, [esp + 4]
mov ecx, [esp + 8]
inc edx
jmp next
exit:
mov eax, edx
ret 8

============================================
; https://www.autoitscript.com/forum/topic/210242-help-with-best-way-to-do-this-function/?do=findComment&comment=1518527
; andreik asm code + my change starting search from 10 (will return a minimum = 10010 which is correct...
; ...as elements of structure go from 10 to 10009)
mov esi, [esp + 4]
mov ecx, [esp + 8]

; xor edx, edx ; blanks edx (same as mov edx, 0)
mov edx, 10

next:
lodsd
cmp eax, edx
je increase
loop next
jmp exit
increase:
mov esi, [esp + 4]
mov ecx, [esp + 8]
inc edx
jmp next
exit:
mov eax, edx
ret 8

============================================
; https://stackoverflow.com/questions/42795616/unsigned-integers-in-assembly
; search lowest value found in test elements (10 to 10009 => 10) and return it in eax (e.g. AutoIt $aCall[0])
; remember that integers starting from 080000000h (-2147483647) to 0FFFFFFFFh (-1) are signed integers, so...
; ...if we mov edx, 0FFFFFFFFh and want it to be an unsigned integer, then some jump instructions has to...
; ...be changed : no more jg, jl, etc... (signed interpretation) but ja, jb, etc... (unsigned interpretation)

; testing the lowest value of test elements (which are integers from 10 to 10009) depending on an...
; initial mov edx, ... (test also the whole structure elements which contain lots of 0FFFFFFFFh !)

; 000000000h = 0
; 07FFFFFFFh = 2147483647
; 080000000h = -2147483648
; 080000001h = -2147483647
; 0FFFFFFFEh = -2
; 0FFFFFFFFh = -1

mov esi, [esp + 4]
mov ecx, [esp + 8] ; counter for LOOP/LOOPcc

; mov edx, 000000000h ; then jl found_lower => 0 (good) and jb found_lower => 0 (good) ...
; ... when loop only in test elements (which seems the best way to loop)

; mov edx, 000000000h ; then jl found_lower => -1 (bad) and jb found_lower => 0 (good) ...
; ... when loop in test elements + all remaining elements of the structure (as 0FFFFFFFFh will be found !)

; mov edx, 07FFFFFFFh ; then jl found_lower => 10 (good) and jb found_lower => 10 (good) ...
; ... when loop only in test elements (which seems the best way to loop)

; mov edx, 07FFFFFFFh ; jl found_lower => -1 (bad) but jb found_lower => 10 (good) ...
; ... when loop in test elements + all remaining elements of the structure (as 0FFFFFFFFh will be found !)

; Below, same result if test on panel elements or on the whole structure elements (including panel elements)

; mov edx, 080000000h ; then jl found_lower => -2147483648 (bad) but jb found_lower => 10 (good)
; mov edx, 080000001h ; then jl found_lower => -2147483647 (bad) but jb found_lower => 10 (good)
; mov edx, 0FFFFFFFEh ; then jl found_lower => -2 (bad) but jb found_lower => 10 (good)
mov edx, 0FFFFFFFFh ; then jl found_lower => -1 (bad) but jb found_lower => 10 (good)

find_lowest:
lodsd
cmp eax, edx

; jl found_lower ; bad result for signed integers 080000000h to 0FFFFFFFFh
jb found_lower ; good result for unsigned integers 080000000h to 0FFFFFFFFh

continueloop:
loop find_lowest
jmp exit

found_lower:
mov edx, eax
jmp continueloop

exit:
mov eax, edx ; returned to AutoIt $aCall[0]
ret 8

=====================================
; several clicks on Test button will display the minimum values > test elements (which go from 10 to 10009)

mov esi, [esp + 4]  ; 1st AutoIt parameter (first test element of AutoIt structure)
mov ecx, [esp + 8]  ; 2nd AutoIt parameter (counter for LOOP/LOOPcc)
mov edx, 0FFFFFFFFh ; watch out as -1 if treated as signed integer (by jg, jl, etc...)

find_lowest:
lodsd               ; the "no-operand" syntax (esi is the source operand, eax the destination operand)
cmp eax, edx

; jl found_lower    ; 0 bad (as -1 first time, then only 1 inc edx => 0) then 1, 2... (all bad)
jb found_lower      ; 10010 good (1st number > 10 when test elements go from 10 to 10009) then 10011, 10012...

continueloop:
loop find_lowest
jmp search_empty

found_lower:
mov edx, eax
jmp continueloop

search_empty:
mov esi, [esp + 4]
mov ecx, [esp + 8]
inc edx

next:
lodsd
cmp eax, edx
je search_empty
loop next

mov eax, edx        ; eax content returned to AutoIt $aCall[0]
ret 8               ; 8 to remove both parameters from stack

It's easy to copy each one of the asm code and paste it directly in the Edit control of the Gui, click compile and test etc... Maybe this AutoIt pattern could be helpful for some users (like me) to discover and test some asm instructions.
Thanks for reading :)
Link to comment
Share on other sites

@pixelsearch It's good that you are practicing. I usually use FASM, a well maintained compiler, available as DLL also (110 kb) so it can be loaded from memory and can produce binary code very fast and without any other dependecies. Ahh and there is an UDF for inline FASM which is also available with an OOP like syntax.

Here is a simple example, I think from ward's UDF:

Func Demo2()
    ; Demo 2: Read Time-Stamp Counter
    $F.Reset()
    $F.Add("use32")
    $F.Add("push ebp")
    $F.Add("mov ebp, esp")
    $F.Add("rdtsc")
    $F.Add("mov ecx, [ebp + 08]")
    $F.Add("mov [ecx], edx")
    $F.Add("pop ebp")
    $F.Add("ret 4")

    ConsoleWrite(String($F.GetBinary()) & @CRLF)

    Local $Ret = MemoryFuncCall("uint", $F.GetFuncPtr(), "uint*", 0)
    MsgBox(0, "Demo 2: Read Time-Stamp Counter", "RDTSC = " & Hex($Ret[1]) &  Hex($Ret[0], 8))
    Return Hex($Ret[1]) &  Hex($Ret[0], 8)
EndFunc

Isn't nice to write asm directly in AutoIt without external dependencies?

When the words fail... music speaks.

Link to comment
Share on other sites

@Andreik Hi, two things

1/ I don't understand how to update the code to have the minimum value be 1. I've been staring at your follow up post and pixelsearch's example where he got it to start at 2 for the past 20 min and can't figure out how to translate it and implement it in my code to start at 1.

2/ I don't understand

Global $tData = DllStructCreate('int Data[20000]')

and how to work with it later as I expand. Is that simply the max value of the array that I will be working with, so for arguments sake if my array is up to 50,000 I would then increase that to 50,000?

 

Thanks.

Link to comment
Share on other sites

1. Just replace the first line of the function GetMinimum() with the code below.

Local $Code = Binary('0x8B7424048B4C2408BA01000000AD39D07404E2F9EB0B8B7424048B4C240842EBEC89D0C20800')

2. That's true.

Global $tData = DllStructCreate('int Data[50000]')

The code above will create a structure that can hold 50k integers and nothing has to be changed in the code.

Edit: to test the code probably you should replace also in LoadSomeTestNumbers() the content of $aNumbers. Instead of 1 just write a different number and let the program identify 1 as minimum.

Func LoadSomeTestNumbers($cListView, $tStruct)
    Local $aNumbers[10] = [15, 1, 6, 5, 7, 9, 3, 8, 12, 25]
    For $Index = 0 To 9
        GUICtrlCreateListViewItem($aNumbers[$Index], $cListView)
        WriteNumber($tData, $aNumbers[$Index])
    Next
EndFunc

Edit#2: you can also have a more specialized function that will accept a new parameter $iMinimum so you can indicate from what number do you want to search for your minimum value. So it doesn't need to be 0 or 1 but anything you want and can be just an optional parameter.

Func GetMinimum($tStruct, $iMinimum = 1)
    Local $Code = Binary('0x8B7424048B4C24088B54240CAD39D07404E2F9EB0B8B7424048B4C240842EBEC89D0C20C00')
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4, 'int', $iMinimum)
    Return $aCall[0]
EndFunc

 

Edited by Andreik

When the words fail... music speaks.

Link to comment
Share on other sites

  • 1 month later...

Just came across this FWIW if there is a simple fix...no biggie, if the lowest number is 100 it returns 1...even though 1 is already used. I have to hit enter again for it to return 101. It might have been a hickup because I didn't run any tests to reproduce it after it happened. Beyond that it's been perfect.

Link to comment
Share on other sites

I am not sure if I understand what issue do you have. Did you have all numbers up to 100 already allocated (lowest number 100) and the next number returned it's 1 instead of 101? If this is the case you have a problem in your code logic. The code below allocate all numbers up to 100, so 100 it's the lowest number and when I click on 100th cell the next number generated it's 101, as expected.

#include <WinAPIDiag.au3>

Global $hListView, $cListView
Global $tData = DllStructCreate('int Data[20000]')

$hMain = GUICreate('Sample code', 400, 400)
$cListView = GUICtrlCreateListView('Numbers', 10, 10, 380, 380, 0x0C, 0x21) ; LVS_SINGLESEL, LVS_SHOWSELALWAYS, LVS_EX_GRIDLINES, LVS_EX_FULLROWSELECT
$hListView = GUICtrlGetHandle($cListView)
GUISetState(@SW_SHOW, $hMain)

FillStruct($tData)

; Allocate first 100 numbers
For $Index = 1 To 100
    GUICtrlCreateListViewItem($Index, $cListView)
    WriteNumber($tData, $Index)
Next

GUIRegisterMsg(0x004E, 'WM_NOTIFY')

Do
    Sleep(10)
Until GUIGetMsg() = -3 ; GUI_EVENT_CLOSE

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
        #forceref $hWnd, $iMsg, $wParam
        Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
        Local $iCode = DllStructGetData($tNMHDR, "Code")
        If $hListView = HWnd(DllStructGetData($tNMHDR, "hWndFrom")) And $iCode = -2 Then    ; NM_CLICK
            Local $tNMITEMACTIVATE = DllStructCreate($tagNMITEMACTIVATE, $lParam)
            ; When I click a particular cell (let's say 100th cell of the listview)
            If DllStructGetData($tNMITEMACTIVATE, 'Index') = 99 Then
                Local $Minimum = GetMinimum($tData)
                GUICtrlCreateListViewItem($Minimum, $cListView)
                WriteNumber($tData, $Minimum)
            EndIf
        EndIf
        Return 'GUI_RUNDEFMSG'
EndFunc

Func FillStruct($tStruct)
    Local $Code = Binary('0x8B7424048B4C2408C706FFFFFFFF83C604E2F5C20800')
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4)
EndFunc

Func GetMinimum($tStruct, $iMinimum = 1)
    Local $Code = Binary('0x8B7424048B4C24088B54240CAD39D07404E2F9EB0B8B7424048B4C240842EBEC89D0C20C00')
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4, 'int', $iMinimum)
    Return $aCall[0]
EndFunc

Func WriteNumber($tStruct, $Minimum)
    Local $Code = Binary('0x8B7424048B4C24088B54240CAD83F8FF7409E2F8B8FFFFFFFFEB088956FCB800000000C20C00')
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4, 'int', $Minimum)
    Return $aCall[0]
EndFunc

 

Edited by Andreik

When the words fail... music speaks.

Link to comment
Share on other sites

  • 8 months later...

Something like this?

#include <WinAPIDiag.au3>

Global $tData = DllStructCreate('int Data[20]')

FillStruct($tData)

DllStructSetData($tData, 'Data', 22, 6)
DllStructSetData($tData, 'Data', 23, 9)
DllStructSetData($tData, 'Data', 25, 11)
DllStructSetData($tData, 'Data', 25, 17)
_WinAPI_DisplayStruct($tData, 'int Data[20]')

DeleteNumber($tData, 25)
_WinAPI_DisplayStruct($tData, 'int Data[20]')

Func FillStruct($tStruct)
    Local $Code = Binary('0x8B7424048B4C2408C706FFFFFFFF83C604E2F5C20800')
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4)
EndFunc

Func DeleteNumber($tStruct, $iValue)
    Local $Code = Binary('0x8B7424048B4C24088B54240CAD39D07507C746FCFFFFFFFFE2F2C20C00')
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4, 'int', $iValue)
EndFunc

 

When the words fail... music speaks.

Link to comment
Share on other sites

Posted (edited)

Yes, that's it exactly thanks. One more another thing...I tried to figure it out myself, but I don't understand how this is working...particularly how the Binary $Code is created in the first place, where does that string come from. Or what to search for exactly to figure this out.

Anyway, can you give me a search function to search for how many of a particular value are in the structure (I've expanded the use of this)? And also tell me what exactly I can read up on, or what to search for, to try and learn about this and coming up binary strings necessary to do things I want?

Thanks

Edited by Champak
Link to comment
Share on other sites

7 hours ago, Champak said:

And also tell me what exactly I can read up on, or what to search for, to try and learn about this and coming up binary strings necessary to do things I want?

Assembly. I usually use FASM but you can use whatever flavor you like.

7 hours ago, Champak said:

One more another thing...I tried to figure it out myself, but I don't understand how this is working...particularly how the Binary $Code is created in the first place, where does that string come from.

8B 74 24 04                 mov    esi, [esp+4]                     ; ESI = pointer to the data struct
8B 4C 24 08                 mov    ecx, [esp+8]                     ; ECX = number of items in the struct
8B 54 24 0C                 mov    edx, [esp+12]                    ; EDX = value to be deleted
                    next:
AD                          lodsd                                   ; Load dword at address DS:ESI into EAX. ESI is incremented by 4.
39 D0                       cmp    eax, edx                         ; Compare data loaded in EAX with the value that you intend to delete
75 07                       jne    skip                             ; If is different then skip the overwrite operation (with default value)
C7 46 FC FF FF FF FF        mov    DWORD PTR [esi-4], 0xffffffff    ; Otherwise overwrite previously compared data with default value
                    skip:
E2 F2                       loop   next                             ; Loop the process until every item in the struct is verified
C2 0C 00                    ret    12                               ; Return from function

 

7 hours ago, Champak said:

Anyway, can you give me a search function to search for how many of a particular value are in the structure (I've expanded the use of this)?

This is possible but it won't break the original functionality, since you tried to dinamically obtain a new minimum (and distinct) value that was not allocated yet?

Global $tData = DllStructCreate('int Data[20]')

FillStruct($tData)

DllStructSetData($tData, 'Data', 22, 6)
DllStructSetData($tData, 'Data', 23, 9)
DllStructSetData($tData, 'Data', 25, 11)
DllStructSetData($tData, 'Data', 25, 17)

ConsoleWrite("Items containing the value 25: " & CountValue($tData, 25) & @CRLF)
ConsoleWrite("Empty items: " & CountValue($tData, -1) & @CRLF)

Func FillStruct($tStruct)
    Local $Code = Binary('0x8B7424048B4C2408C706FFFFFFFF83C604E2F5C20800')
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4)
EndFunc

Func CountValue($tStruct, $iValue)
    Local $Code = Binary('0x8B7424048B4C24088B54240C31DBAD39D0750143E2F889D8C20C00')
    Local $iSize = BinaryLen($Code)
    Local $tCode = DllStructCreate('byte Code[' & $iSize & ']')
    DllStructSetData($tCode, 'Code', $Code)
    Local $aCall = DllCallAddress('int', DllStructGetPtr($tCode), 'ptr', DllStructGetPtr($tStruct), 'int', DllStructGetSize($tStruct) / 4, 'int', $iValue)
    Return $aCall[0]
EndFunc

And here is the ASM code and the corresponding binary data from my Real Time Assembler.

rta.jpg

Edited by Andreik

When the words fail... music speaks.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...