Alles Gute!
Danke für deine großartige Arbeit!
Alles Gute!
Danke für deine großartige Arbeit!
Wenn du in FreeBasci ZString Ptr verwendest, dann kannst du in AutoIt als Typ "str" verwenden ohne _GetStringFromPointer.
Hahaha!
Das ist wieder mal typisch für mich
Hier also die einfache Lösung :
Extern "Windows-MS"
Function Text()As ZString Ptr Export
Return @"Text"
End Function
End Extern
$hDll = DllOpen("Test.dll")
[/autoit][autoit][/autoit][autoit]$aResult = DllCall($hDll, "str", "Text")
MsgBox(0, "", $aResult[0])
Ich mach das meistens so:
Extern "Windows-MS"
Function Text(zText As ZString Ptr)As UInteger Export
*zText = "Text"
Return Len(*zText)
End Function
End Extern
$hDll = DllOpen("Test.dll")
$tText = DllStructCreate("char[256];")
$aResult = DllCall($hDll, "uint", "Text", "ptr", DllStructGetPtr($tText))
MsgBox(0, "", "Text: " & DllStructGetData($tText, 1) & @CRLF & "Len: " & $aResult[0])
E
Edit: Alternativ hätte ich ncoh diese Lösung anzubieten:
Extern "Windows-MS"
Function Text()As ZString Ptr Export
Return @"Text"
End Function
End Extern
$hDll = DllOpen("Test.dll")
[/autoit][autoit][/autoit][autoit]$aResult = DllCall($hDll, "ptr", "Text")
MsgBox(0, "", _GetStringFromPointer($aResult[0]))
Func _GetStringFromPointer($pPtr)
Local $aResult = DllCall("kernel32.dll", "int", "lstrlen", "ptr", $pPtr)
If @error Or Not IsArray($aResult) Then Return SetError(1, 1, False)
Local $iLen = $aResult[0]
Local $tString = DllStructCreate("char[" & ($iLen + 1) & "];", $pPtr)
Return DllStructGetData($tString, 1)
EndFunc
Aber es darf nicht dahin laufen, dass einfach das halbe Englische Wörterbuch (teils auch noch Sinnentfremdet) in den Deutschen Duden aufgenommen wird.
Manchmal gefallen mir die englischen Bezeichnungen aber besser.
Der beste Hörpunkt in einer 5.1-Anlage heißt im Deutschen Referenzhörpunkt, die englische (und auch im Deutschen verwendete) Bezeichnung lautet Sweetspot.
Referenzhörpunkt klingt eher wie eine uralte Kohlemikroaufnahme aus den 30ern
Weiters interessiert sich heute auch keiner mehr, dass z.B.: Kekse ursprünglich aus dem englischen stammen.
Ahhh, Kekse *sabber*
Update im ersten Post
und zwar ein Multithreading-Beispiel für Fortgeschrittene
Die Sourcecodes und die vorkomilierten Dll´s sind im Anhang in GreyScale.zip
E
Beim Experimentieren mit AutoIt Beta 3.3.9.5 hab ich zufällig bemerkt, dass man die einzelnen Elemente einer Struct folgendermaßen ansprechen kann:
[autoit]$tStruct = DllStructCreate("int X;")
$tStruct.X = 12
Auch der Zugriff auch den SubIndex ist möglich, allerdings nur hardcoded, wie folgendes Beispiel zeigt:
[autoit]
$tStruct = DllStructCreate("int X; int Y; int Z; int A[4];")
$tStruct.X = 12
$tStruct.Y = 34
$tStruct.X += 1
$tStruct.Z = $tStruct.X + $tStruct.Y
ConsoleWrite("+ " & $tStruct.X & " + " & $tStruct.Y & " = " & $tStruct.Z & @CRLF)
[/autoit][autoit][/autoit][autoit][/autoit][autoit]For $i = 1 To 4
$tStruct.A($i) = $i ;not working
ConsoleWrite("! " & DllStructGetData($tStruct, "A", $i) & @CRLF)
Next
$tStruct.A(1) = 11
$tStruct.A(2) = 22
$tStruct.A(3) = 33
$tStruct.A(4) = 44
For $i = 1 To 4
ConsoleWrite("+ " & DllStructGetData($tStruct, "A", $i) & @CRLF)
Next
Das wäre für mich eine der wichtigsten und besten Neuerungen gewesen, die eine neue AutoIt Version mit sich gebracht hätte, aber...
nun bin ich auf das hier gestossen: http://www.autoitscript.com/trac/autoit/ticket/2220
Bedeuted das nun, dass ich meine Freude gleich wieder dämpfen kann und dieses Feature etwa doch nicht umgesetzt wird?!
Weiß jemand mehr?
E
Das das so funktioniert, hab ich gar nicht gewusst
Dennoch ist es einfacher ohne ByRef zu arbeiten und in FB die Pointerschreibweise zu benutzen, dann behält man besser den Überblick - zumindest ich
Type testtype
x1 AS DOUBLE
x2 AS DOUBLE
x3 AS DOUBLE
x4 AS DOUBLE
END Type
Extern "Windows-MS"
SUB f_inTest(BYVAL y1 AS DOUBLE, BYVAL y2 AS DOUBLE, BYVAL y3 AS DOUBLE, BYVAL y4 AS DOUBLE, ByVal z AS testtype Ptr) Export
z->x1 = y1 + 1
z->x2 = y2 + 1
z->x3 = y3 + 1
z->x4 = y4 + 1
'RETURN z
END Sub
SUB f_Test(ByVal z1 As testtype Ptr, ByVal z2 AS testtype Ptr) Export
z2->x1 = z1->x1 - 1
z2->x2 = z1->x2 - 1
z2->x3 = z1->x3 - 1
z2->x4 = z1->x4 - 1
'RETURN z2
END Sub
END Extern
Alles anzeigen
Oder via RegExp:
[autoit]StringRegExpReplace($sScript, '(?x)(?:\r?\n?\s*;.*)|' & '((?>"[^"]*")+|' & "(?>'[^']*')+)", "\1")
[/autoit]bzw. um alle Kommentare aus dem kompletten Code zu entfernen:
[autoit]Func _RemoveComments(ByRef $sScript)
$sScript = StringRegExpReplace($sScript, '(?x)(?:\r?\n?\s*;.*)|' & '((?>"[^"]*")+|' & "(?>'[^']*')+)", "\1") ;entferne ;-Komments
$sScript = StringRegExpReplace($sScript, '(?i)(?:[\r\n]\s*)(\#ce|\#comments-end)(.*)', '$1') ;manche #ce haben noch Text dahinter
$sScript = StringRegExpReplace($sScript, '(?x)(?:\r?\n?\s*;.*)|(?s)\r?\n?\s*\#c(?>s|omments-start)(?>(?>"[^"]*")+|' & "(?>'[^']*')+|.)*?\#c(?>e|omments-end)(?-s)|" & '((?>"[^"]*")+|' & "(?>'[^']*')+)", "\1")
EndFunc ;==>_RemoveComments
Hier bitte:
#include <GDIPlus.au3>
[/autoit] [autoit][/autoit] [autoit]_GDIPlus_Startup()
Global $hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\Test.gif")
_ExtractFrames($hImage)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_Shutdown()
ShellExecute(@ScriptDir & "\AllFrames.bmp")
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]Func _ExtractFrames($hImage)
Local $iImgW = _GDIPlus_ImageGetWidth($hImage)
Local $iImgH = _GDIPlus_ImageGetHeight($hImage)
Local $iImgF = _GDIPlus_ImageGetPixelFormat($hImage)
Local $aResult = DllCall($ghGDIPDll, "uint", "GdipImageGetFrameDimensionsCount", "hwnd", $hImage, "uint*", 0)
If @error Then Return SetError(1, 1, False)
Local $iDim = $aResult[2]
Local $tDim = DllStructCreate("byte[" & $iDim * 16 & "];")
$aResult = DllCall($ghGDIPDll, "uint", "GdipImageGetFrameDimensionsList", "hwnd", $hImage, "ptr", DllStructGetPtr($tDim), "int", $iDim)
If @error Then Return SetError(1, 2, False)
Local $iFramesMax = 0
For $i = 1 To $iDim
$aResult = DllCall($ghGDIPDll, "uint", "GdipImageGetFrameCount", "hwnd", $hImage, "ptr", DllStructGetPtr($tDim) + ($i - 1) * 16, "uint*", 0)
If @error Then Return SetError(1, 2, False)
If $aResult[3] > $iFramesMax Then $iFramesMax = $aResult[3]
Next
Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iImgW * $iFramesMax, "int", $iImgH * $iDim, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0)
If @error Then Return SetError(1, 1, False)
Local $hBitmap = $aResult[6]
Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)
Local $iFrames, $hBmpFrame
For $i = 1 To $iDim
$aResult = DllCall($ghGDIPDll, "uint", "GdipImageGetFrameCount", "hwnd", $hImage, "ptr", DllStructGetPtr($tDim) + ($i - 1) * 16, "uint*", 0)
If @error Then Return SetError(1, 2, False)
$iFrames = $aResult[3]
For $j = 1 To $iFrames
DllCall($ghGDIPDll, "uint", "GdipImageSelectActiveFrame", "hwnd", $hImage, "ptr", DllStructGetPtr($tDim) + ($i - 1) * 16, "uint", $j - 1)
$hBmpFrame = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iImgW, $iImgH, $iImgF)
_GDIPlus_ImageSaveToFile($hBmpFrame, @ScriptDir & "\Frame_" & StringFormat("%03s", $i) & "-" & StringFormat("%03s", $j) & ".bmp")
_GDIPlus_GraphicsDrawImageRect($hContext, $hBmpFrame, ($j - 1) * $iImgW, ($i - 1) * $iImgH, $iImgW, $iImgH)
[/autoit] [autoit][/autoit] [autoit]_GDIPlus_BitmapDispose($hBmpFrame)
Next
Next
_GDIPlus_GraphicsDispose($hContext)
_GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\AllFrames.bmp")
_GDIPlus_BitmapDispose($hBitmap)
EndFunc ;==>_ExtractFrames
E
Dafür sind die "|" da - du kannst ganz einfach StringSplit verwenden:
[autoit]$aSplit = StringSplit($aRow[$i], "|")
[/autoit]Schau dir mal die Funktion _Load in meinem Script an
E
Läuft dein AutoIt Script im 64Bit Modus?
Probiers mal mit:
#AutoIt3Wrapper_UseX64=n
[/autoit]E
In dem Beispiel <Rotating Cube 2 + Textures.au3> von UEZ findest du die Funktion Load_BMP_From_Mem:
GDI+ Rotating Cubes
E
Ich hab hier mal ein rudimentäres Tutorial zusammengeklopft, welches zeigen soll, wie man in FreeBasic eine Dll für AutoIt erstellt.
Dieses Tutorial richtet sich in erster Linie an all diejenigen, die mit AutoIt begonnen haben zu programmieren und nun so langsam an die Geschwindigkeitsgrenze von AutoIt stoßen.
Ich habe mich für FreeBasic entschieden, weil es Free ist, eine ähnliche Syntax wie AutoIt hat, sehr klein und ohne unnötige Extras daherkommt und bei zahlreichen Test kleinere und schnellere Dll´s gezaubert hat als andere Compiler.
Wer AutoIt beherscht sollte damit relativ leicht zurechtkommen!
Einrichten von FreeBasic:
Zunächst benötigen wir den Compiler, welcher u.a. hier zu finden ist: http://www.freebasic-portal.de/downloads/aktu…indows-199.html
Als Editor verwende ich FBEdit: http://www.freebasic-portal.de/downloads/ides…dit-ide-30.html
EDIT: Dank BugFix kann man nun auch SciTE als Editor verwenden: FreeBasic läßt sich auch rudimentär in SciTE einbinden
1) FreeBasic installieren:
Einfach FreeBASIC-0.23.0-win32.exe ausführen und den Anweisungen folgen
2) FBEdit.zip in den FreeBasic-Ordner enpacken (z.B.: C:\Programme\FreeBASIC\FbEdit)
3) FBEdit starten:
Beim ersten Start muss man die Pfade eingeben:
Compiler Path: C:\Programme\FreeBASIC
Help Path: C:\Programme\FreeBASIC\FbEdit\Help
Activate FbEdit Lite for beginners mit "Nein" beantworten.
4) Hilfe einrichten:
Um die Hilfe in FbEdit benutzen zu können, muss noch das hier geladen werden: http://www.freebasic-portal.de/downloads/refe…0-23-0-198.html
Nach dem Entpacken in FB.chm umbenennen und in den Hilfe-Ordner kopieren.
Ich selber habe noch "win32.hlp" im Hilfe-Ordner liegen
Diese 4 Hilfen (FB.chm, FbEdit.chm, Windows_Styles.chm u win32.hlp) sind standartmässig bereits eingetragen und können via Options-Help Menu editiert werden
Erstellen einer DLL:
1) FbEdit starten
2) File - New Project
3) Project Name und Description eingeben
4) "Project Type" = "Windows dll" auswählen und OK klicken
5) Folgenden Code ins Editorfenster eintippen:
Extern "Windows-MS"
Function _Add(iX As Integer, iY As Integer)As Integer Export
Return iX + iY
End Function
End Extern
6) Make - Compile im Menü aufrufen oder F5 drücken
Fertig ist die erste Dll
Zum testen benötigen wir noch ein AutoIt-Script:
[autoit]$hDll = DllOpen("Add.dll")
$aResult = DllCall($hDll, "int", "_Add", "int", 1234, "int", 1234)
ConsoleWrite("Ergebnis = " & $aResult[0] & @CRLF)
Kurze Beschreibung der DLL:
Funktionen, welche man mit AutoIt aufrufen möchte, sollten zwischen <Extern "Windows-MS"> und <End Extern> stehen
Dadurch kann man die Funktionen dann mit demselben Namen aufrufen, wie er im Editor auch angegeben ist.
Andernfalls müsste man bei DllCall "_ADD@8" schreiben, und sollte man 3 Parameter übergeben dann: "_ADD@12", bei 4 "_ADD@16" usw...
Die Funktion selber sollte eigentlich selbserklärend sein.
Für jeden Parameter und auch den Rückgabewert muss man einen Datentyp angeben (As Integer)
Das "Export" am Ende der Zeile macht die Funktion "nach aussen hin sichtbar" und muss nur für Funktionen angegeben werden, welche man direkt via AutoIt aufrufen möchte.
Parameter können auch ByRef übergeben werden.
Das funktioniert ungefähr so:
Extern "Windows-MS"
Sub _ByRef(iX As Integer, iY As Integer, ByRef iZ As Integer) Export
iZ = iX + iY
End Sub
End Extern
$hDll = DllOpen("ByRef.dll")
$aResult = DllCall($hDll, "none", "_ByRef", "int", 1234, "int", 1234, "int*", 0)
ConsoleWrite("+ Ergebnis = " & $aResult[3] & @CRLF)
Hier noch ein kurzes Beispiel, wie man den Inlineassembler von FreeBasic benutzt:
Extern "Windows-MS"
Function _ASM_ADD(iX As Integer, iY As Integer)As Integer Export
Dim As Integer iZ
Asm
mov eax, [iX]
mov ebx, [iY]
Add eax, ebx
mov [iZ], eax
End Asm
Return iZ
End Function
End Extern
Alles anzeigen
$hDll = DllOpen("ASM.dll")
$aResult = DllCall($hDll, "int", "_ASM_ADD", "int", 1234, "int", 1234)
ConsoleWrite("+ Ergebnis = " & $aResult[0] & @CRLF)
Verwenden von Arrays:
Um eine große Anzahl von Daten an die Dll zu übergeben bzw. zu erhalten, erstellt man in AutoIt zunächst eine DllStruct und deren Pointer wird an die Dll übergeben.
Beispiel:
2 Arrays vom Typ integer und Singlefloat mit jeweils 100 Einträgen werden benötigt:
In AutoIt erstellt man nun eine DllStruct:
$tStruct = DllStructCreate("int X[100]; float Y[100];")
[/autoit]
In FreeBasic muss man zunächst einen Type definieren, damit der Compiler weiß wie die Daten im Speicher liegen:
Type t_Struct
X(1 To 100) As Integer
Y(0 To 99) As Single
End Type
Sub _Test(pStruct As t_Struct Ptr)
(Hier kann man je nach belieben 1-100 oder 0-99 verwenden)
Der Parameter heisst hier pStruct und ist ein Pointer zu einem Speicherbereich in welchem die Daten lt. t_Struct liegen.
Wie man nun damit arbeitet, soll folgendes Beispiel zeigen:
Type t_CircleData
iMX As Integer
iMY As Integer
aX(0 To 359) As Single
aY(0 To 359) As Single
End Type
Public Const Pi = 3.14159265358979
Public Const Deg2Rad = Pi / 180
Extern "Windows-MS"
Sub _Circle(iX As Integer, iY As Integer, iR As Integer, tCirlce As t_CircleData Ptr) Export
Dim As Single fRad
For i As UInteger = 0 To 359
fRad = i * Deg2Rad
tCirlce->aX(i) = Cos(fRad) * iR + iX
tCirlce->aY(i) = Sin(fRad) * iR + iY
Next
tCirlce->iMX = iX
tCirlce->iMY = iY
End Sub
End Extern
Alles anzeigen
$tCircle = DllStructCreate("int iMX; int iMY; float aX[360]; float aY[360];")
$pCircle = DllStructGetPtr($tCircle)
$hDll = DllOpen("Array.dll")
DllCall($hDll, "none", "_Circle", "int", 400, "int", 400, "int", 180, "ptr", $pCircle)
For $i=1 To 360
$iX = DllStructGetData($tCircle, "aX", $i)
$iY = DllStructGetData($tCircle, "aY", $i)
MouseMove($iX, $iY, 1)
ConsoleWrite($iX & " " & $iY & @CRLF)
Next
Am Schluss noch ein paar Infos:
Wenn man die Datei mit der Endung .fbp mit einem normalen Text-Editor öffnet, dann kann man die Compileroptionen verändern:
Die Zeile sieht in unseren Beispielen so aus:
1=Windows dll,fbc -s gui -dll -export
Wir fügen nun -R hinzu:
1=Windows dll,fbc -s gui -dll -export -R
Wenn wir die Datei nun mit FbEdit öffnen und neu kompilieren, dann entsteht eine neue Datei mit der Endung .asm
Darin finden wir unsere Funktionen als Assembler Code und das kann manchmal ganz nützlich sein.
Die Parameter -fpmode FAST -fpu SSE legen in bestimmten Fällen noch den Turbo ein.
Wenn die Dll fertig ist, dann am besten 2mal komiplieren, einmal ohne und einmal mit diesen Parametern; und überprüfen welche Version schneller ist
(bei einer meinen Tests konnte ich so eine Funktion von etwa 600ms auf 450ms beschleunigen)
Das wars für´s Erste mal...
Bei Interesse an weiteren, spezielleren Beispielen (z.B.: Bildbearbeitung) einfach melden.
Im Anhang sind noch alle obigen Beispiele als Quallcode und comiliert
EDIT 1
Hier zwei Beispiele für Fortgeschrittene:
Anhand eines einfachen Greyscale-Algorithmuses zeige ich hier, wie man in FreeBasic Multithreading realisiert:
GreyScale.bas:
Type t_Param
pPixelData As UInteger Ptr
iPixelCnt As Integer
End Type
Sub _GreyScaleFunc(pParam As t_Param Ptr)
Dim As UByte Ptr pARGB
Dim As UByte iLuma
For i As UInteger = 0 To pParam->iPixelCnt -1
pARGB = @pParam->pPixelData[i]
'Luma = BlauAnteil * 0.11 + GrünAnteil * 0.59 + RotAnteil * 0.3
iLuma = (pARGB[0] * 0.11) + (pARGB[1] * 0.59) + (pARGB[2] * 0.3)
pARGB[0] = iLuma
pARGB[1] = iLuma
pARGB[2] = iLuma
Next
End Sub
Extern "Windows-MS"
Sub _GreyScale(pPixelData As UInteger Ptr, iPixelCnt As Integer) Export
Dim As t_Param tParam(0 To 3)
Dim As Integer iPixel_4 = iPixelCnt / 4
'Einer Threadfunktion kann man nur einen Pointer übergeben, deshalb erstellen wir 4 Variablen vom Typ t_Param und befüllen diese mit den entsprechenden Werten
For i As UInteger = 0 To 3
tParam(i).pPixelData = pPixelData + (iPixel_4 * i) ' Startposition des ersten zu berechnenden Pixels
tParam(i).iPixelCnt = iPixel_4 ' Anzahl der Pixel pro Thread
Next
Dim As Any Ptr pThread(0 To 3)
For i As Integer = 0 To 3
If i = 2 Then Continue For ' zu Testzwecken: 3 Thread überspringen
pThread(i) = ThreadCreate(@_GreyScaleFunc, @tParam(i)) 'starte Threads
Next
For i As Integer = 0 To 3
ThreadWait(pThread(i)) 'warten bis alle Threads fertig
Next
End Sub
End Extern
Alles anzeigen
Und das dazugehörige AutoIt Script zum Testen:
#include <GDIPlus.au3>
[/autoit] [autoit][/autoit] [autoit]Global $sPath = FileOpenDialog("open image", "", "(*.jpg;*.bmp;*.png;*.tif;*.gif)")
If @error Or Not FileExists($sPath) Then Exit
_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]Global $hImage = _GDIPlus_ImageLoadFromFile($sPath)
Global $aData = _CreatePixelData($hImage)
_GDIPlus_ImageDispose($hImage)
Global $hDll = DllOpen(@ScriptDir & "\GreyScale.dll")
Global $iTimer = TimerInit()
DllCall($hDll, "none", "_GreyScale", "ptr", $aData[0], "int", $aData[3] * $aData[4])
Global $iTime = TimerDiff($iTimer)
ConsoleWrite(@error & " " & @extended & @CRLF)
_GDIPlus_ImageSaveToFile($aData[2], @ScriptDir & "\GreyScale.bmp")
[/autoit] [autoit][/autoit] [autoit]_DisposePixelData($aData)
_GDIPlus_Shutdown()
DllClose($hDll)
MsgBox(0, "Fertig", "GreyScale fertig in : " & Round($iTime, 3) & "ms" & @CRLF & " 3 Thread wurde übersprungen, deshalb ist das fertige Bild nicht komplett im Grauton!")
ShellExecute(@ScriptDir & "\GreyScale.bmp")
Func _CreatePixelData($hImage)
Local $iImgW = _GDIPlus_ImageGetWidth($hImage)
Local $iImgH = _GDIPlus_ImageGetHeight($hImage)
Local $tPixelData = DllStructCreate("uint[" & $iImgW * $iImgH & "];")
[/autoit] [autoit][/autoit] [autoit]Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iImgW, "int", $iImgH, "int", $iImgW * 4, "int", 0x0026200A, "ptr", DllStructGetPtr($tPixelData), "int*", 0)
If @error Then Return SetError(1, 1, False)
Local $hBitmap = $aResult[6]
Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)
_GDIPlus_GraphicsDrawImageRect($hContext, $hImage, 0, 0, $iImgW, $iImgH)
_GDIPlus_GraphicsDispose($hContext)
Local $aReturn[5]
$aReturn[0] = DllStructGetPtr($tPixelData)
$aReturn[1] = $tPixelData
$aReturn[2] = $hBitmap
$aReturn[3] = $iImgW
$aReturn[4] = $iImgH
Return $aReturn
EndFunc ;==>_CreatePixelData
Func _DisposePixelData(ByRef $aData)
If Not IsArray($aData) Then Return
_GDIPlus_BitmapDispose($aData[2])
$aData[1] = 0
$aData = 0
EndFunc ;==>_DisposePixelData
Hier derselbe Algo, allerdings in Assembler:
Sub ASM_GREYSCALE(iAddr As UInteger, iPixels As UInteger)
Dim As UInteger iCnt, iMod
iMod = iPixels Mod 4
iCnt = iPixels - iMod
Asm
jmp .GS_Start
.align 16
_GS_11: .float 0.11, 0.11, 0.11, 0.11
_GS_59: .float 0.59, 0.59, 0.59, 0.59
_GS_3: .float 0.3, 0.3, 0.3, 0.3
_GS_Blue: .long 255, 255, 255, 255
.GS_Start:
mov edi,dword[iAddr] 'Startadress Bitmapdata (Pixel)
mov ecx,dword[iCnt] 'number of Pixel
movaps xmm7, [_GS_11]
movaps xmm6, [_GS_59]
movaps xmm5, [_GS_3]
movaps xmm4, [_GS_Blue]
.align 16
.GS_Loop: 'until ecx=0
movdqu xmm0,[edi] 'load 4 pixels to xmm0
movdqa xmm3, xmm0 'Pixels to xmm3
Pand xmm3, xmm4 'And 000000FF
cvtdq2ps xmm3, xmm3 'Int To Float
movdqa xmm2, xmm0 'Pixels to xmm2
PSRLD xmm2, 8 'Green
Pand xmm2, xmm4 'And 000000FF
cvtdq2ps xmm2, xmm2 'Int To Float
movdqa xmm1, xmm0 'Pixels to xmm1
PSRLD xmm1, 16 'Red
Pand xmm1, xmm4 'And 000000FF
cvtdq2ps xmm1, xmm1 'Int To Float
PSRLD xmm0, 24 'Alpha
'Pand xmm0, xmm4 'And 000000FF
PSLLD xmm0, 24 'Alpha
'7=0.11 6=0.59 5=0.3 4=BlueMask 3=Blue 2=Green 1=Red 0=Alpha
mulps xmm3, xmm5 'Blue * 0.11
mulps xmm2, xmm6 'Green * 0.59
mulps xmm1, xmm7 'Red * 0.3
addps xmm3, xmm2 'Blue + Green
addps xmm3, xmm1 'BlueGreen + Red
CVTPS2DQ xmm3, xmm3 'float to int
Pand xmm3, xmm4 'And 000000FF
movdqa xmm2, xmm3
PSLLD xmm2, 8
por xmm3, xmm2 'Luma to 0000FF00
movdqa xmm1, xmm3
PSLLD xmm1, 16
por xmm3, xmm1 'Luma to 00FF0000
por xmm3, xmm0 'Alpha to FF000000
movdqu [edi], xmm3 'write 4 pixels
Add edi,16 'address next pixel: 4 Byte = 1 dword = 1 Pixel
Sub ecx,4 'counter (next pixel)
ja .GS_Loop 'until ecx=0
mov eax, [iMod] 'Falls Pixelanzahl nicht durch 4 teilbar, dann hier restliche Pixel berechnen:
cmp eax, 0
je .GS_End
shl eax, 2 'mal 4
Add edi, eax 'letzter Pixel
Sub edi, 16 'minus 4 Pixel
Xor eax, eax 'Reset
mov [iMod], eax 'Reset iMod
jmp .GS_Loop 'Nochmals Loop für die letzten 4 Pixel (evtl. werden Pixel doppelt berechnet, aber der Geschwindigkeitsvorteil überwiegt)
.GS_End:
End Asm
End Sub
Extern "Windows-MS"
Sub _GreyScale(pPixelData As UInteger Ptr, iPixelCnt As Integer) Export
ASM_GREYSCALE(pPixelData, iPixelCnt)
End Sub
End Extern
Alles anzeigen
#include <GDIPlus.au3>
[/autoit] [autoit][/autoit] [autoit]Global $sPath = FileOpenDialog("open image", "", "(*.jpg;*.bmp;*.png;*.tif;*.gif)")
If @error Or Not FileExists($sPath) Then Exit
_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]Global $hImage = _GDIPlus_ImageLoadFromFile($sPath)
Global $aData = _CreatePixelData($hImage)
_GDIPlus_ImageDispose($hImage)
Global $hDll = DllOpen(@ScriptDir & "\GreyScale.dll")
Global $iTimer = TimerInit()
DllCall($hDll, "none", "_GreyScale", "ptr", $aData[0], "int", $aData[3] * $aData[4])
Global $iTime = TimerDiff($iTimer)
ConsoleWrite(@error & " " & @extended & @CRLF)
_GDIPlus_ImageSaveToFile($aData[2], @ScriptDir & "\GreyScale.bmp")
[/autoit] [autoit][/autoit] [autoit]_DisposePixelData($aData)
_GDIPlus_Shutdown()
DllClose($hDll)
MsgBox(0, "Fertig", "GreyScale fertig in : " & Round($iTime, 3) & "ms")
ShellExecute(@ScriptDir & "\GreyScale.bmp")
Func _CreatePixelData($hImage)
Local $iImgW = _GDIPlus_ImageGetWidth($hImage)
Local $iImgH = _GDIPlus_ImageGetHeight($hImage)
Local $tPixelData = DllStructCreate("uint[" & $iImgW * $iImgH & "];")
[/autoit] [autoit][/autoit] [autoit]Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iImgW, "int", $iImgH, "int", $iImgW * 4, "int", 0x0026200A, "ptr", DllStructGetPtr($tPixelData), "int*", 0)
If @error Then Return SetError(1, 1, False)
Local $hBitmap = $aResult[6]
Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)
_GDIPlus_GraphicsDrawImageRect($hContext, $hImage, 0, 0, $iImgW, $iImgH)
_GDIPlus_GraphicsDispose($hContext)
Local $aReturn[5]
$aReturn[0] = DllStructGetPtr($tPixelData)
$aReturn[1] = $tPixelData
$aReturn[2] = $hBitmap
$aReturn[3] = $iImgW
$aReturn[4] = $iImgH
Return $aReturn
EndFunc ;==>_CreatePixelData
Func _DisposePixelData(ByRef $aData)
If Not IsArray($aData) Then Return
_GDIPlus_BitmapDispose($aData[2])
$aData[1] = 0
$aData = 0
EndFunc ;==>_DisposePixelData
lg
E
Extern "Windows-MS"
Function _Add(iX As Integer, iY As Integer)As Integer Export
Return iX + iY
End Function
End Extern
$hDll = DllOpen("Add.dll")
$aResult = DllCall($hDll, "int", "_Add", "int", 1234, "int", 1234)
ConsoleWrite("Ergebnis = " & $aResult[0] & @CRLF)
Ohne Extern "Windows-MS" müsste man den DllCall so machen: _ADD@8
Oder in deinem Fall ADDIEREN@8
E
Wie name22 schon sagte:
DllStructCreate und den Pointer übergeben:
$hDll = DllOpen(@ScriptDir & "\Test.dll")
[/autoit] [autoit][/autoit] [autoit]$tTestStruct = DllStructCreate("int iInteger; char sString[64]; float fFloat; double fDouble;")
[/autoit] [autoit][/autoit] [autoit]DllCall($hDll, "none", "_Test", "ptr", DllStructGetPtr($tTestStruct))
DllClose($hDll)
ConsoleWrite("! Integer: " & DllStructGetData($tTestStruct, "iInteger") & @CRLF)
ConsoleWrite("! String: " & DllStructGetData($tTestStruct, "sString") & @CRLF)
ConsoleWrite("! Single: " & DllStructGetData($tTestStruct, "fFloat") & @CRLF)
ConsoleWrite("! Double: " & DllStructGetData($tTestStruct, "fDouble") & @CRLF)
Die Dll sieht dann so aus:
Type t_TestStruct
iInteger As Integer
sString As ZString * 64
fFloat As Single
fDouble As Double
End Type
Extern "Windows-MS"
Sub _Test(ByVal pTest As t_TestStruct Ptr) Export
pTest->iInteger = 1234
pTest->sString = "1234"
pTest->fFloat = 1234.1234
pTest->fDouble = 1234.1234
End Sub
End Extern
Alles anzeigen
Übrigens: Extern "Windows-MS" erleichtert das Aufrufen der Funktionen sehr.
E
Eine neuere Lame Version hilft: http://sourceforge.net/tracker/index.php?func=detail&aid=1588283&group_id=290&atid=350290
Der Parameter "--flush" bewirkt, dass die Mp3-Daten sofort ausgegeben werden.
Evtl. muss der Parameter "-X" weggelassen werden!
Dann kannst du mit den Werten etwas experimentieren.
z.B. Sleep(10) statt Sleep(50)
If $hStream And $iSize > 0 Then _BASS_EXT_StreamPutFileBufferData($hStream, $aBuffer, $iSize)
usw...
Um den Filestream überhaupt zu erzeugen benötigt Bass.dll allerdings eine gewisse Mindestmenge an Mp3-Daten.
Der Wert in Zeile 34 darf also nicht zu niedrig sein...
Natürlich kannst du auch die rohen PCM-Daten verschicken
Das geht dann in etwa so:
#AutoIt3Wrapper_UseX64=n
#include "Bass.au3"
#include "BassExt.au3"
If Not FileExists(@ScriptDir & "\TCP_RECEIVE.exe") Then
MsgBox(0, "ERROR", @ScriptDir & "\TCP_RECEIVE.exe not found" & @CRLF & "please compile TCP_RECEIVE.au3 first")
Exit
EndIf
$sIPADDRESS = "127.0.0.1"
$iPORT = 1234
OnAutoItExitRegister("_FreeBass")
[/autoit] [autoit][/autoit] [autoit]HotKeySet("{ESC}", "_Exit")
[/autoit] [autoit][/autoit] [autoit]_BASS_Startup()
_BASS_EXT_STARTUP()
_BASS_SetConfig($BASS_CONFIG_REC_BUFFER, 1000)
[/autoit] [autoit][/autoit] [autoit]_BASS_RecordInit(-1)
$aBuffer = _BASS_EXT_MemoryBufferCreate()
$hRecord = _BASS_RecordStart(44100, 2, 0, $BASS_EXT_RecordProc, $aBuffer[0])
TCPStartup()
$iSocket = TCPListen($sIPADDRESS, $iPORT)
$iPid = Run('"' & @ScriptDir & '\TCP_RECEIVE.exe"')
[/autoit] [autoit][/autoit] [autoit]$iAcceptSocket = -1
While 1
If $iAcceptSocket = -1 Then
$iAcceptSocket = TCPAccept($iSocket)
$iSize = _BASS_EXT_MemoryBufferGetSize($aBuffer)
_BASS_EXT_MemoryBufferGetData($aBuffer, $iSize) ; while not connected -> empty buffer
ContinueLoop
EndIf
$iSize = _BASS_EXT_MemoryBufferGetSize($aBuffer)
If $iSize Then
$bMp3Data = _BASS_EXT_MemoryBufferGetData($aBuffer, $iSize)
$iSent = TCPSend($iAcceptSocket, $bMp3Data)
ConsoleWrite("Bytes: " & BinaryLen($bMp3Data) & " / gesendet: " & $iSent & @CRLF)
EndIf
Sleep(10)
WEnd
Func _Exit()
Exit
EndFunc ;==>_Exit
Func _FreeBass()
ProcessClose($iPid)
TCPCloseSocket($iAcceptSocket)
TCPShutdown()
_BASS_RecordFree()
_BASS_Free()
EndFunc ;==>_FreeBass
#AutoIt3Wrapper_UseX64=n
#include "Bass.au3"
#include "BassExt.au3"
$sIPADDRESS = "127.0.0.1"
$iPORT = 1234
OnAutoItExitRegister("_FreeBass")
[/autoit] [autoit][/autoit] [autoit]_BASS_Startup()
_BASS_EXT_STARTUP()
_BASS_SetConfig($BASS_CONFIG_UPDATEPERIOD, 80)
_BASS_SetConfig($BASS_CONFIG_BUFFER, 100)
_BASS_Init(0, -1, 44100, 0, "")
[/autoit] [autoit][/autoit] [autoit]$aBuffer = _BASS_EXT_MemoryBufferCreate()
[/autoit] [autoit][/autoit] [autoit]TCPStartup()
$ConnectedSocket = TCPConnect($sIPADDRESS, $iPORT)
If $ConnectedSocket = -1 Then
MsgBox(0, "", @error)
Exit
EndIf
$hStream = _BASS_StreamCreate(44100, 2, 0, $STREAMPROC_PUSH, 0)
_BASS_ChannelPlay($hStream, 1)
While 1
[/autoit] [autoit][/autoit] [autoit]$bMp3Data = TCPRecv($ConnectedSocket, 88200)
If BinaryLen($bMp3Data) > 0 Then _BASS_EXT_MemoryBufferAddData($aBuffer, $bMp3Data)
$iSize = _BASS_EXT_MemoryBufferGetSize($aBuffer)
ToolTip("TCP_REICIVE Buffer size: " & $iSize)
If $hStream And $iSize > 0 Then _BASS_EXT_StreamPutBufferData($hStream, $aBuffer, $iSize)
Sleep(10)
WEnd
Func _Exit()
Exit
EndFunc ;==>_Exit
Func _FreeBass()
TCPCloseSocket($ConnectedSocket)
TCPShutdown()
_BASS_Free()
EndFunc ;==>_FreeBass
Die Werte für den Playbackbuffer sind schon fast zu niedrig bei mir.
Am besten du probierst es auch mal mit BassASIO: _BASS_ASIO_ChannelEnable(True, 0, $BASS_EXT_AsioProc, $aBuffer[0])
E
Nach ein paar Tests glaub ich, dass es an lame.exe bzw dem StdOut-Buffer liegt!
Der Encoder gibt die Mp3-Daten nur in 4096-Byte Blöcken heraus!
Wie man das ändert hab ich noch nicht rausgefunden...
E
Hier noch mein Script von damals: Videovorschau-Bild
Falls du nur das "Hallo" benötigst, dann so:
[autoit]$aRegExp = StringRegExp($text, "\{([^{}]*)\}", 3)
_ArrayDisplay($aRegExp)