Jump to content
UEZ

Inline Assembler Snippets

Recommended Posts

Counts the line feeds within a string:

_ASM_StringLFCharCount.au3

#include <AssembleIt.au3>

;~ $_ASSEMBLEIT_FLAG =  2  ;after uncomment this line, run the script, and replace the following line with the content of the clipboard, then delete #include <AssembleIt.au3>

Global $sString, $i

For $i = 1 To 150000
    $sString &= "I forgot that AutoIt uses UCS2 charset" & @CRLF
Next


Global $iRet, $fEnd
Global $tResult = DllStructCreate("dword AmountLF")

Global $t = TimerInit()
$iRet = _ASM_StringLFCharCount_Bin($sString)
;~ $iRet = _AssembleIt("dword", "_ASM_StringLFCharCount", "str", $sString, "ptr", DllStructGetPtr($tResult))
$fEnd = TimerDiff($t)
ConsoleWrite($iRet & " @LF chars found in " & $fEnd & " milliseconds" & @CRLF)
;~ ConsoleWrite($tResult.AmountLF & " @LF chars found in " & $fEnd & " milliseconds" & @CRLF)

Func _ASM_StringLFCharCount_Bin($sString)
    Local $tCodeBuffer = DllStructCreate("byte ASM[27]") ;reserve memory for ASM opcode
    $tCodeBuffer.ASM = "0x8B7424048B7C240831DBAC3C0074093C0A75F783C301EBF2891FC3" ;write opcodes into memory (struct) / length: 27
    Local $tResult = DllStructCreate("dword AmountLF")
    DllCall("user32.dll", "none", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer), "str", $sString, "ptr", DllStructGetPtr($tResult), "int", 0, "int", 0)
    Return $tResult.AmountLF
EndFunc

Func _ASM_StringLFCharCount() ;no wchar support!
    _("use32") ;32Bit!
;~     _("org " & FasmGetBasePtr($Fasm))  ;needed for assembleit debugger
    _("mov esi, dword[esp+4]") ;get start address of the string
    _("mov edi, dword[esp+8]") ;get address to save the result (struct)
    _("xor ebx, ebx") ;set ebx = 0
    _("_loop:")
        _("lodsb") ;load char from [esi] to al register as byte and increment esi by one
        _("cmp al, 0") ;is char = 0
        _("jz _end") ;if yes then jump to end mark
        _("cmp al, 0Ah") ;if not compare it with @lf char
        _("jne _loop") ;if not @lf jump to _loop mark
        _("add ebx, 1") ;if yes increase ebx by one -> ebx += 1
        _("jmp _loop") ;jump to _loop mark
    _("_end:")
;~  _ASMDBG_()
    _("mov [edi], ebx") ;write count result to struct
    _("ret")
EndFunc

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Draws a filled rectangle:

_ASM_DrawRectFilled.au3

#include <AssembleIt.au3>
#include <GDIPlus.au3>
#include <Memory.au3>

_GDIPlus_Startup()

Global Const  $iWidth = 300, $iHeight = 200

Global $fTimer = TimerInit()
Global Const $iStride = 4 * $iWidth
Global $tBitmapData = DllStructCreate("dword pixel[" & $iStride * $iHeight & "]")
Global Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $GDIP_PXF32ARGB, $iStride, DllStructGetPtr($tBitmapData))
ConsoleWrite("GDI+ preperation: " & TimerDiff($fTimer) & @CRLF)

Global $hGUI = GUICreate("ASM Test", $iWidth, $iHeight)
GUISetState()
Global $hGFX = _GDIPlus_GraphicsCreateFromHWND($hGUI)


;~ $_ASSEMBLEIT_FLAG = 2   ;after uncomment this line, run the script, and replace the following line with the content of the clipboard, then delete #include <AssembleIt.au3>

;                                       0           4           8        12         16       20
Global $tRect = DllStructCreate("dword iPosX;dword iPosY;dword iW; dword iH;dword ARGB;dword iWidth;dword iBase")
$tRect.iPosX = 150
$tRect.iPosY = 100
$tRect.iW = 20
$tRect.iH = 30
$tRect.ARGB = 0xFFFF0000
$tRect.iWidth = $iWidth

Global $iRet, $tCodeBuffer = DllStructCreate("byte ASM[192]") ;reserve memory for ASM opcodes
$tCodeBuffer.ASM = "0x8B7424048B7C2408558B6F1831C08B078985A800000083ADA8000000018B47048985AC00000083ADAC000000018B47088985B00000008B470C8985B40000008B47108985B80000008B47148985BC000000E8020000005DC3505351528B9DB00000008B8DB800000031C00385AC0000000385B4000000F7A5BC0000000385B00000000385A8000000890C8683ADB00000000177D4899DB000000083ADB40000000175C55A595B58C3000000000000000000000000000000000000000000000000" ;write opcodes into memory (struct) / length: 192
If $_ASSEMBLEIT_FLAG = 0 Then ;when Assembleit
    $tRect.iBase = FasmGetBasePtr($Fasm)
Else  ;when CallWindowProcW
    $tRect.iBase = DllStructGetPtr($tCodeBuffer)
EndIf

$fTimer = TimerInit()
;~ $iRet = DllCall("user32.dll", "uint", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer), "ptr", DllStructGetPtr($tBitmapData), "ptr", DllStructGetPtr($tRect), "int", 0, "int", 0)
$ret = _AssembleIt("uint", "_ASM_DrawRectFilled", "ptr", DllStructGetPtr($tBitmapData), "ptr", DllStructGetPtr($tRect))
ConsoleWrite("Runtime: " & TimerDiff($fTimer)  & @CRLF)

DrawRectFilled_Manually($tBitmapData, 130, 100, 20, 30, $iWidth)

_GDIPlus_GraphicsDrawImage($hGFX, $hBitmap, 0, 0)

Do
Until GUIGetMsg() = -3

_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_GraphicsDispose($hGFX)
_GDIPlus_Shutdown()

Func DrawRectFilled_Manually($tBitmapData, $iPosX, $iPosY, $iW, $iH, $iWidth, $iARGB = 0xFF000000)
    Local $iX, $iY
    For $iY = $iH - 1 to 0 Step - 1
        For $iX = $iW To 1 Step - 1
            $tBitmapData.Pixel(($iPosX + $iX  + ($iY + $iPosY) * $iWidth)) = $iARGB
        Next
    Next
EndFunc

Func _ASM_DrawRectFilled()
    _("use32")
;~  _("org " & FasmGetBasePtr($Fasm))
    _("mov esi, dword[esp + 4]")                ;start address of bitmap
    _("mov edi, dword[esp + 8]")                ;$tRECT struct

    _("push ebp")
    _("mov ebp, [edi+24]")

    _("xor eax, eax") ;set eax = 0
    ;save the values from $tRect
    _("mov eax, [edi]") ;iPosX
    _("mov [ebp+iPosX], eax")
    _("sub [ebp+iPosX], 1") ;iPosX -= 1
    _("mov eax, [edi + 4]") ;iPosY
    _("mov [ebp+iPosY], eax")
    _("sub [ebp+iPosY], 1") ;iPosY -= 1
    _("mov eax, [edi + 8]") ;iW
    _("mov [ebp+iW], eax")
    _("mov eax, [edi + 12]") ;iH
    _("mov [ebp+iH], eax")
    _("mov eax, [edi + 16]") ;ARGB color value
    _("mov [ebp+iARGB], eax")
    _("mov eax, [edi + 20]") ;iBase pointer
    _("mov [ebp+iWidth], eax")

    _("Call DrawRect")

    _("pop ebp")
    _("ret")

    _("DrawRect:")
        _("push eax")
        _("push ebx")
        _("push ecx")
        _("push edx")

        _("mov ebx, [ebp+iW]")
        _("mov ecx, [ebp+iARGB]")
        _("iY:")
            _("iX:")                    ;$tBitmapData.Pixel((($iPosX + $iX)  + ($iY + $iPosY) * $iWidth)) = $iARGB
            _("xor eax, eax")           ;ax = 0
            _("add eax, [ebp+iPosY]")       ;ax += iPosY
            _("add eax, [ebp+iH]")          ;ax += iH (iY)
            _("mul [ebp+iWidth]")           ;ax *= iWidth
            _("add eax, [ebp+iW]")          ;ax += iW
            _("add eax, [ebp+iPosX]")       ;ax += iPosX
            _("mov dword[esi + eax * 4], ecx")  ;write pixel to bitmap
            _("sub [ebp+iW], 1")            ;iW -= 1 (iX)
            _("ja iX")                  ;jump to iX if above 0
        _("mov [ebp+iW], ebx")              ;restore iW for inner loop
        _("sub [ebp+iH], 1")                ;iH -= 1 (iY)
        _("jnz iY")                     ;jump to iY if not 0

        _("pop  edx")
        _("pop  ecx")
        _("pop  ebx")
        _("pop  eax")
        _("ret")

    _("iPosX dd 0")
    _("iPosY dd 0")
    _("iW dd 0")
    _("iH dd 0")
    _("iARGB dd 0")
    _("iWidth dd 0")
EndFunc

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Replaces a char within a string:

_ASM_ImageInvert.au3

#include <GDIPlus.au3>
#include <AssembleIt.au3>
$sFile = FileOpenDialog("Open", @ScriptDir, "Images (*.bmp;*.png;*gif;*.jpg)", 1)
If @error Then Exit

_ASM_ImageInvert($sFile, @ScriptDir & "\Negative.jpg")

ShellExecute(@ScriptDir & "\Negative.jpg")

Func _asm()
    _("use32")
;~  _("org " & FasmGetBasePtr($Fasm)) ;für den debugger
    _("mov esi, [esp+4]") ;pointer to bitmap
    _("mov ecx, [esp+8]") ;number of pixel=loopcounter and adresscounter
    _("dec ecx") ;we count from 0 to NumberOfPixel-1
    _("schleife:") ;loop until ecx=0
        _("mov eax, [esi+ecx*4]");read pixel at address
    ;~  _asmdbg_()
        _("xor eax, 0x00FFFFFF") ;AARRGGBB, invert color channel
        _("mov [esi+ecx*4], eax");write pixel to address
        _("sub ecx,1") ;decrement counter
        _("jnz schleife") ;jump if counter is NotZero
    _("ret")
EndFunc   ;==>_asm

Func _ASM_ImageInvert($sInput, $sOutput)

    Local $bCode = "0x8B7424048B4C240883E9018B048E35FFFFFF0089048E83E90175F0C3"
    Local $iSize = BinaryLen($bCode)
    _GDIPlus_Startup()
    Local $hImage = _GDIPlus_ImageLoadFromFile($sInput)
    Local $iWidth = _GDIPlus_ImageGetWidth($hImage)
    Local $iHeight = _GDIPlus_ImageGetHeight($hImage)
    Local $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iWidth, $iHeight, $GDIP_ILMWRITE, $GDIP_PXF32ARGB)
    Local $iStride = DllStructGetData($tBitmapData, "Stride")
    Local $iScan0 = DllStructGetData($tBitmapData, "Scan0")
    Local $tPixelData = DllStructCreate("dword Data[" & (Abs($iStride * $iHeight)) & "]", $iScan0)
    Local $tCodeBuffer = DllStructCreate("byte Code[" & BinaryLen($bCode) & "]")

;~  $_ASSEMBLEIT_FLAG=0  ;uncomment to generate CallWindowProc()-code
;~  $return = _assembleit("int", "_asm", "ptr", DllStructGetPtr($tPixelData), "int", $iWidth * $iHeight)
;~  Local $aRet = DllCall("user32.dll", "ptr","CallWindowProcW","ptr", DllStructGetPtr($tCodeBuffer), "ptr", DllStructGetPtr($tPixelData),"int", $iWidth * $iHeight)

    Local $pCodeBuffer = _MemVirtualAlloc(0, $iSize, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
    Local $tCodeBuffer = DllStructCreate("byte Code[" & $iSize & "]", $pCodeBuffer)
    DllStructSetData($tCodeBuffer, "Code", $bCode)
    Local $aRet = DllCallAddress("int:cdecl", $pCodeBuffer, "ptr", DllStructGetPtr($tPixelData), "int", $iWidth * $iHeight)
    _MemVirtualFree($pCodeBuffer, $iSize, $MEM_DECOMMIT)


    _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
    _GDIPlus_ImageSaveToFile($hImage, $sOutput)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
EndFunc   ;==>GetChannel

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Merges an image with an alpha blend image:

_ASM_BitmapCreateBitmapWithAlpha.au3

#include <AssembleIt.au3>
#include <GDIPlus.au3>

_GDIPlus_Startup()
$hBitmap = _GDIPlus_BitmapCreateFromMemory(_imagepng())
$iWidth = _GDIPlus_ImageGetWidth($hBitmap)
$iHeight = _GDIPlus_ImageGetHeight($hBitmap)
$hBitmap_AlphaMask = _GDIPlus_BitmapCreateFromMemory(_alphapng())

$tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)
$pScan = $tBitmapData.Scan0
$iStride = $tBitmapData.Stride
$tPixelData = DllStructCreate("dword[" & (Abs($iStride * $iHeight)) & "]", $pScan)

$tBitmapAlphaMaskData = _GDIPlus_BitmapLockBits($hBitmap_AlphaMask, 0, 0, $iWidth, $iHeight, $GDIP_ILMREAD, $GDIP_PXF32RGB)
$pScanAlpha = $tBitmapAlphaMaskData.Scan0
$iStrideAlpha = $tBitmapAlphaMaskData.Stride
$tPixelAlphaMaskData = DllStructCreate("dword[" & (Abs($iStrideAlpha * $iHeight)) & "]", $pScanAlpha)

;~ $_ASSEMBLEIT_FLAG = 0   ;after uncomment this line, run the script, and replace the following line with the content of the clipboard, then delete #include <AssembleIt.au3>

$t = TimerInit()

$ret = _AssembleIt("ptr", "_ASM_BitmapCreateBitmapWithAlpha", "ptr", DllStructGetPtr($tPixelData), "int", $iWidth * $iHeight, "ptr", DllStructGetPtr($tPixelAlphaMaskData))

ConsoleWrite(TimerDiff($t) & @CRLF)

_GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData)
_GDIPlus_BitmapUnlockBits($hBitmap_AlphaMask, $tBitmapData)

_GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\Result.png")
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_BitmapDispose($hBitmap_AlphaMask)
_GDIPlus_Shutdown()

ShellExecute(@ScriptDir & "\Result.png")

Func _ASM_BitmapCreateBitmapWithAlpha()
    _("use32") ;32Bit!

    _("mov  esi, dword[esp+4]")         ;start address of the bitmap
    _("mov  ecx, dword[esp+8]")         ;number of pixel -> $iWidth * $iHeight
    _("mov  edi, dword[esp+12]")        ;start address of the alpha mask bitmap

    _("_loop1:")
        _("mov  eax,    [esi]")         ;get the pixel from the bitmap
        _("and  eax,    0x00FFFFFF")    ;remove alpha channel
        _("mov  ebx,    [edi]")         ;get the pixel from alpha mask bitmap
        _("and  ebx,    0x00FF0000")    ;get red value only because r=g=b (greyscale). This will be our alpha channel
        _("shl  ebx,    8")             ;shift the value to the alpha channel place AArrggbb
        _("or   eax,    ebx")           ;add the alpha channel value to the bitmap pixel
        _("mov  [esi],  eax")           ;write the pixel to the bitmap -> should be a greyscaled color value
        _("add  esi,    4")             ;address next pixel: 3 Byte = 1 dword = 1 Pixel
        _("add  edi,    4")             ;address next pixel: 3 Byte = 1 dword = 1 Pixel
        _("sub  ecx, 1")                ;counter (next pixel)
    _("ja _loop1")

    _("ret ")                           ;return
EndFunc

;Code below was generated by: 'File to Base64 String' Code Generator v1.20 Build 2015-07-10

Func _alphapng($bSaveBinary = False, $sSavePath = @ScriptDir)
    Local $alphapng
    $alphapng &= 'iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAAAAAB5Gfe6AAAmO0lEQVR42u2df8inZZXGZRAREVkkkmVZZFkSWSRWJAwRQ6KQkdgQIxySWEmMDcMojKIwUUbRIaUJW8nENBp1Sd1xFH8041baOutk21j+Gn80pq5uu9va1rbtlu25ruuc+z73/Tzfd955f898v+ev9/uMf3h97utc59zPO/O+hxwyq1WodeM1PcIPHa+DGUQj/LBJ1YA4uMRn4YdPrgzi4IAQ4pPyI2odqUpPEocDH0ISX5UfGXVUW+V55XBgQ2jFF+ku94/GKqMIChXCAai+ii/SpfToSZVAOIUK4QBikNRLfEiXyreo3tqWP60gnIIgBIMD5fA79a49yT5mrBIKpzBgsOZt4IdP9Vl8aKfQP476k6jypIBwCgkCGaxxG5TDd/VFvEtPqv90WImFY0gQnIHbYC17353v6ot4V06lx0b9WVR5UkiIQkBwBkeIwZrshCTfne/qi/hQTsV/PlaVhSgEBGdwlBisSQSl9ePwoZ5HH+JdOoW+TXVcLn8WIEQhINAIYlARrKVOSKdfrC/1IV7ai+zjx6ugKBQcgnwQrVBdsMbk58OXetqe4l06ZP4F6oRh8XlwIAVCYDtkBrTB2kEwJj/U8+hDvKRD6dtVf5nLnzkIUXAIbgQyWHMIevn58EN90h6yT4w6CVU+BYpEIRg0Nlg7CEx/6v2Q36tP2kP0O8YqYCQKAwYZgWfB6hHg8Xfyefi9+tDuyk9GvbMvPnUOQWHAgDboEKyaCeR+Dr4kn4fv6pN4Sg/hp6BObYvPAgQxZAjOgDZICDgU2Qerd/ySf3SVz8Pn2Ut9ES/lEHua6l21/ImTIIYCgQzoA9qgIDjaEayOCcrxm/s7+Xb4dH5VD/HS7rJPV707yj87iqAACIUBe8Fs0CFQH6y4CdrjH5Fvh0/1IZ7apRyC3+P1XlV8dBbEQAoOgQxkgx7B6phA4e/Hr7kf8tX5dvg8+1AP8dQeqs/wWo+KD8HCKQCCM6APZAN0giPQXlBNsGIE0vG7+5H8Sb4dPp1P9RJP7VIOzWd6vQ8VHxyGMIACIZABewE2SAgwFL0PiglW5fjhfiQ/5cv7vXqKp3QX/Vde70fFB4dBDILQMYhOIAIMRfTBSpvA9cfxh/vZ+5SvzpfzTT2OXuIp3UWf5XU2Kj44DGIICGYEY8Be8DQQAmRB6YMwwUoQCPuX46f7Mfhkfsi3zs/qQzylu+gPqD6o8k8OgxgKhMSAaUAEaATuBeqDMMEKtAH1w/4Mfx6/3I/kb+XT+VIv8dTuqs9hbYjSR2fhFAghGFgvdAgwEbwPaAKMA7TB8hIo7S/7+/HL/ep9tD46H4cP9Tx6iId2KYfiD6HOrcXPjoIYQMEg0AhgABsgDRAGHofRBzIB28CDYCXaX+Efx6/m99On93H4Onuqh3hKl+4Po/46F5+IBDEQQjAwH9AG6AR3QURBmIA7wTIHAfSX9nf7R/a/3ZM/5PPwpZ5HD/EuHXLPs/pIW3gkEsRACDSCM6ANAsE7hCDmQWmDCIJlIVD0q/0j/LP7W/nW91DPo4d4aJfw860u6AsPBUIUDAKNAAaWBz2C2gcxDiIIlolA1e/tn7s/5J8m+fA+Dx9nz6OXeEo3rR+1+pu+8FAcQIEQaAT2AmygTogsOLmY4G1hggiCZSFA/Yq/aP9y/NX9kn8m5PPwcfZ29CEe0k3qx6wuRH08ip/wmCBAwSGYEdgLtAEDUQjaPigEFAQcBktMoNF/zEB/lr9e8nn4OHtTT/HQTuVQfBHqE7X4WSiIwSgQAhigF2SD7ILWBE0QLAOBVn9Of9NP+afa3Gfyu3wdvjkf6nny0i7dn7T6VFt4JBKiICeAAXpBNhACTATbC7gWvCMRiDZYBgLSf2TSP+n4i/wNkA/nQ70dvcRDuom92OrTfeEhQYACIZgRwMB6AQg2NAgmmqCOw6UjsE/9Q/n0/nl0PtRTPLRT+Wes'
    $alphapng &= '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'
    $alphapng &= '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'
    $alphapng &= 'J+EcALoIbA3QJ8DV1/QB4Pofcf3W/k8+hfCz45d8nT3EU/bPawkDGcAHjgAmeOYZawMLAhF4xAn0MXDN1aMpUC3QxuAIgJEItBno70HaEUADdA3g+rfb/tPqf9b1S35RD9H/lsspOAMh+Km3QUPANqLtTqBrgtYCGgT+ZsQn4VwxWJeA6AAtQXgTHktgMkBOwBQAD0k/8m93af8XX9y7F+anfFdvkv+9LUEQAyCwRti7F23gQbDbk9AIPJRiIOdgawGtg/5ewGPQt8FJAJotUBHIGcj3II0BagKmBqB+C4Cdj/n5s/11/Ox9yi/i/6OtAkEImAU0AYPAPfDYTm7FRiA1Qc3B1gJ+KcQkZAzmbXAAYNABJ0QH6D3ABANEAtYAcP0/cv3Ph34cv8t38b9oyyEEApnA20AEfhQESgz0OdhbgO8FogdOmLMHcgdgCYhrQJ2BYwngCdg1wK7HW/3q/tdeC/kS/5+qN954w78ShEAgE1gbNAQe39U1gefgeAqUGIwLAVeB8R5IW1DpAGyBEYHdCJABPAF9AnT6n5L+vdTP4w/5Uv8G65cofRkMHAFMQAJ7ReCpjoBPAs9BWWDj0AKKQW2D3gOju9C6QwcdEFtgisCyA2QDKAGbBrAArPpfjuMP+VJP6f+lCgxk4AjcBC9XAh6EpQmUg9kCZRdoY1DbYN8DDYDhFlQ64MymA3wHSAnABPQGaPTvea7qf136JZ/iKfxXUYEBDIiABF6vBDgNKwFvAuZgSgHfBZoeOLP2wBy7UImA2IImdoAvgcUAHIFKwDYA9jD/Q7/Z344/5Gftv8oUCgIzgdqABDAL9rQxoBzkKCwW8HVw7h7QLjQGoL0HYAZEBzQRqFtAYwAmYDRA0f981q/jD/nU++u2nIEjcBNUAs8XAtEEzMHGAroRDGJQPVB2odFBmCOg7YAEIM/AsgMUAzABcwAo/6t+Hn/IN8X/3ZYzIAKZoBD4mQjUJmAOFguUXSBPwtE5oB4YCYEcAekeoC0od0CdgVgCYwQUA5QGUAC+VPTL/nb8lB/qf1MrMTAEZgJvAyfwkoKwNEGxQAwCrIN1EvY94LtQ3AeGIdC+CvBXIb4F8WV46YASgbgF+A4AA3AEKgEjAKD/laq/HL/U/2ZYYlBNUAi8IgJqAs9BjEK3AHYB3AhKDJYeiBfk2oV4Jx5/KdBHgA9BfTeg64AcgboFhQGYgLkBXu706/hD/v+0VRC4CRoCLzdNgBxMFvAbQcTgsAfwHYI0CEdCYDQCeBOe0AEegXYL8B0gDOAJWAPQ+z/08/hD/W9rBYNqAhFADtQg9BwMC/guYDcCj8HJPYA78eQQmBQBzRCsM8A7QDPQb0GRAG6AEgCY/1l/lf/bvhKCTAAbUcRAsgBSwO9EmoSpBzQH+kE4RwiMbgERAXUI9h2gCLQZ6DtAMUDXAK5f9pd8Kv7fXMGACNgGlUBqgmIB3wU0CS0G+x7oB6GHwPgm0FwEtAX0EVC3oNoBJQJtCcQOEAbYkwzwc80/6v916B+orwyCwK9F4BciUC2wJyyAXUA3AsVg2wPahYYhEJtAl4I1A3ER0NtA34NTBPAe4K/CcgcoAm0JtBGQDJADgP6Xfh0/Bf9frkBAE5AAuyDFQLKADQJbBxWDXQ9gF+J9oA8BbAJ8M8jrQJuC/h2RLgObLaAOQW1BqQNKBNoOkBOgNkDpfz/+gfrKwE1Qc6A2QUoB2wVSDOYe8CuhBmG/CfQpWAEMM5AXAW4BgwjQFhQzoHSAIrCMgNoAHgCNfin+Xa2CoCFQY6BYAIOgxGD0gOaAdqFBCMQmgOtAn4LrxofASAbqVYAiQG8CuAZHB5QInGCApD+O/3d9VRM0BMYsEDFYe0C7kO4DFgJ6KTA5BdsxkIZAvgnVDNQW0EcAtyDOgKYD9jzHEVANoABI+pP836taBJVAagKzAAeBYjD1AOcAd6E2BLQJNCl4UpOCHYCxPTBnYGwBKQLsIrh1G9fg6ADdAjQCegMM'
    $alphapng &= '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'
    $alphapng &= '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'
    $alphapng &= '2n+Z9bdBECaofeAIEIeZQYFgFIABHFhnu2jW+yndtIf4rN6jrzR/Cf+w/3K3f08gmaD0gSPwiQAGp4EBesEhGAVgAAfW+100632UbtpdPJ3Pzmfre++X7If70/GvlP7UBm6C6ANH4HHYMxAEowAM4MB6n4tmrad0007xvXqPPpcf7q/HvxL2n2gC74OKgJ3ANFAvEIIoAAM4sNa7aNZ7JZ3aJV7qT4Z6834j392/8scfBIoJfCcoCDQRaAO2gjMgBFEQh2DhqqXctVN8qGfny/vqfcn32Z+Of+X0exsUE4whoA3kA4cgCsAADqc7i3e76tOl3KRLe4iXeh7+UH46/kNXVP7ABC0CdgJtUBgQglMAhtMchZc/OTW0U3xVz8Pn4Gvlr9bxdyZQH1QE3As8DcigQiAGcBCJVHz2TkpP4qWenc+5X+WH+1fn+FsTsA8qAg7FYJAhGAVgIAeCaOpkV27STXsSH+o5+LJ8un+1jj+PgxYBh+KAgUFwCsBADoM6SdKl3cT36jn4evmHraL8MIFHQUIwYGAQKgVxODFgnFQ+8c9Cu4nv1Tfyj5T81dU/gsD3AkfgDAxCpQAMbw8UUf7shKTdxLv6Kv8tir61I38SgsKAPigQQAEYBKIrPj9e2kM8zz4f/tqT3yBQFjQMwggGARSIgRxG6jiXbtolnkffqE+9v2bkO4FAkGxABgWCUxCHQBHlz/jn0h7iqT4fvstfS/qJYF1G4AzogwKBFIDBQfTFPzlW2ot4nr2rT/LXrS35HQK3QTCoEEDBORQWRbUrp/YiPtT74a9d+SkL3AbBoEIABXFwEm3pD/jfHJPEh3o//MPWmvcnhEEwqBBAgRjEobII1aEc0qG9iA/1a7H1J3aCGDQQCoUA0Zf/mWvP4qV+DXt/1AYNA0AgBXGoKN6aZLtyaof4Tv2hB4T6agNn4BBIgRgCxEjpj49y7S6+qD9g5CcGCQIpCEOA6Mr/7EjXnsQfcOoLgwyBFIQhoTgqyw7p1J7EH4jqhxAcgzgckWmkJ4eH9INBfA9BFILDaPl/cejBIz5DcAwFxLD8z/UfH3IQ1rp1DYi+4o8POehr3Xitxv/K/wPf1UmnM4FQVwAAAABJRU5ErkJggg=='
    Local $bString = _WinAPI_Base64Decode($alphapng)
    If @error Then Return SetError(1, 0, 0)
    $bString = Binary($bString)
    If $bSaveBinary Then
        Local Const $hFile = FileOpen($sSavePath & "\alpha.png", 18)
        If @error Then Return SetError(2, 0, $bString)
        FileWrite($hFile, $bString)
        FileClose($hFile)
    EndIf
    Return $bString
EndFunc   ;==>_alphapng

Func _imagepng($bSaveBinary = False, $sSavePath = @ScriptDir)
    Local $imagepng
    $imagepng &= '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'
    $imagepng &= 'cCf0CBchQM/j0KoyAtAM8IGAh2ej4pgLdwtDIMuC1qUQETQLkSx8iAhmVSoipYSZyHymRPJNhIMBobbyHaSIh+eZBSK8ioh5wBVUigLWorhHUfXWxkS0cOgRGdlDRT1cRKgaTg8XEiKIVqQTGgghPaY8yE4H3cNBV5GAAiSUtABUhKC7ZYgQKWjnXSASdUS4iIpIhORBawcRQYhnbBUNQcApKqFRzYOqEq1obBmXQpCiks8QWTOQIsKIXQVlZkDAQSlku2l5zwkClhEhghRGa9vm1omUXa0b+aIKRNw9M6WIZHKnfu6fZctE7c9Ka2uQEV0lD19rKKA6h0P3VtiFRgdIZZCubvm3MjO4MEKCdHeyFWrZggUyGCihGT6B/CbMzNgi0twF8nGCx67Da4+VzEfZuiUgGxvsfm8+hggQKhoeJAxwiojAHWFCEnQyk4MEaZHHyCRjiiuldZe7+hrIlJ0fJoMZ2mltRa67UyiirWJvgS//nlY3Pu5cKe4WdEp2cEIICc+EgNj9CDK7He6qLwIeLtJlVyNEwLIvCHehuDtak5bdnrYiD0iQIOuULPqczHJkboxByQKyJbYs68Oz18v/JK0cB0Lo7kLuut7Iu9lggHZGoxUFseteIh6fY0bAPf8iZ4hIuGe7Px/3/OEh85GwCEcIJdwxwx7RCmJGONwkC2P3QilmJpQ8zRS26pMAQkuLx601a91WOyr54gLI8x2AkkJaBCHZ91mtkC6oouLWzolTsxsXdvnF8LhWTeQHyK+atzw7WG8h1tzzN+Q9xNzzydwGBhGS/WtCSUElRMM9sR8hAk4WUrORExGLUGU4wwHJPh0iJb8HlXDxgIIkbe55EjjKG0EPUrP4YAnkqRW28oKgFIDhTgZVsv7ODoQEQhFwB0TR4pcAEtBolR93gEcA7jaXZ3PpAFAUUPcAYXmGRAJQKS0DIyxcRCFz7xzM0p8iJLxVXDOgIgCyFs2yAiI7aEEyJ1MQZkFRUWZrKIBQ2lFh67UAqkbeqEw2IvDINJeICElVcXcgAKGECD2AiGznQsCWvrJ2aiAKAw0zkDndzx8gon3lFi1bK+JatBDotVTMZXhWi5nvABgQlBB04g23EoDhAQpbD86GBSDC4CgZACx/HjvQRRzhEBaUQLDV8onwtOBAoUSiMUBGxwZftUsQAs/gIEAYiXB3o4gqEZIJs8VSiyAgqv6pilha+M70Q82/MQwNehAGZUZ7QiKflIdLCKydhSABgbSGnKKgA54gMDXcqgcEfT7DTE0tj2UIFHWf4KFCd/PIK9JSnpAAGT0fp4lovX9+ORF3I6ClICIjOYhQmSE/3yHGJLIJMHdtISOyOyXo4glEqUESAqJmRmKAdLgD4Sgi3QxuiscukcWMi4WwUOh5HRKi9ZBdv9f+BN1bxFCdP7Y3FIgSETXfu2hnCU6IWoSbUUWZpa1quysiSkMNDyAsw6iCwUTwAaGHCN1DIAJxcwKieWU0zIu18je/vlMYIoA65ldMNKxqbpfDWyJu/04BY1eo+OMWHEhU1CM80Vy6t1PFjA272iZx/9aPBkUdGZfbHcsUK48fekE2TgUyw44zbtvAtseQP+Y6U0SACGaRGGSEQfgYa291lcR83HLWgFaYttQ+Y6Z0t0Sa5v6CzGiHAGmesAed3iB5ZruOSLQbgITM9e2n8zVIJBBMQNiuPpkYl2czJ7vGIC9IEEy4PZtxEXmcF2WOljNmSBW4JzxKlciRDUgVZu+FDKAkNVpJvZuptNPgrWRhvgV3iIhl2yMSrXJ2sr0mzvBgEImHJq5KkqpuntU8Hj+SSGSWrbxs1SAjRDIoi7upSpYMbdqTrSJpXiNIKYxwBFVE6OE5/AlhcZkPq7eCNYQi4pmT5qcX7q2WoErWCY/HH/H4CMp8+HeFbhvmqJAORPGG3Oebyb+ojcNQ4ShEENLSWDZZ2QtKQyoaEJbIgGkCnHn6jSr5FRGtl26fpaHgRIRR0KKZi2bx1kC33YEH'
    $imagepng &= '88gkWozs2Cw8LHvAEDIEQXGrDk1AsE2d8kZR3MwRokop2RVQNK9iiDDBIxF6RWvXglkOCy1hXGVeGKjMfblTINq5mSdIkhMpMINHRgiXILONkPmDzXc8AQOzgBAinAdbEWi1FtpgB4q5eXO0VASCDduBR3BG6KtbO7jzCJNCcxOyaMkGTHYdgIiTBmbJiKBlc80SCAfpTsLzG+1iT4PPJYq6eSYicYh0WdZYZAGvLgqEQKhq2fxEpSTgS6/RrgJLUeawFtlEewQj4KGEt4FEHoFiMZ+hVslljM4iwWSuh+frSkcbk2iGcQQRreQkPeCQ1tg3iHqucCPCnCozvowI8wiR0sJACzBEgC7tOAaCOT5ps0eS2lKWt0I3oVlk7RsMQYBwydYtS/YddNmAXJ1PjgjFaQk6UsTNQar2OaUCoCLmppQcLKITQlpsJncDVIok0BQIhxVRJFKZYSzD/Tzo1gAccz7N7EpDyDycat8lJ0mJoIvkgUi0MRq8QCTE7mDRTEZFNcH0Xfmbf1v+Qx7ozD+FpZXOsDkhU9poDSIdcypT4HCSAoFDqT6jnJirz0yUJWQ3dtsNsZkZOsKsnXvhLkSqaKnVJLjDVzgnZ3eno0Ai6KSHz08AqpIT7sKufdmQrhQAk9XEUBnIqr5hwQ0EiBDJijCClJySWpu2RMbFFujnQZC0DxfzXE4ac8B348EZmGH2QFkXeewGmVQVMwsPERFKRBVqVmPmDRvecQOSVtFa6kxE3gY22UESDAjgiYdEK5Gwe+xtahEQERGx7LVnPA7terWiEzPA1DgXlNYKJ2idHIwMV9Jg4GhnHTswrVXPSngDAKFZWMARbWrdKiHsnmujkSR0mFB5YFcnuj0eCcQ833tcu7Wg3Ma2blkk0D2iJXAEXCRB6vYJ53CviXXmZFGlc7fWac20kBYYCUoYfAfEz1+W2TfNMz4QVMIdEc7Q7PQiItzaGehKJjMVpXutFaAneprhxkHNuc88n4lIAFOTCJCtpLsWZWTHKQ2yyToYFLDkd6aKt0ENKBTSwyHqcCojcdPsurVRT1gEIubJaejcs8Z1KNzD3ZkUAtIgLtqmNTJXdnMbWX2uwj3y5YUwdmN4d4hmo+EzSSPCs2Jr+ED2/wG6U6iqAbiZEE7UcFGBs0CzSYgdmLwDlXNaFC6gEZ4sHXebH26Jhr4StDYQIfriSZpgQJmRu8xwh4gaIj90tDlgIz55eES4mYioSjXPIjHc2HJNvlcAcEEovVFWgHAohBptuICWIASYyTxENMJGCyJ83CiQRE7gI9sVAJ5nXdqITpTzJATugYCoJqgQCAVKKYiYPCa4iuTANSGH8GBeeObBbj8/Z95CbfA2YkLN62VMHBmtEPWcm863xa2ARRVEhTsb7p8NfQ4uWiIodMLNlAVzOSEiYR4RUKnRQDOfqwhSCgmHE8IMU8IAvTW3EnnD2nwFQjrhgIh6lseUSLhVZmSsFRptxp2ovyDx4yzftRVsQY+kIEm+woxz0WCb5Ic4shLNU6XasjklWvgKtJ5H2yC61QXSCkZKNvcMzrBwQ7FjngyIaEKYidNGfGoek8GbETnCKyrzFHeehLKh8zsOwa6ayPkUxT3hOY1G+mgTUsbjsScEbtDEqkQiALeYGTTepgS7+NQarU991AYPNVJA6z3Es7zO6mtmzDzG5ufrGmFUabSaeaQskBzMWWS3SUSjLSYdJUdaM+NN5qivSFoUMycl9IEgPRLocwpF++yGkvuHBKCoOYCdiyYGw+bk7MhKJUS7ht+6eUTRkkOpSA4IEqGkeYRAKWIOESOqmaoI0IAs0eIwSICedBChOBa79xqNytRwlWTZSVCVwmLhAJTFUQknZ7JYy6ri5sgxEzx7MS2FgJklfRSiKFSHW3ulioTo6NlfKdy9oWnhu7LDPYRFhCE1QugqSg/L0VpGI3MPdxWJgHtMWY/N2I6Q1noYOsMlDzoZoa1ThCXpjeIi3oCrYFgiVm4oWsLDaqWI'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '6EECE4NFNdWIOQPNMxbQ8tLP1lzCtmPSSiM8UtS8relr84DGj5j9TuZ1Fa0zmC3FqTkqYsvmIiI76SCE1DLvvm4macoGG6cEvKT5g0qBoAoE7FLiNPPwREUpMBddRAhCUMTFHJ72oNksukd4FIeiudTnYggqtUlApZl2gM6wTkIJolALJJ94XoyOUkTD3dxzLoMiHiHmqiWV9VC1ou6RuieIULT5P+/M4lXDEXQtzAxBdzo60coIYQmymgGD5vtjARWscA0sKMYoXadgVI9eCwUBL2ntSVXtRQ3pwiKymX75C0/+3f/iHy0P8U/92rf3oz+I6eqlQyuynrY0UlB6n4x3P7pnw95//H/5D7/01VfffutDs1Lh24thKfaDH/zpf/Ff/53Xbrz0lb/4lfv372421YM1qolP07RaLLp+ES5nx2sTLg57m4axDsv9hU1THYe6rZ/cvv/hrXun6+2DBw9X/eLJJ586vHZ1PZwOp2fD3Qt98uWDy08O09lS+qQYuIAeC4g6qkQV9CCUcGooVKPZ3NI1CTstZwZZ3ZRSVEZWTT6Um6NtrfOIUT0CRURCiwHevES5I6mkDHBm2My22jvj78dITeT5eLz+YN6R2GLkTCnZ7cnY9dPxqT/ihrY3SmX3l4VHaOTrb32xMAuOEJ2kaFucUnf7XSO6JAdIeENmYGDuMxKDJ5O2WQo+Tis7r9rEVuEI3YH3u4EWmBBQqnxU1eDSbHWzAxdzc0opSodqk2nnnrWcXrQArUS4h5eySDA/U2DBbByoFEofkT4aaYTDUlAb0SMCCgltvKkQpNf4LMZwEXHz0uuxTe8fn/WHqyf2Dq5yu3d2rLG1flEm6WNYXVkt1/36NE7un11srvwH/9E/99nPvHb7g08Y/Xa07WZzfHaie4fDpHz2+f/rf/O3/tLnn/rqz/74P/iNPxgphQvUoT/qa/XTR9vqPDkedE8ODzrBIMR7b3/04d37dx8c7y0Wl68cPPHi1YP9pUICstlOi8WNw2/93LvP37/7gw/tt/6r8b//r2h3lduz9syrpx9WCrGdCMeiFINMhtwRGqR4rFjM3CL3P4KElBQTRIfmA1k0tTvea+e1lgqlKlgjFK/8TLLnmhYjQouK0M1mhsw8IXq839AbHWW3TuCxnv/TRQUiohT9xyr+x3yH2d9KxEUNTlUU8TQhoktY9qcl6MKaeq/kyifjKFBUndlEwgUoDFSRoKk4CwQqTL8ehJXc6ZLmK6G7KQMQQO0IoFhbtqUQSduniCbrmS1uoLlJrrlklJmOrSLM0At2FA94zpWTcqTqj7d0tZUMAo0I9ApljSiQEnClFRGgN0wCL6qgIaykDAPRKc2FhFJrULQWllnq05Zw5pOqsgJ/5is3Lu4/fPaGvHypHvbd3tWjwFmJ8/FkfPTg+GI9fPJwfOP1j/+Ff/Of++f/5V//6L2PatVx8PVZPT09G/x8ZYvf+v/87kfntxfHdz/6w+8dj8Mzzz2zvLq4d+v+uHaIXpydb8fterNZb7Y3bl462t+///7JH/zBD24fn16/efTya0/++Bdf+uIXXnn+5tWjrhQtU0gNGTYWXO5futYtF5+8+dsllkcvf3vYnHZZg1QjZZIQSila4SWg5gYOhAhyuYIExFAFYxFRsi15Z5j3Fp3otHN+r1Yo6mR4V4ox1j4xqPrqz3Hn09c8EecFsW0YGaKaK/MSRcbMZmlWv0nX/dTesEQUhQWQtkSrybebcbRIUmLKrP9IylgwTOASE0Fq30wVU/AsQiUKo2f0KL0WhUQVCRGosnRRiouqd9priIqrNJ6WZkqFMq86S7B52bbtbYKIpv1pfgNBlUkaXJVsNenUZ6PTcC9CxrxOcqYeCSXM53UtbdOhE3BXNLpreEhacyc/NM0VKTI7GuVCAwaRypt5zWgaqsIhKgh0zhCOsC641C7X65Umzw/VUBFc+Nee27/WbV54Wq6uqMtuPVUtstzrFvDz0+0nj+LN9x/+xV/6'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= 'BxhjjGfbQ4NPdRonhHg2KGGHh/sENpsB4DROSiUwTe6wYRpBVtDM6TGOo41et+N2vZls3G7W42azXo9nm9FqBQJqm822Xy37vXJx8lD6qVRfb+uy75aFpcO7H35wfPdeXxjwWhbjsIn3f7R85ecudBOhSqeFo0rKWaBKyd3Mu53a7al2atWkrX0li8oUdZwWi96JyWuhTIipk4WjjD72UoKwrPcj+0s0xldjPcw2IZZ7EWY2WwSEE9oaanX0VE/zJncVNTcIO+0x1nDvpLBGjeoUKX3llhHXBitv/2j9yfu6J1Md1uNayp6LFI2+V68B5IhgSsN7EH3XhXs161d7uRByHCZAFouOKF5GWWp3YuV0vPrczWe+8PLXvvXjr7781Pa0DmdlGNY2DAx24qg1glxfbB/+IL742vvj0fLu5sdeLMs6/OC7H77/nH71p5988kXZfuejg9fXr77x8aUPfviFJ176uas37+rqR1ef+ODatXf2+odr2bh32quHsY0CYjLNPayz2h0eRcsIT7EpPDrAzWsEihgwGkjti7pXb2rgRJzDLPeasc/lTuncOE7C2NLIbsqRf6AzqBiGsukXEg//lXp/cfvRB6uDZ7707KaT9f3pg4/vrqeh+nQxDGHDeDKVDpNMpyene5u1BxZ9P43eKWupqkUlttuJVLAzm8iNeRXR0Sd3S/pjtXF7sZm2w3CxGcZhmqbz9YW7B8ownVfbRoSorwrhogs5Pj579OBCBGLsYrFc8tKlVX9p/85379bN9mDRVw/AlzqcfPyGHx/3i6EOPX0oIrUjfPJqS66EUdH2LWQNTHKa6kh0XXF39+iCk1uFd11RDw9Ppk2hFg+PsF4ZUWaDk/AIMxcR1ZJ7VXZ6ph2Xc8fUb+VXBrlMC6l98VkUS0agWu1FotWyktDnZENd1YO6PXr/g/rgveHASrgME7uuW0rn0nHV9Z0v6mYzmEff915KwguL5VK7rhmZJFgYsVgsuq6LzWZk2Q4HB2f46i9++blf/PIzl49ulMXmJIbjwgnTejiZJrl6tBpXy8XQPylX9y4++f0PHr51cPCVSz+6hcWth5//maPD6/b+bxx/8sNHX/qFm8//9568ODk++L0f2T/44Pit9156cOvFXj/3o1W98vx3nr3xzo1nvne098mmX1WJrpr05uxKSbzG3KGN+joRSqG5hUnTi6a9aHQiSMyn2tTTITrULn+7uTB9M5spbo7tS9eFacAWdAUsooNeLLyLONwuJsOv8NFfuvf7f/TRrfGVz/ZP7nXBzYPzTx5dPLoYhu3Gq5mVTz65V/3J/qiDbdMNahyH9fk4DANYk5HroaqdiCDcqgOsdTsM2ybvrHW72YzrzbDZjsOwHYb1ej2M43YcbJq242hubu5u2+3WA+fbi83FFANq+pQutVvo0eWj84en773xPXKC7gUqIrrl3tmDd/ff+6O9r/70o+k80fYpXI0qCk5mrlqcQPin5bJ9DaGbUtyVrOYW0alM5o0LnQvDEOlKBnctn/2FxmsUmZcXadstPVerjewwC1OS8sXUa0ZQc5nFY0FtwiBpHioxm001XxctFpc6PvHJ3fFHf8byyDhN43ZFXV46KL1IULEoy74si4UvFotF6UiaWdZUqqqa4vEopVMtKqKqA6s9nPZ98aW//lPf+JWvv9BdORwPLiY/X3MczeoGXrjX13Gc3GS5othhPz364MEnA5987er+6tLtexf68OEXXrn01Fee/rPf++hP/vbHo+1d/czNg28/u3rt6rT1O7cebrnRg4vFvQ+f/uj9F8/vv6p9HB18UmhjFKM0q3SUrkuTrE7VEGNYCWq+3oheNAgL74IdxJn7otEHypTecI9dyD1clFmCejiS6ozCTrQOCkjXx1S9lFLKow4vDCf/y/Gd5Uffef9+LL526frXX8Xy0js/uv/6xw8//uS0Dptq4zjpgsOXv/7i+mwd23L9xZe3kw/D1izbNra9BJCkmQAOhpmP4+C1'
    $imagepng &= 'SqBO03azGdZrG6ZpGDbDsL5YD8PWEBFhtW6HYaw1Is7Ozi4u1pvNuN7WYbuxcV2UpQiLXLt+6elnbn7w9gd/8ke/o0JKFzIK1akYz1ey333uJ4bNunN0kerwAkRgEqqn+ebOjC1CRDprU9sOLEEnXBr0OW/e9p18b15O/OovtJVLTYiEkBLNLiR3F6fFeRNE5t5zM6OqKz3rWfPGmhB6BqqSy0nEzERFVd3CigmqrlZXzx7sv/WDbTyM4rToVPvlMgyddCraLwUOG7xXho9uUNWudMvVsuu7RbeIFDcUBbHqCskR08WjDWv3F//ZX/mZX/2J5RniWIfRRuc0WcREFVfxsHG9Gb2GFYF2Nhy/feftcXPzxevX969Oq8P12Xbvzvby03z+Z5+9+xC/8bdev/f6vRVW+z/x9P6XnuwWeufDO37/or+27LlcnD26du/2iydRn3jy1mr/vOISdAwKDeiHCBWnqER0QQ93YlkWSp3Q9uSk3Sc1maBURJpYBnJ1XHPd3UOB+QiXohSp1UpETwHmeaLYKpacdPDtv2LHv3Lnz969fetc+eTXnrnyhc+fUt74wcfvfHj28NH9ChsN08V2OD355jefXV1avf/ntw6OruqTV7zCB4O3NfejuwjgNcICHoLtOLgbq9dxrLVO41iHabPdnp2djNuN1SnCjXZyflZH22zGzWaok203w1RdSwn3YdyyL9IX7br9fnnt2r4U+a3f/K179+4uVwcN7IJGFFXWs4vy5Fe6a5d92EZYznzaqgvJosbhjnAqDTFKBGhEoRRDTc4POIarakdxDwi7YC/FES6sQpVXf6GJWuYRr0jhzpg8dsg0U+BnyiowYXqZ5AqU1ASmgVwz9hFWwAWhwoDkIlQVqF62zfJHfzo++tB7L0rBzh0SyuJRpYABNzebrJqZq6oW7fs+BR9TrdkTaKfREYF6PuBi9a1//uf+wq9/8cbDxbiWjXEat+M4THVSUktXvWbeuBjZ7+8tD3j+7ge3v/fuQ5+e+uwzV/YvbYbSPfVCeNiHP3r68v6rP/nietz8/f/3J9/5wW3eLzc+c+X6V66s9g8/+dGjs4d+tDLvMCyGG3duPX/nweLq4f3Ll49rF0VcrPPqCA0JM829UUKqsAJEzdCaj1sFjw01svKnCC3H5ko4xENFdiEpTSGLiJkToiqM6LxuVV4g/4enf7J6/49vb92O+ie+/NzitRePt9N7bz34+OH2fHM2htcKn7YnxyefeenGZ37shfd+8F4X3eXnnx3W22mzsTpN41jrZF6tTrVOqZPOILpZr32qFJmmaX2x3qzXZ+fnk9Xq0zhNk1UfpmG9OZnG7TTFOG3Xaw/vFotcKqDKftF1RbtSLh0ePPn09bv3j/+//+AfdCpdV5o9VFCg0XG7PoVc3X/lc+7Vq6VJcluVUp3mJT31c88VUdNFXtRzbWhXpnAFQwnEgrmgDQoGkCuATajls3+xsdZnT204GdB5b1HKJy2c8+pPBoQspNSAezq4piOiIbw5kqeYWyKcDqE4pThKV48+eqf7+N1hfxIORSjQaZpKKYvForq5mbuXjqJRp9wR3Agzjqi1pvmjV/PJOlGRaTtanK2++pd+8lf/+s9dGsr40DdD3Y5eVcxH5AZ20pmrOVSl9Adcsb73+2/86UfvXS546cuv6OHRdIz+xpUnn39+86hOd+5ffsZ/7JtPnTyM7757+83v3T5578Frn33iyS89p5cP3n33w3t3HlzfX22nujnC1c3dax/dury8fHzl6MS3ZOmJsFyKLp2qp8q7aNRc3qUppxCymgvzDIOCTptJvez8Z6qnlfHC21hdhQKpblK0S7P6gMLO3f7lo/s/f/+PHt599NBGv3J048tX47kn1ud4593jdz45HqbtaG6jDVyfb8Z+vf3St57bnp/V+8OlG09O4zjU8WI91mqOSoR52mjoMGw3F2uvbrV6tWGzPTs7m6ZxGqdxHCx8hG2HoYap0NriIDcbShEt'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= 'tiTmlvpJKWXN5SQeP/7k/i/feu/nP/rowx/+8sO33/v8wcPT1USzfvfmHjHVzXjy+d2zJ4/vvH791t7six+8sz7f+KIrAQoJNcicGNtGZJZTJ8yOO8EHjH/3773xX/3D10//+kcf/Nu/vv/L92/Ppteu3njI82PI5EWDHUBEOmM19dYKAwCEglgxQEgc1C2ICEgRgiDRhf7WPgrEMHBzZvAk3Wyxi2n9N//+sz/5P+P4YDZfGnXEM1J3LMG4mRQocsdDnxJxL6kyO+K8y6rT+erMrCIGgNU6dV1Kksb1Rm3TqDQIaGbtmI1wZgLAnAciQWCR3ETRUgsFMNBkNfcpd12ZFMz7vhfmzTQhcq0GECmJmV9eiFPKzLR1yxE6Qt91t27d6oeZasnkzz5z59kXXnz2lVd2D/Zdves6ogQEAIyQTF1yGvoeAdfrqVTnlNU8AkU68EJRkYfjU3v+6hJT/6e/fHSYwhEcScyrWSYOQEdoZePESIFcfVtAx4ge6G7C3PZQDJdUti2ssOWzGZEQahj3YkruQeFgFsxOIUAAqBDtsHM3wYTIqD5tNurGjBEe0DpOAbYT2f/vIXBhzHYPdQqRnDh7A/+1vhi4ePIBHIIEHNyqMQWSJ/csM11OALyeTj579NjvV30rZrI43L/av3Q17V9ZXJsfjteBz9P67PTegwH7JzsxhjEkEkIUQkDKGJQjlpGWzoe5u/Xs4vW/e/v1r1/79I9++qN/9vF6NQ5XZt+adesf/EvcOfzz5/7xh74nbhV4tDIL55QCmQ0Ct68d3dpAeHTF5vABMPDMyMQCAEBmAB5AUIUy5WW3qB//7Mn3/+DJg3cgd3s7NxyR3FmoIx66ndE1c8qSFNwtMNzcdKxFy8arEOSuyWveWidPTqYuD4iOSBF2sXdn/8pKLqWESKatkRJNlRNzEnNHBBE0NxsNApaLhUPUWollvV4363Ot2hxB280XKlyAwzinLvWllAcPHvSzmarOZ/M3vvbKS6+8NgwLQYPELKn9Lmaok7cSZmgZdQcRAWTou2kqHGAEpRbisQI9OVn/1ku7P/joyjsf3ru234UBBqSUyULDFSyxMOFYKpN0xKPWEBL3RmWDoEgeaIbC3oyHBgQkjDXc3ReYavgUHmph2GBiEC1fLoAsFRHI3RnZANWN3EVEmVvvu5oFBrb+o4udywUMHS5/0XoYYRttN6HtWp6I3ZWJEcFDzS94le3+sPVKIgQwEJKmflJACO49Cqw/PPmQvvdJl/Jw4+pyNjvE2p+e8nyxwi6Ce49w51KEM+c0AGb2fsbXrwwvPH/jzktXb74+3yP5xR/85ff/73+ZefbKq1ev3RlOPv10dXe6c3vSpz/od958D3c2ngLdgNyDE4G7qgUhACZkiJjIOWccxyAVxkAq2vxn2IoQE7OTAbN46Nt/8elf/Vs7++nOcg+Ha2iTIEqi+WJnhng6npgZ0mCG681UdQMaQ9chOZLWaXQCYnazZjzxMKuudUNt+Iltmiku5skLChGGeztpt46GcMBIRAqBQAhATCDswlOZJMkypXGUaSoB1m53ws0uSsxSyhix9ZAikYhM4zhNmyEvhfbKaPu7y73dnXUtyA6gzJD6PI4TsbqTR5RazaxjqmaTqhAbupAn6apCQCRcrTY8y8P/7u/c/D+cnD05WR3Muqn5drfr54b3RSAsEAgeiQNB2jCRk7gbUiQgQ0APYiKgqBEOKQkC+FRCcJBMjg4AxMHc6thb9z1TUMCFHRYVEDBaDRghaCATt/r0yyf+qyrEVom7BHG3nw6QmXmEJPmSWWy2NSIBtOoHBGSRiHZPQffONUgQnSDQmVF01pls0oTr4y8+O3F+7fpw7ZVbxxvt1jjEIJHcpqHDfpjPFrP9mQ+dHVzfee4bz9x65ZlZjke/+Ph7/+QnH33v870Xls/e5Btp9+Tts+NR8cbh6HDjg7dt92G5/hsfzW9U69ClhkItYSBCBjC5VoieuH37GS50Zoe4'
    $imagepng &= '+DchOHpFxuAF9fXRp4++9we0+Uh2jwhkAab9DCNYSOv08OxsXdbSDRXNo2ithCyZ5vOlgR6f1pSklk21aQtVgpCtpgywtTwAtjfrhQGuBbWYGKFJgkAIlMTADcA8PLwNToSEzJxkZ+jqVBBwGAYzrdoss1jtMvzusQ0ge62VmjE2pwhDgPl8fuvZZ/N8WI1jKwEKaDzWxpIStsjMTRvhjr1ElKpVGSCsdjLsdd1qKpL5JPDhml/dx//612//k3//NkyMs+ZaD2+Qlga7aP4GR2TSWqWJnxxACAWDCQORgwKggEliBBAi91rFkwgAogh6RYBwKW5OnBHRK2BkRAAcQTNyz1TYVn2ixd5i6p5qkI3hFkHR+NGwpQhcfhMu1zHqGhhCHTb1aiuXNmsGNdmUmZtLGyLcgxm/zHZiCnfT4MTuAOFiiamrWRMM0oGu4PG63Ojo+u6unlclGWiY97vLvk89zPfSfCcNfXfn2ZvXjtLJzz547z+8e+/PPhnl9Ff+7sERzM82qwdP7WQ+8+s5V/RJR5r48Uc3hE7737obNxFLxegjMHG4dYEb9IZNCPdQQ0mKARbY1FbwiGB3TLLS2JldGTYPP/qr/3kcH8yHHTKSro9+8IiyOdezMUwDgJCFBBnH9UpL2ZnvzxeLUksda4e5ckD2UsdWUUxh2CIfQAAZAJnhUqjZArqZU0rMqWoNUABpH28i2hmGcZrMDJHcTGsVidHOd3Z2wOF8te76RELiOOekjJUgY+/htdZARCba+jqDiQMgd/0zB9def+OFl772ys7VK5zT1kEM4R6lKnHiBEzKYF0SBlpXdQSRzsbCQiklEbGY0LkYY6k7aJ+dxm8+f/DZt2/+8fcf7fUZ0ZXBKdBCiNwDIwQcjbQlkhkcIVrmbRvHRCCi4gpIicUh3FoPBxGxqbtOzIwQVSeicAtDzizgYarIzTrk7AEKZX/ZX71S7gaCW9hFM8tXxv0Ly1Q7DJqA0LjHrSgvGpMGAAEkiVmTHeir7y0EV1NoQRkPAOcW9b70NjYuryRmMiMZ4HhcPby3unqjX3aDDdwzdIx9EkmWycR71nLy9s8efHj2+GefT6uns2U+GvbLF/bp5jxu7D2doZ2u42y96vAUexZJPXTHX8yWn6Wjg/OC4DShtdYAAEyOue20CaNVogs5hrtTK54HqlxRup3lIm2e3v/+v4FP/ny53HUaQjUCz05PLYxcQ6fGHe/6jgl12ghYNGa5q2pV35gWojT0+0ybqazdy/aUcfctCGv7Y3DzC2AlArQ4Ebq5CNctDgs8vEHUVbVlvlJKbew8PTslkqqq63rl6uFi6DdPTyLLxtVHa9kXcyPmnFJKqcmjZq4FFv3w4nMvPHf72WEYHCIRVSvtb6oTYsZtFhJQVduIxsxGISmlxDklhKCAKIYoSIURAuf1ZPV7L1/7wScPz+6P+/O+shW3RuggJsQwMwEiYgQQQYDwVm6+jbeHA7AwAzJ4bKmngKaKwkzo5gQBCMLIiEJgbT8Q0HLAgsQEDNE5BuaJu/OVpiGcAq3NNg1FsL0HXyYkmmN2a5O+CGSYbetimLmhVcKDtkRq2II7EAnIo20icUtgaReDC4fjpTeLQFIvUOHuio7S4bUQfHQ2CkSaKLumqGvZJAzy9ZmdHV/f3HmtzGsKSE+zFbClU+C4OpOddZ7GYpsylRhPiPTp6flj+AKvs4zaGU4EYdZx2qCHeQpEIncTotY81pSvANdwQErdskOWz9+5+1f/6vSjX8yWNwRtmsY8mxFTQrBpDNfEhF3HLVQ+btxUGJJwtXH15ISQJAESMAuCQHQQG0Ag5HCHCxxiE5QbK65Jllu7iaqhI6F5y4I3giJsNpsWVWFuqw0stYa7auu2E/eqqvPFgtRXdWLkTd20iLAI55yZuZkm1IyJdoZhb7nsUjKztnsGhPbQkxAxmTkTYMoeVMvk6innmBzRmrofuZvGtdYqhCwJgcUdA7+o5dnDvf/mm8//syfv'
    $imagepng &= 'miojJiSzVnQLYcHEQrLRihDCIIgYDYEaiAgJsEG5CBtNQMy2yqVHkGCDLhWMFmMeSEb3aiokIhkABcK3MU8LtbR/uHN0q6x+ae5waZG9IEI1b23TobdsemrO3PBo+h2bORFqgDATEktqM0NzDJhd2m7zRd8qXgbwiEiYAiAa3xuRsHpYIhpPpvfztYevfuPqh/fYN7u6OgEEEUfUMtS0fDwfVge7J8Pe5JHB5BlSgqKaKnQRmclx6qZ1Xq18PIPz0/XDu7Y89BAGCigSJIhBZG5K0GTjThkg1mHiSB4Z0RhWlOZd3rF08vZfPvrrf+7rz/vZLqV+KiNyImAWAnNhwtSHuyTIHa/Oz9al5m7wQAj0KGYVAcbakKuj6gYAJWWtYTZtb03uidCkbUNTkAW4uzFyEnHA7WaOMblDnTzlrf+dmAhR2MxqKRF+ER8AJuy7PG42n336ee6709VarRpqQGCiLnc5JY8wq0bR9YslyBt3bj5z5zbNFv3OrO/QLSKckZrXbhoLtFgFEZjnJG5aI4hgGDL3/vT0LDRT6kqZgKKTIjzbFBvHswXKZqS/+/KtH3/y4C/efnCtW0atJXIPBkEU4OrKSqAJRRAj3B2hLcfAI5DRnYm8HaxBiMCtTNQtnJgIEMPNA4TIzQZJFNscB0UIQhABUBBU9f7WFXrh2dO/+SW5EreydYcLgBheZMnxK64guDCdEwG1WR+83Z/djZkAEjNs9xq4pXkzsV20ErRodtd1zWwmkjywveqsFgzmLGk1PfrJ++cv/NrZ899KK81W3aPF/6p3iulsWktkX1uERuI6ObhXDEecHNG7gpxSJ7tHtJdTBscpisqJq9gqR+9UAarXVqbQNsHVghF7QA4sBOdgFrST0pGVJz/+d3d/+EekZ3l+wMhQx8ScUtfldHZ+HmF93282GzULkFrXiNIPWVJqNU+ByJITC5uqaa0VkSI8IIjBo+EdJCAMMYBbnJMQiBEcHVEhzLfuHXcXYURWi4iAlACg1rot2W8dzogAIUn6lFLK7l6rbk6nSZUZCcnJc05D7ltaZciznPvFzu63Xnr92o1ri6Mrz9x+IXddzqkWi4Y9jWgjU/hlJYRvS0YcU8oAZLXO+o4Jx3EippyzMBeFDtOmqIeua+Hz4996Ye+tz8ank+8LpkAC3loNAmtVEvQIAVBhqhQta5QAK4g7CLGiOQe4YWCz4zBCALAhkHNzTzCjRzZkyideOCwjVDMhiSA1YAgWSHnmPAN4yrhVNC/NJ3EBo7/8Rbu0AcLWQwt2sfYK1QLgEYIo3OjjLXvhziKX36L2p2pgpfbzqqoiuf0IsyRidmdbkjz+oH7wE3/5O7aKz7sumQkFcAaSMB26kKhkoMjniDlibhQSCgAZs50va9SgMWryOhVQIqAuSw1yciR3D8cIFg4itgCNSkBA5KEETFIRd3K/uz67/4M/fPTed7tywrIAFCYU5vZG2EyTmaXE0zS2caJWRcTZbDZZTSlZHQNh2NmfpW5ab1anj3NO7q6mZjVAA5wQETg8gkDRkfqU5h1SgNY6hjggWAC2ESmgtSdQaM9DUVAL99pQthBAxBBmpsTESM3aaWau5hAsQuAZCVMehplgb6rFNkf7V3/39//hS9948XBnt1vsMNNsNqRE7QxXtUtYZJvQoHHhAx0tcZpqrebgwQh7i0ErgElQAgBm8lKrBqJErDXy49PNa9f3f+vl+q//6hPYm7kDeLTiUWY2dVUDQt77+u8HoRCLY8ZEIIAozNJushAEyLxFxLAIEDbwMCEyMhMjkamRMDFBOIDHNkOzVeaJCE5X5eN3PY6bK+PLl/0FSxIvXSPt4tpwIb5dg7c+WABvTPtWFYUILBIRqgZIl95GZoqACGz1G1tUq4M3B1EEALKIh4MaBOJo+uKtGQ6mJISduopweIR1TJW4kCAAgjFAuMHWNBwQzpJHQgvriRhZqnOYZiCDhMm2DCwUFEKySZEJEouBIWxgJKFr/U15'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '8aGtZhmBt9lD7VDWYmrQ1EIIIciamZobIuUbuv/V2z/5F39aoUjKq9XE/Oz61YtnH9eQta6sLdAjhCj3xf6zq5vLZx8FZKZoTVPidT7IsPvhD3/kbe2AYWcURMJAts2QKOI4PzStiUVEmJiybDbTkHLOKY9DLXZ3d6SBrq4vWaSWev/uQVvdT1s76d3DIVhySkPOrZmqDplTYiT85vWbr371FWkwUTCMw5iYixYzK7WYmTCDR11mhAiDUmaBEKBWKxMh9MAjnmtPFgwR4WoQAYn7exCZ81yre0GPpqFdDziyptHy1QPgXS3VmCKxCyGHBxD0qkl0RgCBujJLIKl7X3UhIVEYkAdCIDECORIAoZMEAAQKyVnvi4yQEDkM+lIZHcmDCYAIEdCMEQgdPTgNY4BDqFlRawAQ2k/V9G3YNwLweVrfg3QY7ggBxB4AFqWU0hom2Ty/3t5ca6u2FkABTh988vGHn3w0TvvtdHm5v77YXzx/b395tUOjqG6qLNg3dB7GTKbRmuEjFwWZh5yZ2DHylDkxC7sjZRlyVlX3CAg9L4CxtfPEtiMHS63aVKsu86zULi8vocFpObW1QIVV1/FyZII6L0tRVbBmHgCM7u7amBiJZagD+b/5x//KV7/58Ga7uTgd1/3+xQ++/1vf//4Pp90FWNS7OyYwyDlPiJyGzQ9++OP33ntFziPtW5lbfTicCuep1Pntuzdpt6MhYZKcEriNTB3YV1Q30+Zid8HMl1eXm+1lojHLSMwequb7/cV2uy9reXd7Nx/n7XaTUzrN81rbMI3bccoC8/HheLgP1/l4XOb566++ur97txmGKQmPiQYBiKZV1+qqBJiYKFyXhSNSgLfGFr2vHAgYyAaJCLzvuqG2ChbsQM4iOZgcxALncura71AdGGK79YtdS+Pqw1y3tXhmEMqIQBDMCNivlggATEyAjNzzjwgOYUzM1O2ayIgMIOeZA2CPjiEQgPRTMFiXij/WLc4Y/b73JRZkgr4moLNhWprWAMRQiCXCwjFzAgQzQ0B+JI50lRydy9sdKoVMbB2B2XoPHIBAl/Vdq7CUDMmAbj78+OPvfWeYBkkbyTvmYRjGceJQbXMVSEMSED+vFxBMrbdx3LW3H5NIr6ekMSFTQMSqFASJy7K21oDJrZdXXd1UTd1rKUSoDq1Wj7CirS2bF6OWst5VHZSR1/sjbaVJcFms1qMZVAgFzBxIbhpmMmSN2Bjf/dWXge3D37rRaNPwfq2nNOw++/5nzLi7/vCDF9s/mIY3p9MV0/Hh4cNX73306Q+ur292Ipe7y9v5MDzf/PIXP/+Pf+dHKtOb268HNFiKzyvkwYeRkLGqY8U8vnr1KqWUOY/jmIcsY5qGTBYPp+P9XCUNhnG6O5ZShmH38mbDAqfTCZBLtoGkLevt3TcezQOaudamailxGjOjubkvDgjWFCwQuSP/Wzm5NbKAiNmNmSlhbZWIGUnDGyHB+aSGAKmrkCi1XgUKCKDmjhJjIHped+MyZeOLRdmqYQTjCYUBN0QRbhAeYXhGJ5+vpWAeYENK7qqmgzAgmiNR77AbC/eePgA9DhscsB+ivdeJzKOP17tpNiBYCIFM3eHMXAsPYo5wIW9uEWD+WIq0M4jEEUlS4gh0MDwL3QEB0SMcEC0ICQkcCSQPjIAa62H2aIAOON5sLj/8+IPt7kJkM2y327TbyHZ/PQzDCEqMKEmIexuGH2nvIYLu2EzgHMUIswBgMqqlAYQ1S0mstnmZ+zXDzFs7raeKIEi1nFZHXjygtBIKQwqtImSnmOcjUYKQh9OCYKOMXj1mW09mTRVcpgShCcJbAYAWVdxK82/evLt4vktXaSzITN//0Q+cmSZeSxsQXr3/0e/tX72+/+bZRF9/8/b5ex++evGqrCu4v/jwg5cIh+PpB9/7ze9++snhOL9999HxcFvqKpCTs5elEb3T2I3Tbhi3aYAxOSEmZMD5ePfuXbH6KJ/jAMBpM7x87xkTHZbj'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= 'yADR+bVu3SqEj0WInjgL6XlLov59jwACx3AnIBE1UzdCYuZ+a+7HIhQ0U4Doiyr/NWLe+QzSC0fpzhMSsGhmxsQAwJAABMBRzD2QIpzQQ/rzGhA9CNnCiRhYwFyIyM5ac+RHD2mnI9K3fIzf1jP2QeQT7hgBhSUobZ/fvP/xJ9f7C6Y0bKbdbjuNE5GkKV2/2E/jABWbtcAws3CrtZViLMmtna0tnaxmFoQdAVRLWR+fmg4RrfXbyLDbAJGVZseVGWk/poE3TduprMspBtlt9019Xtcyl1IsjXJ5cxHejdQ4jBMgvnl9HwEiXGsVEjMLM8ig4dmprbWEUZLU8efogyREVPUxJ1M4tXu3Po5i4Qk9XGMaiPjMuHbwcRhSSuFGjFMeGcnNKSHT/5+tP/nVLUvPO7G3WWu3X3va20WfLZkUkymJIiVZIllWlSBLJYmSVUSpZKAmnnlgGDXx/2DAYxseeGQPbMAwbNiQYFiWUSqVGjKTmcwuIjOa29/Tft3u1nrf14O193dvUo5BIOLGuTfO2d/ee73N8/weNgEkcZnrm+iAAKkoch3CYb8p69rh/M3rK1MpyjmxEtNqsch88fL5KzWbLVeMThFBqdv2F4szFbrbN4UQNtu2HdAXs3mejOFZVqJZWRXOcYImg9pehl0csB92h/0gcd+F632zHYaDKJWLDz/4ta+v3lfso1oQ5xFIIyOqREAyA5lqG0QCFFNJ1R0DTTkglj41ESFiIkt2M1ACTEQw42QJV0s0aUAg0GOOy9vUTYupmlIFVXOOEUGiJt68mSbmM6ARcVr/45SZQulsIaQpSjS1spQMh6YupZmkGguRZIoegtGDMNb+SZg1aiKIU8OEzMgMKiKY1/X5xx/N5uvC+zzzeZ4naXTusvm6LNceVELTBwPiFNoeuq4LgwGNq1wzZYYwDDEGcDmQC20jMZpzRti2nQ6hrmdgaGS+LmPTk6iW5Lx3BQFR37EJ+7yGFcSo7f0QBkFipFDMS/FkffBCQ8EhdN3dHYSQl2U62qKIqQGQxp7JYqB9hN5T5Z0HFFQuijAMYjBb1RWF/fXQeg85FFnGnJH3CMBMRcF5njumYIzkvGMRHfo+Zb53IfRDTDBUCOAzH4YeARzzAEHjwCaZR4vD62cvguBsta6ysiiL+WKZE15fXc/m89liOaipCqrtD019cskKfd+UMxc24U3M+jDAoenjTlAFqFDEoAfp+hhU9NC2fZSua3fb3aGPfRgimkmrEbLZg8J79bfnF08qyRoYIocCIwEHG+teJk73TKr1U9oceTYzjZGQGZ2BxnQ1UzOJQoRGYFEdeSUTlZTfCGCKPMqtwVwSaiIGI0MwtXHbBHKMV1BJ6onkDFczYsemChgB1WJK2eLj5JTG6HIbpemABAQGaXrjRIATyIENVCSlCdmx4wWDd3sABMKoQkRAiKgE1AOQwXJxWtWV85SVxXyxWM0XPsuyzNfVrF7MvLpuM2gwds6Uk/q3H0SCqkV2HGP03keVQ9P6LKMQumanEYAZ2bQL0kleVt57g5jleTfEqMLs8txzxV5ccxg6HTQTLj2Evtns233M6lwgmgzOiqEJpAiKcuibZj90fWLYaoxgFsKQZ3k05U494b1KZDyp6jIv2kOTF5RlfhhC5n1VogNZFvOzYcCMMfOG4JiSFZiNRQRMPbmopiIGltWliJgqEeWZR4CuHYhdWdbWGlXKBtwCqDGzIesQY9dwVUnQzf5QzypDaYI8ePRkNp91zUHJHBekLJi5Mvdqbb9/+vl1sBhmqybIF198ut2/qmaFz1bx0O7vb5vDYRh6C8M+hkjkxSwKGBMzMQWIzG4OgKoCFdiscewpE1EUE1B2rGrMqMnYRUyjMMaOSFRmTkiAGIWJLE3VyQwEARyRMgRQTbsqHAGdnljUHBIjismEiAcAI4cECIppYsLE4EhMQNWhSwpfRiNTNUuSneRcQrDxZFBQiTBCdIyQAFNygCEzRnUA6JBFoySm'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= 'sGgAnr11KlHdrLIiI+fQQMJAICrREptdhbwBgSqCmgWILVTeLx4uFk9WWZlQCATj8/+2Fhyh1wm8nO5LAMcjDvL4jtQpLFanmQknl4QZIIRk3FXDd9LMJ9e2HuuQdyb09CtHKqIYJdniqHQYufaqgIaOMA3C01BEAAhsFAZElZRbkCgEya4xxfTYKChwTlQBUY+sLUNml+ZFx3WoiWjUnEkH2t2/eO9i4dm9evr5l3/2k+EZucODX/vo8a99kL9pY2dueZL1B9jtEF0EPLT3m9hU7Syjoq0dLMqCIrOQE4y9OmHKaAih2feMsWT16Oa5tHu5u2vib/z27e/8T5pFLUCPdPN4/8XQHp5mq0+3crc9PFxliBpCPNbuk8/TUnOcPh3VpIRLESSIiDHK5BOIAECQqRrzNEg4Jr8fy0pCSwpvTSwtTdOncXkDmnSHaR2hogBOJclIAQFElf/pP/uvGVKW93QqGSK5EGLbdeScqvV9bJu+63tEDEO8vbrbbw5mGi2gCIQoQ+NDj9KDRQJMm2dhcmWODiGKUxOJYGIxJrEUT6UcWx5b7fvBF37xaLZ+b52fFKKxb4e0gNV3TQ/v2Of0V51HaEcP9viV72psRqL3pC8T0xSZiW9v6bfPQIzx3dMgddTvflniFiqMHvZxG5kqWgQkJzbulRPU0TQiMgKp6VH4MJ7X+LZOmNYLie49NveWYrN4jJQ7avF1ikVJo1Vf1/dtXORWhRdOXjw40VWmv/awnju/jdWvf8vPZ4f7F5Vca72Qcl3nRWHAZenWi1Wuc44kg2lbea3QJPbCyNSGYddylrscibEo5sVcfWnhthy2v9Bv/cbu2/+Fnjy5Wn4SZxeP9M3HiyJw/LdfXb0OxcN6HD2+i/FxzKIyaXimUxHMOT669keyEBxXlpa8pvCWcQvTsQxiE09eU0TfeEqzS9XC8TemkvVoWwPVcSnB/+S//GcaIhgkG3LucyQ2sb6LiICMfWvNYVCNVVWKxs3Vrt31RtDrEGPAPmaCai3vNyS9sfqU+weKnnMm7AZoOxsGRUEACOac88SMysjDAUNErmj+aLF4NJvNi50N2kVvGGGqa1Rhms9Mrmc4zvvTS3S84zXFN43rp2M1gm+tGDiRyiCaOiSH9O5HMjLK4VecYukImZBPmByGMUZJ26pJFGlTcJUYRDMmdEkpqREBEF2MYiPSAI+4aRjjJcE5Sonn6dtmIlF9K7xL3kGdACfjh2ogSOAHRMgi2Dw2m4ermwd1XOZ73+62X3VPf3h/Np89+PaT4sHCEQ6b267p83xdF3MHLK06yFzmDYgxZ8YoouoFWYmA0ZcZEogAu8LnHEXFYmZxeL4p9f70N37fn7rr+eXPit8cLt67/skPzn75Zw9l+3/7vHvw+PJylg8yFeiijOlQHCf9biRXpyxIULUQonM+Gf8RvBkYDDQS5vE4sUh8oeN1UEgpt2TTK+x4dL9j0U6NAU3eeWdjQYb8d//eH6LP1KjfD1lGecHA1IcgogAUg4QQzIAdE2q77TbbQ4iDDiHEKCZ+GAyj7vbYdciqaIbkvE+fj/TB+oGJDanvoyDmhc+DaYyhiwYuWy6q82p+UdarWlG0jyjgMQHbgJFgnOym/DVLziKbqhoiQgXUEQST9mdm+i6vYbrKRwvvaO8ixDRjfrejehc3adNSeVI4Jg8LKvIIUVHgd46blCYXMAICQfKyqmoENCUSFWQE5lx9RoSsGTlXZOg5c0jkmm449CEvy7rI1TQIOiNiY5fWnKnPM0BDAkq4CSTTASgOhl3XI/i7u5uTcHNCN5UeCqlyK/s3Ww/t7OIR+MX84bx+Mvezy6YP+7trHioMCqEzZnElORDtIqD4MipioZCJzzNEttY4YJAgShgzhB4av3/zvH3/rDj/jnaHWdHr7HKon7y4g/P7X/zWxxd89n6EEKnDmJtE9pDuXSaHSAYYJJqZo7GxS6uio74fAFSTLHR8KzHz27nn+LHKhKdPuahy'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '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'
    $imagepng &= '5HgwKLjQGIyng8n0aJJkUbjme2F/kU5H6f3u+vc/unOQzscH4zUZ1PxQGzmeTm5tbPmunetCQU0uWASX8Faw4j+jla5fOojKs3HhqryIzvwBjNUYAKAuGbp/MFAYg6tuhAjMQdZ/cxQPzqXhABmjJUQaQ2wARBhSBYmxNu/e3Pujm44FeQGsAM2PRyeHJ1UHEyOhMhQSjhRUmBeAdWs37+5qbpQ0JaIRoUucy2pHveLXXfyUSxLqBfzHaC2/Nc6tgISrhuSVhP+OAFq2tGujy0oQRKBD6WECPn8RPzsU8wy5SkY2tDyEESWGF8UyB8Dy/Zof1l2vEAXA0LZIzQ+UKKaTsaWtilW5trmxc7UHoIiTVFNYr1T5gsVWYXXcx1+9GY34+kYDcDMc9TGgMtWLWbLeCDd7rTAKlFFexZokyUl/maWi11nvVloyK2rVSANQxPOdXgc79iBbrDdqjchrtSLCSMxVx6uALN8fxlOJexXf0UrlrN5a8z3oW5AQ5NqsEIrYDFpMAK44Z5BSzx6Nlg6iECK/6iX5Qonctaz5IqmGvlYyjYv5kiuhGdZ+1aM2g4a0tqr1EfjF/zuAV8leFCyTJWlFKmqdVm5+s3Bfvj7d8EUQ2rNMQm2swLZC9T++OPrbrxNie5/c+97mjeovDs5QxqNabY6kF1jcwFTFFJBioZI4ViJTxeKsf/rPj5+trTXWo+rJ6WKRxX/y7z8uWHb4eP/9ne3vfnx7KGMwl0uopUoABRppopWCGqGSib0amIXgCGGMycoqtpoN4Lth14sDAC8970ppBEt3nby0yVxuA7Ct2OloMJxO0tHMQK2hUkZKqCFAGmmhFeY0pG63u97bu2p5DpTaaBn6Tvx2dPDqwKccAWoMBgRpDQkESiuXse69LURdqCyzQlbA8pbHmL7jxjfvZt4uZyGlVqExCDBY4YUv/fol98qsoHJGY7zqhVXaMKiwEZbt2o7ztG8+f9JfTHKL4nqgfaa0xkkSK6VwLvPxUgNWiTy/4cZK8VlBqBUEbpEVJLO2a5u7V3d297Y627WcJ7aimFip0JJZV9udbDb57PwtXRgfMqnj7Z1ofHZmUw8T2qw4jo9wk1nE9Yw6Oh892d+3jdMKeh9+sNWJbMe1SFUAI2sYYwTGmSEYeBTEhextruV5MUnyoFq1GcRLzCS588H1diVK07zqkjjJM4habQ8wsYzTdFJAAgvJs6RgjKSLWd11qpWQSxHzGGMUuVVs8Gg2rgQuJnCyEBJZgYNudLvzlL86PQ8AE7Gb+bTe6fz4pwcTdXZ1J2QJFrrytnPz6dq9J2j7m6PjB16MOXRBUXG9H/34yX9/OIGg9Wef/uB737k34rHDcUhRgeHBcHZ49jq0zX7/zKiiWwkgYmf9wWBZnJzH02E/no63wjpALFprvx2//uLJk4btCl8/n52rdOk4dsGsWTLCWiCoNUBGaaXLhhhpzAo+CYDWhpdIWowQeOfTL0ERCECEgQHKaIUwUEoAoE3ZCYkuq4PKWUNDCLFNnHQ6zeZLjADAQBuVQUAhRQVQhTQSusTfu7u7995dv1XFEBGIgZK26yxPJicvDpgFcoggwggCo4AGSkBtGdS6t8WcChBESA6AMcqAC6rjxRtFXy7z3g1hXb5jEEAGQMEFxhATvNJ2vp158DvGQKONhgp4jgs953iZfvls+fJUeYC5mCipLWxrZAtlKCQMAy+sNtvdej0yDgMCkDizG7YRMDkzd7ZqH368tXl31113NVLLcTYVCjpOIeFsnLSr7t6D7osXk5/9r5999GH97gd7s5HYf3mAnNpQFbYf9BoBz8w//vS5G5Kre92f/NPDNOG3NnvXdpu96zVFivN+7gQuNqbZrs+VAIp1Q+8snsyytOlbDiWQwMVCSgq2tsKbuxuxmgGd1jvhXKq3gzE0kkF4eDLmiepWmtWAKmAAYloUa+0WdcksTQDD6ZJ71KtEHsKyGVXOh5M3R32HYMclYeQZpBKeG0qt'
    $imagepng &= '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'
    $imagepng &= 'iG+DrY3IrxQH88HbF4le6M2t5vE4v721cX3n6tDiXz788lf/9HK70/3jj/Z0nqvzLCm4jPTx6QxrYLgi0L5xfT1wvfEw2brSSvN4OF8M+8NFkrTabQcHy1i0e/WPbt1apsu17e6bZJKI3M5Jlqrd9TYzUCNGiaaU8VgLoCsucwGccq25ciiBgtsumKd5GqcQYQRRs+ZxgwoFgoo5OuvXK41myzvtz4b92BRJb3Nt98Gt08n4J788+PlJwaMWzWV/MPnTD7/7wz//i9TGahAPzfJpOvjqxeHx2fh4PBwtlhRbDg5utHqnZ5OI4htXulIh6FAGilwsvzo82amvYwUzEX/3xl0em1jzDJiT8awX+lu95uPBYeaD02yY53Aj6oyTEcEACW0IMBhgADUAQkqGMUK4JCCUOB180YIEMIJIQ6iUlhCBdzykK/nIGFMCjLUxEGNltEFAa4A/3atuNjSY0t0uer9L1pHz3jq8ZkOQaIhB5862TVzDoQQGI2SAUUJrACAGGgCLuaPj8+VwwBDWQjoEQ40UgKEyIk3ItU6DhUJBhTHSq5Ln8hReiFb6cm5bJdeMLu1Kl6mfSxj8RYYYaSUBIhpom2jHdh+9Hv/0OU9n6UZUIhsA9d1CQguQBrECn0GGYiFyXSAEGLQtSF3oVC12pRZdvbqxtt0JQ5+rIoVpIQulxHy2THgumBonSTaPJ2eHxCaOcrVS2w+6nz3++qvfPLp/59rdG9sW8QC2gKVOR/Hz56M682/f7QmVn77l9z/ceHJ89NNfPZm/Pe901v70B7c3ug3JuVuxnu4fjc6mFdstjIqT9MZWOzZiMp81KxF1WMJ5GmdpnELMapV6s1nFCLiu60Qwy9L9N8Pp+cgmLIoc28bVZhDYNlKKMWwhazhNseLVihUbjaUkBAilCNLcKBtDnguMYDUKgI0Oz07jPDsdjdNMskpYyIwpU3M9lzmZUsbC60Fjy6nXcXOg2CLNBif9T/7Dv/3+v/pef3gOoHq8//bh588gkD3btkD46MVBrx7dvboBqLW21nBdMJHZ2WI0LiavXr/MC56MFiTP71xdv7bVnohkmBTTyURmsUiWzZa1SIdUN97sj48PX2zUq9vdXgis8/FMYOMShLSS2qyqHQFQSimlpVbo0iFdjvarmVqVn/67lMvVv4JVyyC61H/KUhl8u3IlotNeLb3ZYQ1GO21Qd7Ko4C6CGBN9tesSXwmkCEQrHheFiBijhdHM90PLnRy8NkJQjC2EiMYSGdclYpaGoePsdEVGmEAFKGH/75YxrnZe5TLLaEPwHzDdL20O5e6sXBJrrQnGCGGAlKLst6/Th08GgTSIAQ6RA4nt2hIYy6a1hmf5JhdpHqcw5x52bFq7EnX21isbHa+7Xo96a9hjtgsNAFKbOFlO+tN4kGWLZZbNv/ztyxevhlXXa9jWItXSAkPRPx0Pfv2Lp1VKSZN0b/SavkeRjZZmMUqZbYc+zGihUtDtVApSPH54wEezO5trwrKAx4wpPN/uD6ePHr25ut7wK9aTsz6y6I2NiiNJPE+qtWpqVJzn+TwJg5AyL4uLVtvrdKLpNP/8988il1iWulrtqRQUWFmECgF811nmS84wlDrh8VoYzebp2Ig1i87m4/5iKSE9XqQyT31qCSNzmS3zBIoitCv94dyzzXF/ZCu/3agAG0pmc64DRDjhjb1W69p6PE7u7+xe370NmOVFJKjV5/Hy669ffLTekdn0zHDTsEWaB57TiNioULbnaAgOT4Znx0cHZ8cecFFBMXYbV9btbrUaRY9+97Tie//x4w8spYbD2dP+2WSJP7m91bYhnFuM4Iym2Iae8SUEqU6MEmZF/lxlxMumHa0NLJVQAPXqASBLks67kOPyz5VS5dd/6Zq+3Bb//wEAMNrJ3KQ1Li8AAAAASUVORK5CYII='
    Local $bString = _WinAPI_Base64Decode($imagepng)
    If @error Then Return SetError(1, 0, 0)
    $bString = Binary($bString)
    If $bSaveBinary Then
        Local Const $hFile = FileOpen($sSavePath & "\image.png", 18)
        If @error Then Return SetError(2, 0, $bString)
        FileWrite($hFile, $bString)
        FileClose($hFile)
    EndIf
    Return $bString
EndFunc   ;==>_imagepng

Func _WinAPI_Base64Decode($sB64String)
    Local $aCrypt = DllCall("Crypt32.dll", "bool", "CryptStringToBinaryA", "str", $sB64String, "dword", 0, "dword", 1, "ptr", 0, "dword*", 0, "ptr", 0, "ptr", 0)
    If @error Or Not $aCrypt[0] Then Return SetError(1, 0, "")
    Local $bBuffer = DllStructCreate("byte[" & $aCrypt[5] & "]")
    $aCrypt = DllCall("Crypt32.dll", "bool", "CryptStringToBinaryA", "str", $sB64String, "dword", 0, "dword", 1, "struct*", $bBuffer, "dword*", $aCrypt[5], "ptr", 0, "ptr", 0)
    If @error Or Not $aCrypt[0] Then Return SetError(2, 0, "")
    Return DllStructGetData($bBuffer, 1)
EndFunc   ;==>_WinAPI_Base64Decode

 


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Inverts (negative) an image:

_ASM_ImageCreateNegativeMMX.au3

#include <AssembleIt.au3>
#include <GDIPlus.au3>

$file = FileOpenDialog("Select 24 or 32 Bpp image!", @ScriptDir, "Image (*.jpg;*.bmp;*.png)", 1 + 2)
If @error Then Exit

_GDIPlus_Startup()
$hBitmap = _GDIPlus_BitmapCreateFromFile($file)
$iWidth = _GDIPlus_ImageGetWidth($hBitmap)
$iHeight = _GDIPlus_ImageGetHeight($hBitmap)

$tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)
$pScan = $tBitmapData.Scan0
$iStride = $tBitmapData.Stride * 4

$tPixelData = _DllStructCreateAlign16("dword[" & (Abs($iStride * $iHeight)) & "]", $pScan)
$tPixelMask = _DllStructCreateAlign16("byte mask[16]")
$tPixelMask.mask = "0xFFFFFF00FFFFFF00FFFFFF00FFFFFF00" ;BBGGRRAA invert bitmask for 4 pixels (128 bit)

;~ $_ASSEMBLEIT_FLAG = 0   ;after uncomment this line, run the script, and replace the following line with the content of the clipboard, then delete #include <AssembleIt.au3>

$t = TimerInit()

$ret = _AssembleIt("ptr", "_ASM_ImageCreateNegativeMMX", "ptr", DllStructGetPtr($tPixelData), "int", $iWidth * $iHeight, "ptr", DllStructGetPtr($tPixelMask))

ConsoleWrite(TimerDiff($t) & @CRLF)

_GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData)
_GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\Inverted.png")
_GDIPlus_Shutdown()

ShellExecute(@ScriptDir & "\Inverted.png")


Func _ASM_ImageCreateNegativeMMX()
    _("use32") ;32Bit!
;~     _("org " & FasmGetBasePtr($Fasm))  ;needed for assembleit debugger

    _("mov esi, dword[esp+4]") ;Startadress Bitmapdata (Pixel) -> scan0
    _("mov ecx, dword[esp+8]") ;number of Pixel -> $iWidth * $iHeight
    _("mov edi, dword[esp+12]") ;
;~  _ASMDBG_()

    _("movdqu   xmm0,   [edi]") ;copy invert bitmask to xmm0 register -> MOVe Double Quadword Unaligned (SSE2)

    _("align 16")
    _("_loop1:")

    _("movdqu   xmm1,   [esi]") ;load pixel -> MOVe Double Quadword Unaligned
;~  _("xorpd    xmm1,   xmm0") ;invert pixel without alpha channel SSE2
;~  _("xorps    xmm1,   xmm0") ;invert pixel without alpha channel SSE
    _("pxor     xmm1,   xmm0") ;invert pixel without alpha channel MMX
    _("movdqa   [esi],  xmm1") ;write pixel (SSE2) -> MOVe Double Quadword Aligned

    _("add esi, 16") ;address next 4 pixel: 16 Byte = 4 dword = 4 Pixel
    _("sub ecx, 4") ;counter (next 4 pixel)
    _("ja _loop1") ;until ecx=0

    _("ret ") ;return
EndFunc   ;==>_invert

Func _DllStructCreateAlign16($tStruct, $pPointer = "") ;align auf 16-byte adresse
    Local $tTemp = DllStructCreate($tStruct)
    Local Const $iAlign16 = Mod(DllStructGetSize($tTemp), 16)
    $tTemp = 0
    Switch $iAlign16
        Case 0
            If $pPointer <> "" Then Return DllStructCreate($tStruct, $pPointer)
            Return DllStructCreate($tStruct)
        Case Else
            If $pPointer <> "" Then DllStructCreate("align " & $iAlign16 & ";" & $tStruct, $pPointer)
            Return DllStructCreate("align " & $iAlign16 & ";" & $tStruct)
    EndSwitch
EndFunc   ;==>_DllStructCreateAlign16

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Draws a line using the GDIPlus lib:

_ASM_DrawLineUsingGDIPlus.au3

#include <AssembleIt.au3>
#include <GDIPlus.au3>


_GDIPlus_Startup()
Global $hModule_GDIp = _WinAPI_GetModuleHandle("gdiplus.dll")

Global Const $iWidth = 512, $iHeight = 512
Global $tPixels = DllStructCreate("uint [" & $iWidth * $iHeight & "]")
Global Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $GDIP_PXF32ARGB, $iHeight * 4, DllStructGetPtr($tPixels))
Global Const $hGfx = _GDIPlus_ImageGetGraphicsContext($hBitmap)
Global Const $hPen = _GDIPlus_PenCreate(0xFFF0F080, 4)
_GDIPlus_GraphicsSetSmoothingMode($hGfx, 4)

Global $tGDIP_Ptr_Handles = DllStructCreate("dword gfx;dword pen;dword GdipGraphicsClear;dword GdipDrawLine;")
$tGDIP_Ptr_Handles.gfx = $hGfx  ;0
$tGDIP_Ptr_Handles.pen = $hPen  ;4
$tGDIP_Ptr_Handles.GdipGraphicsClear = _WinAPI_GetProcAddress($hModule_GDIp, "GdipGraphicsClear") ;8
$tGDIP_Ptr_Handles.GdipDrawLine = _WinAPI_GetProcAddress($hModule_GDIp, "GdipDrawLine") ;12

;~ $_ASSEMBLEIT_FLAG = 0   ;after uncomment this line, run the script, and replace the following line with the content of the clipboard, then delete #include <AssembleIt.au3>

$t = TimerInit()

$ret = _AssembleIt("int", "_ASM_DrawLineUsingGDIPlus", "dword", DllStructGetPtr($tGDIP_Ptr_Handles))

ConsoleWrite(TimerDiff($t) & @CRLF)

If FileExists(@ScriptDir & "\Test_ASM.png") Then FileDelete(@ScriptDir & "\Test_ASM.png")
_GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\Test_ASM.png")
_GDIPlus_GraphicsDispose($hGfx)
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_PenDispose($hPen)
_GDIPlus_Shutdown()

ShellExecute(@ScriptDir & "\Test_ASM.png")

Func _ASM_DrawLineUsingGDIPlus()
    _("use32") ;32Bit!

;~  _("org " & FasmGetBasePtr($Fasm))  ;needed for assembleit debugger

    _("mov  esi, dword[esp + 4]")   ;get the address of the $tGDIP_Ptr_Handles struct

    ;push parameters which is needed to call the gdiplus functions
    _("pushd 0xFF808080")       ;$iARGB color format to use for clear graphics
    _("pushd [esi]")            ;$hGraphics handle
    _("call dword[esi + 8]")    ;call _GDIPlus_GraphicsClear

    _("push 200.0")             ;value for $fY2
    _("push 200.0")             ;value for $fX2
    _("push 0.0")               ;value for $fY1
    _("push 0.0")               ;value for $fX1
    _("pushd [esi + 4]")        ;$hPen handle
    _("pushd [esi]")            ;$hGraphics handle
    _("call dword[esi + 12]")   ;call _GDIPlus_GraphicsDrawLine

;~  _ASMDBG_()
    _("ret") ;return
EndFunc

 


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Replaces a unicode char within a string:

_ASM_StringReplaceWChar.au3

#include <AssembleIt.au3>
#include <Array.au3>

;~ $_ASSEMBLEIT_FLAG = 2   ;after uncomment this line, run the script, and replace the following line with the content of the clipboard, then delete #include <AssembleIt.au3>

Global $sString
For $i = 1 To 1
    $sString &= "I forgot that AutoIt uses UCS2 charset ● J'ai oublié qu'AutoIt utilise le jeu de caractères UCS2 ● 我忘了AutoIt的使用UCS2字符集 ● Ich habe vergessen, daß AutoIt verwendet UCS2 Zeichensatz ● Ξέχασα ότι AutoIt χρησιμοποιεί UCS2 σύνολο χαρακτήρων ● Я забув, що AutoIt використовує UCS2 набір символів " & $i & @CRLF
Next

Global $tASM_Parameter = DllStructCreate("word search;word replace")
$tASM_Parameter.search = AscW("●")
$tASM_Parameter.replace = AscW("*")

Local $sRet, $fEnd, $tCodeBuffer = DllStructCreate("byte ASM[39]") ;reserve memory for ASM opcodes
$tCodeBuffer.ASM = "0x8B7424048B7C240831DB31C9668B1F668B4F0266AD6683F800740B6639D875F366894EFEEBEDC3" ;write opcodes into memory (struct) / length: 39

;~ ConsoleWrite($sString & @CRLF)
$t = TimerInit()
$sRet = DllCall("user32.dll", "none", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer), "wstr", $sString, "ptr", DllStructGetPtr($tASM_Parameter), "int", 0, "int", 0)[2]
;~ _ArrayDisplay($sRet)
;~ $sRet = _AssembleIt("none", "_ASM_StringReplaceWChar", "wstr", $sString, "ptr", DllStructGetPtr($tASM_Parameter))
$fEnd = TimerDiff($t)

ConsoleWrite("Replaced in " & $fEnd & " milliseconds" & @CRLF & $sRet)

Func _ASM_StringReplaceWChar()
    _("use32") ;32Bit!
;~     _("org " & FasmGetBasePtr($Fasm))  ;needed for assembleit debugger
    _("mov esi, dword[esp+4]") ;get start address of the string
    _("mov edi, dword[esp+8]") ;pointer to the parameter struct
    _("xor ebx, ebx") ;ebx = 0
    _("xor ecx, ecx") ;ecx = 0
    _("mov bx, [edi]") ;copy search wstring to bx register
    _("mov cx, [edi + 2]");copy replace wstring to cx register
    _("_loop:")
        _("lodsw") ;load char as wide char (word) and increase the pointer to next wchar
        _("cmp ax, 0") ;end of string reached
        _("jz _end") ;if yes then jump to end mark
        _("cmp ax, bx") ;compare wchar from string with search wchar
        _("jne _loop") ;if not equal than get next wchar from string
;~      _ASMDBG_()
        _("mov word[esi - 2], cx") ;if equal replace wchar (esi - 2 is because lodsw increases pointer)
        _("jmp _loop") ;get next wchar from string
    _("_end:")
    _("ret") ;return
EndFunc

 


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Okay UEZ!
go ahead like this!  :)


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

Compares two bitmap bitwise for difference and returns 0 or 1 accordingly.

 

_ASM_BitCompareBitmapsMMX.au3

#include <AssembleIt.au3>
;~ #include <GDIPlus.au3>
#include <ScreenCapture.au3>

_GDIPlus_Startup()
Global Const $hGDIBitmap1 = _ScreenCapture_Capture("", 0, 0, 199, 199)
Global Const $hGDIBitmap2 = _ScreenCapture_Capture("", 0, 0, 199, 199)
;~ Global Const $hGDIBitmap2 = _ScreenCapture_Capture("", 0, 10, 199, 209) ;just to get a diffent image

Global Const $hBitmap1 = _GDIPlus_BitmapCreateFromHBITMAP($hGDIBitmap1)
Global Const $hBitmap2 = _GDIPlus_BitmapCreateFromHBITMAP($hGDIBitmap2)

_WinAPI_DeleteObject($hGDIBitmap1)
_WinAPI_DeleteObject($hGDIBitmap2)

Local $fTimer = TimerInit()
Global $iResult = _ASM_BitCompareBitmapsMMX($hBitmap1, $hBitmap2)
ConsoleWrite("Runtime overall: " & TimerDiff($fTimer) & " ms." & @CRLF)
ConsoleWrite("Equal: " & $iResult & @CRLF)
ConsoleWrite("Image dimension: " & _GDIPlus_ImageGetWidth($hBitmap1)  & "x" & _GDIPlus_ImageGetHeight($hBitmap1) & " px" & @CRLF)

_GDIPlus_ImageDispose($hBitmap1)
_GDIPlus_ImageDispose($hBitmap2)
_GDIPlus_Shutdown()


Func _ASM_BitCompareBitmapsMMX($hBitmap1, $hBitmap2)
    Local $aDim1 = _GDIPlus_ImageGetDimension($hBitmap1), $aDim2 = _GDIPlus_ImageGetDimension($hBitmap2)
    If BitOR($aDim1[0] <> $aDim2[0], $aDim1[1] <> $aDim2[1]) Then Return False

    Local $tBitmapData1 = _GDIPlus_BitmapLockBits($hBitmap1, 0, 0, $aDim1[0], $aDim1[1], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    Local $pScan1 = $tBitmapData1.Scan0
    Local $iStride1 = $tBitmapData1.Stride * 4
    Local $tPixelData1 = DllStructCreate("dword[" & Abs($iStride1 * $aDim1[1]) & "]", $pScan1)

    Local $tBitmapData2 = _GDIPlus_BitmapLockBits($hBitmap2, 0, 0, $aDim2[0], $aDim2[1], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    Local $pScan2 = $tBitmapData2.Scan0
    Local $tPixelData2 = DllStructCreate("dword[" & Abs($iStride1 * $aDim1[1])  & "]", $pScan2)

    Local $tCodeBuffer = DllStructCreate("byte ASM[55]") ;reserve memory for ASM opcodes
    $tCodeBuffer.ASM = "0x8B7424048B7C24088B4C240CB801000000F30F6F0EF30F6F17660FEFCA660F3817C9750D83C61083C71083E90477E2EB05B800000000C3"
    Local $fTimer = TimerInit()
;~  Local $iRet = _AssembleIt("uint", "_BitCompareMMX", "ptr", DllStructGetPtr($tPixelData1), "ptr", DllStructGetPtr($tPixelData2), "int", $aDim1[0] * $aDim1[1])

    Local $aRet = DllCall("user32.dll", "uint", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer), _
                          "ptr", DllStructGetPtr($tPixelData1), _
                          "ptr", DllStructGetPtr($tPixelData2), _
                          "uint", $aDim1[0] * $aDim1[1], _
                          "int", Null)

    Local $fTimer_End = TimerDiff($fTimer)
    ConsoleWrite("Runtime ASM only: " & $fTimer_End & " ms" & @CRLF)

    _GDIPlus_BitmapUnlockBits($hBitmap1, $tBitmapData1)
    _GDIPlus_BitmapUnlockBits($hBitmap2, $tBitmapData2)

;~  Return $iRet
    Return $aRet[0]
EndFunc

Func _BitCompareMMX()
    _("use32") ;32Bit!
;~  _("org " & FasmGetBasePtr($Fasm))  ;needed for assembleit debugger
    _("mov esi, dword[esp+4]") ;points to beginning of the bitmap1 in the memory (scan0)
    _("mov edi, dword[esp+8]") ;points to beginning of the bitmap2 in the memory (scan0)
    _("mov ecx, dword[esp+12]") ;amount of pixels to read (width * height)
    _("mov eax, 1") ;eax it the return value -> 1 = equal, 0 = not equal
    _("_loop1:")
        _("movdqu   xmm1,   [esi]") ;copy 4 byte to xmm1 register (128 bit) from bitmap1
        _("movdqu   xmm2,   [edi]") ;copy 4 byte to xmm1 register (128 bit) from bitmap2
        _("pxor     xmm1,   xmm2")  ;xmm1 xor xmm2 ->  0xor0 and 1xor1 = 0, otherwise 1
        _("ptest    xmm1,   xmm1") ;PTEST set the ZF flag if all bits in the result are 0 of the bitwise AND of the first source operand (first operand) and the second source operand (second operand).
        _("jnz      _NotEqual") ;xmm1 <> xmm2 because zero flag not set
        _("add esi, 16") ;get next 4 pixels from bitmap1
        _("add edi, 16") ;get next 4 pixels from bitmap2
        _("sub ecx, 4")  ;decrease pixel count by 4 -> 4 pixel will be read at once
        _("ja _loop1")  ;exit loop when all pixels were read
    _("jmp  _End")

    _("_NotEqual:")
    _("mov eax, 0") ;set return value to 0

    _("_End:")
    _("ret") ;return eax
EndFunc

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Gets the average color of a bitmap.

 

_ASM_BitmapGetAverageColorValue.au3

#include <AssembleIt.au3>
#include <GDIPlus.au3>

Global Const $sFile = FileOpenDialog("Select an image", "", "Images (*.jpg;*.bmp;*.png;*.gif;*.tif)")
If @error Then Exit MsgBox(0, "Information", "Nothing selected")

_GDIPlus_Startup()
Global Const $hBitmap = _GDIPlus_BitmapCreateFromFile($sFile)

Local $fTimer = TimerInit()
Global $iResult = _ASM_BitmapGetAverageColorValue($hBitmap)
ConsoleWrite("Runtime overall: " & TimerDiff($fTimer) & " ms." & @CRLF)
MsgBox(0, "Test", "Average color value: 0x" & Hex($iResult, 8) & @CRLF)

_GDIPlus_ImageDispose($hBitmap)
_GDIPlus_Shutdown()


Func _ASM_BitmapGetAverageColorValue($hBitmap) ;coded by UEZ build 2016-02-08
    Local $aDim = _GDIPlus_ImageGetDimension($hBitmap)
    If @error Then Return SetError(0, 0, 0)
    Local Const $iPixels = $aDim[0] * $aDim[1]
    Local $tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $aDim[0], $aDim[1], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    Local $pScan = $tBitmapData.Scan0
    Local $iStride = $tBitmapData.Stride * 4
    Local $tPixelData = DllStructCreate("dword[" & Abs($iStride * $aDim[1]) & "]", $pScan)
    Local $tStruct_ARGB = DllStructCreate("uint Alpha;uint Red;uint Green;uint Blue")

    Local $tCodeBuffer = DllStructCreate("byte ASM[75]")
    $tCodeBuffer.ASM = "0x8B7424048B7C24088B4C240C8B0689C381E3FF000000015F0C89C381E300FF0000C1EB08015F0889C381E30000FF00C1EB10015F0489C381E3000000FFC1EB18011F83C60483E90177C2C3"
    Local $fTimer = TimerInit()
;~  Local $iRet = _AssembleIt("ptr", "_ASM_BitmapCountARGBColors", _
;~                          "ptr", DllStructGetPtr($tPixelData), _
;~                          "ptr", DllStructGetPtr($tStruct_ARGB), _
;~                          "uint", $iPixels)


    Local $aRet = DllCall("user32.dll", "none", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer), _
                          "ptr", DllStructGetPtr($tPixelData), _
                          "ptr", DllStructGetPtr($tStruct_ARGB), _
                          "uint", $iPixels, _
                          "int", Null)
    ConsoleWrite("Runtime ASM only: " & TimerDiff($fTimer) & " ms." & @CRLF)

    _GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData)
    Local $iResult = 0x1000000 * Int($tStruct_ARGB.Alpha / $iPixels) + 0x10000 * Int($tStruct_ARGB.Red / $iPixels) + 0x100 * Int($tStruct_ARGB.Green / $iPixels) + Int($tStruct_ARGB.Blue / $iPixels)
    Return $iResult
EndFunc

Func _ASM_BitmapCountARGBColors()
    _("use32") ;32Bit!
    _("mov esi, dword[esp+4]") ;points to beginning of the bitmap in the memory (scan0)
    _("mov edi, dword[esp+8]") ;points to the beginning of the struct in the memory
    _("mov ecx, dword[esp+12]") ;amount of pixels to read (width * height)
    _("_loop1:")
        _("mov dword eax, [esi]") ;copy the current AARRGGBB value to eax

        _("mov ebx, eax")   ;make a copy of eax for "faster" access
        _("and ebx, 0x000000FF") ;mask the blue channel
        _("add dword[edi + 12], ebx") ;add blue value which is saved in the struct -> each struct value is 4 bytes long and blue starts at memory + 12

        _("mov dword ebx, eax")
        _("and ebx, 0x0000FF00")    ;now the same with green channel
        _("shr ebx, 8")             ;shift the green value to the right -> 0000GG00 - > 000000GG
        _("add dword[edi + 8], ebx") ;add green value

        _("mov dword ebx, eax")
        _("and ebx, 0x00FF0000") ;and red channel
        _("shr ebx, 16")        ;-> 00RR0000 - > 000000RR
        _("add dword[edi + 4], ebx") ;add red value

        _("mov dword ebx, eax")
        _("and ebx, 0xFF000000")    ;and finally with alpha channel
        _("shr ebx, 24")            ;-> AA000000 - > 000000AA
        _("add dword[edi], ebx") ;add alpha value

        _("add esi, 4") ;get next color word from bitmap
        _("sub ecx, 1") ;decrease pixel count
        _("ja _loop1")  ;if pixel count = zero then exit loop
    _("ret") ;finished
EndFunc

 

_ASM64_BitmapGetAverageColorValue.au3

#AutoIt3Wrapper_UseX64=y
#include <GDIPlus.au3>
#include <Memory.au3>

Global $sFile = FileOpenDialog("Select a bitmap", "", "Image (*.jpg;*.png;*.bmp;*.gif;*.tif)")
If @error Then Exit

_GDIPlus_Startup()
Global Const $hBitmap = _GDIPlus_BitmapCreateFromFile($sFile)

Global $fTimer = TimerInit()
Global $iResult = ASM64_BitmapGetAverageColor($hBitmap)
ConsoleWrite("Runtime overall: " & TimerDiff($fTimer) & " ms" & @CRLF)
ConsoleWrite("Image dimension: " & _GDIPlus_ImageGetWidth($hBitmap) & "x" & _GDIPlus_ImageGetHeight($hBitmap) & " px" & @CRLF)

MsgBox(0, "Test", "Average color value: 0x" & Hex($iResult, 8) & @CRLF & @CRLF)

_GDIPlus_ImageDispose($hBitmap)
_GDIPlus_Shutdown()


Func ASM64_BitmapGetAverageColor($hBitmap)
    Local $aDim = _GDIPlus_ImageGetDimension($hBitmap)
    If @error Then Return SetError(0, 0, 0)
    Local Const $iPixels = $aDim[0] * $aDim[1]
    Local $tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $aDim[0], $aDim[1], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    Local $pScan = $tBitmapData.Scan0
    Local $iStride = $tBitmapData.Stride * 4
    Local $tPixelData = DllStructCreate("dword[" & Abs($iStride * $aDim[1]) & "]", $pScan)
    Local $tStruct_ARGB = DllStructCreate("uint64 Alpha;uint64 Red;uint64 Green;uint64 Blue")

    Local $tCodeBuffer = _DllStructCreate64("byte ASM[158]")
    $tCodeBuffer.ASM = "0x575653554889CE4889D74C89C3488B06504825FF000000480147185848C1E8204825FF00000048014718488B065048C1E8084825FF000000480147105848C1E8284825FF00000048014710488B065048C1E8104825FF000000480147085848C1E8304825FF00000048014708488B065048C1E8184825FF0000004801075848C1E8384825FF0000004801074883C6084883EB020F8774FFFFFF5D5B5E5FC3"

    Local $fTimer = TimerInit()
    DllCallAddress("uint:cdecl", DllStructGetPtr($tCodeBuffer), "ptr", DllStructGetPtr($tPixelData), "ptr", DllStructGetPtr($tStruct_ARGB), "int", $iPixels)
    Local $fTimer_End = TimerDiff($fTimer)
    ConsoleWrite("Runtime ASM only: " & $fTimer_End & " ms" & @CRLF)

    _GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData)
    Local $iResult = 0x1000000 * Int(Round($tStruct_ARGB.Alpha / $iPixels, 0)) + 0x10000 * Int(Round($tStruct_ARGB.Red / $iPixels, 0)) + 0x100 * Int(Round($tStruct_ARGB.Green / $iPixels, 0)) + Int(Round($tStruct_ARGB.Blue / $iPixels, 0))
    Return $iResult
EndFunc   ;==>ASM64_BitmapGetAverageColor

Func _DllStructCreate64($struct) ;align auf 16-byte adresse
    Local $temp = DllStructCreate($struct)
    Local $tempsize = DllStructGetSize($temp) + 64
    Local $ptr = DllStructGetPtr($struct)
    Local $a1 = Mod(Number($ptr), 64)
    Local $temp = 0
    Local $mem = _MemVirtualAlloc($ptr + $a1, $tempsize, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
    Local $a2 = Mod(Number($mem), 64) ;rest div 16 adresse = offset
    Local $sstruct = DllStructCreate($struct, (Number($mem) - $a2 + 64))
    Return $sstruct ;auf 16 alingned pointer
EndFunc   ;==>_DllStructCreate64_2

#cs _ASM64_BitmapCountARGBColors
    use64           ;64Bit! -> ;first 4 parameters will be saved in rcx,rdx,r8,r9

    push rdi
    push rsi
    push rbx
    push rbp

    mov rsi, rcx    ;pointer to first pixel in memory from the bmp
    mov rdi, rdx    ;pointer to memory from struct
    mov rbx, r8     ;amount of pixels

    loop1:

    mov rax, [rsi]          ;read 2 pixels to 64 bit register
    push rax                ;save 64 bit register
    and rax, 0xFF           ;mask blue color value from lower 32 bit register
    add [rdi + 24], rax     ;add blue color value to struct
    pop rax                 ;restore saved register to add blue from higher 32 bit register
    shr rax, 32             ;shift color value
    and rax, 0xFF           ;mask color value
    add [rdi + 24], rax     ;add blue color value to struct

    mov rax, [rsi]          ;read 2 pixels to 64 bit register
    push rax                ;save 64 bit register
    shr rax, 8              ;shift green color value
    and rax, 0xFF           ;mask green color value from lower 32 bit register
    add [rdi + 16], rax     ;add green color value to struct
    pop rax                 ;restore saved register to add green from higher 32 bit register
    shr rax, 40             ;shift color value
    and rax, 0xFF           ;mask color value
    add [rdi + 16], rax     ;add green color value to struct

    mov rax, [rsi]          ;read 2 pixels to 64 bit register
    push rax                ;save 64 bit register
    shr rax, 16             ;shift red color value
    and rax, 0xFF           ;mask red color value from lower 32 bit register
    add [rdi + 8], rax      ;add red color value to struct
    pop rax                 ;restore saved register to add red from higher 32 bit register
    shr rax, 48             ;shift color value
    and rax, 0xFF           ;mask color value
    add [rdi + 8], rax      ;add red color value to struct

    mov rax, [rsi]          ;read 2 pixels to 64 bit register
    push rax                ;save 64 bit register
    shr rax, 24             ;shift alpha color value
    and rax, 0xFF           ;mask alpha color value from lower 32 bit register
    add [rdi], rax          ;add alpha color value to struct
    pop rax                 ;restore saved register to add alpha from higher 32 bit register
    shr rax, 56             ;shift color value
    and rax, 0xFF           ;mask color value
    add [rdi], rax          ;add alpha color value to struct

    add rsi, 8  ;get next 2 pixels
    sub rbx, 2
    ja loop1

    pop rbp
    pop rbx
    pop rsi
    pop rdi

    ret
#ce

 

AndyG's x86 version using MMX/SSE from here

_ASM_BitmapGetAverageColorValue_MMX.au3

#include <assembleit2_64.au3>
#include <WinAPI.au3>

#AutoIt3Wrapper_UseX64=n


#cs _averagepixel                        ;Pixel ((A+B+C+D)/4)
    Use32                                ;32Bit!

    mov edi,dword[esp+4]                 ;pointer bitmap
    mov ecx,dword[esp+8]                 ;width bitmap
    mov ebx,dword[esp+12]                ;height bitmap


    mov eax,ebx                          ;h
    mul ecx                              ;w*h
    mov ecx,eax                          ;w*h=number of pixel
    movd xmm3,ecx                        ;0,0,0,w*h
    pshufd xmm3,xmm3,0                   ;w*h,w*h,w*h,w*h

    sub ecx,1                            ;from 0 to (w*h)-1
    shl ecx,2                            ;w*h*4 bytes

    mov edx,0
    movd xmm1,edx                        ;xmm1 ARGB every pixel
    movd xmm2,edx                        ;xmm2 sumn all A,R,G,B

    _asmdbg_()

    @pixel_count:                        ;all pixel

    movd xmm0,[edi+ecx]                  ;pixel ARGB into xmm
    PUNPCKLBW xmm0,xmm1                  ;000000000A0R0G0B
    PUNPCKLBW xmm0,xmm1                  ;000A000R000G000B
    PADDD xmm2,xmm0                      ;add all A,R,G,B

    sub ecx,4
    jnz @pixel_count                     ;loop all pixel

    _asmdbg_()

    movdqa xmm6,xmm2                     ;save xmm2

    PSRLDQ xmm2,8                        ;shift right 8 bytes = 0,0,A,R
    CVTDQ2PD xmm4,xmm2                   ;convert to double
    CVTDQ2PD xmm5,xmm3                   ;convert to double
    DIVPD xmm4,xmm5                      ;divide sum_all_pixel / number_all_pixel
    CVTPD2DQ xmm7,xmm4                   ;convert double to integer
    PSLLDQ xmm7,8                        ;shift left 8 bytes = 000A000R00000000

   _asmdbg_()

    MOVDQA xmm2,xmm6                     ;restore xmm2 A,R,G,B
    CVTDQ2PD xmm4,xmm2                   ;convert to double 0,0,G,B
    CVTDQ2PD xmm5,xmm3                   ;convert to double
    DIVPD xmm4,xmm5                      ;divide sum_all_pixel / number_all_pixel
    CVTPD2DQ xmm6,xmm4                   ;convert double to integer = 00000000000G000B
    ORPS xmm7,xmm6                       ;xmm7=000A000R000G000B =average color all pixel

    PACKUSWB xmm7,xmm7                   ;
    PACKUSWB xmm7,xmm7                   ;ARGBARGBARGBARGB
    movd eax,xmm7                        ;return average ARGB

    ret

#ce



Global $hDLL_User32 = DllOpen("user32.dll")
$DesktopWidth = DllCall($hDLL_User32, "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
$DesktopWidth = $DesktopWidth[0]
$DesktopHeight = DllCall($hDLL_User32, "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight
$DesktopHeight = $DesktopHeight[0]

Global $ptr_bitmap, $hbmp                ;byref _CreateNewBmp32($iwidth, $iheight, ByRef $ptr, ByRef $hbmp)

$hdc_bitmap = _CreateNewBmp32($DesktopWidth, $DesktopHeight, $ptr_bitmap, $hbmp) ;hdc empty bitmap
$hdc_desktop = _WinAPI_GetDC(0)          ;hdc desktop

_WinAPI_BitBlt($hdc_bitmap, 0, 0, $DesktopWidth, $DesktopHeight, $hdc_desktop, 0, 0, $SRCCOPY);bitblt desktop into bitmap

;#############################################################################################
;if you need the assembled code, uncomment the following lines and use DllCallAddress()
;~ $binarycode = _AssembleIt2("retbinary", "_averagepixel") ;gibt nur den assemblierten code zurück
;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $binarycode = ' & $binarycode & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $binarycode = ' & StringLen($binarycode) & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
;nur für dllcalladdress() benötigt, den binarycode braucht man nur ein mal erstellen
;~ $tCodeBuffer = _dllstructcreate64("byte[" & StringLen($binarycode) / 2 - 1 & "]") ;reserve Memory for opcodes
;~ DllStructSetData($tCodeBuffer, 1, $binarycode)
;~     $ret = DllCallAddress("uint:cdecl", DllStructGetPtr($tCodeBuffer), "ptr", $ptr_bitmap, "int_ptr", $DesktopWidth, "int_ptr", $DesktopHeight)
;~     ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ret = ' & $ret[0] & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
;~     $ret = $ret[0]
;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ret = ' & $ret & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
;#############################################################################################


$ret = _AssembleIt2("uint", "_averagepixel", "ptr", $ptr_bitmap, "int_ptr", $DesktopWidth, "int_ptr", $DesktopHeight)
$ret=hex($ret,8)
MsgBox(262144, 'Debug line ~' & @ScriptLineNumber, 'Selection:' & @CRLF & '$ret' & @CRLF & @CRLF & 'Return:' & @CRLF & $ret) ;### Debug MSGBOX


_DeleteBitmap32($hdc_bitmap, $ptr_bitmap, $hbmp) ;Ressourcen freigeben





Func _CreateNewBmp32($iwidth, $iheight, ByRef $ptr, ByRef $hbmp) ;erstellt leere 32-bit-Bitmap; Rückgabe $HDC und $ptr und handle auf die Bitmapdaten
    $hcdc = _WinAPI_CreateCompatibleDC(0) ;Desktop-Kompatiblen DeviceContext erstellen lassen
    $tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
    DllStructSetData($tBMI, 1, DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
    DllStructSetData($tBMI, 2, $iwidth)
    DllStructSetData($tBMI, 3, -$iheight) ;minus =standard = bottomup
    DllStructSetData($tBMI, 4, 1)
    DllStructSetData($tBMI, 5, 32)       ;32 Bit = 4 Bytes => AABBGGRR
    $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hbmp = $adib[0]                     ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
    $ptr = $adib[4]                      ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
    _WinAPI_SelectObject($hcdc, $hbmp)   ;objekt hbitmap in DC
    Return $hcdc                         ;DC der Bitmap zurückgeben
EndFunc                                  ;==>_CreateNewBmp32

Func _DeleteBitmap32($DC, $ptr, $hbmp)
    _WinAPI_DeleteDC($DC)
    _WinAPI_DeleteObject($hbmp)
    $ptr = 0
EndFunc                                  ;==>_DeleteBitmap

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Guest

Great job
Maybe you're the one who can make it work better.
If this method possible to done in Assembler then perhaps my bad solution that takes 30 seconds can take  much less time in Assembler

Share this post


Link to post
Share on other sites
6 minutes ago, wakillon said:

_ASM64_BitmapGetAverageColor.au3

Where did you get this name?

 

Further, I would say it is the same.


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

OMG !.. I can't believe this... Assembly code inside autoit ?. Is it really possible?

Oh, i have tried to learn HLA once and stopped because lack of time. That is all my assembly knowledge. Anyhow, i am interested in it. So, now i think i can use asm code in autoit. Want to learn more. 


My Contributions

UDF Link Viewer   --- A tool to visit the links of some most important UDFs 

 Includer_2  ----- A tool to type the #include statement automatically 

 Digits To Date  ----- date from 3 integer values

PrintList ----- prints arrays into console for testing.

 Alert  ------ An alternative for MsgBox 

 MousePosition ------- A simple tooltip display of mouse position

GRM Helper -------- A littile tool to help writing code with GUIRegisterMsg function

Access_UDF  -------- An UDF for working with access database files. (.*accdb only)

 

Share this post


Link to post
Share on other sites

@UEZ do you have an example how to Reverse Byte Order ? I'm not talking about reversing bits in byte, but reversing entire buferes ?

 


Signature beginning:   Wondering who uses AutoIT and what it can be used for ?
* GHAPI UDF - modest beginning - communication with GitHub REST API Forum Rules *
ADO.au3 UDF     POP3.au3 UDF     XML.au3 UDF    How to use IE.au3  UDF with  AutoIt v3.3.14.x  for other useful stuff click the following button

Spoiler

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. 

My contribution (my own projects): * Debenu Quick PDF Library - UDF * Debenu PDF Viewer SDK - UDF * Acrobat Reader - ActiveX Viewer * UDF for PDFCreator v1.x.x * XZip - UDF * AppCompatFlags UDF * CrowdinAPI UDF * _WinMergeCompare2Files() * _JavaExceptionAdd() * _IsBeta() * Writing DPI Awareness App - workaround * _AutoIt_RequiredVersion() * Chilkatsoft.au3 UDF * TeamViewer.au3 UDF * JavaManagement UDF * VIES over SOAP * WinSCP UDF * GHAPI UDF - modest begining - comunication with GitHub REST APIErrorLog.au3 UDF - A logging Library *

My contribution to others projects or UDF based on  others projects: * _sql.au3 UDF  * POP3.au3 UDF *  RTF Printer - UDF * XML.au3 UDF * ADO.au3 UDF SMTP Mailer UDF * Dual Monitor resolution detection * * 2GUI on Dual Monitor System * _SciLexer.au3 UDF * SciTE - Lexer for console pane

Useful links: * Forum Rules * Forum etiquette *  Forum Information and FAQs * How to post code on the forum * AutoIt Online Documentation * AutoIt Online Beta Documentation * SciTE4AutoIt3 getting started * Convert text blocks to AutoIt code * Games made in Autoit * Programming related sites * Polish AutoIt Tutorial * DllCall Code Generator * 

Wiki: Expand your knowledge - AutoIt Wiki * Collection of User Defined Functions * How to use HelpFile * Good coding practices in AutoIt * 

IE Related:  * How to use IE.au3  UDF with  AutoIt v3.3.14.x * Why isn't Autoit able to click a Javascript Dialog? * Clicking javascript button with no ID * IE document >> save as MHT file * IETab Switcher (by LarsJ ) * HTML Entities * _IEquerySelectorAll() (by uncommon) * IE in TaskScheduler

I encourage you to read: * Global Vars * Best Coding Practices * Please explain code used in Help file for several File functions * OOP-like approach in AutoIt * UDF-Spec Questions *  EXAMPLE: How To Catch ConsoleWrite() output to a file or to CMD *

"Homo sum; humani nil a me alienum puto" - Publius Terentius Afer
"Program are meant to be read by humans and only incidentally for computers and execute" - Donald Knuth, "The Art of Computer Programming"
:naughty:  :ranting:, be  :) and       \\//_.

Anticipating Errors :  "Any program that accepts data from a user must include code to validate that data before sending it to the data store. You cannot rely on the data store, ...., or even your programming language to notify you of problems. You must check every byte entered by your users, making sure that data is the correct type for its field and that required fields are not empty."

Signature last update: 2019-10-01

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Beege
      Here is the latest assembly engine from Tomasz Grysztar, flat assembler g as a dll which I compiled using original fasm engine. He doesn't have it compiled in the download package but it was as easy as compiling a exe in autoit if you ever have to do it yourself. Just open up the file in the fasm editor and press F5. 
      You can read about what makes fasmg different from the original fasm HERE if you want . The minimum you should understand is that this engine is bare bones by itself not capable of very much. The macro engine is the major difference and it uses macros for basically everything now including implementing the x86 instructions and formats. All of these macros are located within the include folder and you should keep that in its original form.  
      When I first got the dll compiled I couldn't get it to generate code in flat binary format. It was working but size of output was over 300 bytes no matter what the assembly code and could just tell it was outputting a different format than binary. Eventually I figured out that within the primary "include\win32ax.inc"', it executes a macro "format PE GUI 4.0" if x86 has not been defined. I underlined macro there because at first I (wasted shit loads of time because I) didn't realize it was a macro (adding a bunch of other includes) since in version 1 the statement "format binary" was a default if not specified and specifically means add nothing extra to the code. So long story short, the part that I was missing is including the cpu type and extensions from include\cpu folder. By default I add x64 type and SSE4 ext includes. Note that the x64 here is not about what mode we are running in, this is for what instructions your cpu supports. if you are running on some really old hardware that may need to be adjusted or if your on to more advanced instructions like the avx extensions, you may have to add those includes to your source. 
      Differences from previous dll function
      I like the error reporting much better in this one. With the last one we had a ton error codes and a variable return structure depending on what kind of error it had. I even had an example showing you what kind of an error would give you correct line numbers vs wouldn't. With this one the stdout is passed to the dll function and it simply prints the line/details it had a problem with to the console. The return value is the number of errors counted.
      It also handles its own memory needs automatically now . If the output region is not big enough it will virtualalloc a new one and virtualfree the previous.  
      Differences in Code
      Earlier this year I showed some examples of how to use the macros to make writing assembly a little more familiar. Almost all the same functionality exists here but there are a couple syntax sugar items gone and slight change in other areas. 
      Whats gone is FIX and PTR. Both syntax sugar that dont really matter. 
      A couple changes to structures as well but these are for the better. One is unnamed elements are allowed now, but if it does not have a name, you are not allowed to initialize those elements during creation because they can only be intialized via syntax name:value . Previously when you initialized the elements, you would do by specifying values in a comma seperated list using the specific order like value1,value2,etc, but this had a problem because it expected commas even when the elements were just padding for alignment so this works out better having to specify the name and no need for _FasmFixInit function. "<" and ">" are not longer used in the initializes ether.
      OLD: $sTag = 'byte x;short y;char sNote[13];long odd[5];word w;dword p;char ext[3];word finish' _(_FasmAu3StructDef('AU3TEST', $sTag));convert and add definition to source _(' tTest AU3TEST ' & _FasmFixInit('1,222,<"AutoItFASM",0>,<41,43,43,44,45>,6,7,"au3",12345', $sTag));create and initalize New: $sTag = 'byte x;short y;char sNote[13];long odd[5];word w;dword p;char ext[3];word finish' _(_fasmg_Au3StructDef('AU3TEST', $sTag)) ;convert and add definition to source _(' tTest AU3TEST x:11,y:22,sNote:"AutoItFASM",odd:41,odd+4:42,odd+8:43,w:6,p:7,ext:"au3",finish:12345');create and initalize Extra Includes
      I created a includeEx folder for the extra macros I wrote/found on the forums. Most of them are written by Thomaz so they may eventually end up in the standard library. 
      Edit: Theres only the one include folder now. All the default includes are in thier own folder within that folder and all the custom ones are top level.  
       Align.inc, Nop.inc, Listing.inc
      The Align and Nop macros work together to align the next statement to whatever boundary you specified and it uses multibyte nop codes to fill in the space. Filling the space with nop is the default but you can also specify a fill value if you want. Align.assume is another macro part of align.inc that can be used to set tell the engine that a certain starting point is assumed to be at a certain boundary alignment and it will do its align calculations based on that value. 
      Listing is a macro great for seeing where and what opcodes are getting generated from each line of assembly code.  Below is an example of the source and output you would see printed to the console during the assembly. I picked this slightly longer example because it best shows use of align, nop, and then the use of listing to verify the align/nop code. Nop codes are instructions that do nothing and one use of them is to insert nop's as space fillers when you want a certian portion of your code to land on a specific boundary offset. I dont know all the best practices here with that (if you do please post!) but its a type of optimization for the cpu.  Because of its nature of doing nothing, I cant just run the code and confirm its correct because it didnt crash. I need to look at what opcodes the actual align statements made and listing made that easy. 
      source example:
      _('procf _main stdcall, pAdd') _(' mov eax, [pAdd]') _(' mov dword[eax], _crc32') _(' mov dword[eax+4], _strlen') _(' mov dword[eax+8], _strcmp') _(' mov dword[eax+12], _strstr') _(' ret') _('endp') _('EQUAL_ORDERED = 1100b') _('EQUAL_ANY = 0000b') _('EQUAL_EACH = 1000b') _('RANGES = 0100b') _('NEGATIVE_POLARITY = 010000b') _('BYTE_MASK = 1000000b') _('align 8') _('proc _crc32 uses ebx ecx esi, pStr') _(' mov esi, [pStr]') _(' xor ebx, ebx') _(' not ebx') _(' stdcall _strlen, esi') _(' .while eax >= 4') _(' crc32 ebx, dword[esi]') _(' add esi, 4') _(' sub eax, 4') _(' .endw') _(' .while eax') _(' crc32 ebx, byte[esi]') _(' inc esi') _(' dec eax') _(' .endw') _(' not ebx') _(' mov eax, ebx') _(' ret') _('endp') _('align 8, 0xCC') ; fill with 0xCC instead of NOP _('proc _strlen uses ecx edx, pStr') _(' mov ecx, [pStr]') _(' mov edx, ecx') _(' mov eax, -16') _(' pxor xmm0, xmm0') _(' .repeat') _(' add eax, 16') _(' pcmpistri xmm0, dqword[edx + eax], 1000b') ;EQUAL_EACH') _(' .until ZERO?') ; repeat loop until Zero flag (ZF) is set _(' add eax, ecx') ; add remainder _(' ret') _('endp') _('align 8') _('proc _strcmp uses ebx ecx edx, pStr1, pStr2') ; ecx = string1, edx = string2' _(' mov ecx, [pStr1]') ; ecx = start address of str1 _(' mov edx, [pStr2]') ; edx = start address of str2 _(' mov eax, ecx') ; eax = start address of str1 _(' sub eax, edx') ; eax = ecx - edx | eax = start address of str1 - start address of str2 _(' sub edx, 16') _(' mov ebx, -16') _(' STRCMP_LOOP:') _(' add ebx, 16') _(' add edx, 16') _(' movdqu xmm0, dqword[edx]') _(' pcmpistri xmm0, dqword[edx + eax], EQUAL_EACH + NEGATIVE_POLARITY') ; EQUAL_EACH + NEGATIVE_POLARITY ; find the first *different* bytes, hence negative polarity' _(' ja STRCMP_LOOP') ;a CF or ZF = 0 above _(' jc STRCMP_DIFF') ;c cf=1 carry _(' xor eax, eax') ; the strings are equal _(' ret') _(' STRCMP_DIFF:') _(' mov eax, ebx') _(' add eax, ecx') _(' ret') _('endp') _('align 8') _('proc _strstr uses ecx edx edi esi, sStrToSearch, sStrToFind') _(' mov ecx, [sStrToSearch]') _(' mov edx, [sStrToFind]') _(' pxor xmm2, xmm2') _(' movdqu xmm2, dqword[edx]') ; load the first 16 bytes of neddle') _(' pxor xmm3, xmm3') _(' lea eax, [ecx - 16]') _(' STRSTR_MAIN_LOOP:') ; find the first possible match of 16-byte fragment in haystack') _(' add eax, 16') _(' pcmpistri xmm2, dqword[eax], EQUAL_ORDERED') _(' ja STRSTR_MAIN_LOOP') _(' jnc STRSTR_NOT_FOUND') _(' add eax, ecx ') ; save the possible match start') _(' mov edi, edx') _(' mov esi, eax') _(' sub edi, esi') _(' sub esi, 16') _(' @@:') ; compare the strings _(' add esi, 16') _(' movdqu xmm1, dqword[esi + edi]') _(' pcmpistrm xmm3, xmm1, EQUAL_EACH + NEGATIVE_POLARITY + BYTE_MASK') ; mask out invalid bytes in the haystack _(' movdqu xmm4, dqword[esi]') _(' pand xmm4, xmm0') _(' pcmpistri xmm1, xmm4, EQUAL_EACH + NEGATIVE_POLARITY') _(' ja @b') _(' jnc STRSTR_FOUND') _(' sub eax, 15') ;continue searching from the next byte _(' jmp STRSTR_MAIN_LOOP') _(' STRSTR_NOT_FOUND:') _(' xor eax, eax') _(' ret') _(' STRSTR_FOUND:') _(' sub eax, [sStrToSearch]') _(' inc eax') _(' ret') _('endp') Listing Output:
      00000000: use32 00000000: 55 89 E5 procf _main stdcall, pAdd 00000003: 8B 45 08 mov eax, [pAdd] 00000006: C7 00 28 00 00 00 mov dword[eax], _crc32 0000000C: C7 40 04 68 00 00 00 mov dword[eax+4], _strlen 00000013: C7 40 08 90 00 00 00 mov dword[eax+8], _strcmp 0000001A: C7 40 0C D8 00 00 00 mov dword[eax+12], _strstr 00000021: C9 C2 04 00 ret 00000025: localbytes = current 00000025: purge ret?,locals?,endl?,proclocal? 00000025: end namespace 00000025: purge endp? 00000025: EQUAL_ORDERED = 1100b 00000025: EQUAL_ANY = 0000b 00000025: EQUAL_EACH = 1000b 00000025: RANGES = 0100b 00000025: NEGATIVE_POLARITY = 010000b 00000025: BYTE_MASK = 1000000b 00000025: 0F 1F 00 align 8 00000028: 55 89 E5 53 51 56 proc _crc32 uses ebx ecx esi, pStr 0000002E: 8B 75 08 mov esi, [pStr] 00000031: 31 DB xor ebx, ebx 00000033: F7 D3 not ebx 00000035: 56 E8 2D 00 00 00 stdcall _strlen, esi 0000003B: 83 F8 04 72 0D .while eax >= 4 00000040: F2 0F 38 F1 1E crc32 ebx, dword[esi] 00000045: 83 C6 04 add esi, 4 00000048: 83 E8 04 sub eax, 4 0000004B: EB EE .endw 0000004D: 85 C0 74 09 .while eax 00000051: F2 0F 38 F0 1E crc32 ebx, byte[esi] 00000056: 46 inc esi 00000057: 48 dec eax 00000058: EB F3 .endw 0000005A: F7 D3 not ebx 0000005C: 89 D8 mov eax, ebx 0000005E: 5E 59 5B C9 C2 04 00 ret 00000065: localbytes = current 00000065: purge ret?,locals?,endl?,proclocal? 00000065: end namespace 00000065: purge endp? 00000065: CC CC CC align 8, 0xCC 00000068: 55 89 E5 51 52 proc _strlen uses ecx edx, pStr 0000006D: 8B 4D 08 mov ecx, [pStr] 00000070: 89 CA mov edx, ecx 00000072: B8 F0 FF FF FF mov eax, -16 00000077: 66 0F EF C0 pxor xmm0, xmm0 0000007B: .repeat 0000007B: 83 C0 10 add eax, 16 0000007E: 66 0F 3A 63 04 02 08 pcmpistri xmm0, dqword[edx + eax], 1000b 00000085: 75 F4 .until ZERO? 00000087: 01 C8 add eax, ecx 00000089: 5A 59 C9 C2 04 00 ret 0000008F: localbytes = current 0000008F: purge ret?,locals?,endl?,proclocal? 0000008F: end namespace 0000008F: purge endp? 0000008F: 90 align 8 00000090: 55 89 E5 53 51 52 proc _strcmp uses ebx ecx edx, pStr1, pStr2 00000096: 8B 4D 08 mov ecx, [pStr1] 00000099: 8B 55 0C mov edx, [pStr2] 0000009C: 89 C8 mov eax, ecx 0000009E: 29 D0 sub eax, edx 000000A0: 83 EA 10 sub edx, 16 000000A3: BB F0 FF FF FF mov ebx, -16 000000A8: STRCMP_LOOP: 000000A8: 83 C3 10 add ebx, 16 000000AB: 83 C2 10 add edx, 16 000000AE: F3 0F 6F 02 movdqu xmm0, dqword[edx] 000000B2: 66 0F 3A 63 04 02 18 pcmpistri xmm0, dqword[edx + eax], EQUAL_EACH + NEGATIVE_POLARITY 000000B9: 77 ED ja STRCMP_LOOP 000000BB: 72 09 jc STRCMP_DIFF 000000BD: 31 C0 xor eax, eax 000000BF: 5A 59 5B C9 C2 08 00 ret 000000C6: STRCMP_DIFF: 000000C6: 89 D8 mov eax, ebx 000000C8: 01 C8 add eax, ecx 000000CA: 5A 59 5B C9 C2 08 00 ret 000000D1: localbytes = current 000000D1: purge ret?,locals?,endl?,proclocal? 000000D1: end namespace 000000D1: purge endp? 000000D1: 0F 1F 80 00 00 00 00 align 8 000000D8: 55 89 E5 51 52 57 56 proc _strstr uses ecx edx edi esi, sStrToSearch, sStrToFind 000000DF: 8B 4D 08 mov ecx, [sStrToSearch] 000000E2: 8B 55 0C mov edx, [sStrToFind] 000000E5: 66 0F EF D2 pxor xmm2, xmm2 000000E9: F3 0F 6F 12 movdqu xmm2, dqword[edx] 000000ED: 66 0F EF DB pxor xmm3, xmm3 000000F1: 8D 41 F0 lea eax, [ecx - 16] 000000F4: STRSTR_MAIN_LOOP: 000000F4: 83 C0 10 add eax, 16 000000F7: 66 0F 3A 63 10 0C pcmpistri xmm2, dqword[eax], EQUAL_ORDERED 000000FD: 77 F5 ja STRSTR_MAIN_LOOP 000000FF: 73 30 jnc STRSTR_NOT_FOUND 00000101: 01 C8 add eax, ecx 00000103: 89 D7 mov edi, edx 00000105: 89 C6 mov esi, eax 00000107: 29 F7 sub edi, esi 00000109: 83 EE 10 sub esi, 16 0000010C: @@: 0000010C: 83 C6 10 add esi, 16 0000010F: F3 0F 6F 0C 3E movdqu xmm1, dqword[esi + edi] 00000114: 66 0F 3A 62 D9 58 pcmpistrm xmm3, xmm1, EQUAL_EACH + NEGATIVE_POLARITY + BYTE_MASK 0000011A: F3 0F 6F 26 movdqu xmm4, dqword[esi] 0000011E: 66 0F DB E0 pand xmm4, xmm0 00000122: 66 0F 3A 63 CC 18 pcmpistri xmm1, xmm4, EQUAL_EACH + NEGATIVE_POLARITY 00000128: 77 E2 ja @b 0000012A: 73 0F jnc STRSTR_FOUND 0000012C: 83 E8 0F sub eax, 15 0000012F: EB C3 jmp STRSTR_MAIN_LOOP 00000131: STRSTR_NOT_FOUND: 00000131: 31 C0 xor eax, eax 00000133: 5E 5F 5A 59 C9 C2 08 00 ret 0000013B: STRSTR_FOUND: 0000013B: 2B 45 08 sub eax, [sStrToSearch] 0000013E: 40 inc eax 0000013F: 5E 5F 5A 59 C9 C2 08 00 ret 00000147: localbytes = current 00000147: purge ret?,locals?,endl?,proclocal? 00000147: end namespace 00000147: purge endp?  
      procf and forcea macros
      In my previous post I spoke about the force macro and why the need for it. I added two more macros (procf and forcea) that combine the two and also sets align.assume to the same function. As clarified in the previous post, you should only have to use these macros for the first procedure being defined (since nothing calls that procedure). And since its the first function, it should be the starting memory address which is a good place to initially set the align.assume address to. 
      Attached package should include everything needed and has all the previous examples I posted updated. Let me know if I missed something or you have any issues running the examples and thanks for looking
       
      Update 04/19/2020:
      A couple new macros added. I also got rid of the IncludeEx folder and just made one include folder that has the default include folder within it and all others top level.
      dllstruct macro does the same thing as _fasmg_Au3StructDef(). You can use either one; they both use the macro.
      getmempos macro does the delta trick I showed below using anonymous labels. 
      stdcallw and invokew macros will push any parameters that are raw (quoted) strings as wide characters
      Ifex include file gives .if .ifelse .while .until  the ability to use stdcall/invoke/etc inline. So if you had a function called "_add" you could do .if stdcall(_add,5,5) = 10. All this basically does in the background is perform the stdcall and then replaces the comparison with eax and passes it on to the original default macros, but is super helpful for cleaning up code and took a ton of time learning the macro language to get in place. 
       
      Update 05/19/2020:
      Added fastcallw that does same as stdcallw only
      Added fastcall support for Ifex
      Corrected missing include file include\macro\if.inc within win64au3.inc 
      fasmg 5-19-2020.zip
       
      Previous versions:
       
    • By UEZ
      Here a little script to load a TGA image file and create a GDI+ bitmap. Currently supported TGA formats are  1/8/15/16/24 and 32-bit.
      As v0.85 is written completely in AutoIt, it might take some time to convert larger 8/15/16/24/32-bit images. ☕
       
      _GDIPlus_TGAImageLoadFromFile.au3 UDF
      v0.85 without assembler acceleration code but with RLE support:
      ;Coded by UEZ #AutoIt3Wrapper_UseX64=n #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WinAPIFiles.au3> ; #FUNCTION# ==================================================================================================================== ; Name ..........: _GDIPlus_TGAImageLoadFromFile ; Description ...: Loads a TGA compressed (RLE) / uncompressed image file (1/8/15/16/24/32-bit) and converts it to a GDI+ bitmap format. ; Syntax ........: _GDIPlus_TGAImageLoadFromFile($sFile[, $bPrintInfo = False.]) ; Parameters ....: $sFile - TGA file name to load from disk. ; $bPrintInfo - [optional] Prints some information about the TGA image to console. Default is False. ; Return values .: Success: GDI+ bitmap handle ; Failure: error 1 - file cannot be opened ; error 2 - TGA image is not in one of these formats: 1/8/15/16/24/32-bit ; error 3 - unsupported TGA image type ; error 4 - unable to read file to struct ; error 5 - unknown TGA pixel depth ; error 6 - return bitmap cannot be created ; Version .......: v0.85 build 2019-11-08 beta ; Author ........: UEZ ; Remarks .......: 8/15/16/24/32-bit images might be slow on converting ^^ ; Related .......: _GDIPlus_BitmapCreateFromScan0, _GDIPlus_ImageRotateFlip, DllStructCreate, _WinAPI_CreateFile, _WinAPI_SetFilePointer ; Link ..........: https://www.loc.gov/preservation/digital/formats/fdd/fdd000180.shtml, http://www.fileformat.info/format/tga/egff.htm ; Example .......: Yes ; =============================================================================================================================== Func _GDIPlus_TGAImageLoadFromFile($sFile, $bPrintInfo = False) Local Const $hFile = _WinAPI_CreateFile($sFile, 2, 2) If Not $hFile Then Return SetError(1, 0, 0) Local Const $tagTGAHeader = "align 1;byte idLength;byte colormapType;byte imageType;word firstEntryIndex;word colormapLength;byte colormapEntrySize;word xOrigin;word yOrigin;word width;word height;byte pixelDepth;byte imageDescriptor" Local Const $tagTGAFooter = "dword extAreaOffset;dword devDirOffset;byte imageID[18]" Local Const $tagTGAExtention = "align 1;word extSize;byte authorName[41];byte authorComments[324];word timeM;word timeD;word timeY;word timeHr;word timeMin;word timeSec;byte jobName[41];word jobTimeHr;word jobTimeMin;word jobTimeSec;byte swID[41];word swVersionNr;byte swVersionLetter;long keyColor;word pxAspectRatioNum;word pxAspectRatioDom;word gammaNum;word gammaDom;dword colCorrOffset;dword postStampOffset;dword scanLineOffset;byte attribType" Local Const $tTGAHeader = DllStructCreate($tagTGAHeader) Local $tTGAFooter = DllStructCreate($tagTGAFooter) Local Const $tTGAExtention = DllStructCreate($tagTGAExtention) Local $dwBytesRead, $tTGAImageID, $tagTGAImageID, $iColorValuesStartPos = 0 _WinAPI_ReadFile($hFile, $tTGAHeader, DllStructGetSize($tTGAHeader), $dwBytesRead) $iColorValuesStartPos += $dwBytesRead If $tTGAHeader.idLength > 0 Then $tagTGAImageID = "byte imageID[" & $tTGAHeader.idLength & "]" $tTGAImageID = DllStructCreate($tagTGAImageID) _WinAPI_ReadFile($hFile, $tTGAImageID, $tTGAHeader.idLength, $dwBytesRead) $iColorValuesStartPos += $dwBytesRead EndIf Local Const $iPxDepth = $tTGAHeader.pixelDepth If Not BitOR($iPxDepth = 32, $iPxDepth = 24, $iPxDepth = 16, $iPxDepth = 15, $iPxDepth = 8, $iPxDepth = 1) Then _WinAPI_CloseHandle($hFile) Return SetError(2, 0, 0) EndIf #cs ImageType Image Data Type Colormap Encoding 0 No image data included in file No No 1 Colormapped image data Yes No 2 Truecolor image data No No 3 Monochrome image data No No 9 Colormapped image data Yes Yes 10 Truecolor image data No Yes 11 Monochrome image data No Yes #ce If Not BitOR($tTGAHeader.imageType = 0x01, $tTGAHeader.imageType = 0x02, $tTGAHeader.imageType = 0x03, $tTGAHeader.imageType = 0x09, $tTGAHeader.imageType = 0x0A, $tTGAHeader.imageType = 0x0B) Then _WinAPI_CloseHandle($hFile) Return SetError(3, 0, 0) EndIf Local $iW = $tTGAHeader.width, $iH = $tTGAHeader.height, $colorwidth = $tTGAHeader.colormapEntrySize / 8, _ $colorTblSize = $tTGAHeader.colormapLength * $colorwidth Local $dwBufferSize = FileGetSize($sFile) Local $tSrcBmp = DllStructCreate("ubyte color[" & $dwBufferSize & "]") _WinAPI_ReadFile($hFile, $tSrcBmp, $dwBufferSize, $dwBytesRead) _WinAPI_SetFilePointer($hFile, -26, $FILE_END) _WinAPI_ReadFile($hFile, $tTGAFooter, 26, $dwBytesRead) Local $sFooter = StringTrimRight(BinaryToString($tTGAFooter.imageID), 1), $iOffset = 0, $iOffset2, $iOffset3 If Not StringCompare($sFooter, "TRUEVISION-XFILE.") Then ;read extension information to struct if available $iOffset = $tTGAFooter.extAreaOffset _WinAPI_SetFilePointer($hFile, $iOffset, $FILE_BEGIN) _WinAPI_ReadFile($hFile, $tTGAExtention, 0x01EF, $dwBytesRead) Else $tTGAFooter.extAreaOffset = 0 EndIf _WinAPI_CloseHandle($hFile) If $dwBytesRead = 0 Then Return SetError(4, _WinAPI_GetLastError(), 0) Local $bRLE = BitOR($tTGAHeader.imageType = 0x09, $tTGAHeader.imageType = 0x0A, $tTGAHeader.imageType = 0x0B) If $bPrintInfo Then ConsoleWrite("idLength: " & $tTGAHeader.idLength & @CRLF) ConsoleWrite("colormapType: " & $tTGAHeader.colormapType & @CRLF) ConsoleWrite("imageType: " & $tTGAHeader.imageType & @CRLF) ConsoleWrite("firstEntryIndex: " & $tTGAHeader.firstEntryIndex & @CRLF) ConsoleWrite("colormapLength: " & $tTGAHeader.colormapLength & @CRLF) ConsoleWrite("colormapEntrySize: " & $tTGAHeader.colormapEntrySize & @CRLF) ConsoleWrite("xOrigin: " & $tTGAHeader.xOrigin & @CRLF) ConsoleWrite("yOrigin: " & $tTGAHeader.yOrigin & @CRLF) ConsoleWrite("width: " & $tTGAHeader.width & @CRLF) ConsoleWrite("height: " & $tTGAHeader.height & @CRLF) ConsoleWrite("pixelDepth: " & $iPxDepth & @CRLF) ConsoleWrite("imageDescriptor: " & $tTGAHeader.imageDescriptor & @CRLF) If $tTGAHeader.idLength > 0 Then ConsoleWrite("ImageID: " & RemoveNullChars($tTGAImageID.imageID) & @CRLF) If $iOffset Then ConsoleWrite("authorName: " & RemoveNullChars($tTGAExtention.authorName) & @CRLF) ConsoleWrite("authorComments: " & RemoveNullChars($tTGAExtention.authorComments) & @CRLF) ConsoleWrite("jobName: " & RemoveNullChars($tTGAExtention.jobName) & @CRLF) ConsoleWrite("swID: " & RemoveNullChars($tTGAExtention.swID) & @CRLF) EndIf ConsoleWrite("RLE packed: " & $bRLE & @CRLF) EndIf Local Static $tDestBmp ;must be static otherwise bitmap data might get corrupted or in worst case script will crash Local $stride, $iPixelFormat Switch $iPxDepth Case 1 ;1-bit $iPixelFormat = $GDIP_PXF01INDEXED $stride = BitAND(($iW * 1) + 1, BitNOT(1)) $tDestBmp = DllStructCreate("uint color[" & $stride * $iH & "];") Case 8, 24 $iPixelFormat = $GDIP_PXF24RGB $stride = BitAND(($iW * 3) + 3, BitNOT(3)) $tDestBmp = DllStructCreate("ubyte color[" & $stride * $iH & "];") Case 15, 16 $iPixelFormat = $GDIP_PXF16RGB555 $stride = BitAND(($iW * 2) + 2, BitNOT(2)) $tDestBmp = DllStructCreate("ubyte color[" & $stride * $iH & "];") Case 32 $iPixelFormat = $GDIP_PXF32ARGB $stride = $iW * 4 $tDestBmp = DllStructCreate("ubyte color[" & $stride * $iH & "];") Case Else Return SetError(5, 0, 0) EndSwitch If Mod($stride, 4) <> 0 Then $stride += 4 - Mod($stride, 4) Local Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH, $iPixelFormat, $stride, $tDestBmp) If @error Or Not $hBitmap Then Return SetError(6, @error, 0) Local $c, $q, $x, $y, $t1, $t2, $t3, $t4, $col, $red, $green, $blue, $alpha, $iLen, $iStart, $iEnd, $iLength, $iWW Local Const $hDLL = DllOpen("msvcrt.dll") Switch $iPxDepth Case 1 ;1-bit For $y = 0 To $iH - 1 $t1 = $y * $stride DllCall($hDLL, "ptr:cdecl", "memcpy", "ptr", DllStructGetPtr($tDestBmp) + $t1, "ptr", DllStructGetPtr($tSrcBmp) + BitShift($t1, 3), "uint", $stride) Next Case 8 ;8-bit ;if a color table is available, just use it If $tTGAHeader.colormapType = 1 Then Local $tMapColorTbl = DllStructCreate("ubyte bgr[" & $colorTblSize & "]", DllStructGetPtr($tSrcBmp, "color") + $tTGAHeader.firstEntryIndex) Switch $bRLE Case 0 For $y = 0 To ($iH - 1) $iOffset = $y * $iW + $colorTblSize $iOffset2 = $y * $stride For $x = 0 To ($iW - 1) $t1 = $iOffset2 + $x * 3 $t2 = $tSrcBmp.color($iOffset + $x + 1) * $colorwidth Switch $colorwidth Case 3, 4 $tDestBmp.color($t1 + 1) = $tMapColorTbl.bgr($t2 + 1) $tDestBmp.color($t1 + 2) = $tMapColorTbl.bgr($t2 + 2) $tDestBmp.color($t1 + 3) = $tMapColorTbl.bgr($t2 + 3) Case 2 ;convert from RGB555 to RGB $col = BitOR(BitShift($tMapColorTbl.bgr($t2 + 2), -8), $tMapColorTbl.bgr($t2 + 1)) ;RGB555 $tDestBmp.color($t1 + 1) = BitShift(BitAND($col, 0x001F), -3) ;B $tDestBmp.color($t1 + 2) = BitShift(BitShift(BitAND($col, 0x03E0), 5), -3) ;G $tDestBmp.color($t1 + 3) = BitShift(BitShift(BitAND($col, 0x7C00), 10), -3) ;R EndSwitch Next Next Case Else ;RLE encoded TGA images $c = 0 $x = 0 $y = 0 $iOffset = $colorTblSize + 1 $iStart = Int($iColorValuesStartPos + $colorTblSize) $iEnd = $tTGAFooter.extAreaOffset > 0 ? $tTGAFooter.extAreaOffset : $dwBufferSize $iLength = $iEnd - $iStart - 1 $iWW = $iW - 1 $t3 = $colorwidth = 2 ? 2 : 3 While $c <= $iLength $iOffset2 = Int($tSrcBmp.color($iOffset + $c)) $iLen = BitAND($iOffset2, 0x7F) + 1 If BitAND($iOffset2, 0x80) Then ; check for packet format ;run length packet format $c += 1 $iOffset3 = Int($tSrcBmp.color($iOffset + $c)) * $t3 $t2 = $y * $stride For $q = 1 To $iLen $t1 = $t2 + $x * 3 Switch $colorwidth Case 3, 4 $tDestBmp.color($t1 + 1) = $tMapColorTbl.bgr($iOffset3 + 1) $tDestBmp.color($t1 + 2) = $tMapColorTbl.bgr($iOffset3 + 2) $tDestBmp.color($t1 + 3) = $tMapColorTbl.bgr($iOffset3 + 3) Case 2 ;convert from RGB555 to RGB $col = BitOR(BitShift($tMapColorTbl.bgr($iOffset3 + 2), -8), $tMapColorTbl.bgr($iOffset3 + 1)) ;RGB555 $tDestBmp.color($t1 + 1) = BitShift(BitAND($col, 0x001F), -3) ;B $tDestBmp.color($t1 + 2) = BitShift(BitShift(BitAND($col, 0x03E0), 5), -3) ;G $tDestBmp.color($t1 + 3) = BitShift(BitShift(BitAND($col, 0x7C00), 10), -3) ;R EndSwitch $x += 1 If $x > $iWW Then $x = 0 $y += 1 $t2 = $y * $stride EndIf Next $c += 1 Else ;raw packet format $c += 1 $t2 = $y * $stride For $q = 1 To $iLen $iOffset3 = Int($tSrcBmp.color($iOffset + $c)) * $t3 $t1 = $t2 + $x * 3 Switch $colorwidth Case 3, 4 $tDestBmp.color($t1 + 1) = $tMapColorTbl.bgr($iOffset3 + 1) $tDestBmp.color($t1 + 2) = $tMapColorTbl.bgr($iOffset3 + 2) $tDestBmp.color($t1 + 3) = $tMapColorTbl.bgr($iOffset3 + 3) Case 2 ;convert from RGB555 to RGB $col = BitOR(BitShift($tMapColorTbl.bgr($iOffset3 + 2), -8), $tMapColorTbl.bgr($iOffset3 + 1)) ;RGB555 $tDestBmp.color($t1 + 1) = BitShift(BitAND($col, 0x001F), -3) ;B $tDestBmp.color($t1 + 2) = BitShift(BitShift(BitAND($col, 0x03E0), 5), -3) ;G $tDestBmp.color($t1 + 3) = BitShift(BitShift(BitAND($col, 0x7C00), 10), -3) ;R EndSwitch $x += 1 If $x > $iWW Then $x = 0 $y += 1 $t2 = $y * $stride EndIf $c += 1 Next EndIf WEnd EndSwitch Else ;convert it to grayscale Switch $bRLE Case 0 For $y = 0 To $iH - 1 $iOffset = $y * $iW + $colorTblSize $iOffset2 = $y * $stride For $x = 0 To $iW - 1 $t1 = $iOffset + $x - 2 $t2 = $iOffset2 + $x * 3 $blue = $tSrcBmp.color($t1 + 1) $green = $tSrcBmp.color($t1 + 2) $red = $tSrcBmp.color($t1 + 3) $col = $red $col = $col < 0 ? 0 : $col > 255 ? 255 : $col $tDestBmp.color($t2 + 1) = $col $tDestBmp.color($t2 + 2) = $col $tDestBmp.color($t2 + 3) = $col Next Next Case Else $c = 0 $x = 0 $y = 0 $iOffset = $colorTblSize + 1 $iStart = Int($iColorValuesStartPos + $colorTblSize) $iEnd = $tTGAFooter.extAreaOffset > 0 ? $tTGAFooter.extAreaOffset : $dwBufferSize $iLength = $iEnd - $iStart - 1 $iWW = $iW - 1 While $c <= $iLength $iOffset2 = Int($tSrcBmp.color($iOffset + $c)) $iLen = BitAND($iOffset2, 0x7F) + 1 If BitAND($iOffset2, 0x80) Then ; check for packet format ;run length packet format $c += 1 $iOffset3 = Int($tSrcBmp.color($iOffset + $c)) * 3 $blue = $iOffset3 $green = $iOffset3 + 1 $red = $iOffset3 + 2 $col = ($red + $green + $blue) / 9 $col = $col < 0 ? 0 : $col > 255 ? 255 : $col $t2 = $y * $stride For $q = 1 To $iLen $t1 = $t2 + $x * 3 $tDestBmp.color($t1 + 1) = $col $tDestBmp.color($t1 + 2) = $col $tDestBmp.color($t1 + 3) = $col $x += 1 If $x > $iWW Then $x = 0 $y += 1 $t2 = $y * $stride EndIf Next $c += 1 Else ;raw packet format $c += 1 $t2 = $y * $stride For $q = 1 To $iLen $iOffset3 = Int($tSrcBmp.color($iOffset + $c)) * 3 $blue = $iOffset3 $green = $iOffset3 + 1 $red = $iOffset3 + 2 $col = ($red + $green + $blue) / 9 $col = $col < 0 ? 0 : $col > 255 ? 255 : $col $t1 = $t2 + $x * 3 $tDestBmp.color($t1 + 1) = $col $tDestBmp.color($t1 + 2) = $col $tDestBmp.color($t1 + 3) = $col $x += 1 If $x > $iWW Then $x = 0 $y += 1 $t2 = $y * $stride EndIf $c += 1 Next EndIf WEnd EndSwitch EndIf Case 15, 16, 24, 32 ;15/16/24/32-bit, as the bitmap format is the same we can use memcpy to copy the pixel data directly to the memory. ;Exeptions are 15/16/24-bit images whose width is not a divider of 4! If BitOR($iPxDepth = 15, $iPxDepth = 16, $iPxDepth = 24) Then If BitOR(Mod($iW, 4), $bRLE) Then Switch $iPxDepth Case 15, 16 Switch $bRLE Case 0 $t4 = $iW * 2 For $y = 0 To ($iH - 1) $iOffset = $y * $t4 $iOffset2 = $y * $stride For $x = 0 To ($iW - 1) $t3 = $x * 2 $t1 = $iOffset + $t3 $t2 = $iOffset2 + $t3 ;RGB555 $tDestBmp.color($t2 + 1) = $tSrcBmp.color($t1 + $colorTblSize + 1) $tDestBmp.color($t2 + 2) = $tSrcBmp.color($t1 + $colorTblSize + 2) Next Next Case Else $c = 0 $x = 0 $y = 0 $iStart = Int($iColorValuesStartPos + $colorTblSize) $iEnd = $tTGAFooter.extAreaOffset > 0 ? $tTGAFooter.extAreaOffset : $dwBufferSize $iLength = $iEnd - $iStart - 1 $iWW = $iW - 1 While $c <= $iLength $iOffset2 = Int($tSrcBmp.color($colorTblSize + $c + 1)) $iLen = BitAND($iOffset2, 0x7F) + 1 If BitAND($iOffset2, 0x80) Then ; check for packet format ;run length packet format $c += 1 $t3 = $y * $stride For $q = 1 To $iLen $t1 = $t3 + $x * 2 $t2 = $colorTblSize + $c $tDestBmp.color($t1 + 1) = $tSrcBmp.color($t2 + 1) $tDestBmp.color($t1 + 2) = $tSrcBmp.color($t2 + 2) $x += 1 If $x > $iWW Then $x = 0 $y += 1 $t3 = $y * $stride EndIf Next $c += 2 Else ;raw packet format $c += 1 $t3 = $y * $stride For $q = 1 To $iLen $t1 = $t3 + $x * 2 $t2 = $colorTblSize + $c $tDestBmp.color($t1 + 1) = $tSrcBmp.color($t2 + 1) $tDestBmp.color($t1 + 2) = $tSrcBmp.color($t2 + 2) $x += 1 If $x > $iWW Then $x = 0 $y += 1 $t3 = $y * $stride EndIf $c += 2 Next EndIf WEnd EndSwitch Case 24 Switch $bRLE Case 0 $t4 = $iW * 3 For $y = 0 To $iH - 1 $iOffset = $y * $t4 $iOffset2 = $y * $stride For $x = 0 To ($iW - 1) $t3 = $x * 3 $t1 = $iOffset + $t3 $blue = $tSrcBmp.color($t1 + 1) $green = $tSrcBmp.color($t1 + 2) $red = $tSrcBmp.color($t1 + 3) $t2 = $iOffset2 + $t3 $tDestBmp.color($t2 + 1) = $blue $tDestBmp.color($t2 + 2) = $green $tDestBmp.color($t2 + 3) = $red Next Next Case Else $c = 0 $x = 0 $y = 0 $iStart = Int($iColorValuesStartPos + $colorTblSize) $iEnd = $tTGAFooter.extAreaOffset > 0 ? $tTGAFooter.extAreaOffset : $dwBufferSize $iLength = $iEnd - $iStart - 1 $iWW = $iW - 1 While $c <= $iLength $iOffset2 = Int($tSrcBmp.color($c + 1)) $iLen = BitAND($iOffset2, 0x7F) + 1 If BitAND($iOffset2, 0x80) Then ; check for packet format ;run length packet format $c += 1 $blue = $tSrcBmp.color($c + 1) $green = $tSrcBmp.color($c + 2) $red = $tSrcBmp.color($c + 3) $t2 = $y * $stride For $q = 1 To $iLen $t1 = $t2 + $x * 3 $tDestBmp.color($t1 + 1) = $blue $tDestBmp.color($t1 + 2) = $green $tDestBmp.color($t1 + 3) = $red $x += 1 If $x > $iWW Then $x = 0 $y += 1 $t2 = $y * $stride EndIf Next $c += 3 Else ;raw packet format $c += 1 $t2 = $y * $stride For $q = 1 To $iLen $blue = $tSrcBmp.color($c + 1) $green = $tSrcBmp.color($c + 2) $red = $tSrcBmp.color($c + 3) $t1 = $t2 + $x * 3 $tDestBmp.color($t1 + 1) = $blue $tDestBmp.color($t1 + 2) = $green $tDestBmp.color($t1 + 3) = $red $x += 1 If $x > $iWW Then $x = 0 $y += 1 $t2 = $y * $stride EndIf $c += 3 Next EndIf WEnd EndSwitch EndSwitch Else For $y = 0 To $iH - 1 $t1 = $y * $stride DllCall($hDLL, "ptr:cdecl", "memcpy", "ptr", DllStructGetPtr($tDestBmp) + $t1, "ptr", DllStructGetPtr($tSrcBmp) + $t1, "uint", $stride) Next EndIf Else Switch $bRLE Case 0 For $y = 0 To $iH - 1 $t1 = $y * $stride DllCall($hDLL, "ptr:cdecl", "memcpy", "ptr", DllStructGetPtr($tDestBmp) + $t1, "ptr", DllStructGetPtr($tSrcBmp) + $t1, "uint", $stride) Next Case Else $c = 0 $x = 0 $y = 0 $iStart = Int($iColorValuesStartPos + $colorTblSize) $iEnd = $tTGAFooter.extAreaOffset > 0 ? $tTGAFooter.extAreaOffset : $dwBufferSize $iLength = $iEnd - $iStart - 1 $iWW = $iW - 1 While $c <= $iLength $iOffset2 = Int($tSrcBmp.color($c + 1)) $iLen = BitAND($iOffset2, 0x7F) + 1 If BitAND($iOffset2, 0x80) Then ; check for packet format ;run length packet format $c += 1 $blue = $tSrcBmp.color($c + 1) $green = $tSrcBmp.color($c + 2) $red = $tSrcBmp.color($c + 3) $alpha = $tSrcBmp.color($c + 4) $t2 = $y * $stride For $q = 1 To $iLen $t1 = $t2 + $x * 4 $tDestBmp.color($t1 + 1) = $blue $tDestBmp.color($t1 + 2) = $green $tDestBmp.color($t1 + 3) = $red $tDestBmp.color($t1 + 4) = $alpha $x += 1 If $x > $iWW Then $x = 0 $y += 1 $t2 = $y * $stride EndIf Next $c += 4 Else ;raw packet format $c += 1 $t2 = $y * $stride For $q = 1 To $iLen $blue = $tSrcBmp.color($c + 1) $green = $tSrcBmp.color($c + 2) $red = $tSrcBmp.color($c + 3) $alpha = $tSrcBmp.color($c + 4) $t1 = $t2 + $x * 4 $tDestBmp.color($t1 + 1) = $blue $tDestBmp.color($t1 + 2) = $green $tDestBmp.color($t1 + 3) = $red $tDestBmp.color($t1 + 4) = $alpha $x += 1 If $x > $iWW Then $x = 0 $y += 1 $t2 = $y * $stride EndIf $c += 4 Next EndIf WEnd EndSwitch EndIf EndSwitch DllClose($hDLL) ;TGA image is stored bottom up in file. Need to flip it. If BitAND($tTGAHeader.imageDescriptor, 0x30) <> 0x20 Then _GDIPlus_ImageRotateFlip($hBitmap, $GDIP_Rotate180FlipX) $tSrcBmp = 0 Return $hBitmap EndFunc ;==>_GDIPlus_TGAImageLoadFromFile ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: RemoveNullChars ; Description ...: Converts a null terminated binary string to a string ; Author ........: UEZ ; =============================================================================================================================== Func RemoveNullChars($bin) Local $a = StringRegExp($bin, "[[:xdigit:]+]{2}", 3), $s, $i If @error Then Return $s For $i = 0 To UBound($a) - 1 If $a[$i] = "00" Then ExitLoop $s &= Chr(Dec($a[$i])) Next Return $s EndFunc ;==>RemoveNullChars ;------------- Example ------------- Global $sFile = FileOpenDialog("Select a TGA file", "", "TGA image(*.tga)") If @error Then Exit _GDIPlus_Startup() Global $endtime, $timer = TimerInit() Global $hImage = _GDIPlus_TGAImageLoadFromFile($sFile, True) If @error Then ConsoleWrite(@error & " / " & @extended & @CRLF) _GDIPlus_Shutdown() Exit EndIf $endtime = TimerDiff($timer) ;~ _GDIPlus_ImageSaveToFile($hImage, @ScriptDir & "\Converted.png") ;~ ShellExecute(@ScriptDir & "\Converted.png") Global $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage) Global $hGui = GUICreate("TGA Image Loader by UEZ", $iW, $iH) GUISetState() Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGui) _GDIPlus_GraphicsDrawImageRect($hGraphics, $hImage, 0, 0, $iW, $iH) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE _GDIPlus_BitmapDispose($hImage) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_Shutdown() Exit Case $GUI_EVENT_RESTORE _GDIPlus_GraphicsDrawImageRect($hGraphics, $hImage, 0, 0, $iW, $iH) EndSwitch WEnd  
      v0.80 with assembler acceleration (thanks to AndyG for Assembleit2) but without RLE support yet:
      ;Coded by UEZ #AutoIt3Wrapper_Compile_Both=y #AutoIt3Wrapper_UseX64=n #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <Memory.au3> #include <WinAPIFiles.au3> ; #FUNCTION# ==================================================================================================================== ; Name ..........: _GDIPlus_TGAImageLoadFromFile ; Description ...: Loads an uncompressed TGA image file (1/8/15/16/24/32-bit) and converts it to a GDI+ bitmap format. ; Syntax ........: _GDIPlus_TGAImageLoadFromFile($sFile[, $bPrintInfo = False.]) ; Parameters ....: $sFile - TGA file name to load from disk. ; $bPrintInfo - [optional] Prints some information about the TGA image to console. Default is False. ; Return values .: Success: GDI+ bitmap handle ; Failure: error 1 - file cannot be opened ; error 2 - TGA image is not in one of these formats: 1/8/15/16/24/32-bit ; error 3 - unsupported TGA image type ; error 4 - unable to read file to struct ; error 5 - unknown TGA pixel depth ; error 6 - return bitmap cannot be created ; Version .......: v0.80 build 2019-10-23 beta ; Author ........: UEZ - thanks to AndyG for Assembleit2 ; Remarks .......: No RLE compressed TGA image support yet! ; Related .......: _GDIPlus_BitmapCreateFromScan0, _GDIPlus_ImageRotateFlip, DllStructCreate, _WinAPI_CreateFile, _WinAPI_SetFilePointer ; Link ..........: https://www.loc.gov/preservation/digital/formats/fdd/fdd000180.shtml, http://www.fileformat.info/format/tga/egff.htm ; Example .......: Yes ; =============================================================================================================================== Func _GDIPlus_TGAImageLoadFromFile($sFile, $bPrintInfo = False) Local Const $hFile = _WinAPI_CreateFile($sFile, 2, 2) If Not $hFile Then Return SetError(1, 0, 0) Local Const $tagTGAHeader = "align 1;byte idLength;byte colormapType;byte imageType;word firstEntryIndex;word colormapLength;byte colormapEntrySize;word xOrigin;word yOrigin;word width;word height;byte pixelDepth;byte imageDescriptor" Local Const $tagTGAFooter = "dword extAreaOffset;dword devDirOffset;byte imageID[18]" Local Const $tagTGAExtention = "align 1;word extSize;byte authorName[41];byte authorComments[324];word timeM;word timeD;word timeY;word timeHr;word timeMin;word timeSec;byte jobName[41];word jobTimeHr;word jobTimeMin;word jobTimeSec;byte swID[41];word swVersionNr;byte swVersionLetter;long keyColor;word pxAspectRatioNum;word pxAspectRatioDom;word gammaNum;word gammaDom;dword colCorrOffset;dword postStampOffset;dword scanLineOffset;byte attribType" Local Const $tTGAHeader = DllStructCreate($tagTGAHeader) Local Const $tTGAFooter = DllStructCreate($tagTGAFooter) Local Const $tTGAExtention = DllStructCreate($tagTGAExtention) Local $dwBytesRead, $tTGAImageID, $tagTGAImageID _WinAPI_ReadFile($hFile, $tTGAHeader, DllStructGetSize($tTGAHeader), $dwBytesRead) If $tTGAHeader.idLength > 0 Then $tagTGAImageID = "byte imageID[" & $tTGAHeader.idLength & "]" $tTGAImageID = DllStructCreate($tagTGAImageID) _WinAPI_ReadFile($hFile, $tTGAImageID, $tTGAHeader.idLength, $dwBytesRead) EndIf Local Const $iPxDepth = $tTGAHeader.pixelDepth If Not BitOR($iPxDepth = 32, $iPxDepth = 24, $iPxDepth = 16, $iPxDepth = 15, $iPxDepth = 8, $iPxDepth = 1) Then _WinAPI_CloseHandle($hFile) Return SetError(2, 0, 0) EndIf #cs ImageType Image Data Type Colormap Encoding 0 No image data included in file No No 1 Colormapped image data Yes No 2 Truecolor image data No No 3 Monochrome image data No No 9 Colormapped image data Yes Yes 10 Truecolor image data No Yes 11 Monochrome image data No Yes #ce If Not BitOR($tTGAHeader.imageType = 0x01, $tTGAHeader.imageType = 0x02, $tTGAHeader.imageType = 0x03) Then _WinAPI_CloseHandle($hFile) Return SetError(3, 0, 0) EndIf Local $iW = $tTGAHeader.width, $iH = $tTGAHeader.height, $bytesPerPixel = $iPxDepth / 8, $colorwidth = $tTGAHeader.colormapEntrySize / 8, _ $colorTblSize = $tTGAHeader.colormapLength * $colorwidth If $tTGAHeader.colormapEntrySize < 24 Then $bytesPerPixel = 4 Local Const $dwBufferSize = FileGetSize($sFile) Local $tSrcBmp = DllStructCreate("ubyte color[" & $dwBufferSize + $colorTblSize & "]") _WinAPI_ReadFile($hFile, $tSrcBmp, $dwBufferSize + $colorTblSize, $dwBytesRead) _WinAPI_SetFilePointer($hFile, -26, $FILE_END) _WinAPI_ReadFile($hFile, $tTGAFooter, 26, $dwBytesRead) Local $sFooter = StringTrimRight(BinaryToString($tTGAFooter.imageID), 1), $iOffset = 0, $iOffset2 If Not StringCompare($sFooter, "TRUEVISION-XFILE.") Then ;read extension information to struct if available $iOffset = $tTGAFooter.extAreaOffset _WinAPI_SetFilePointer($hFile, $iOffset, $FILE_BEGIN) _WinAPI_ReadFile($hFile, $tTGAExtention, 0x01EF, $dwBytesRead) EndIf _WinAPI_CloseHandle($hFile) If $dwBytesRead = 0 Then Return SetError(4, _WinAPI_GetLastError(), 0) If $bPrintInfo Then ConsoleWrite("idLength: " & $tTGAHeader.idLength & @CRLF) ConsoleWrite("colormapType: " & $tTGAHeader.colormapType & @CRLF) ConsoleWrite("imageType: " & $tTGAHeader.imageType & @CRLF) ConsoleWrite("firstEntryIndex: " & $tTGAHeader.firstEntryIndex & @CRLF) ConsoleWrite("colormapLength: " & $tTGAHeader.colormapLength & @CRLF) ConsoleWrite("colormapEntrySize: " & $tTGAHeader.colormapEntrySize & @CRLF) ConsoleWrite("xOrigin: " & $tTGAHeader.xOrigin & @CRLF) ConsoleWrite("yOrigin: " & $tTGAHeader.yOrigin & @CRLF) ConsoleWrite("width: " & $tTGAHeader.width & @CRLF) ConsoleWrite("height: " & $tTGAHeader.height & @CRLF) ConsoleWrite("pixelDepth: " & $iPxDepth & @CRLF) ConsoleWrite("imageDescriptor: " & $tTGAHeader.imageDescriptor & @CRLF) If $tTGAHeader.idLength > 0 Then ConsoleWrite("ImageID: " & RemoveNullChars($tTGAImageID.imageID) & @CRLF) If $iOffset Then ConsoleWrite("authorName: " & RemoveNullChars($tTGAExtention.authorName) & @CRLF) ConsoleWrite("authorComments: " & RemoveNullChars($tTGAExtention.authorComments) & @CRLF) ConsoleWrite("jobName: " & RemoveNullChars($tTGAExtention.jobName) & @CRLF) ConsoleWrite("swID: " & RemoveNullChars($tTGAExtention.swID) & @CRLF) EndIf EndIf Local Static $tDestBmp ;must be static otherwise bitmap data might get corrupted or in worst case script will crash Local $stride, $iPixelFormat Switch $iPxDepth Case 1 ;1-bit $iPixelFormat = $GDIP_PXF01INDEXED $stride = BitAND(($iW * 1) + 1, BitNOT(1)) $tDestBmp = DllStructCreate("uint color[" & $stride * $iH + 1 & "];") Case 8, 24 $iPixelFormat = $GDIP_PXF24RGB $stride = BitAND(($iW * 3) + 3, BitNOT(3)) $tDestBmp = DllStructCreate("uint color[" & $stride * $iH + 1 & "];") Case 15, 16 $iPixelFormat = $GDIP_PXF16RGB555 $stride = BitAND(($iW * 2) + 2, BitNOT(2)) $tDestBmp = DllStructCreate("uint color[" & $stride * $iH + 1 & "];") Case 32 $iPixelFormat = $GDIP_PXF32ARGB $stride = $iW * 4 $tDestBmp = DllStructCreate("uint color[" & $stride * $iH + 1 & "];") Case Else Return SetError(5, 0, 0) EndSwitch If Mod($stride, 4) <> 0 Then $stride += 4 - Mod($stride, 4) Local Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH, $iPixelFormat, $stride, $tDestBmp) If @error Or Not $hBitmap Then Return SetError(6, @error, 0) Local $fTimer = TimerInit() Local $x, $x1, $y, $t1 Local Const $hDLL = DllOpen("msvcrt.dll") Local Const $tagParam = "ptr tSrcBmp;ptr tDestBmp;dword strideSrc;dword strideDest;dword w;dword h;dword colorTblSize;dword t1;dword t2" Local $tParam If @AutoItX64 Then $tParam = _DLLStructCreate64($tagParam) Else $tParam = DLLStructCreate($tagParam) EndIf $tParam.tSrcBmp = DllStructGetPtr($tSrcBmp) $tParam.tDestBmp = DllStructGetPtr($tDestBmp) $tParam.strideDest = $stride $tParam.w = ($iW - 1) $tParam.h = ($iH - 1) $tParam.colorTblSize = $colorTblSize Switch $iPxDepth Case 1 ;1-bit For $y = 0 To $iH - 1 $t1 = $y * $stride DllCall($hDLL, "ptr:cdecl", "memcpy", "ptr", DllStructGetPtr($tDestBmp) + $t1, "ptr", DllStructGetPtr($tSrcBmp) + BitShift($t1, 3), "uint", $stride) Next Case 8 ;8-bit ConsoleWrite("Using Assembler code to speed-up..." & @CRLF) ;if a color table is available, just use it If $tTGAHeader.colormapType = 1 Then Local $tMapColorTbl = DllStructCreate("ubyte bgr[" & $colorTblSize & "]", DllStructGetPtr($tSrcBmp, "color") + $tTGAHeader.firstEntryIndex) Local $tParam2, $tagParam2 = "align 1;ptr tSrcBmp;ptr tDestBmp;ptr colormap;dword strideSrc;dword strideDest;dword w;dword h;dword colorTblSize;dword colorwidth;dword t1;dword t2;byte r5;byte g5;byte b5;" If @AutoItX64 Then $tParam2 = _DLLStructCreate64($tagParam2) Else $tParam2 = DllStructCreate($tagParam2) EndIf $tParam2.tSrcBmp = DllStructGetPtr($tSrcBmp) $tParam2.tDestBmp = DllStructGetPtr($tDestBmp) $tParam2.colormap = DllStructGetPtr($tMapColorTbl) $tParam2.strideSrc = $iW $tParam2.strideDest = $stride $tParam2.colorwidth = $colorwidth $tParam2.w = ($iW - 1) $tParam2.h = ($iH - 1) $tParam2.colorTblSize = $colorTblSize Switch @AutoItX64 Case False Local Const $bBinASM8cm_x86 = Binary("0x608B7C242431C990909090909090909089C8F7670C03471C89472489C8F7671089472831DB8B472401D8030789C231C08A02F767208B570801C28B32B803000000F7E303472803470489C5837F200275476689F26683E21F66C1E20388572E6689F26681E2E00366C1EA0566C1E20388572D6689F26681E2007C66C1EA0A66C1E20388572C31C00A472CC1E0080A472DC1E0080A472E89C6897500433B5F147684413B4F180F8665FFFFFF61C20400") Local $tBinASM8cm_x86 = DllStructCreate("ubyte asm[" & BinaryLen($bBinASM8cm_x86) & "]") $tBinASM8cm_x86.asm = $bBinASM8cm_x86 DllCallAddress("none", DllStructGetPtr($tBinASM8cm_x86), "ptr", DllStructGetPtr($tParam2)) Case Else Local Const $bBinASM8cm_x64 = Binary("0x575653554989CF41BE000000009090904489F041F7671841034728418947304489F041F7671C418947344531ED418B47304401E84903074889C24831C08A0241F7672C498B57104801C2448B0A4831C048C7C00300000041F7E541034734490347084989C041837F2C02755A4831D2664489CA6683E21F66C1E2034188573A4831D2664489CA6681E2E00366C1EA0566C1E203418857394831D2664489CA6681E2007C66C1EA0A66C1E2034188573831C0410A4738C1E008410A4739C1E008410A473A4189C145890841FFC5453B6F200F8657FFFFFF41FFC6453B77240F862DFFFFFF5D5B5E5FC20800") Local $tBinASM8cm_x64 = _DLLStructCreate64("ubyte asm[" & BinaryLen($bBinASM8cm_x64) & "]") $tBinASM8cm_x64.asm = $bBinASM8cm_x64 DllCallAddress("none", DllStructGetPtr($tBinASM8cm_x64), "ptr", DllStructGetPtr($tParam2)) EndSwitch Else ;convert it 1:1 directly Switch @AutoItX64 Case False $tParam.strideSrc = $iW $tParam.colorTblSize -= 2 Local Const $bBinASM8_x86 = Binary("0x8B7C2404BB00000000B900000000909089C8F7670889471C89C8F7670C8947208B471C01D8034718030789C252B803000000F7E30347200347045A8B328930433B5F1076DB31DB413B4F1476C3C20400") Local $tBinASM8_x86 = DllStructCreate("ubyte asm[" & BinaryLen($bBinASM8_x86) & "]") $tBinASM8_x86.asm = $bBinASM8_x86 DllCallAddress("none", DllStructGetPtr($tBinASM8_x86), "ptr", DllStructGetPtr($tParam)) Case Else $tParam.strideSrc = $iW Local Const $bBinASM8_x64 = Binary("0x575653554989CF49836F2002BB00000000B9000000009090909090909090909089C841F767104989C289C841F767144989C34D89D04901D84D0347204D030748C7C00300000048F7E34C01D8490347084D8B08448908FFC3413B5F1876D44831DBFFC1413B4F1C76B75D5B5E5FC20800") Local $tBinASM8_x64 = _DLLStructCreate64("ubyte asm[" & BinaryLen($bBinASM8_x64) & "]") $tBinASM8_x64.asm = $bBinASM8_x64 DllCallAddress("none", DllStructGetPtr($tBinASM8_x64), "ptr", DllStructGetPtr($tParam)) EndSwitch EndIf Case 15, 16, 24, 32 ;15/16/24/32-bit, as the bitmap format is the same we can use memcpy to copy the pixel data directly to the memory. ;Exeptions are 15/16/24-bit images whose width is not a divider of 4! If BitOR($iPxDepth = 15, $iPxDepth = 16, $iPxDepth = 24) And Mod($iW, 4) Then ConsoleWrite("Using Assembler code to speed-up..." & @CRLF) Switch $iPxDepth Case 15, 16 $tParam.strideSrc = $iW * 2 Switch @AutoItX64 Case False Local Const $bBinASM1516_x86 = Binary("0x8B7C2404BB00000000B900000000909089C8F7670889471C89C8F7670C894720B802000000F7E35003471C034718030789C2580347200347048B32668930433B5F1076DC31DB413B4F1476C4C20400") Local $tBinASM1516_x86 = DllStructCreate("ubyte asm[" & BinaryLen($bBinASM1516_x86) & "]") $tBinASM1516_x86.asm = $bBinASM1516_x86 DllCallAddress("none", DllStructGetPtr($tBinASM1516_x86), "ptr", DllStructGetPtr($tParam)) Case Else Local Const $bBinASM1516_x64 = Binary("0x575653554989CFBB00000000B90000000090909090909090909090909090909089C841F767104989C189C841F767144989C25389D8D1E04C89D24801C2490357084D89C84901C04D0347204D0307498B00488902FFC3FFC3413B5F1876D55BFFC1413B4F1C76B95D5B5E5FC20800") Local $tBinASM1516_x64 = _DLLStructCreate64("ubyte asm[" & BinaryLen($bBinASM1516_x64) & "]") $tBinASM1516_x64.asm = $bBinASM1516_x64 DllCallAddress("none", DllStructGetPtr($tBinASM1516_x64), "ptr", DllStructGetPtr($tParam)) EndSwitch Case 24 $tParam.strideSrc = $iW * 3 Switch @AutoItX64 Case False Local Const $bBinASM24_x86 = Binary("0x8B7C2404BB00000000B900000000909089C8F7670889471C89C8F7670C894720B803000000F7E35003471C034718030789C2580347200347048B328930433B5F1076DD31DB413B4F1476C5C20400") Local $tBinASM24_x86 = DllStructCreate("ubyte asm[" & BinaryLen($bBinASM24_x86) & "]") $tBinASM24_x86.asm = $bBinASM24_x86 DllCallAddress("none", DllStructGetPtr($tBinASM24_x86), "ptr", DllStructGetPtr($tParam)) Case Else Local Const $bBinASM24_x64 = Binary("0x575653554989CF4831C990909090909089C841F767104989C189C841F767144989C24831DB48C7C00300000048F7E34C89D24801C2490357084D89C84901C04D0347204D0307498B00488902FFC3FFC3413B5F1876CFFFC1413B4F1C76B25D5B5E5FC20800") Local $tBinASM24_x64 = _DLLStructCreate64("ubyte asm[" & BinaryLen($bBinASM24_x64) & "]") $tBinASM24_x64.asm = $bBinASM24_x64 DllCallAddress("none", DllStructGetPtr($tBinASM24_x64), "ptr", DllStructGetPtr($tParam)) EndSwitch EndSwitch Else For $y = 0 To $iH - 1 $t1 = $y * $stride DllCall($hDLL, "ptr:cdecl", "memcpy", "ptr", DllStructGetPtr($tDestBmp) + $t1, "ptr", DllStructGetPtr($tSrcBmp) + $t1, "uint", $stride) Next EndIf EndSwitch ConsoleWrite(TimerDiff($fTimer) & " ms" & @CRLF) DllClose($hDLL) ;TGA image is stored bottom up in file. Need to flip it. If BitAND($tTGAHeader.imageDescriptor, 0x30) <> 0x20 Then _GDIPlus_ImageRotateFlip($hBitmap, $GDIP_Rotate180FlipX) $tSrcBmp = 0 Return $hBitmap EndFunc ;==>_GDIPlus_TGAImageLoadFromFile ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: RemoveNullChars ; Description ...: Converts a null terminated binary string to a string ; Author ........: UEZ ; =============================================================================================================================== Func RemoveNullChars($bin) Local $a = StringRegExp($bin, "[[:xdigit:]+]{2}", 3), $s, $i If @error Then Return $s For $i = 0 To UBound($a) - 1 If $a[$i] = "00" Then ExitLoop $s &= Chr(Dec($a[$i])) Next Return $s EndFunc ;==>RemoveNullChars ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: _DLLStructCreate64 ; Description ...: Creates a struct for x64 assembler code execution ; Author ........: AndyG ; =============================================================================================================================== Func _DLLStructCreate64($struct) ;align auf 16-byte Adresse Local $temp = DllStructCreate($struct) Local $tempsize = DllStructGetSize($temp) + 64 Local $ptr = DllStructGetPtr($struct) Local $a1 = Mod(Number($ptr), 64) Local $temp = 0 Local $mem = _MemVirtualAlloc($ptr + $a1, $tempsize, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE) Local $mem_dllstructcreate64_internal = $mem Local $a2 = Mod(Number($mem), 64) ;rest div 16 adresse = offset Local $sstruct = DllStructCreate($struct, (Number($mem) - $a2 + 64)) Return $sstruct ;auf 16 alingned pointer EndFunc ;==>_DLLStructCreate64 Global $sFile = FileOpenDialog("Select a TGA file", "", "TGA image(*.tga)") If @error Then Exit _GDIPlus_Startup() Global $hImage = _GDIPlus_TGAImageLoadFromFile($sFile, True) If @error Then ConsoleWrite(@error & " / " & @extended & @CRLF) _GDIPlus_Shutdown() Exit EndIf ;save result ;~ _GDIPlus_ImageSaveToFile($hImage, @ScriptDir & "\Converted.png") ;~ ShellExecute(@ScriptDir & "\Converted.png") Global $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage) Global $hGui = GUICreate("TGA Image Loader by UEZ", $iW, $iH) GUISetState() Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGui) _GDIPlus_GraphicsDrawImageRect($hGraphics, $hImage, 0, 0, $iW, $iH) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE _GDIPlus_BitmapDispose($hImage) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_Shutdown() Exit Case $GUI_EVENT_RESTORE _GDIPlus_GraphicsDrawImageRect($hGraphics, $hImage, 0, 0, $iW, $iH) EndSwitch WEnd  
      Here my rookie assembler code ^^:
      #cs _ASM8cm_x86 use32 define tSrcBmp dword[edi] define tDestBmp dword[edi + 04] define colortable dword[edi + 08] define strideSrc dword[edi + 12] define strideDest dword[edi + 16] define w dword[edi + 20] define h dword[edi + 24] define colorTblSize dword[edi + 28] define colorwidth dword[edi + 32] define iOffset dword[edi + 36] define iOffset2 dword[edi + 40] define r5 byte[edi + 44] define g5 byte[edi + 45] define b5 byte[edi + 46] pushad ;~ _ASMDBG_() mov edi, dword[esp + 36] ;pointer to the struct xor ecx, ecx; y = 0 align 16 _y: mov eax, ecx mul strideSrc add eax, colorTblSize mov iOffset, eax ;iOffset = y * $strideSrc + $colorTblSize mov eax, ecx mul strideDest mov iOffset2, eax ;iOffset2 = y * $strideDest xor ebx, ebx ;x = 0 _x: mov eax, iOffset add eax, ebx ;iOffset + x add eax, tSrcBmp mov edx, eax ;edx = iOffset + x + tSrcBmp xor eax, eax mov al, byte[edx] ;get index from color table mul colorwidth ;multiply it with colorwidth -> eax = index of the color table mov edx, colortable add edx, eax mov esi, dword[edx] ;get the color from the color table mov eax, 3 mul ebx ; add eax, iOffset2 ; add eax, tDestBmp ;$x * 3 + iOffset2 + tDestBmp = t1 mov ebp, eax cmp colorwidth, 2 jne _col_rgb mov dx, si ;BitShift(BitAND($col, 0x001F), -3) ;B and dx, 0x001F shl dx, 3 mov b5, dl mov dx, si ;BitShift(BitShift(BitAND($col, 0x03E0), 5), -3) ;G and dx, 0x03E0 shr dx, 5 shl dx, 3 mov g5, dl mov dx, si ;BitShift(BitShift(BitAND($col, 0x7C00), 10), -3) ;R and dx, 0x7C00 shr dx, 10 shl dx, 3 mov r5, dl xor eax, eax ;eax = 0 or al, r5 ;generate rgb value from rgb555 shl eax, 8 or al, g5 shl eax, 8 or al, b5 mov esi, eax _col_rgb: mov dword[ebp], esi ;write to destination inc ebx cmp ebx, w jbe _x inc ecx cmp ecx, h jbe _y ;~ _ASMDBG_() popad ret ;4 #ce _ASM8cm_x86 #cs _ASM8cm_x64 use64 define tSrcBmp qword[r15] define tDestBmp qword[r15 + 08] define colortable qword[r15 + 16] define strideSrc dword[r15 + 24] define strideDest dword[r15 + 28] define w dword[r15 + 32] define h dword[r15 + 36] define colorTblSize dword[r15 + 40] define colorwidth dword[r15 + 44] define iOffset dword[r15 + 48] define iOffset2 dword[r15 + 52] define r5 byte[r15 + 56] define g5 byte[r15 + 57] define b5 byte[r15 + 58] define x r13d define y r14d push rdi push rsi push rbx push rbp mov qword r15, rcx mov y, 0 align 16 _y: mov eax, y mul strideSrc add eax, colorTblSize mov iOffset, eax ;iOffset = y * $strideSrc + $colorTblSize mov eax, y mul strideDest mov iOffset2, eax ;iOffset2 = y * $strideDest xor x, x ;x = 0 _x: mov eax, iOffset add eax, x ;iOffset + x add rax, tSrcBmp mov rdx, rax ;edx = iOffset + x + tSrcBmp xor rax, rax mov al, byte[rdx] ;get index from color table mul colorwidth ;multiply it with colorwidth -> eax = index of the color table mov rdx, colortable add rdx, rax mov r9d, dword[rdx] ;get the color from the color table xor rax, rax mov rax, 3 mul x ; add eax, iOffset2 ; add rax, tDestBmp ;$x * 3 + iOffset2 + tDestBmp = t1 mov r8, rax cmp colorwidth, 2 jne _col_rgb xor rdx, rdx mov dx, r9w ;BitShift(BitAND($col, 0x001F), -3) ;B and dx, 0x001F shl dx, 3 mov b5, dl xor rdx, rdx mov dx, r9w ;BitShift(BitShift(BitAND($col, 0x03E0), 5), -3) ;G and dx, 0x03E0 shr dx, 5 shl dx, 3 mov g5, dl xor rdx, rdx mov dx, r9w ;BitShift(BitShift(BitAND($col, 0x7C00), 10), -3) ;R and dx, 0x7C00 shr dx, 10 shl dx, 3 mov r5, dl xor eax, eax ;eax = 0 or al, r5 ;generate rgb value from rgb555 shl eax, 8 or al, g5 shl eax, 8 or al, b5 mov r9d, eax _col_rgb: mov dword[r8], r9d ;write to destination inc x cmp x, w jbe _x inc y cmp y, h jbe _y pop rbp pop rbx pop rsi pop rdi ret 8 #ce #cs _ASM8_x86 use32 pushad mov edi, dword[esp + 36] ;pointer to the struct define tSrcBmp dword[edi] define tDestBmp dword[edi + 04] define strideSrc dword[edi + 08] define strideDest dword[edi + 12] define w dword[edi + 16] define h dword[edi + 20] define colorTblSize dword[edi + 24] define iOffset dword[edi + 28] define iOffset2 dword[edi + 32] mov ecx, 0 ; y align 16 _y: mov eax, ecx mul strideSrc add eax, colorTblSize mov iOffset, eax ;iOffset = y * $strideSrc + $colorTblSize mov eax, ecx mul strideDest mov iOffset2, eax ;iOffset2 = y * $strideDest xor ebx, ebx ;x = 0 _x: mov ebp, iOffset sub ebp, 2 add ebp, ebx add ebp, tSrcBmp ;ebp = t1 mov eax, 3 mul ebx add eax, iOffset2 add eax, tDestBmp ;eax = t2 mov esi, dword[ebp] ;get the color from source bitmap mov dword[eax], esi ;write to destination inc ebx cmp ebx, w jbe _x inc ecx cmp ecx, h jbe _y popad ret ;4 #ce _ASM8_x86 #cs _ASM8_x64 use64 push rdi push rsi push rbx push rbp define tSrcBmp qword[r15] define tDestBmp qword[r15 + 08] define strideSrc [r15 + 16] define strideDest [r15 + 20] define w [r15 + 24] define h [r15 + 28] define colorTblSize [r15 + 32] define iOffset [r15 + 36] define iOffset2 [r15 + 40] mov qword r15, rcx sub qword colorTblSize, 2 mov ebx, 0 ;w - 1 mov ecx, 0 ;h - 1 align 16 _y: mov eax, ecx mul dword strideSrc mov r10, rax ;r10 = y * $strideSrc mov eax, ecx mul dword strideDest mov r11, rax ;r11 = y * $strideDest _x: mov r8, r10 add r8, rbx add r8, colorTblSize add r8, tSrcBmp ;r8 = t1 mov rax, 3 mul rbx add rax, r11 add rax, tDestBmp ;eax = t2 mov r9, [r8] ;get the color from source bitmap mov dword[rax], r9d ;write to destination inc ebx cmp ebx, w jbe _x xor rbx, rbx inc ecx cmp ecx, h jbe _y pop rbp pop rbx pop rsi pop rdi ret 8 #ce _ASM8_x64 #cs _ASM1516_x86 use32 mov edi, dword[esp + 4] ;pointer to the struct define tSrcBmp ptr[edi] define tDestBmp ptr[edi + 04] define strideSrc dword[edi + 08] define strideDest dword[edi + 12] define w dword[edi + 16] define h dword[edi + 20] define colorTblSize dword[edi + 24] define iOffset dword[edi + 28] define iOffset2 dword[edi + 32] mov ebx, 0 ; x mov ecx, 0 ; y align 16 _y: mov eax, ecx mul strideSrc mov iOffset, eax ;iOffset = y * $strideSrc mov eax, ecx mul strideDest mov iOffset2, eax ;iOffset2 = y * $strideDest _x: mov eax, 2 mul ebx ;x * 2 push eax add eax, iOffset add eax, colorTblSize add eax, tSrcBmp mov edx, eax ;edx = t1 pop eax ;restore x * 2 add eax, iOffset2 add eax, tDestBmp ;eax = t2 mov esi, dword[edx] ;get the color from source bitmap mov word[eax], si ;write to destination inc ebx cmp ebx, w jbe _x xor ebx, ebx inc ecx cmp ecx, h jbe _y ret ;4 #ce _ASM1516_x86 #cs _ASM1516_x64 use64 ;~ define tSrcBmp dword[r15 + 0] ;~ define tDestBmp dword[r15 + 8] ;~ define strideS dword[r15 + 16] ;~ define strideD dword[r15 + 20] ;~ define width dword[r15 + 24] ;~ define height dword[r15 + 28] ;~ define colorTblSize dword[r15 + 32] ;~ define t1 dword[r15 + 36] ;not needed ;~ define t2 dword[r15 + 40] ;not needed push rdi push rsi push rbx push rbp mov qword r15, rcx mov ebx, 0 ;dword[r15 + 24] ;ebx = w - 1 mov ecx, 0 ;dword[r15 + 28] ;ecx = h - 1 align 16 _y: mov eax, ecx mul dword[r15 + 16] mov r9, rax mov eax, ecx mul dword[r15 + 20] mov r10, rax push rbx _x: mov eax, ebx shl eax, 1 mov rdx, r10 add rdx, rax add rdx, [r15 + 8] mov r8, r9 add r8, rax add r8, [r15 + 32] add r8, [r15] mov rax, [r8] mov [rdx], rax inc ebx inc ebx cmp ebx, dword[r15 + 24] jbe _x pop rbx inc ecx cmp ecx, dword[r15 + 28] jbe _y pop rbp pop rbx pop rsi pop rdi ret 8 #ce _ASM1516_x64 #cs _ASM24_x86 use32 mov edi, dword[esp + 4] ;pointer to the struct define tSrcBmp dword[edi] define tDestBmp dword[edi + 04] define strideSrc dword[edi + 08] define strideDest dword[edi + 12] define w dword[edi + 16] define h dword[edi + 20] define colorTblSize dword[edi + 24] define iOffset dword[edi + 28] define iOffset2 dword[edi + 32] mov ebx, 0 ; x mov ecx, 0 ; y align 16 _y: mov eax, ecx mul strideSrc mov iOffset, eax ;iOffset = y * $strideSrc mov eax, ecx mul strideDest mov iOffset2, eax ;iOffset2 = y * $strideDest _x: mov eax, 3 mul ebx ;x * 3 push eax add eax, iOffset add eax, colorTblSize add eax, tSrcBmp mov edx, eax ;edx = t1 pop eax ;restore x * 3 add eax, iOffset2 add eax, tDestBmp ;eax = t2 mov esi, dword[edx] ;get the color from source bitmap mov dword[eax], esi ;write to destination inc ebx cmp ebx, w jbe _x xor ebx, ebx inc ecx cmp ecx, h jbe _y ret ;4 #ce _ASM24_x86 #cs _ASM24_x64 use64 ;~ define tSrcBmp dword[r15 + 0] ;~ define tDestBmp dword[r15 + 8] ;~ define strideS dword[r15 + 16] ;~ define strideD dword[r15 + 20] ;~ define width dword[r15 + 24] ;~ define height dword[r15 + 28] ;~ define colorTblSize dword[r15 + 32] ;~ define t1 dword[r15 + 36] ;not needed ;~ define t2 dword[r15 + 40] ;not needed push rdi push rsi push rbx push rbp mov qword r15, rcx xor rcx, rcx align 16 _y: mov eax, ecx mul dword[r15 + 16] mov r9, rax mov eax, ecx mul dword[r15 + 20] mov r10, rax xor rbx, rbx _x: mov rax, 3 mul rbx mov rdx, r10 add rdx, rax add rdx, [r15 + 8] mov r8, r9 add r8, rax add r8, [r15 + 32] add r8, [r15] mov rax, [r8] mov [rdx], rax ;copy 64 bits inc ebx inc ebx cmp ebx, dword[r15 + 24] jbe _x inc ecx cmp ecx, dword[r15 + 28] jbe _y pop rbp pop rbx pop rsi pop rdi ret 8 #ce _ASM24_x64  
      If you find a TGA image which is in scope of this script but doesn't convert it properly, please report it here.
      Thanks.
    • By Beege
      Here is an old goodie from ms demonstrating concepts behind multithreading and using mutexes to control sharing the screen. Its unfortunately just a console application so you have to press compile (f7) to run (can get annoying if you want to play with the code) but still pretty cool :). Each little question mark box (could be any character (used to be a smiley face in win 7)) is its own thread keeping track of its own coordinates. Each thread shares the screenmutex by kinda waiting in line for ownership of it. When the thread gains control it updates the screen, then releases the mutex for the next thread. 

       
      First I wrote it in pure autoit to confirm all working as expected. The Console functions actually threw me for a loop. They actual want the whole value of the coord structs and not a ptr to it so that "struct" without a * was a little uncommon. Below au3 code is just the lonely cell bouncing around.
      Func _BounceAU3() ;set a random starting id. we use this to rotate the colors Local $iMyID = Random(1, 15, 1) Local $tMyCell = DllStructCreate('char mc'), $tOldCell = DllStructCreate('char oc') Local $tMyAttrib = DllStructCreate('word ma'), $tOldAttrib = DllStructCreate('word oa') Local $tCoords = DllStructCreate($tagCOORD), $tOld = DllStructCreate($tagCOORD) Local $tDelta = DllStructCreate($tagCOORD) ;Random start and delta values $tCoords.X = Random(0, 119, 1) $tCoords.Y = Random(0, 29, 1) $tDelta.X = Random(-3, 3, 1) $tDelta.Y = Random(-3, 3, 1) ;set character/cell attributes $tMyCell.mc = $iMyID > 16 ? 0x01 : 0x02 ; doesnt seem to make a differnce in windows 10 $tMyAttrib.ma = BitAND($iMyID, 0x0F) ; Set the character color Do ;check the last position values DllCall('kernel32.dll', "bool", "ReadConsoleOutputCharacter", "handle", $g_hStdHandle, "struct*", $tOldCell, "dword", 1, "struct", $tOld, "dword*", 0) DllCall('kernel32.dll', "bool", "ReadConsoleOutputAttribute", "handle", $g_hStdHandle, "struct*", $tOldAttrib, "dword", 1, "struct", $tOld, "dword*", 0) ;if the last postion was this cell, blank/empty the cell. (Otherwise its been taken over by another thread) If ($tOldCell.oc = $tMyCell.mc) And ($tOldAttrib.oa = $tMyAttrib.ma) Then DllCall('kernel32.dll', "bool", "WriteConsoleOutputCharacter", "handle", $g_hStdHandle, "byte*", 0x20, "dword", 1, "struct", $tOld, "dword*", 0) EndIf ;write the current cell DllCall('kernel32.dll', "bool", "WriteConsoleOutputCharacter", "handle", $g_hStdHandle, "struct*", $tMyCell, "dword", 1, "struct", $tCoords, "dword*", 0) DllCall('kernel32.dll', "bool", "WriteConsoleOutputAttribute", "handle", $g_hStdHandle, "struct*", $tMyAttrib, "dword", 1, "struct", $tCoords, "dword*", 0) ;update coords $tOld.X = $tCoords.X $tOld.Y = $tCoords.Y $tCoords.X += $tDelta.X $tCoords.Y += $tDelta.Y ;change directions if we are out of bounds If $tCoords.X < 0 Or $tCoords.X >= 120 Then $tDelta.X *= -1 If $tCoords.Y < 0 Or $tCoords.Y >= 30 Then $tDelta.Y *= -1 Sleep(75) Until GUIGetMsg() = -3 EndFunc ;==>_BounceAU3  
      From there the that function converted into assembly so we can call as a thread. The only real differences are the extra parameters we passing as a structure and I also generate the random starting values in autoit instead, then pass them to the function. Here is what the main assembly function looks like. I added comments for each peice of code from au3 that we are translating:
      _('procf _Bounce uses ebx, pParms') ; ; create the local variables _(' locals') _(' BlankCell db 32') ; this first group covers the variables from the original script _(' MyCell db ?') _(' OldCell db ?') _(' MyAtt dw ?') _(' OldAtt dw ?') _(' tCoords COORD') _(' tDelta COORD') _(' tOld COORD') _(' bytesread dw ?') ; _(' iMyID dw ?') ; this group of local vars cover holding all the other paramerters we are passing in tParms _(' g_hScreenMutex dd ?') _(' g_hRunMutex dd ?') _(' g_hStdHandle dd ?') _(' pfWaitForSingleObject dd ?') _(' pfReleaseMutex dd ?') _(' pfReadChar dd ?') _(' pfReadAttr dd ?') _(' pfWriteChar dd ?') _(' pfWriteAttr dd ?') _(' endl') ; ;all of these push/pops are to transfer the rest of variables from tParms structure to the local variables we created ;first mov the structure address into ebx _(' mov ebx, [pParms]') ; ; now push and pop the values into the variables ; use _winapi_displaystruct() to view all the offsets being used in the [ebx+offset] lines _(' pushw [ebx]') ; _(' popw word[tCoords+COORD.X]') _(' pushw word[ebx+2]') ; _(' popw word[tCoords+COORD.Y]') _(' pushw word[ebx+4]') ; _(' popw word[tDelta+COORD.X]') _(' pushw word[ebx+6]') ; _(' popw word[tDelta+COORD.Y]') _(' pushw word[ebx+8]') ; _(' popw word[iMyID]') _(' push dword[ebx+12]') ; _(' pop dword[g_hScreenMutex]') _(' push dword[ebx+16]') ; _(' pop dword[g_hRunMutex]') _(' push dword[ebx+20]') ; _(' pop dword[g_hStdHandle]') _(' push dword[ebx+24]') ; _(' pop dword[pfWaitForSingleObject]') _(' push dword[ebx+28]') ; _(' pop dword[pfReleaseMutex]') _(' push dword[ebx+32]') ; _(' pop dword[pfReadChar]') _(' push dword[ebx+36]') ; _(' pop dword[pfReadAttr]') _(' push dword[ebx+40]') ; _(' pop dword[pfWriteChar]') _(' push dword[ebx+44]') ; _(' pop dword[pfWriteAttr]') _('.if word[iMyID] > 16') ; $tMyCell.mc = $iMyID > 16 ? 0x01 : 0x02 (no difference in windows 10) _(' mov word[MyCell], 1') _('.else') _(' mov word[MyCell], 2') _('.endif') ; _('pushw word[iMyID]') ; $tMyAttrib.ma = BitAND($iMyID, 0x0F) _('popw word[MyAtt]') _('and word[MyAtt], 15') ; _('.repeat') ; do ; ; Wait infinetly for the screen mutex to be available, then take ownership _(' invoke pfWaitForSingleObject, [g_hScreenMutex], -1') ; ; DllCall('kernel32.dll', "bool", "WriteConsoleOutputCharacter", "handle", $hStdHandle, "byte*", 0x20, "dword", 1, "struct", $tOld, "dword*", 0) _(' invoke pfReadChar, [g_hStdHandle], addr OldCell, 1, dword[tOld], addr bytesread') ; _(' invoke pfReadAttr, [g_hStdHandle], addr OldAtt, 1, dword[tOld], addr bytesread') ; ; _(' mov al, byte[MyCell]') ;If ($tOldCell.oc = $tMyCell.mc) And ($tOldAttrib.oa = $tMyAttrib.ma) Then _(' mov cl, byte[MyAtt]') _(' .if (byte[OldCell] = al) & (byte[OldAtt] = cl)') _(' invoke pfWriteChar, [g_hStdHandle], addr BlankCell, 1, dword[tOld], addr bytesread') _(' .endif') ; ; DllCall('kernel32.dll', "bool", "WriteConsoleOutputCharacter", "handle", $hStdHandle, "struct*", $tMyCell, "dword", 1, "struct", $tCoords, "dword*", 0) _(' invoke pfWriteChar, [g_hStdHandle], addr MyCell, 1, dword[tCoords], addr bytesread') _(' invoke pfWriteAttr, [g_hStdHandle], addr MyAtt, 1, dword[tCoords], addr bytesread') ; _(' pushw word[tCoords+COORD.X]') ;$tOld.X = $tCoords.X _(' popw word[tOld+COORD.X]') ; _(' pushw word[tCoords+COORD.Y]') ;$tOld.Y = $tCoords.Y _(' popw word[tOld+COORD.Y]') _(' mov ax, word[tDelta+COORD.X]') ; $tCoords.X += $tDelta.X _(' add word[tCoords+COORD.X], ax') ; _(' mov ax, word[tDelta+COORD.Y]') ; $tCoords.Y += $tDelta.Y _(' add word[tCoords+COORD.Y], ax') ; ; If $tCoords.X < 0 Or $tCoords.X >= 120 Then $tDelta.X *= -1 _(' .if (word[tCoords+COORD.X] < 0 | word[tCoords+COORD.X] >= 120)') _(' neg word[tDelta+COORD.X]') _(' .endif') _(' .if (word[tCoords+COORD.Y] < 0 | word[tCoords+COORD.Y] >= 30)') _(' neg word[tDelta+COORD.Y]') _(' .endif') ; ; release the screen mutex _(' invoke pfReleaseMutex, [g_hScreenMutex]') ; ; wait 100 ms for the Runmutex to be available. _(' invoke pfWaitForSingleObject, [g_hRunMutex], 100') ; ; a return of 258 means it timed out waiting and that the run mutex (owned by the main autoit thread) is still alive. ; when the run mutex handle gets closed this will return a fail or abandonded. _('.until eax <> 258') ; ;exit thread _(' ret') _('endp')  
      And finally how we call that assembled function from autoit to create the theads:
      ;create mutex for sharing the screen thats not owned by main thread Global $g_hScreenMutex = _WinAPI_CreateMutex('', False) ; ;create mutex that tells the threads to exit that is owned by main thread Global $g_hRunMutex = _WinAPI_CreateMutex('', True) ... ... ;assemble function Local $tBinExec = _fasmg_Assemble($g_sFasm, False) ;Local $tBinExec = _fasmg_CompileAu3($g_sFasm) If @error Then Exit (ConsoleWrite($tBinExec & @CRLF)) ;this is struct is for all the values Im passing to the thread. ;this will hold are random start x,y,delta values, handles, and pointers to functions called within the thread $tParms = DllStructCreate('short start[4];word myid;dword hands[3];ptr funcs[6]') $tParms.start(1) = Random(0, 119, 1) $tParms.start(2) = Random(0, 29, 1) $tParms.start(3) = Random(-3, 3, 1) $tParms.start(4) = Random(-3, 3, 1) $tParms.myid = 1 $tParms.hands(1) = $g_hScreenMutex $tParms.hands(2) = $g_hRunMutex $tParms.hands(3) = $g_hStdHandle $tParms.funcs(1) = _GPA('kernel32.dll', 'WaitForSingleObject') $tParms.funcs(2) = _GPA('kernel32.dll', 'ReleaseMutex') $tParms.funcs(3) = _GPA('kernel32.dll', 'ReadConsoleOutputCharacterA') $tParms.funcs(4) = _GPA('kernel32.dll', 'ReadConsoleOutputAttribute') $tParms.funcs(5) = _GPA('kernel32.dll', 'WriteConsoleOutputCharacterA') $tParms.funcs(6) = _GPA('kernel32.dll', 'WriteConsoleOutputAttribute') ;create 128 threads with different start values and colors for each one For $i = 1 To 128 $tParms.myid = $i $tParms.start(1) = Random(0, 119, 1) $tParms.start(2) = Random(0, 29, 1) $tParms.start(3) = Random(-3, 3, 1) $tParms.start(4) = Random(-3, 3, 1) If $tParms.start(3) + $tParms.start(4) = 0 Then $tParms.start(3) = (Mod(@MSEC, 2) ? 1 : -1) ; adjusting non-moving (0,0) delta values.. DllCall("kernel32.dll", "hwnd", "CreateThread", "ptr", 0, "dword", 0, "struct*", $tBinExec, "struct*", $tParms, "dword", 0, "dword*", 0) Sleep(50) Next MsgBox(262144, '', '128 Threads Created') ;Close the run mutex handle. This will cause all the threads to exit _WinAPI_CloseHandle($g_hRunMutex) _WinAPI_CloseHandle($g_hScreenMutex) MsgBox(262144, '', 'Mutex handles closed. All Threads should have exited') Exit The attachment below contains both the compiled and source assembly. To play with the assembly source you need to add the fasmg udf in my sig. The compiled version should not need anything. Let me know if you have any issues.
      Special thanks to @trancexx for teaching me this with her clock example
      Bounce.zip
       
    • By Beege
      Years ago I tried to put some functionality together to do some of this here. I started off in the right direction but it ended up getting out of control. Any new thing I learned along the way (as I was creating it), I kept trying to add in and it all became a mess. One of my primary goals with that was to make sure the code could always be pre-compiled and still run. That part did work and I was able create a couple of good projects with it, but still a lot of parts I wouldn't consider correct now and certainly not manageable. 
      Here is a redo of what I was going for there only this time I'm not going to be generating any of the assembly code. That's all going to be done using the built in macro engine already within fasm.dll and the macros written by Tomasz Grysztar (creator of fasm) so this time I don't have to worry about any of the code that gets generated. Im not going to touch the source at all. In fact there is not even going to be _fasmadd or global variables tracking anything. None of that is needed with the added basic and extended headers that you can read more about in the fasm documentation. You can use almost all of whats in the documentation section for basic/extended headers but ignore the parts about import,exports,resources,text encoding. doesn't really apply here.
      Here are examples I came up with that covers a lot of core functionality to write assembly code in a manner that you already know how. If/while using multiple conditional logic statements,  multiple functions, local variables, global variables, structures, COM interfaces, strings as parameters, nesting function calls. These are all things you dont even have to think about when your doing it in autoit and I'm hoping this helps bring some of that same comfort to fasm. 
      These 3 simple callback functions will be used through out the examples  
      Global $gConsoleWriteCB = DllCallbackRegister('_ConsoleWriteCB', 'dword', 'str;dword'), $gpConsoleWriteCB = DllCallbackGetPtr($gConsoleWriteCB) Global $gDisplayStructCB = DllCallbackRegister('_DisplayStructCB', 'dword', 'ptr;str'), $gpDisplayStructCB = DllCallbackGetPtr($gDisplayStructCB) Global $gSleepCB = DllCallbackRegister('_SleepCB', 'dword', 'dword'), $gpSleepCB = DllCallbackGetPtr($gSleepCB) Func _ConsoleWriteCB($sMsg, $iVal) ConsoleWrite($sMsg & $iVal & @CRLF) EndFunc ;==>_ConsoleWriteCB Func _DisplayStructCB($pStruct, $sStr) _WinAPI_DisplayStruct(DllStructCreate($sStr, $pStruct), $sStr, 'def=' & $sStr) EndFunc ;==>_DisplayStructCB Func _SleepCB($iSleep) Sleep($iSleep) EndFunc ;==>_SleepCB  
      proc/endp - like func and endfunc with some extra options. "uses" statement will preserve the registers specified. stdcall is the default call type if not specified. DWORD is the default parameter size if not specified. ret value is also handled for you. You don't have to worry about adjusting a number every time you throw on an extra parameter. In fact you don't ever have to specify/touch ebp/esp at all with these macros. See Basic headers -> procedures for full description.
      force - just a macro I added for creating a anonymous label for the first/primary function to ensure the code gets generated. The problem we are getting around is this: in our example, _main is never actually called anywhere within fasm code and fasm engine detects that and thinks the code is doing nothing. Because of that it wants to skip generating that code and all code that was called by it leaving you with nothing. This is actually a great feature but we obviously want to make an exception for our main/initial/primary function that starts it all off so thats all this does.
      Func _Ex_Proc() $g_sFasm = '' _('force _main') _('proc _main uses ebx, parm1, parm2') ; _('proc _main stdcall uses ebx, parm1:DWORD, parm2:DWORD'); full statement _(' mov ebx, [parm1]') _(' add ebx, [parm2]') _(' mov eax, ebx') _(' ret') _('endp') Local $tBinary = _FasmAssemble($g_sFasm) If @error Then Exit (ConsoleWrite($tBinary & @CRLF)) Local $iAdd = DllCallAddress('dword', DllStructGetPtr($tBinary), 'dword', 5, 'dword', 5) ConsoleWrite('Parm1+Parm2=' & $iAdd[0] & @CRLF) EndFunc ;==>_Ex_Proc  
          Here Im showing you calling _ConsoleWriteCB autoit function we set up as a callback. Its how you would call any function in autoit from fasm.
          Strings - Notice Im creating and passing "edx = " string to the function on the fly. So helpful!
          invoke - same as a stdcall with brackets []. Use this for when calling autoit functions
       
      Func _Ex_Callback() $g_sFasm = '' _('force _main') _('proc _main, pConsoleWriteCB, parm1, parm2') _(' mov edx, [parm1]') _(' add edx, [parm2]') _(' invoke pConsoleWriteCB, "edx = ", edx') ; ;~ _(' stdcall [pConsoleWriteCB], "edx = ", edx') ; same as invoke _(' ret') _('endp') Local $tBinary = _FasmAssemble($g_sFasm) If @error Then Exit (ConsoleWrite($tBinary & @CRLF)) DllCallAddress('ptr', DllStructGetPtr($tBinary), 'ptr', $gpConsoleWriteCB, 'dword', 5, 'dword', 5) EndFunc ;==>_Ex_Callback  
      Showing .while/.endw, .if/.elseif/.else/.endif usage. .repeat .until are also macros you can use. See Extended Headers -> Structuring the source. Ignore .code, .data, .end - Those are gonna be more for a full exe.
      invokepcd/invokepd - these are macros I added that are the same as invoke, just preserve (push/pop) ECX or both ECX and EDX during the call. Below is also a good example of what can happen when you don't preserve registers that are caller saved (us calling the function) vs callie saved (us creating the function). EAX,ECX,EDX are all caller saved so when we call another function like the autoit callback _ConsoleWriteCB, those registers could have very different values then what was in them before the call. This function below should do at least two loops, but it doesn't (at least on my pc) without preserving ECX because ECX is no longer zero when the function returns.
      Keep the same thought in mind for registers EBX,ESI,EDI when you are creating assembly functions (callie saved). If your functions uses those registers, You need to preserve and restore them before your code returns back to autoit or else you could cause a similar effect to autoit. "trashing" registers is a term I've seen used alot when referring to these kind of mistakes
      Func _Ex_IfElseWhile() $g_sFasm = '' _('force _main') _('proc _main uses ebx, pConsoleWriteCB') _(' xor edx, edx') ; edx=0 _(' mov eax, 99') ; _(' mov ebx, 10') _(' xor ecx, ecx') ; ecx=0 _(' .while ecx = 0') _(' .if eax<=100 & ( ecx | edx )') ; not true on first loop _(' inc ebx') _(' invokepcd pConsoleWriteCB, "Something True - ebx=", ebx') _(' ret') _(' .elseif eax < 99') ; Just showing you the elseif statement _(' inc ebx') _(' .else') ;~ _(' invokepcd pConsoleWriteCB, "Nothing True - ebx=", ebx') ; comment this and uncomment the line below _(' invoke pConsoleWriteCB, "Nothing True - ebx=", ebx') _(' inc edx') ; this will make next loop true _(' .endif') _(' .endw') _(' ret') _('endp') Local $tBinary = _FasmAssemble($g_sFasm) If @error Then Exit (ConsoleWrite($tBinary & @CRLF)) DllCallAddress('dword', DllStructGetPtr($tBinary), 'ptr', $gpConsoleWriteCB) EndFunc ;==>_Ex_IfElseWhile  
          Sub Functions : You already understand this. Not really "sub", its just another function you call. And those functions call other functions and so on.
          fix : syntax sugar - Look how easy it was to replace invoke statement with our actual autoit function name
          ptr : more sugar - same thing as using brackets [parm1]
          Nesting : In subfunc1 we pass the results of two function calls to the same function we are calling
      Func _Ex_SubProc() $g_sFasm = '' ;replace all '_ConsoleWriteCB' statments with 'invoke pConsoleWriteCB' before* assembly _('_ConsoleWriteCB fix invoke pConsoleWriteCB') _('force _main') _('proc _main uses ebx, pConsoleWriteCB, parm1, parm2') _(' mov ebx, [parm1]') _(' add ebx, [parm2]') _(' _ConsoleWriteCB, "ebx start = ", ebx') _(' stdcall _subfunc1, [pConsoleWriteCB], [parm1], [parm2]') _(' _ConsoleWriteCB, "ebx end = ", ebx') _(' ret') _('endp') ; _('proc _subfunc1 uses ebx, pConsoleWriteCB, parm1, parm2') _(' mov ebx, [parm1]') _(' _ConsoleWriteCB, " subfunc1 ebx start = ", ebx') _(' stdcall _SubfuncAdd, <stdcall _SubfuncAdd, [parm1], [parm2]>, <stdcall _SubfuncAdd, ptr parm1, ptr parm2>') ; Nesting functions _(' _ConsoleWriteCB, " _SubfuncAdd nested <5+5><5+5> = ", eax') _(' _ConsoleWriteCB, " subfunc1 ebx end = ", ebx') _(' ret') _('endp') ; _('proc _SubfuncAdd uses ebx, parm1, parm2') _(' mov ebx, [parm1]') _(' add ebx, [parm2]') _(' mov eax, ebx') _(' ret') _('endp') Local $tBinary = _FasmAssemble($g_sFasm) If @error Then Exit (ConsoleWrite($tBinary & @CRLF)) DllCallAddress('dword', DllStructGetPtr($tBinary), 'ptr', $gpConsoleWriteCB, 'dword', 5, 'dword', 5) EndFunc ;==>_Ex_SubProc  
      This demonstrates the struct macro. See basic headers -> Structures for more info
      _FasmAu3StructDef will create an equivalent formated structure definition. All elements already have a sizeof.#name created internally. So in this example sizeof.AUTSTRUCT.x would equal 8. sizeof.AUTSTRUCT.z would equal 16 (2*8). I have added an additional one sot.#name (sizeoftype) for any array that gets created. Below is the source of what gets generate from 'dword x;dword y;short z[8]'. Also dont get confused that in fasm data definitions,  d is for data as in db (data byte) or dw (data word). Not double like it is in autoit's dword (double word). See intro -> assembly syntax -> data definitions
         
      struct AUTSTRUCT x dd ? y dd ? z dw 8 dup ? ends define sot.AUTSTRUCT.z 2 Func _Ex_AutDllStruct() $g_sFasm = '' Local Const $sTag = 'dword x;dword y;short z[8]' _(_FasmAu3StructDef('AUTSTRUCT', $sTag)) _('force _main') _('proc _main uses ebx, pDisplayStructCB, pAutStruct') _(' mov ebx, [pAutStruct]') ; place address of autoit structure in ebx _(' mov [ebx+AUTSTRUCT.x], 1234') _(' mov [ebx+AUTSTRUCT.y], 4321') _(' xor edx, edx') _(' mov ecx, 5') ; setup ecx for loop instruction _(' Next_Z_Index:') ; set elements 1-6 (0-5 here in fasm) _(' mov [ebx+AUTSTRUCT.z+(sot.AUTSTRUCT.z*ecx)], cx') ; cx _(' loop Next_Z_Index') _(' invoke pDisplayStructCB, [pAutStruct], "' & $sTag & '"') _(' mov [ebx+AUTSTRUCT.z+(sot.AUTSTRUCT.z*6)], 666') _(' mov [ebx+AUTSTRUCT.z+(sot.AUTSTRUCT.z*7)], 777') _(' ret') _('endp') Local $tBinary = _FasmAssemble($g_sFasm) If @error Then Exit (ConsoleWrite($tBinary & @CRLF)) Local $tAutStruct = DllStructCreate($sTag) DllCallAddress('ptr', DllStructGetPtr($tBinary), 'ptr', $gpDisplayStructCB, 'struct*', $tAutStruct) _WinAPI_DisplayStruct($tAutStruct, $sTag) EndFunc ;==>_Ex_AutDllStruct  
      Here shows the locals/endl macros for creating local variables. See basic headers -> procedures. We create a local string and the same dll structure as above. Notice that you can initialize all the values of the structure on creation. There is a catch to this though that I will show you in next example.
      addr macro - This will preform the LEA instruction in EDX and then push the address on to the stack. This is awesome, just remember its using EDX to perform that and does not preserve it. You'll pretty much want to use that for any local variables you are passing around.
      Edit: I shouldn't say things like that so causally.  Use the addr macro as much as you want but remember that it is adding a couple of extra instuctions each time you use it so if your calling invoke within a loop and ultimate performance is one of your goals, you should probably perform the LEA instructions before the loop and save the pointer to a separate variable that your would then use in the loop. 
      Func _Ex_LocalVarsStruct() $g_sFasm = '' Local Const $sTag = 'dword x;dword y;short z[8]' _(_FasmAu3StructDef('POINT', $sTag)) _('force _main') _('proc _main, pDisplayStructCB') _(' locals') _(' sTAG db "' & $sTag & '", 0') ; define local string. the ', 0' at the end is to terminate the string. _(' tPoint POINT 1,2,<0,1,2,3,4,5,6,7>') ; initalize values in struct _(' endl') _(' invoke pDisplayStructCB, addr tPoint, addr sTAG') _(' mov [tPoint+POINT.x], 4321') _(' mov [tPoint+POINT.z+sot.POINT.z*2], 678') _(' invoke pDisplayStructCB, addr tPoint, addr sTAG') _(' ret') _('endp') Local $tBinary = _FasmAssemble($g_sFasm) If @error Then Exit (ConsoleWrite($tBinary & @CRLF)) Local $ret = DllCallAddress('ptr', DllStructGetPtr($tBinary), 'ptr', $gpDisplayStructCB) EndFunc ;==>_Ex_LocalVarsStruct  
      Back to the catch. Alignment is the problem here but only with the initializes. I'm handling all the alignment ok so you don't have to worry about that for creating structures that need alignment, only if you are using the one liner initialize in locals. The problem comes from extra padding being defined to handle the alignment, but fasm doesn't really know its just padding so without adding extra comma's to the initiator statement, your data ends up in the padding or simply fails. The _FasmFixInit will throw in the extra commas needed to skip the padding.
      Func _Ex_LocalVarStructEx() $g_sFasm = '' $sTag = 'byte x;short y;char sNote[13];long odd[5];word w;dword p;char ext[3];word finish' _(_FasmAu3StructDef('POINT', $sTag)) _('force _main') _('proc _main, pDisplayStructCB') _(' locals') _(' tPoint POINT ' & _FasmFixInit('1,222,<"AutoItFASM",0>,<41,43,43,44,45>,6,7,"au3",12345', $sTag)) _(' endl') _(' invoke pDisplayStructCB, addr tPoint, "' & $sTag & '"') _(' ret') _('endp') Local $tBinary = _FasmAssemble($g_sFasm) If @error Then Exit (ConsoleWrite($tBinary & @CRLF)) DllCallAddress('dword', DllStructGetPtr($tBinary), 'ptr', $gpDisplayStructCB) EndFunc ;==>_Ex_LocalVarStructEx  
      I love this one and it is really not even that hard to explain. We got multiple functions and want to be able to call them individually. Here I simply use the primary function to tell me where all the functions are. I load all the offsets (byte distance from start of code) of each each function in to a dllstruct, then once its passed back to autoit, adjust all the offsets by where they are actually located in memory (pointer to dll). From there you can call each individual function as shown previously. full code is in the zip. 
      String functions came from link below. I ended up modifying strcmp to get a value I understand. CRC32 func is all mine. Made it so easy being able to call _strlen and then use while statements like I normally would    https://www.strchr.com/strcmp_and_strlen_using_sse_4.2
      Func _Ex_SSE4_Library() $g_sFasm = '' _('force _main') _('proc _main stdcall, pAdd') _(' mov eax, [pAdd]') _(' mov dword[eax], _crc32') _(' mov dword[eax+4], _strlen') _(' mov dword[eax+8], _strcmp') _(' mov dword[eax+12], _strstr') _(' ret') _('endp') _('proc _crc32 uses ebx ecx esi, pStr') ; _('endp') _('proc _strlen uses ecx edx, pStr') ; _('endp') _('proc _strcmp uses ebx ecx edx, pStr1, pStr2') ; ecx = string1, edx = string2' ; _('endp') _('proc _strstr uses ecx edx edi esi, sStrToSearch, sStrToFind') ; _('endp') Local $tBinary = _FasmAssemble($g_sFasm) If @error Then Exit (ConsoleWrite($tBinary & @CRLF)) Local $pBinary = DllStructGetPtr($tBinary) Local $sFunction_Offsets = 'dword crc32;dword strlen;dword strcmp;dword strstr' $tSSE42 = DllStructCreate($sFunction_Offsets) $ret = DllCallAddress('ptr', $pBinary, 'struct*', $tSSE42) _WinAPI_DisplayStruct($tSSE42, $sFunction_Offsets, 'Function Offsets') ;Correct all addresses $tSSE42.crc32 += $pBinary $tSSE42.strlen += $pBinary $tSSE42.strcmp += $pBinary $tSSE42.strstr += $pBinary $sTestStr = 'This is a test string!' ConsoleWrite('$sTestStr = ' & $sTestStr & @CRLF) $iCRC = DllCallAddress('int', $tSSE42.crc32, 'str', $sTestStr) ConsoleWrite('CRC32 = ' & Hex($iCRC[0]) & @CRLF) $aLen = DllCallAddress('int', $tSSE42.strlen, 'str', $sTestStr) ConsoleWrite('string len = ' & $aLen[0] & ' :1:' & @CRLF) $aFind = DllCallAddress('int', $tSSE42.strcmp, 'str', $sTestStr, 'str', 'This iXs a test') ConsoleWrite('+strcmp = ' & $aFind[0] & @CRLF) $aStr = DllCallAddress('int', $tSSE42.strstr, 'str', 'This is a test string!', 'str', 'test') ConsoleWrite('Strstr = ' & $aStr[0] & @CRLF) EndFunc ;==>_Ex_SSE4_Library  
      I'm extremely happy I got a com interface example working. I AM. That being said.. I'm pretty fucking annoyed I cant find the original pointer when using using built in ObjCreateInterface I've tired more than just whats commented out. It anyone has any input (I know someone here does!) that would be great. Using the __ptr__ from _autoitobject works below. Example will delete the tab a couple times.
      Edit: Got that part figured out. Thanks again trancexx!
      Func _Ex_ComObjInterface() $g_sFasm = '' ;~ _AutoItObject_StartUp() ;~ Local Const $sTagITaskbarList = "QueryInterface long(ptr;ptr;ptr);AddRef ulong();Release ulong(); HrInit hresult(); AddTab hresult(hwnd); DeleteTab hresult(hwnd); ActivateTab hresult(hwnd); SetActiveAlt hresult(hwnd);" ;~ Local $oList = _AutoItObject_ObjCreate($sCLSID_TaskbarList, $sIID_ITaskbarList, $sTagITaskbarList) Local Const $sCLSID_TaskbarList = "{56FDF344-FD6D-11D0-958A-006097C9A090}", $sIID_ITaskbarList = "{56FDF342-FD6D-11D0-958A-006097C9A090}" Local Const $sTagITaskbarList = "HrInit hresult(); AddTab hresult(hwnd); DeleteTab hresult(hwnd); ActivateTab hresult(hwnd); SetActiveAlt hresult(hwnd);" Local $oList = ObjCreateInterface($sCLSID_TaskbarList, $sIID_ITaskbarList, $sTagITaskbarList) _('interface ITaskBarList,QueryInterface,AddRef,Release,HrInit,AddTab,DeleteTab,ActivateTab,SetActiveAlt') ; _('force _main') _('proc _main uses ebx, pSleepCB, oList, pGUIHwnd') _(' comcall [oList],ITaskBarList,HrInit') _(' xor ebx, ebx') _(' .repeat') _(' invoke pSleepCB, 500') ; wait _(' comcall [oList],ITaskBarList,DeleteTab,[pGUIHwnd]') ; delete _(' invoke pSleepCB, 500') ; wait _(' comcall [oList],ITaskBarList,AddTab,[pGUIHwnd]') ; add back _(' comcall [oList],ITaskBarList,ActivateTab,[pGUIHwnd]') ; actvate _(' inc ebx') _(' .until ebx=4') _(' ret') _('endp') Local $tBinary = _FasmAssemble($g_sFasm) If @error Then Exit (ConsoleWrite($tBinary & @CRLF)) Local $GUI = GUICreate("_Ex_ComObjInterface ------ DeleteTab") GUISetState() ;~ DllCallAddress('ptr', DllStructGetPtr($tBinary), 'ptr', $gpSleepCB, 'ptr', $oList.__ptr__, 'dword', Number($GUI)) DllCallAddress('ptr', DllStructGetPtr($tBinary), 'ptr', $gpSleepCB, 'ptr', $oList(), 'dword', Number($GUI)) EndFunc ;==>_Ex_ComObjInterface  
      Lastly here is an example of how to use a global variable. Without using the org statement, this value is just an offset like the functions in the library example. In order for your code to know that location, it needs to know where the real starting address is so we have to pass that to our functions. Once you have it, if you write your code proper and preserve registers correctly, you can just leave in EBX. From what I understand, if all functions are following stdcall rules, that register shouldn't change in less you change it. Something cool and important to remember is these variables will hold whatever values left in them till you wipe the memory (dll structure) holding your code. keep that in mind if you made your dll structure with a static keyword. If thats the case treat them like static variables
      Func _Ex_GlobalVars() $g_sFasm = '' _('_ConsoleWriteCB fix invoke pConsoleWriteCB') ; _('force _main') _('proc _main uses ebx, pMem, pConsoleWriteCB, parm1') _(' mov ebx, [pMem]') ; This is where are code starts in memory. _(' mov [ebx + g_Var1], 111') _(' add [ebx + g_Var1], 222') _(' _ConsoleWriteCB, "g_Var1 = ", [ebx + g_Var1]') _(' stdcall subfunc1, [pMem], [pConsoleWriteCB], [parm1]') _(' mov eax, g_Var1') _(' ret') _('endp') ; _('proc subfunc1 uses ebx, pMem, pConsoleWriteCB, parm1') _(' mov ebx, [pMem]') _(' mov [ebx + g_Var1], 333') _(' _ConsoleWriteCB, "g_Var1 from subfunc1= ", [ebx + g_Var1]') _(' stdcall subfunc2, [pConsoleWriteCB], [parm1]') ; no memory ptr passed. ebx should be callie saved _(' _ConsoleWriteCB, "g_Var1 from subfunc1= ", [ebx + g_Var1]') _(' stdcall subfunc2, [pConsoleWriteCB], [parm1]') _(' ret') _('endp') ; _('proc subfunc2, pConsoleWriteCB, parm1') _(' add [ebx + g_Var1], 321') _(' _ConsoleWriteCB, "g_Var1 from subfunc2= ", [ebx + g_Var1]') _(' ret') _('endp') ; _('g_Var1 dd ?') ; <--------- Global Var Local $tBinary = _FasmAssemble($g_sFasm) If @error Then Exit (ConsoleWrite($tBinary & @CRLF)) Local $iOffset = DllCallAddress('dword', DllStructGetPtr($tBinary), 'struct*', $tBinary, 'ptr', $gpConsoleWriteCB, 'dword', 55)[0] ConsoleWrite('$iOffset = ' & $iOffset & @CRLF) Local $tGVar = DllStructCreate('dword g_Var1', DllStructGetPtr($tBinary) + $iOffset) ConsoleWrite('Directly access g_Var1 -> ' & $tGVar.g_Var1 & @CRLF) ; direct access EndFunc ;==>_Ex_GlobalVars  
      FasmEx.zip
    • By Beege
      Special thanks to Ward for his udf and Trancexx for her assembly examples as they have played a huge role in my learning of asm.    UDF Requires  >Beta version 3.3.9.19 or higher. Also Requires >Wards Fasm UDF.  Direct Download Link   FASMEx.zip   FasmEx 9-29-2013.zip   This is dead. See new version here : 
       
       
       
×
×
  • Create New...