Hashim Posted February 11 Author Posted February 11 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. Werty 1
junkew Posted February 11 Posted February 11 Good to see you resolved it. I updated my example with the matching based on a checksum by using replace/stringreplace just counting and adding the bytes to a certain checksum. Hashim 1 FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
Werty Posted February 12 Posted February 12 (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 February 12 by Werty Hashim 1 Some guy's script + some other guy's script = my script!
Hashim Posted February 12 Author Posted February 12 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. Werty and argumentum 1 1
Werty Posted February 12 Posted February 12 (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 February 12 by Werty Hashim 1 Some guy's script + some other guy's script = my script!
junkew Posted February 13 Posted February 13 (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 expandcollapse popup#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 February 13 by junkew Hashim 1 FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
junkew Posted February 13 Posted February 13 (edited) And you could offcourse build a CNN (Convolutional Neural Network)😉 https://www.linkedin.com/posts/andreashorn1_𝗧𝗵𝗶𝘀-𝗶𝘀-𝗵𝗮𝗻𝗱𝘀-𝗱𝗼𝘄𝗻-𝗼𝗻𝗲-ugcPost-7294745573667037184-cCuM?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAA9u1cBwzbrqlJUhZseMBnOqHDoQcSGcpQ Edited February 13 by junkew Hashim 1 FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
Hashim Posted February 14 Author Posted February 14 (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 February 14 by Hashim
Werty Posted February 14 Posted February 14 (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.. expandcollapse popup#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 February 14 by Werty Some guy's script + some other guy's script = my script!
Hashim Posted February 14 Author Posted February 14 (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.. expandcollapse popup#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 February 14 by Hashim
Werty Posted February 14 Posted February 14 (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. Or even a ram problem, that a computer with ECC ram would handle it better. Edited February 14 by Werty Hashim 1 Some guy's script + some other guy's script = my script!
Hashim Posted February 14 Author Posted February 14 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. 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. Werty 1
Werty Posted February 14 Posted February 14 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!
Werty Posted February 16 Posted February 16 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. Hashim 1 Some guy's script + some other guy's script = my script!
junkew Posted Sunday at 01:46 PM Posted Sunday at 01:46 PM (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 expandcollapse popup#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 Sunday at 01:49 PM by junkew Hashim 1 FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
junkew Posted Sunday at 03:50 PM Posted Sunday at 03:50 PM 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. expandcollapse popup#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) Werty and Hashim 2 FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
Werty Posted Sunday at 06:26 PM Posted Sunday at 06:26 PM (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 Sunday at 08:39 PM by Werty Hashim 1 Some guy's script + some other guy's script = my script!
Hashim Posted Sunday at 10:07 PM Author Posted Sunday at 10:07 PM (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: expandcollapse popup000000,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 Sunday at 10:14 PM by Hashim
Werty Posted Sunday at 11:44 PM Posted Sunday at 11:44 PM (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. Edited Monday at 12:04 AM by Werty junkew and Hashim 2 Some guy's script + some other guy's script = my script!
Hashim Posted Monday at 07:53 PM Author Posted Monday at 07:53 PM (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. 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? Edited Monday at 08:23 PM by Hashim
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now