Vielen Dank für eure netten Antworten.
Ich habe an meinem Rahmenprogramm noch etwas „herumgeschneidert“ und hoffe, dass es nun auch in fremder Umgebung funktioniert.
Statt über $CmdLine die Phase einzustellen, ist es einfacher den Wert in Zeile 22 einzutragen.
Protokoll() ist mein Autoit-Debugger. Bitte nicht daran stören.
Ich habe noch eine Frage:
Wäre es möglich, im Assemblerprogramm den Debugger-Aufruf z.B. so zu gestalten
Stelle3) _asmdbg_()
und dann im Debugger-Fenster die Zeichenfolge Stelle3 anzuzeigen? Das würde ungemein helfen.
Hier mein Rahmenprogramm:
C
;#AutoIt3Wrapper_Run_Au3Stripper=y
#cs ----------------------------------------------------------------------------
Rahmenprogramm für den Test von Assemblerfunktionen
$CmdLine[1] = Pfad-/Dateiname der Bitmapdatei
$CmdLine[2] = Bearbeitungsphase
Für Tests weiterer Assemblerfunktionen die Parameter für
_AssembleIt2() und DllCallAddress() sowie die Funktion Auswerten() anpassen.
#ce ----------------------------------------------------------------------------
#cs
#include "HilfsFunktionen.au3"
Global $Protokoll1=2 ; =2, dann wird protokolliert, aber beim ersten
; Aufruf ist die Datei zunächst zu löschen.
; =0, dann wird nicht protokolliert
; =1, dann wird protokolliert, ohne die Datei vorher zu löschen
$ProgrammName="FarbenZaehlen" ; für Protokoll
#ce
;-------------------------------------------------------------------------
;Protokoll("Anfang1")
; ===================================================================
; Bearbeitungsphase festlegen
$phase=2
$sFile=""
If $CmdLine[0]<>0 Then $sFile=$CmdLine[1]
If $CmdLine[0]=2 Then $phase=$CmdLine[2]
; -------------------------------------------------------------------
;$phase =1 _AssembleIt2("uint"
; Der Binärcode wird erzeugt und an Ort und Stelle abgearbeitet.
; Debuggen möglich. Diese Phase dient dem Test des Assemblerprogramms
; =2 _AssembleIt2("retbinary"
; Nach abgeschlossenem Test wird nunmehr der fertige Binärcode
; erzeugt. Zunächst wird allen Debugger-Aufrufe _asmdbg_() ein
; Semikolon voangestellt. Der Binärcode erscheint in der Datei
; binarycode.txt.
; Anschließend wird das Programm mittels der Funktion
; DllCallAddress("uint:cdecl" ausgeführt.
; =3 Der in Phase 2 erzeugte Binärcode wird der Datei binarycode.txt
; entnommen und mittels der Funktion DllCallAddress("uint:cdecl"
; ausgeführt.
; =0 oder ="" Der in der Datei binarycode.txt stehende Binärcode
; wurde direkt in das Programm als Variable $binarycode
; eingetragen und das Programm sollte dann auch compiliert werden.
; ===================================================================
#include <GDIPlus.au3>
;#include <WinAPI.au3>
;#include <Array.au3>
;#include <GUIConstantsEx.au3>
;#include <StructureConstants.au3>
;#include <WindowsConstants.au3>
#include <assembleit2_64.au3>;~
;#include <#FuncASS.au3>
#AutoIt3Wrapper_UseX64=n
#cs _countpixelcolors ;
Use32 ;32Bit!
org $PTR_SOURCE_ASMCODE ;only needed for assembleit debugger
mov edi,dword[esp+4] ;pointer bitmap
mov ecx,dword[esp+8] ;width bitmap
mov ebx,dword[esp+12] ;height bitmap
mov esi,dword[esp+16] ;pointer pixelstruct
movd xmm1,dword[esp+20] ;pointer textstruct
rdtsc ;timer sichern
push eax
;~ _asmdbg_() ;debugger
mov eax,ebx ;h
mul ecx ;w*h
mov edx,eax ;w*h
movd xmm0, edx ;sichern anzahl
;zuerst werden die Pixel durchlaufen, die Farbe jedes Pixels wird an der Speicherstelle seines "Farbwerts" hochgezählt
@pixel_count: ;alle pixel
mov eax,[edi] ;farbe
and eax,0xFFFFFF ;eliminieren alpha-channel
;~ _asmdbg_()
inc dword [esi+eax*4] ;farbwert=farbwert+1, address=colorRGB^^
;add dword [esi+eax*4],1 ;schneller?
add edi,4 ;nächste farbe
sub edx,1 ;pixelcounter
jnz near @pixel_count ;jump if not zero(<0)
;***********************************************************************************
;jetzt werden die gezählten Farbwerte nacheinander als Text in HEX-Darstellung und der Anzahl als Integerwert in eine textstruct geschrieben
;Format: 6BF1E5,1234567@crlf
movd xmm4,edi ;sichern pointer bitmap
mov edx,0x1000000 ;anzahl farben 0xFFFFFF +1
movd ebx,xmm1 ;pointer textstruct
mov edi,-4 ;pointer colorstruct
@count_colors:
sub edx,1 ;jedes pixel
; jz @end ;alle pixel durchlaufen
mov ecx,[esi+edx*4] ;ecx=anzahl, edx=farbwert; esi=pointer pixelstruct
cmp ecx,0
je @count_colors ;wenn ungleich null...ist farbe gefunden
;~ _asmdbg_()
;hex-werte farbe =6 Bytes
;aus den 6 nibbles die 6 bytes machen, nibble+48 (0x30) =ASCII-Ziffer
;zuerst aus den beiden bytes ( Bit 4444333322221111) die nibble erweitern zu 0000444400003333 und 0000222200001111
movd xmm3,eax ;sichern wg registerpressure
movd xmm4,edx ;aka push/pop
movd xmm5,esi
movd xmm6,ecx
mov eax,edx
mov edi,eax
;schneller ist natürlich eine LUT^^, aber so geht es auch
;**************************************************************
mov edx,0 ;6 nibbles
_int2hex:
mov ecx,20 ;5*4 shiften
lea esi,[4*edx] ;anzahl der zu shiftenden bits
sub ecx,esi ;ecx=20,ecx
shr eax,cl ;nach al shiften
and al,0xF ;obere 4 nibble eliminieren
cmp al,9 ;größer oder kleiner als A?
jle _groesserA
add al,7 ;A-F
_groesserA:
add al,48 ;1-9
mov byte[ebx+edx],al ;ascii-hexcode in struct
mov eax,edi
add edx,1
; _asmdbg_()
cmp edx,6 ;alle 6 nibble bearbeitet?
jne _int2hex
add ebx,edx ;ein zeichen (6 bytes) weiter
mov byte [ebx],44 ;komma
add ebx,1 ;ein zeichen weiter
mov edi,ebx ;pointer text
movd ebx,xmm6 ;anzahl integer
;************************************************************
;aus einer Zahl(Registerinhalt) einen ZiffernString machen: http://dcla.rkhb.de/umwandlung/int2dez.html
;und in die struct schreiben
push ebx ;alle benötigten Register sichern
push ecx ;alle benötigten Register sichern
mov eax, ebx ;Zahl laden
mov ebx, 10 ;Divisor
xor ecx, ecx ;ECX=0 (Anzahl der Ziffern)
Schleife_1:
xor edx, edx
div ebx ; EDX:EAX / EBX = EAX Rest EDX
push dx ; LIFO
add cl,1 ; ADD soll schneller sein als INC
or eax, eax ; AX = 0?
jnz Schleife_1 ; nein: nochmal
Schleife_2:
pop ax ; gepushte Ziffern zurückholen
or al, 00110000b ; Umwandlung in ASCII
stosb ; Nur AL nach [EDI] (EDI ist ein Zeiger auf den String)
loop Schleife_2 ; bis keine Ziffern mehr da sind
mov byte [edi],0Dh ;CR CarriageReturn, man könnte auch ein Komma (ascii=2C) einsetzen, dazu noch ein nullbyte als EndOfString
add edi,1 ;ein Byte weiter
pop ecx ;Register wiederherstellen
pop ebx ;Register wiederherstellen
;************************************************************Ende Ziffer aus Register
movd esi,xmm5
movd edx,xmm4 ;restaurieren
mov ebx,edi
cmp edx,0
jne @count_colors ;schleife alle farben
@end:
pop ebx
;rdtsc
sub eax,ebx
ret
#ce
_GDIPlus_Startup() ; Initialisiert (startet) Microsoft Windows GDI+
Global $ptr_bitmap, $hbmp, $iwidth, $iheight ;werden ByRef von _CreateNewBmp32FromFile ausgefüllt
; -------------------------------------
; Bitmapdatei zergliedert zur Verfügung stellen
If $sFile = "" Then
;$sFile = "rot1.bmp"
$sFile = FileOpenDialog("Zu untersuchende Bitmap-Datei", @ScriptDir, "Bilder (*.jpg;*.bmp;*.png)")
EndIf
$DC_bitmap = _CreateNewBmp32FromFile($sFile, $ptr_bitmap, $hbmp, $iwidth, $iheight)
; siehe D:\AU\Assembler\#FuncASS.au3
; -------------------------------------
; Die $colorstruct bereitstellen
$colorstruct = DllStructCreate("uint[" & 256 ^ 3 & "]");anzahl möglicher Farben
$ptr_colorstruct = DllStructGetPtr($colorstruct)
; -------------------------------------
; Die $textstruct bereitstellen.
$textstruct = DllStructCreate("char[" & 18 * $iwidth * $iheight & "]");maximale Anzahl Zeichen
$ptr_textstruct = DllStructGetPtr($textstruct)
;9 Stellen integer
;6 Stellen Hexdarstellung
;1 Stellen Komma
;2 Stellen CRLF
; -------------------------------------
; Bearbeitung durchführen
Select
Case $phase=1
;Protokoll("$phase1::"&$phase)
Local $ret = _AssembleIt2("uint", "_countpixelcolors", "ptr", $ptr_bitmap, _
"int_ptr", $iwidth, "int_ptr", $iheight, "int_ptr", $ptr_colorstruct, "int_ptr", $ptr_textstruct)
Auswerten($textstruct)
Case $phase=0
;Protokoll("$phase0::"&$phase)
$binarycode = "0x8B7C24048B4C24088B5C240C8B742410660F6E4C24140F315089D8F7E189C2660F6EC28B0725FFFFFF00FF048683C70483EA010F85EAFFFFFF660F6EE7BA00000001660F7ECBBFFCFFFFFF83EA018B0C9683F90074F5660F6ED8660F6EE2660F6EEE660F6EF189D089C7BA00000000B9140000008D34950000000029F1D3E8240F3C097E020407043088041389F883C20183FA0675D901D3C6032C83C30189DF660F7EF3535189D8BB0A00000031C931D2F7F3665280C10109C075F366580C30AAE2F9C6070D83C701595B660F7EEE660F7EE289FB83FA000F856DFFFFFF5B0F3129D8C3"
;Protokoll("$phase0::"&$phase)
Ausfuehren($binarycode)
Case $phase=2
;rotokoll("$phase2::"&$phase)
asmdbg(@ScriptLineNumber) ; Direktiven _asmdbg_() mit ";" versehen
$binarycode = _AssembleIt2("retbinary", "_countpixelcolors")
;rotokoll("$binarycode:..:"&$binarycode)
; Binären Assemblercode als Datei ausgeben:
$h=FileOpen("binarycode.txt",2)
FileWrite($h,StringMid($binarycode,3)) ; Ohne 0x
FileClose($h)
Ausfuehren($binarycode)
Case $phase=3
;Protokoll("$phase3::"&$phase)
$h=FileOpen("binarycode.txt")
$binarycode="0x"&FileRead($h)
FileClose($h)
Ausfuehren($binarycode)
EndSelect
MsgBox(0,"","Fertig",1)
;Protokoll("Exit")
Exit
;======================================================================
#cs ----------------------------------------------------------------------------
Erhält den durch die Assemblierung erzeugten Maschinencode $binarycode
und arbeitet diesen ab.
Als globale Variable müssen existiern:
- $ptr_bitmap Zeiger auf die Structur, welche die Bitmap-Daten enthält
- $iwidth Zeiger auf die Breite der Bitmap (Anzahl der Pixel-Spalten)
- $iheight Zeiger auf die Höhe der Bitmap (Anzahl der Pixel-Zeilen
- $ptr_colorstruct Zeiger auf Arbeitfeld (Structur) mit der Anzahl von
256^3 32-Bit-Integers, in welchem das Ass-Programm
die Farben zählt
- $ptr_textstruct Zeiger auf eine Structur, in welcher das Ass-Programm
das Ergebnis hinterlässt
#ce ----------------------------------------------------------------------------
Func Ausfuehren($binarycode)
;Protokoll("Ausführen >>>>")
$tCodeBuffer = DllStructCreate("byte[" & StringLen($binarycode) / 2 - 1 & "]") ;reserve Memory for opcodes
DllStructSetData($tCodeBuffer, 1, $binarycode)
$t = TimerInit()
; -----------
DllCallAddress("uint:cdecl", DllStructGetPtr($tCodeBuffer), _
"ptr", $ptr_bitmap, "int_ptr", $iwidth, "int_ptr", $iheight, _
"int_ptr", $ptr_colorstruct, "int_ptr", $ptr_textstruct)
; -----------
$m = TimerDiff($t)
; in der Structur $textstruct stehen nun die gefundenen Farben
; in der Form RRGGBB,Anzahl@LF
MsgBox(0, "Timer ASM picelcounter", "Within " & Int($m) & "ms " )
Auswerten($textstruct)
;Protokoll("Ausführen <<<<")
EndFunc
;======================================================================
#cs ----------------------------------------------------------------------------
Wertet das Ergebnis des Assemblerprogramms aus
#ce ----------------------------------------------------------------------------
Func Auswerten($textstruct)
;Protokoll("Auswerten >>>>")
$text = DllStructGetData($textstruct, 1)
$text = StringTrimRight($text, 1) ;letztes LF entfernen
$text = StringReplace($text, @CR, @CRLF) ;autoit is fast too^^
$number_colors = @extended + 1
;Protokoll("$number::"&$number_colors)
;Protokoll("$text:.:"&$text)
;Protokoll("Ausführen <<<<")
$colorarray = StringSplit($text, @LF)
Opt("WinTitleMatchMode", 2) ; 1=vom Anfang, 2=enthält, 3=genau, 4=fortgeschritten, -1 bis -4=Groß-/Klein ignorieren
WinSetState("SciTE","",@SW_HIDE )
Sleep(500)
_ArrayDisplay($colorarray,"$colorarray")
;Protokoll("Auswerten <<<<")
EndFunc
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#include-once
#cs ----------------------------------------------------------------------------
_CreateNewBmp32FromFile
asmdbg
Auswerten
#ce ----------------------------------------------------------------------------
;======================================================================
#cs ----------------------------------------------------------------------------
Zergliedert eine Bitmap-Datei
$bmpfile Pfad-/Dateiname der zue zergliedernden Datei
Hinterlässt:
$ptr Ponter auf das Pixelfeld der Datei. 4 Bytes je Pixel.
Beginnend mit dem linken oberen Pixel, zeielweise bis zum rechten unteren Pixel.
$hbmp Siehe: https://learn.microsoft.com/de-de/windows/win32/gdi/device-independent-bitmaps
$iwidth Breite der Bitmap, d.h. Anzahl Pixel pro Zeile
$iheight Höhe der Bitmap, d.h. Anzahl der Zeilen
#ce ----------------------------------------------------------------------------
#include <GDIPlus.au3>
Func _CreateNewBmp32FromFile($bmpfile, ByRef $ptr, ByRef $hbmp, ByRef $iwidth, ByRef $iheight) ;ptr to bitmapdata, it is possible to manipulate one pixel if needed
;Protokoll("_CreateNewBmp32FromFile >>>>")
Local $hbitmap, $hdc, $hcdc
$hbitmap = _GDIPlus_ImageLoadFromFile($bmpfile)
If @error Or $hbitmap = 0 Then
MsgBox(0, "Func _CreateNewBmp32FromFile()", "Error opening File: " & @CRLF & $bmpfile)
;Protokoll("_CreateNewBmp32FromFile <<<<")
Return -1
EndIf
$hbmpfile = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hbitmap)
$iwidth = _GDIPlus_ImageGetWidth($hbitmap)
$iheight = _GDIPlus_ImageGetHeight($hbitmap)
$hcdc = _WinAPI_CreateCompatibleDC(0)
_WinAPI_SelectObject($hcdc, $hbmpfile) ;image im hcdc
;neue bitmap
$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
$hdc = _WinAPI_CreateCompatibleDC(0)
_WinAPI_SelectObject($hdc, $hbmp) ;leere bitmap im hdc
_WinAPI_BitBlt($hdc, 0, 0, $iwidth, $iheight, $hcdc, 0, 0, $srccopy);image in leere bitmap
_WinAPI_DeleteDC($hcdc)
_WinAPI_DeleteObject($hbmpfile)
;Protokoll("_CreateNewBmp32FromFile <<<<")
Return $hdc ;DC der Bitmap zurückgeben
EndFunc ;==>_CreateNewBmp32FromFile
;======================================================================
#cs ----------------------------------------------------------------------------
Sucht den letzten Abschnitt mit Assemblercodse #cs .... #ce vor diesem
Funktionsaufruf auf und stellt im Assemblercode den Direktiven _asmdbg_()
ein Semikolon voran.
Als $number ist @ScriptLineNumber einzutragen. Das heißt, der Aufruf muss
immer so aussehen:
asmdbg(@ScriptLineNumber)
#ce ----------------------------------------------------------------------------
Func asmdbg($number)
;Protokoll("asmdbg >>>>")
$script=@ScriptFullPath
; -------------------------------------
; Scrip-Datei in Array $linearr einlesen
$lineanz=0
Local $linearr[$lineanz]
$h=FileOpen($script)
While 1
$line=FileReadLine($h)
If @error=-1 Then ExitLoop ; Dateiende
;Protokoll("$line::"&$line)
ReDim $linearr[$lineanz+1]
$linearr[$lineanz]=$line
$lineanz+=1
WEnd
FileClose($h)
;_ArrayDisplay($linearr)
; -------------------------------------
; Assemblerabschnitt suchen
$csx=-1
$cex=-1
$ass=0 ; d.h. außerhalb Kommentarabschnitt
For $i=0 To $number
;Protokoll("$i:.:"&$i)
;Protokoll("$linearr[$i]:.:"&$linearr[$i])
Select
Case StringInStr($linearr[$i],"#cs")
If $ass=1 Then Fehler("Zwei #cs folgen aufeinander - Zeile "&$i)
;If $cex<>-1 Then Fehler("Zwei #cs folgen aufeinander - Zeile "&$i
$csx=$i
$ass=1 ; d.h. innerhalb Kommentarabschnitt
Case StringInStr($linearr[$i],"#ce")
If $ass=0 Then Fehler("Vor #ce kein #cs gefunden - Zeile "&$i)
$cex=$i
$ass=0 ; d.h. Assemblerabschnitt beendet
EndSelect
Next
If $csx=-1 OR $cex=-1 Then Fehler("Keinen Assemblercode gefunden - Zeile "&$i)
If $cex<$csx Then Fehler("Kommentarabschnitt endet nicht - Zeile "&$csx)
; -------------------------------------
; Array $linearr in Hilsdatei ausgeben und dabei die _asmdbg_() mit ";" versehen
$hh=FileOpen("hilf.au3",2)
For $i=0 To $lineanz-1
If $i>$csx AND $i<$cex Then
$pos=StringInStr($linearr[$i],"_asmdbg_()")
If $pos Then ; _asmdbg_() gefunden
$po=StringInStr($linearr[$i],";",0,1,1,$pos)
If $po=0 Then ; es gibt noch kein ";"
If Stringleft($linearr[$i],1)<>" " Then
$linearr[$i]=";"&$linearr[$i]
Else
$linearr[$i]=";"&StringMid($linearr[$i],2)
EndIf
EndIf
EndIf
EndIf
FileWriteLine($hh,$linearr[$i])
Next
FileClose($hh)
;MsgBox(0,"","111")
FileCopy("hilf.au3",$script,1)
;MsgBox(0,"","222")
$sciteExe="C:\Program Files (x86)\AutoIt3\SciTE\SciTE.exe"
Run($sciteExe&" "&$script)
Opt("WinTitleMatchMode", 2) ; 1=vom Anfang, 2=enthält, 3=genau, 4=fortgeschritten, -1 bis -4=Groß
While 1
Sleep(100)
WinActivate(@ScriptName)
If WinActive(@ScriptName) Then Exitloop
WEnd
;Protokoll("asmdbg <<<<")
EndFunc
;-----------------
Func Fehler($text)
MsgBox(0,"",$text)
Exit
EndFunc
;-----------------
Alles anzeigen

