Jump to content

Recommended Posts

Posted

Yes, I ended up removing the Do loop when I realised the same, it was useful to increase accuracy for previous versions of the script that would return nothing when nothing was recognised, but since these latest versions seem to fallback to returning 0000 or 1111 for unrecognised numbers it's no longer necessary. Thanks for the optimisation tips, I knew writing to the file each time was slow but didn't know of a better way to do it, I'll convert it to use an array instead.

Posted (edited)

oops, one more, we dont need to create the dllstruct a million times either, just once in the top...

Global $posx = 1715, $posy = 705, $result = "", $code[4], $capture, $pixels = DllStructCreate('dword[2816]')
.
.
.
.
Func Getnumber($result)
    
    Local $code[4] = [0,0,0,0], $value = 64; dllstructcreate was here, moved to top
    DllCall('gdi32.dll', 'dword', 'GetBitmapBits', 'ptr', $capture, 'dword', DllStructGetSize($pixels), 'ptr', DllStructGetPtr($pixels))

For $loop = 1 To 2816 Step 440
    $code[0] += DllStructGetData($pixels, 1, $loop   ) > 4278190080 ? $value:0
    $code[1] += DllStructGetData($pixels, 1, $loop+29) > 4278190080 ? $value:0
    $code[2] += DllStructGetData($pixels, 1, $loop+58) > 4278190080 ? $value:0
    $code[3] += DllStructGetData($pixels, 1, $loop+87) > 4278190080 ? $value:0
    $value /= 2
Next
    Return String($digit[$code[0]]) & String($digit[$code[1]]) & String($digit[$code[2]]) & String($digit[$code[3]])
EndFunc

For some reason we cant hardcode the dllstructgetsize and getptr, so they'll have to stay.

Edited by Werty

Some guy's script + some other guy's script = my script!

Posted
19 hours ago, Werty said:

oops, one more, we dont need to create the dllstruct a million times either, just once in the top...

Global $posx = 1715, $posy = 705, $result = "", $code[4], $capture, $pixels = DllStructCreate('dword[2816]')
.
.
.
.
Func Getnumber($result)
    
    Local $code[4] = [0,0,0,0], $value = 64; dllstructcreate was here, moved to top
    DllCall('gdi32.dll', 'dword', 'GetBitmapBits', 'ptr', $capture, 'dword', DllStructGetSize($pixels), 'ptr', DllStructGetPtr($pixels))

For $loop = 1 To 2816 Step 440
    $code[0] += DllStructGetData($pixels, 1, $loop   ) > 4278190080 ? $value:0
    $code[1] += DllStructGetData($pixels, 1, $loop+29) > 4278190080 ? $value:0
    $code[2] += DllStructGetData($pixels, 1, $loop+58) > 4278190080 ? $value:0
    $code[3] += DllStructGetData($pixels, 1, $loop+87) > 4278190080 ? $value:0
    $value /= 2
Next
    Return String($digit[$code[0]]) & String($digit[$code[1]]) & String($digit[$code[2]]) & String($digit[$code[3]])
EndFunc

For some reason we cant hardcode the dllstructgetsize and getptr, so they'll have to stay.

Great catch again, I've now implemented both solutions. Minor nitpick is that WriteFileFromArray doesn't currently support LF line endings so I have to use dos2unix on the output, which I reported as a bug here, but apart from that it works perfectly.

Just out of interest, if in the future I wanted to use this to brute-force a larger range of serial numbers (7, 8 or 9 digits instead of 6) the amount of failed cases might get a little too much to handle manually like I am now, and this also requires that I run the script with two different methods and diff both files. Is there an easy way of making it so that the script does fallback to returning nothing instead of 0000 when nothing is recognised, so that I can then bring back the Do Until loop to take a little more time on those particular numbers? If this would require too much work don't worry about it, but if it's an easy change it would be a huge improvement to the robustness of the script.

Also as requested I have now donated to AutoIt, thanks once again everyone.

Posted (edited)

Are there any patterns in which serials/results that fail? Is it the same every run, the same results that fails, or is it random, it's really difficult to help when we dont have access to the tools.exe program to test ourselfes

As for the filewritefromarray, you could instead of using an array use a single big string, then it's just a simple filewrite.

Local $BigString = ""
For $loop = 0 To 999999

        ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100)
        _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020)
        $BigString &= String(StringFormat('%06i', $loop)) & "," & String(GetNumber($result)) & @LF
Next
_WinAPI_DeleteDC($hCDC)
FileWrite($db, $BigString)

Something like this.

Edited by Werty

Some guy's script + some other guy's script = my script!

Posted (edited)
Quote

 larger range of serial numbers (7, 8 or 9 digits instead of 6) 

A little hard to say as it depends on what font you have bold, italic etc. As far as I can see below is not failing at any digits.

This demo script would work for any number of characters as long as you teach the system how it works with the magic strings.

There are many ways to speed it up (for example by taking a smaller snapshot within the digit matrix area)

Script explanation

  • It scales the bitmap back to 8*8 = 64 bytes and just compares the string (Scaling smaller did not work with initial testing)
    Local $pBitmap= _GDIPlus_ImageResize($pBitmap1, 8, 8) ;resize image
  • Get the magic numbers
    local $learnTheDigits=false    ;~Use this to learn the 0-9 digit magic values

 

  • Paste the magic lines (by just comparing the magic numbers as string, speed could be improved by comparing the binary values)
    if ($stringForDigit='0x00022220020000220200022202002020020020200220002022000020002222') then $num=0
    if ($stringForDigit='0x00002000002220000000200000002000000220000002000000020000002222') then $num=1
    if ($stringForDigit='0x00022220020000220000002200002200000022000020000022000000222222') then $num=2
    if ($stringForDigit='0x00022220020000220000002200002200000022000000002022000020002222') then $num=3
    if ($stringForDigit='0x00000220000022000022020002000200020002000222222000002200000022') then $num=4
    if ($stringForDigit='0x02222222020000000222220000000020000000200000002022000020002222') then $num=5
    if ($stringForDigit='0x00002220002200000200000002222200022222000200002022000020002222') then $num=6
    if ($stringForDigit='0x02222222000000220000020000002000000020000020000000200000002000') then $num=7
    if ($stringForDigit='0x00022220020000220200002200222200002222000200002022000020002222') then $num=8
    if ($stringForDigit='0x00022220020000220200002200222222002222200000002000002200002200') then $num=9
  • Iterate 6 digits (or 7,8,9)
$charHigh=5 ;~ As it starts counting from 0
  • Do it full speed / turning of the explainer part
    local $showDigits=false

     


full script
 

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <ScreenCapture.au3>

dim $bmpData, $w, $h, $s
dim $pic[10],$BitmapFilename, $hImage, $Bmp

; Initialize GDI+ library
_GDIPlus_Startup()

#Region ### START Koda GUI section ### Form=
$frmCompare = GUICreate("Another bitmap brute-forcing thread", 1024, 768, 193, 125)

for $picId=0 to 9
    $BitmapFilename = @UserProfileDir & "\downloads\examples\" & string($picId) & ".png"
    $pBitmap = _GDIPlus_BitmapCreateFromFile($BitmapFilename)
    $hImage=_GDIPlus_ImageLoadFromFile($BitmapFilename)
    $Bmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
;~          $hBitmap = _GDIPlus_ImageLoadFromFile($BMPFile)

;~  ConsoleWrite("Bitmap Width:    " & _GDIPlus_ImageGetWidth($pBitmap) & @CRLF )
;~     ConsoleWrite("Bitmap Height:      " & _GDIPlus_ImageGetHeight($pBitmap) & @CRLF)

    $Pic[$picId] = GUICtrlCreatePic("", 32, 24+($picId*60), 100, 100, BitOR($SS_NOTIFY,$WS_GROUP,$WS_CLIPSIBLINGS))

    _WinAPI_DeleteObject(GUICtrlSendMsg($Pic[$picId], $STM_SETIMAGE, $iMAGE_BITMAP, $Bmp))
Next

$editBox = GuiCtrlCreateEdit("Analytics box", 250,14,700,750)
GUICtrlSetFont($editBox, 8, 100, 0, "Courier New")
$Button1 = GUICtrlCreateButton("Analyse", 104, 700, 75, 25, 0)
$Button2 = GUICtrlCreateButton("Button2", 104, 730, 75, 25, 0)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

$picIdWidth=100
$picIdHeight=100
$picIdX=0
$picIdY=0

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            _GDIPlus_Shutdown()
            Exit
        Case $Button1
            analyse()
        Case $Button2
    EndSwitch
WEnd

func analyse()
    WinActivate($frmCompare)

    Local $wPos = WinGetPos($frmCompare)
;~      $aArray[0] = X position    $aArray[1] = Y position    $aArray[2] = Width    $aArray[3] = Height
    Local $aClientSize = WinGetClientSize($frmCompare)
;~  $aArray[0] = Width of window's client area    $aArray[1] = Height of window's client area
    Local $cLeft= ($wpos[2]-$aClientSize[0])/2
    Local $cTop= ($wPos[3]-$aClientSize[1])-2
    Local $bytesPerDigit = 1 ;~ could be 1 or 2 or 3 bytes

    for $picId=0 to 9
         Local $cPos = ControlGetPos ( $frmCompare, "", $pic[$picId] )

;~          $aArray[0] = X position
;~     $aArray[1] = Y position
;~     $aArray[2] = Width
;~     $aArray[3] = Height
;~

    ;~ $tLeft, $tRight, $tTop, $tBottom, $color = 0xFF, $PenWidth = 1
    ;~      _Screen_DrawRect($wpos[0]+$cLeft+$cPos[0],$wPos[0]+$cPos[0] + $cPos[2], $wPos[1] + $cTop +$cPos[1], $wPos[1] + $cTop + $cPos[1] + $cPos[3])

    local $learnTheDigits=false    ;~Use this to learn the 0-9 digit magic values
    local $showDigits=true
    local $charLow=1, $charHigh=1
    if ($learnTheDigits = false) Then
        $charLow=0
        $charHigh=5
    EndIf

    for $charId=$charlow to $charHigh
            local $charWidth=29
            local $leftMatrix=($charId*$charWidth)+$wpos[0]+$cLeft+$cPos[0]
            local $rightMatrix=$charWidth+($charId*$charWidth)+$wPos[0]+$cLeft+$cPos[0]
            local $topMatrix= $wPos[1] + $cTop +$cPos[1] + 10
            local $bottomMatrix=$wPos[1] + $cTop + $cPos[1] + $cPos[3] -2 -11

            local $x, $y

            Local $bytesForDigit="", $widthMatrix=0, $heightMatrix=0, $stride=0
    ;~      Func GetImageDataFromScreen($left, $right, $top, $bottom, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride, $picIdmgBytes=3)

;~Play with this to take a smaller area
            GetImageDataFromScreen($leftMatrix, $topMatrix, $rightMatrix,  $bottomMatrix, $bytesForDigit, $widthMatrix, $heightMatrix, $stride, $bytesPerDigit)

;~  consolewrite(BinaryLen($bytesForDigit) & " " & stringlen($bytesForDigit) & " " & $widthMatrix & "-" & $heightMatrix & "-" &  $stride &@CRLF)

            local $textoutput= "     0         1         2         3         4         5         6         7         8         " & @CRLF
                  $textoutput&="     012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" & @CRLF

;~             strip 0x
;~ consolewrite(stringleft(string($bytesForDigit),20))
            local $stringForDigit=string($bytesForDigit)
;~          consolewrite(binarylen($bytesforDigit) & "-" & stringlen($stringforDigit) & "-" & $stringforDigit)
    if ($learnTheDigits=true) then
        consolewrite("                     if ($stringForDigit='" & $stringforDigit & "') then $num=" & $picId)
    Else

;~ consolewrite($bytesForDigit & @crlf)
;~          consolewrite($stringForDigit & @CRLF)

;~             local $stringLine1=stringRegExpReplace($stringForDigit,"((0+2A)|(22))","")
;~             local $count1=@extended
;~             $stringline1=stringreplace($stringLine1,"0","")
;~             local $checksum=@extended-$count1
;~             $stringline1=stringreplace($stringLine1,"222222","")
;~             $checksum+=@extended
;~             $checksum=$checksum+stringlen($stringline1)

            local $num=" "
;~             if ($checksum=636) or ($checksum=653) then $num=0
;~             if ($checksum=719) then $num=1
;~             if ($checksum=674) then $num=2
;~             if ($checksum=661) then $num=3
;~             if ($checksum=666) then $num=4
;~             if ($checksum=650) then $num=5
;~             if ($checksum=699) or ($checksum=716) then $num=6
;~             if ($checksum=732) or ($checksum=734) then $num=7
;~             if ($checksum=655) then $num=8
;~             if ($checksum=659) or ($checksum=676) then $num=9

                     if ($stringForDigit='0x00022220020000220200022202002020020020200220002022000020002222') then $num=0
                     if ($stringForDigit='0x00002000002220000000200000002000000220000002000000020000002222') then $num=1
                     if ($stringForDigit='0x00022220020000220000002200002200000022000020000022000000222222') then $num=2
                     if ($stringForDigit='0x00022220020000220000002200002200000022000000002022000020002222') then $num=3
                     if ($stringForDigit='0x00000220000022000022020002000200020002000222222000002200000022') then $num=4
                     if ($stringForDigit='0x02222222020000000222220000000020000000200000002022000020002222') then $num=5
                     if ($stringForDigit='0x00002220002200000200000002222200022222000200002022000020002222') then $num=6
                     if ($stringForDigit='0x02222222000000220000020000002000000020000020000000200000002000') then $num=7
                     if ($stringForDigit='0x00022220020000220200002200222200002222000200002022000020002222') then $num=8
                     if ($stringForDigit='0x00022220020000220200002200222222002222200000002000002200002200') then $num=9
                consolewrite($num)
            EndIf

        if ($showDigits=true) then
;~          consolewrite("-" & $checksum & "-" & $stringLine1 & @CRLF)

;~          $stringLine1=StringRegExpReplace($stringLine1,"[1-9A-Za-z]+","1")

;~          For $picIdLine = 0 To $heightMatrix-1 step 2
            For $picIdLine = 0 To $heightMatrix-1

            ;~  From the screenshots we can ignore the first 16 bytes (remember in text its 2 characters
            ;~  $binaryLine=BinaryMid($bmp1Data,($picId*$BMP1LineWidth)+16,$BMP1LineWidth)
            ;~  and we only need 4 digits which takes about 28 characters and 1 character separator =
                local $stringLine=stringMid($stringForDigit,($picIdLine * ($stride * 2))+3,($stride*2)-3)
        ;~ Lets make it readable
                $stringLine=StringReplace($stringLine,"0",".")
;~              $stringLine=StringRegExpReplace($stringLine,"[0]+",".")
;~              $stringLine=StringRegExpReplace($stringLine,"[1-9A-Za-z]+","1")
;~              $stringLine=StringRegExpReplace($stringLine,"1+","x")

                $textoutput&=stringformat("%02i",$picIdLine) & " : " & $stringLine & @CRLF
            next

            ControlSetText("","",$editBox,$textOutput)

    ;~      Not working propertly?
;~          local $checkSum=PixelChecksum($leftMatrix, $rightMatrix , $topMatrix, $bottomMatrix, 1, 0 ,1)
;~          consolewrite($checksum & " - ")

;~ Minus two just as it influences the next screenshot
            _Screen_DrawRect( $leftMatrix, $rightMatrix-4 , $topMatrix, $bottomMatrix)

;~          if ($charId=1) then
;~              MsgBox($MB_SYSTEMMODAL, "Title", "This message box will timeout after 10 seconds or select the OK button.", 10)
;~          EndIf

            SLEEP (100)
        EndIf

        Next
consolewrite(@crlf)
    Next
EndFunc

Func GetImageDataFromScreen($left, $top, $right, $bottom, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride, $picIdmgBytes=3)
local $Scan0, $pixelData, $hbScreen, $pBitmap, $pBitmapCap, $handle, $bitMapdata, $pixelFormat

; Capture screen to load the bitmap to search in
;~   _ScreenCapture_Capture(@UserProfileDir & "\downloads\examples\test.png",$left, $top, $right, $bottom,False)
;~   _ScreenCapture_Capture("",$left, $top, $right, $bottom,False)
    $hbScreen=_ScreenCapture_Capture("",$left, $top, $right, $bottom,False)

    local $pBitmap1 = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap
    _WinAPI_DeleteObject($hbScreen) ;release GDI bitmap resource because not needed anymore

 Local $pBitmap= _GDIPlus_ImageResize($pBitmap1, 8, 8) ;resize image
;~  Local $pBitmap= _GDIPlus_ImageScale($hBitmap, 0.5, 0.5) ;resize image

;Get $tagGDIPBITMAPDATA structure
;~   ConsoleWrite("Bitmap Width:    " & _GDIPlus_ImageGetWidth($pBitmap) & @CRLF )
;~   ConsoleWrite("Bitmap Height:      " & _GDIPlus_ImageGetHeight($pBitmap) & @CRLF)

;~  24 bits (3 bytes) or 16 bits (2 bytes) comparison
    if ($picIdmgBytes=1) then
        $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD,    $GDIP_PXF04INDEXED)
    Endif
    if ($picIdmgBytes=2) then
        $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF16RGB555)
;~      $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    EndIf
    if ($picIdmgBytes=3) then
        $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB)
;~      $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    endIf

    If @ERROR Then MsgBox(0,"","Error locking region " & @error)

    $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.
    $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap.
    $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap.
    $PixelFormat = DllStructGetData($BitmapData, "PixelFormat");Pixel format - Integer that specifies the pixel format of the bitmap
    $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap.

    $pixelData = DllStructCreate("ubyte lData[" & (abs($Stride) * $Height-1) & "]", $Scan0)
    $BMPDataStart = $BMPDataStart & DllStructGetData($pixeldata,"lData")

    _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData)
    _GDIPlus_ImageDispose ($pBitmap)
    _WinAPI_DeleteObject ($pBitmap)
    _WinAPI_DeleteObject ($hbScreen)

EndFunc;==>GetImage

; Draw rectangle on screen.
Func _Screen_DrawRect($tLeft, $tRight, $tTop, $tBottom, $color = 0xFF, $PenWidth = 1)
    Local $hDC, $hPen, $obj_orig, $x1, $x2, $y1, $y2
    $x1 = $tLeft
    $x2 = $tRight
    $y1 = $tTop
    $y2 = $tBottom
    $hDC = _WinAPI_GetWindowDC(0) ; DC of entire screen (desktop)
    $hPen = _WinAPI_CreatePen($PS_SOLID, $PenWidth, $color)
    $obj_orig = _WinAPI_SelectObject($hDC, $hPen)

    _WinAPI_DrawLine($hDC, $x1, $y1, $x2, $y1) ; horizontal to right
    _WinAPI_DrawLine($hDC, $x2, $y1, $x2, $y2) ; vertical down on right
    _WinAPI_DrawLine($hDC, $x2, $y2, $x1, $y2) ; horizontal to left right
    _WinAPI_DrawLine($hDC, $x1, $y2, $x1, $y1) ; vertical up on left

    ; clear resources
    _WinAPI_SelectObject($hDC, $obj_orig)
    _WinAPI_DeleteObject($hPen)
    _WinAPI_ReleaseDC(0, $hDC)
EndFunc   ;==>_UIA_DrawRect

 

Edited by junkew
Posted (edited)
On 2/12/2025 at 10:28 PM, Werty said:

Are there any patterns in which serials/results that fail? Is it the same every run, the same results that fails, or is it random, it's really difficult to help when we dont have access to the tools.exe program to test ourselfes

As for the filewritefromarray, you could instead of using an array use a single big string, then it's just a simple filewrite.

Local $BigString = ""
For $loop = 0 To 999999

        ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100)
        _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020)
        $BigString &= String(StringFormat('%06i', $loop)) & "," & String(GetNumber($result)) & @LF
Next
_WinAPI_DeleteDC($hCDC)
FileWrite($db, $BigString)

Something like this.

Unfortunately sharing the tool is out of the question, it's an internal tool and even though all the products involved are pretty old, the company is very litigious when it comes to protecting the copyrights - I've already been told off by legal for including too much information in my last thread. The false positives aren't much, a mere 37 in the full set of 1 million inputs, although when scaling it up to 7 or 8 digits, 370 or 3700 would be a lot harder to fix manually - not to mention that just knowing which outputs are wrong requires an extra run to diff against and doubles the time needed. 

I can confirm that on two different runs none of the false positives were the same, so this doesn't seem likely to be a recognition problem but a problem of the machine's resources being occasionally blocked and the script needing more time to process those particular serials, which is where argumentum's Do-Until loop idea comes in handy. However if it would be too much work to rewrite the script to return nothing instead of those few false positives I understand completely and you've helped enough already, thank you again.

Edited by Hashim
Posted (edited)

You wrote earlier...

On 2/12/2025 at 10:25 PM, Hashim said:

fallback to returning nothing instead of 0000

does that mean 0000 is never a valid result?

If that's the case we can just put the do-until back and check if the result is 0000, if it is then repeat the bitblt until it's not.
 

Local $BigString = ""
For $loop = 0 To 999999

        ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100)
   Do
        _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020)
        $result = GetNumber($result)
   Until $result <> "0000"
        $BigString &= String(StringFormat('%06i', $loop)) & "," & String($result) & @LF
Next
_WinAPI_DeleteDC($hCDC)
FileWrite($db, $BigString)

So all in all the complete script should look something like this..

#include <WinAPI.au3>

Run("tool.exe")
Local $tool = WinWaitActive("tool", "", 3)

$db = FileOpen(@ScriptDir & "\serials.csv", 1)

;Be sure $posx and $posy is pointing at the correct spot!
Global $posx = 829, $posy = 456, $result = "", $code[4], $BigString = "", $pixels = DllStructCreate('dword[2816]')
;Lookup table to avoid searching
Global $digit[115] = [1,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0, _
                      0,0,0,0,0,0,0,0,0,0,6,0,0,0,3,2,0,0,0,0, _
                      0,0,0,0,0,0,0,0,9,0,0,0,0,0,8,0,0,0,0,0, _
                      0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,5]

$hDDC = _WinAPI_GetDC(0)
$hCDC = _WinAPI_CreateCompatibleDC($hDDC)
$hBmp = _WinAPI_CreateCompatibleBitmap($hDDC, 88, 32)
        _WinAPI_SelectObject($hCDC, $hBmp)

For $loop = 0 To 999999

        ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100)
  Do
        _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020)
        $result = GetNumber($result)
  Until $result <> "0000"
        $BigString &= String(StringFormat('%06i', $loop)) & "," & String($result) & @LF
Next
_WinAPI_DeleteDC($hCDC)
FileWrite($db, $BigString)
Exit

Func Getnumber($result)
    
    Local $code[4] = [0,0,0,0], $value = 64
    DllCall('gdi32.dll', 'dword', 'GetBitmapBits', 'ptr', $hBmp, 'dword', DllStructGetSize($pixels), 'ptr', DllStructGetPtr($pixels))

For $loop = 1 To 2816 Step 440
    $code[0] += DllStructGetData($pixels, 1, $loop   ) > 4278190080 ? $value:0
    $code[1] += DllStructGetData($pixels, 1, $loop+29) > 4278190080 ? $value:0
    $code[2] += DllStructGetData($pixels, 1, $loop+58) > 4278190080 ? $value:0
    $code[3] += DllStructGetData($pixels, 1, $loop+87) > 4278190080 ? $value:0
    $value /= 2
Next
    Return String($digit[$code[0]]) & String($digit[$code[1]]) & String($digit[$code[2]]) & String($digit[$code[3]])
EndFunc

 

Edited by Werty

Some guy's script + some other guy's script = my script!

Posted (edited)
9 hours ago, Werty said:

You wrote earlier...

does that mean 0000 is never a valid result?

If that's the case we can just put the do-until back and check if the result is 0000, if it is then repeat the bitblt until it's not.
 

Local $BigString = ""
For $loop = 0 To 999999

        ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100)
   Do
        _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020)
        $result = GetNumber($result)
   Until $result <> "0000"
        $BigString &= String(StringFormat('%06i', $loop)) & "," & String($result) & @LF
Next
_WinAPI_DeleteDC($hCDC)
FileWrite($db, $BigString)

So all in all the complete script should look something like this..

#include <WinAPI.au3>

Run("tool.exe")
Local $tool = WinWaitActive("tool", "", 3)

$db = FileOpen(@ScriptDir & "\serials.csv", 1)

;Be sure $posx and $posy is pointing at the correct spot!
Global $posx = 829, $posy = 456, $result = "", $code[4], $BigString = "", $pixels = DllStructCreate('dword[2816]')
;Lookup table to avoid searching
Global $digit[115] = [1,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0, _
                      0,0,0,0,0,0,0,0,0,0,6,0,0,0,3,2,0,0,0,0, _
                      0,0,0,0,0,0,0,0,9,0,0,0,0,0,8,0,0,0,0,0, _
                      0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, _
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,5]

$hDDC = _WinAPI_GetDC(0)
$hCDC = _WinAPI_CreateCompatibleDC($hDDC)
$hBmp = _WinAPI_CreateCompatibleBitmap($hDDC, 88, 32)
        _WinAPI_SelectObject($hCDC, $hBmp)

For $loop = 0 To 999999

        ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100)
  Do
        _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020)
        $result = GetNumber($result)
  Until $result <> "0000"
        $BigString &= String(StringFormat('%06i', $loop)) & "," & String($result) & @LF
Next
_WinAPI_DeleteDC($hCDC)
FileWrite($db, $BigString)
Exit

Func Getnumber($result)
    
    Local $code[4] = [0,0,0,0], $value = 64
    DllCall('gdi32.dll', 'dword', 'GetBitmapBits', 'ptr', $hBmp, 'dword', DllStructGetSize($pixels), 'ptr', DllStructGetPtr($pixels))

For $loop = 1 To 2816 Step 440
    $code[0] += DllStructGetData($pixels, 1, $loop   ) > 4278190080 ? $value:0
    $code[1] += DllStructGetData($pixels, 1, $loop+29) > 4278190080 ? $value:0
    $code[2] += DllStructGetData($pixels, 1, $loop+58) > 4278190080 ? $value:0
    $code[3] += DllStructGetData($pixels, 1, $loop+87) > 4278190080 ? $value:0
    $value /= 2
Next
    Return String($digit[$code[0]]) & String($digit[$code[1]]) & String($digit[$code[2]]) & String($digit[$code[3]])
EndFunc

 

It is a valid result, which is why I need to manually check, otherwise it would be as simple as just making sure it's never "0000" like you mentioned. Currently the incorrect results also return 0000 instead of just returning nothing, which is what I was referring to.

Edited by Hashim
Posted (edited)

Hmm, maybe check again if the result is 0000, if it returns 0000 again it must be correct, otherwise it will return the new correct result.

Local $BigString = ""
For $loop = 0 To 999999

        ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100)
        _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020)
        $result = GetNumber($result)
        
        If $result = "0000" Then
            _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020)
            $result = GetNumber($result)
        EndIf
            
        $BigString &= String(StringFormat('%06i', $loop)) & "," & String($result) & @LF
Next
_WinAPI_DeleteDC($hCDC)
FileWrite($db, $BigString)

It's not failproof, but you said the errors never (so far) occur the same place, so should be ok, else make it a triple check.

But as you also mentioned, it could be hardware related, imagine the script being so fast that it runs faster than a 60hz monitor, then you would need a faster monitor. :D

Or even a ram problem, that a computer with ECC ram would handle it better.

Edited by Werty

Some guy's script + some other guy's script = my script!

Posted
1 hour ago, Werty said:

Hmm, maybe check again if the result is 0000, if it returns 0000 again it must be correct, otherwise it will return the new correct result.

Local $BigString = ""
For $loop = 0 To 999999

        ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100)
        _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020)
        $result = GetNumber($result)
        
        If $result = "0000" Then
            _WinAPI_BitBlt($hCDC, 0, 0, 88, 32, $hDDC, $posx, $posy, 0x00CC0020)
            $result = GetNumber($result)
        EndIf
            
        $BigString &= String(StringFormat('%06i', $loop)) & "," & String($result) & @LF
Next
_WinAPI_DeleteDC($hCDC)
FileWrite($db, $BigString)

It's not failproof, but you said the errors never (so far) occur the same place, so should be ok, else make it a triple check.

But as you also mentioned, it could be hardware related, imagine the script being so fast that it runs faster than a 60hz monitor, then you would need a faster monitor. :D

Or even a ram problem, that a computer with ECC ram would handle it better.

Wow, kicking myself for not thinking of this, so simple yet so genius. I'll test now. :D

Posted
39 minutes ago, Hashim said:

I'll test now

Please also post an update on the "elapsed" time that you posted.

000000,17.3893 elapsed
000001,19.3955 elapsed
000002,4.952 elapsed
000003,5.7421 elapsed
000004,4.4015 elapsed
000005,4.6038 elapsed
000006,4.3785 elapsed
000007,4.8244 elapsed
000008,4.9788 elapsed
000009,5.0533 elapsed
000010,4.2012 elapsed
000011,4.3916 elapsed
000012,5.0254 elapsed
000013,5.2419 elapsed
000014,4.2951 elapsed
000015,4.4227 elapsed
000016,4.804 elapsed
000017,4.9286 elapsed
000018,3.9473 elapsed
000019,4.7 elapsed
000020,5.8118 elapsed
000021,19.3781 elapsed
000022,4.6165 elapsed
000023,4.7874 elapsed
000024,5.0672 elapsed
000025,4.9123 elapsed
000026,4.8596 elapsed
000027,5.0079 elapsed
000028,4.6646 elapsed
000029,5.0613 elapsed
000030,4.5557 elapsed

It'll be interesting to see the change after we moved all that stuff out of the loop.

Some guy's script + some other guy's script = my script!

Posted

Come to think of it, if you used the loop you posted for the other tool with 3 digits from your first thread, then you might have gotten wrong results, as the "Do" in the Do-Until loop is placed wrong, if an error/false positive occur then it repeats and ControlClick's one more time, thereby changing the number it was supposed to be checking, so if you had gotten 37 false positives you would have ControlClicked 1000037 times instead of 1000000 times, missing out on some, causing the order of the results to be out of sync...
 

For $loop = 0 To 999999

    Do
        $serial = StringFormat('%06i', $loop)
        ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100)
        $hDDC = _WinAPI_GetDC(0)
        $hCDC = _WinAPI_CreateCompatibleDC($hDDC)
        $hBmp = _WinAPI_CreateCompatibleBitmap($hDDC, 34, 20)
        _WinAPI_SelectObject($hCDC, $hBmp)
     ;Do should be here
        _WinAPI_BitBlt($hCDC, 0, 0, 34, 20, $hDDC, $posx, $posy, 0x00CC0020)
        _WinAPI_DeleteDC($hCDC)
        $result = GetNumber($result)
    Until ((StringLen($result) = 4) and StringIsDigit($result))

    FileWrite($db, $serial & "," & $result & @LF)

Next

We have changed it in this new version, just concerned that you used it in your first thread about the tool with 3 digits, then you'd have a wrong list and have to redo it.

Some guy's script + some other guy's script = my script!

Posted (edited)
  • Cleaned up demo script
    • Added some choices in the GUI to play around with understanding on whats happening with bits, bytes, string
  • 8x8 resizing to compare less bits
#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <ScreenCapture.au3>

;~ These are the magic bytes for the 8x8 resized image to identify the numbers 0-9
;~ You can learn them by feeding 10 images having 0-9 at the 1 position (so 2nd character as first is a space
global $digits[10] = [ _
'0x0002222002000022020002220200202002002020022000202200002000222200', _
'0x0000200000222000000020000000200000022000000200000002000000222200', _
'0x0002222002000022000000220000220000002200002000002200000022222220', _
'0x0002222002000022000000220000220000002200000000202200002000222200', _
'0x0000022000002200002202000200020002000200022222200000220000002200', _
'0x0222222202000000022222000000002000000020000000202200002000222200', _
'0x0000222000220000020000000222220002222200020000202200002000222200', _
'0x0222222200000022000002000000200000002000002000000020000000200000', _
'0x0002222002000022020000220022220000222200020000202200002000222200', _
'0x0002222002000022020000220022222200222220000000200000220000220000' _
]

local $charWidth=29 ;~Important as thats the width of te consecutive digits on screen

;~ Dont move the window during analysis as then the calculation of the matrix will be off as we dont recalculate every time
dim $bmpData, $w, $h, $s
dim $pic[10],$BitmapFilename, $hImage, $Bmp

; Initialize GDI+ library
_GDIPlus_Startup()

#Region ### START Koda GUI section ### Form=
$frmCompare = GUICreate("Another bitmap brute-forcing thread", 1280, 768, 193, 125)

;~ Put all the pictures on screen
for $picId=0 to 9
    $BitmapFilename = @UserProfileDir & "\downloads\examples\" & string($picId) & ".png"
    $pBitmap = _GDIPlus_BitmapCreateFromFile($BitmapFilename)
    $hImage=_GDIPlus_ImageLoadFromFile($BitmapFilename)
    $Bmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
;~          $hBitmap = _GDIPlus_ImageLoadFromFile($BMPFile)

    $Pic[$picId] = GUICtrlCreatePic("", 32, 24+($picId*60), 100, 100, BitOR($SS_NOTIFY,$WS_GROUP,$WS_CLIPSIBLINGS))
    _WinAPI_DeleteObject(GUICtrlSendMsg($Pic[$picId], $STM_SETIMAGE, $iMAGE_BITMAP, $Bmp))
Next

;~ Box for analyzing showing the information
$editBox = GuiCtrlCreateEdit("Analytics box", 450,14,700,750)
GUICtrlSetFont($editBox, 8, 100, 0, "Courier New")

Local $idLearnCheckbox = GUICtrlCreateCheckbox("Learn the digits", 44, 640, 125, 25)
Local $idShowCheckbox  = GUICtrlCreateCheckbox("Show the bits/highlight", 44, 672, 125, 25)
Local $idSlowCheckbox  = GUICtrlCreateCheckbox("Slow down", 44, 704, 95, 25)

$ButtonAnalyze = GUICtrlCreateButton("Analyze", 44, 730, 75, 25, 0)
$Button2 = GUICtrlCreateButton("Button2", 104, 730, 75, 25, 0)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

#region ### While the GUI ###
While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            _GDIPlus_Shutdown()
            Exit
        Case $ButtonAnalyze
            analyse(_IsChecked($idLearnCheckbox), _IsChecked($idShowCheckbox), _IsChecked($idSlowCheckbox))
        Case $Button2
    EndSwitch
WEnd
#EndRegion
Func _IsChecked($idControlID)
        Return BitAND(GUICtrlRead($idControlID), $GUI_CHECKED) = $GUI_CHECKED
EndFunc   ;==>_IsChecked

func analyse($learnTheDigits=false, $showDigits=true, $slowDown=false)
;~  local $learnTheDigits=false    ;~Use this to learn the 0-9 digit magic values
;~  local $showDigits=true        ;~ For showing the bits in detail to show whats happening
;~  local $slowDown=false          ;~ With or without sleep waiting
    local $charLow=1, $charHigh=1  ;~ For learning which areas to analyse

    WinActivate($frmCompare)

    Local $wPos = WinGetPos($frmCompare)
;~      $aArray[0] = X position    $aArray[1] = Y position    $aArray[2] = Width    $aArray[3] = Height
    Local $aClientSize = WinGetClientSize($frmCompare)
;~  $aArray[0] = Width of window's client area    $aArray[1] = Height of window's client area
    Local $cLeft= ($wpos[2]-$aClientSize[0])/2
    Local $cTop= ($wPos[3]-$aClientSize[1])-2

    Local $bytesPerDigit = 1 ;~ could be 1 or 2 or 3 bytes

    for $picId=0 to 9
         Local $cPos = ControlGetPos ( $frmCompare, "", $pic[$picId] )
;~          $aArray[0] = X position ;~     $aArray[1] = Y position ;~     $aArray[2] = Width ;~     $aArray[3] = Height

        if ($learnTheDigits = false) Then
            $charLow=0
            $charHigh=5
        EndIf

        for $charId=$charlow to $charHigh
            ;~ Calculate the matrix where the digit is based on the control where the picture is in, as absolute coordinates so window location also in the calculation
            local $leftMatrix=($charId*$charWidth)+$wpos[0]+$cLeft+$cPos[0]
            local $rightMatrix=$charWidth+($charId*$charWidth)+$wPos[0]+$cLeft+$cPos[0]
            local $topMatrix= $wPos[1] + $cTop +$cPos[1] + 10
            local $bottomMatrix=$wPos[1] + $cTop + $cPos[1] + $cPos[3] -2 -11

            local $x, $y

            Local $bytesDataForDigit="", $widthMatrix=0, $heightMatrix=0, $stride=0
    ;~      Func GetImageDataFromScreen($left, $right, $top, $bottom, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride, $picIdmgBytes=3)

;~Play with this to take a smaller area
            GetImageDataFromScreen($leftMatrix, $topMatrix, $rightMatrix,  $bottomMatrix, $bytesDataForDigit, $widthMatrix, $heightMatrix, $stride, $bytesPerDigit)

;~          consolewrite(BinaryLen($bytesDataForDigit) & " " & stringlen($bytesDataForDigit) & " " & $widthMatrix & "-" & $heightMatrix & "-" &  $stride &@CRLF)

            local $stringForDigit=string($bytesDataForDigit)

            if ($learnTheDigits=true) then
                consolewrite("'" & $stringforDigit & "', _")
            Else
                $num=getNumber($stringForDigit)
                consolewrite($num)
            EndIf

        if ($showDigits=true) then
            showDigitInEditbox($stringForDigit, $heightMatrix, $stride)

    ;~      Not working propertly?
;~          local $checkSum=PixelChecksum($leftMatrix, $rightMatrix , $topMatrix, $bottomMatrix, 1, 0 ,1)

;~ Just draw a redbox around what we are analysing
;~ Minus 4 just as it influences the next screenshot
            _Screen_DrawRect( $leftMatrix, $rightMatrix-4 , $topMatrix, $bottomMatrix)

            if $SlowDown then SLEEP (100)
        EndIf

        Next
consolewrite(@crlf)
    Next
EndFunc
func showDigitInEditbox($stringForDigit, $heightMatrix, $stride)
    local $textoutput
    $textOutput=stringmid($stringForDigit,3)

    $textOutput=StringRegExpReplace($textOutput,"[0-9a-z]{8}","$0"&@CRLF)
    $textOutput=StringReplace($textoutput,"0",".")
;~     $textOutput=StringRegExpReplace($textOutput,"[1-9A-Za-z]+","X")
    ControlSetText("","",$editBox,$textOutput)
EndFunc

func getNumber($stringForDigit)
    local $num=" "
    for $i=0 to 9
        if ($digits[$i]=$stringForDigit) then return $i
    next
    return $num
EndFunc

Func GetImageDataFromScreen($left, $top, $right, $bottom, byref $BMPDataStart, byref $Width, byRef $Height, byref $Stride, $picIdmgBytes=3)
local $Scan0, $pixelData, $hbScreen, $pBitmap, $pBitmapCap, $handle, $bitMapdata, $pixelFormat

; Capture screen to load the bitmap to search in
;~   _ScreenCapture_Capture(@UserProfileDir & "\downloads\examples\test.png",$left, $top, $right, $bottom,False)
;~   _ScreenCapture_Capture("",$left, $top, $right, $bottom,False)
    $hbScreen=_ScreenCapture_Capture("",$left, $top, $right, $bottom,False)

    local $pBitmap1 = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap
    _WinAPI_DeleteObject($hbScreen) ;release GDI bitmap resource because not needed anymore

 Local $pBitmap= _GDIPlus_ImageResize($pBitmap1, 8, 8) ;resize image
;~  Local $pBitmap= _GDIPlus_ImageResize($pBitmap1, 4, 4) ;resize image

;~  Local $pBitmap= _GDIPlus_ImageScale($pBitmap1, 0.15, 0.15) ;resize image

;Get $tagGDIPBITMAPDATA structure
;~   ConsoleWrite("Bitmap Width:    " & _GDIPlus_ImageGetWidth($pBitmap) & @CRLF )
;~   ConsoleWrite("Bitmap Height:      " & _GDIPlus_ImageGetHeight($pBitmap) & @CRLF)

;~  24 bits (3 bytes) or 16 bits (2 bytes) comparison or 1 byte
    local $iFormat=$GDIP_PXF16RGB555
    if ($picIdmgBytes=1) then $iFormat=$GDIP_PXF04INDEXED
    if ($picIdmgBytes=2) then $iFormat=$GDIP_PXF16RGB555
    if ($picIdmgBytes=3) then $iFormat=$GDIP_PXF24RGB

    $BitmapData= _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD,    $iFormat)

    If @ERROR Then MsgBox(0,"","Error locking region " & @error)

    $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.
    $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap.
    $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap.
    $PixelFormat = DllStructGetData($BitmapData, "PixelFormat");Pixel format - Integer that specifies the pixel format of the bitmap
    $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap.

    $pixelData = DllStructCreate("ubyte lData[" & (abs($Stride) * $Height) & "]", $Scan0)
    $BMPDataStart = $BMPDataStart & DllStructGetData($pixeldata,"lData")

    _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData)
    _GDIPlus_ImageDispose ($pBitmap)
    _WinAPI_DeleteObject ($pBitmap)
    _WinAPI_DeleteObject ($hbScreen)

EndFunc;==>GetImage

; Draw rectangle on screen.
Func _Screen_DrawRect($tLeft, $tRight, $tTop, $tBottom, $color = 0xFF, $PenWidth = 1)
    Local $hDC, $hPen, $obj_orig, $x1, $x2, $y1, $y2
    $x1 = $tLeft
    $x2 = $tRight
    $y1 = $tTop
    $y2 = $tBottom
    $hDC = _WinAPI_GetWindowDC(0) ; DC of entire screen (desktop)
    $hPen = _WinAPI_CreatePen($PS_SOLID, $PenWidth, $color)
    $obj_orig = _WinAPI_SelectObject($hDC, $hPen)

    _WinAPI_DrawLine($hDC, $x1, $y1, $x2, $y1) ; horizontal to right
    _WinAPI_DrawLine($hDC, $x2, $y1, $x2, $y2) ; vertical down on right
    _WinAPI_DrawLine($hDC, $x2, $y2, $x1, $y2) ; horizontal to left right
    _WinAPI_DrawLine($hDC, $x1, $y2, $x1, $y1) ; vertical up on left

    ; clear resources
    _WinAPI_SelectObject($hDC, $obj_orig)
    _WinAPI_DeleteObject($hPen)
    _WinAPI_ReleaseDC(0, $hDC)
EndFunc   ;==>_UIA_DrawRect

 

Edited by junkew
Posted
  • Regarding speed maybe it makes a difference with stretchblt directly going to a smaller size instead of bitblt
    Example for screenshot in a smaller size.

 

#include <GDIPlus.au3>
#include <ScreenCapture.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

Func CaptureAndResize($savePath, $newWidth, $newHeight)
    ; GDI+ initialiseren
    _GDIPlus_Startup()

    ; Schermresolutie ophalen
    Local $iScreenWidth = @DesktopWidth
    Local $iScreenHeight = @DesktopHeight

    ; HDC's ophalen
    Local $hDC = _WinAPI_GetDC(0)
    Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC)

    ; Bitmap maken
    Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iScreenWidth, $iScreenHeight)
    Local $hOldObj = _WinAPI_SelectObject($hMemDC, $hBitmap)

    ; Scherminhoud kopiëren met StretchBlt (resize mogelijk)
    _WinAPI_StretchBlt($hMemDC, 0, 0, $newWidth, $newHeight, $hDC, 0, 0, $iScreenWidth, $iScreenHeight, $SRCCOPY)

    ; Screenshot opslaan als bestand
    _ScreenCapture_SaveImage($savePath, $hBitmap)

    ; Opruimen
    _WinAPI_SelectObject($hMemDC, $hOldObj)
    _WinAPI_DeleteObject($hBitmap)
    _WinAPI_DeleteDC($hMemDC)
    _WinAPI_ReleaseDC(0, $hDC)
    _GDIPlus_Shutdown()
EndFunc

; Gebruik de functie om een screenshot te maken en te resizen naar 800x600
CaptureAndResize(@UserProfileDir & "\downloads\examples\" & "screenshot_resized.jpg", 800, 600)

 

Posted (edited)

I already tried that with my method, with no good result, to much information is lost no matter how i tried resizing it, tried all the filters and different sizes, but maybe it'll work using another method, like checksum as you mentioned earlier, and stuffed in a lookup table

Though, my method already only reads 28 times, so it would have to be resized to something smaller than 28 pixels in a square to be faster.

Putting a timer into my GetNumber() function i get insanely fast times like...
 

Func Getnumber($result)
    $t2 = TimerInit()
    Local $code[4] = [0,0,0,0], $value = 64
    DllCall('gdi32.dll', 'dword', 'GetBitmapBits', 'ptr', $capture, 'dword', DllStructGetSize($pixels), 'ptr', DllStructGetPtr($pixels))

For $loop = 1 To 2816 Step 440
    $code[0] += DllStructGetData($pixels, 1, $loop   ) > 4278190080 ? $value:0
    $code[1] += DllStructGetData($pixels, 1, $loop+29) > 4278190080 ? $value:0
    $code[2] += DllStructGetData($pixels, 1, $loop+58) > 4278190080 ? $value:0
    $code[3] += DllStructGetData($pixels, 1, $loop+87) > 4278190080 ? $value:0
    $value /= 2
Next
Consolewrite("Time: " & TimerDiff($t2) & @crlf)
    Return String($digit[$code[0]]) & String($digit[$code[1]]) & String($digit[$code[2]]) & String($digit[$code[3]])
EndFunc
Time: 0.0582
Time: 0.0583
Time: 0.0804
Time: 0.0641
Time: 0.0816
Time: 0.0582
Time: 0.0581

it's the other stuff that takes longer, here times I get for a full run.
 

6.0095
6.9233
6.9252
6.8122
7.2931
6.7959
6.9708

..with the bitblt stuff.

Maybe later I'll try making the getnumber() func into a C Dll, though with only 28 checks it's hardly gonna be worth it. 😛

Edited by Werty

Some guy's script + some other guy's script = my script!

Posted (edited)
19 hours ago, Werty said:

Come to think of it, if you used the loop you posted for the other tool with 3 digits from your first thread, then you might have gotten wrong results, as the "Do" in the Do-Until loop is placed wrong, if an error/false positive occur then it repeats and ControlClick's one more time, thereby changing the number it was supposed to be checking, so if you had gotten 37 false positives you would have ControlClicked 1000037 times instead of 1000000 times, missing out on some, causing the order of the results to be out of sync...
 

For $loop = 0 To 999999

    Do
        $serial = StringFormat('%06i', $loop)
        ControlClick($tool, "", "TTabSheet1", "primary", 1, 100, 100)
        $hDDC = _WinAPI_GetDC(0)
        $hCDC = _WinAPI_CreateCompatibleDC($hDDC)
        $hBmp = _WinAPI_CreateCompatibleBitmap($hDDC, 34, 20)
        _WinAPI_SelectObject($hCDC, $hBmp)
     ;Do should be here
        _WinAPI_BitBlt($hCDC, 0, 0, 34, 20, $hDDC, $posx, $posy, 0x00CC0020)
        _WinAPI_DeleteDC($hCDC)
        $result = GetNumber($result)
    Until ((StringLen($result) = 4) and StringIsDigit($result))

    FileWrite($db, $serial & "," & $result & @LF)

Next

We have changed it in this new version, just concerned that you used it in your first thread about the tool with 3 digits, then you'd have a wrong list and have to redo it.

 

I had already removed the Do loop when I ran the first benchmarks but this is a great catch for the older version. Ultimately shouldn't be an issue though since I also sort, deduplicate and run various integrity checks on the output files using Bash/GNU tools.

Interestingly, the latest benchmarks seem to be virtually the same as the previous ones:

000000,20.2162
000001,3.6562
000002,4.666
000003,4.9287
000004,4.9238
000005,5.4529
000006,4.839
000007,4.9723
000008,5.1397
000009,5.2648
000010,4.913
000011,5.4363
000012,3.8289
000013,4.7454
000014,5.255
000015,5.0618
000016,5.3634
000017,4.4406
000018,4.7828
000019,5.1919
000020,4.8406
000021,5.0635
000022,4.9752
000023,5.0518
000024,5.8142
000025,3.8615
000026,5.4087
000027,5.0363
000028,4.255
000029,5.2425
000030,5.3523
000031,4.2784
000032,4.8176
000033,5.4404
000034,5.0938
000035,4.2843
000036,4.0313
000037,4.8468
000038,5.1112
000039,4.5882
000040,5.066
000041,4.6753
000042,5.3156
000043,4.8075
000044,4.4237
000045,5.063
000046,5.2948
000047,4.7343
000048,5.5518
000049,4.84
000050,4.9125

 

Maybe BitBLT/AutoIT/Windows were already optimising out the changes you made?

I also run all my benchmarks with the timer init just before the BitBlit call (or for Nine's original script, the _GetScreen_GetScreen() function), so it's not a measurement of the full loop, in this version the full loop averages about 16 ms. Maybe we're at the point where speeding things up any further would require more advanced optimisations like chunking?

Edited by Hashim
Posted (edited)

HAHA, major speed increase, we've been doing it wrong, we've been using _WinAPI_GetDC(0) all the time which is the whole desktop, when we should have been using _WinAPI_GetWindowDC() instead, it's now like 5 times faster for me as it went from the whole desktop @3440x1440 to the test gui I've been using @640x480, and speed increased dramatically. :)

Changes to make...

$hDDC = _WinAPI_GetDC(0)
;should be
$hDDC = _WinAPI_GetWindowDC($tool)

;Change $posx and $posy to point at the correct spot, this is now not from the desktop 0,0 but from the tools.exe windows start position.

So speed increase depends on the size of the tools.exe window, maybe you can even resize it to be smaller. :)

Times i get now for full cycle with bitblt and all...

0.5085
0.5136
1.3745
0.5044
0.4402
0.4155
0.9733

Try it and report back with times, it's awesome. :D

Edited by Werty

Some guy's script + some other guy's script = my script!

Posted (edited)
20 hours ago, Werty said:

HAHA, major speed increase, we've been doing it wrong, we've been using _WinAPI_GetDC(0) all the time which is the whole desktop, when we should have been using _WinAPI_GetWindowDC() instead, it's now like 5 times faster for me as it went from the whole desktop @3440x1440 to the test gui I've been using @640x480, and speed increased dramatically. :)

Changes to make...

$hDDC = _WinAPI_GetDC(0)
;should be
$hDDC = _WinAPI_GetWindowDC($tool)

;Change $posx and $posy to point at the correct spot, this is now not from the desktop 0,0 but from the tools.exe windows start position.

So speed increase depends on the size of the tools.exe window, maybe you can even resize it to be smaller. :)

Times i get now for full cycle with bitblt and all...

0.5085
0.5136
1.3745
0.5044
0.4402
0.4155
0.9733

Try it and report back with times, it's awesome. :D

This looks really promising but unfortunately I can't seem to reproduce it, are you sure your version is returning good values? When I run it all outputs return 1111 again, although I've experimented with every single posx and posy that's even close. I added screenshot functionality to debug the capture and it looks like it should definitely be close to there. Any idea what might be going on here?

 

debug 4691.png

debug 2268.png

Edited by Hashim

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
  • Recently Browsing   0 members

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