Das Tutorial wird mal kurz und schmerzlos .
Prinzipiell schreiben wir eine DLL in Perseus und rufen sie in AutoIt auf.
1 - Perseus DLL schreiben
Dazu zunächst das aktuelle Build herunterladen, Notepad++ öffnen und eine neue Datei namens Test.p++ anlegen. Jetzt wollen wir dem Compiler mitteilen, dass wir eine DLL schreiben wollen. Dazu kommt in die erste Zeile folgendes (warum siehe Wiki):
Dann überlegen wir mal, was die DLL überhaupt machen soll. Rein aus Jux zeichnet die Funktion in diesem Tutorial eine Sinuskurve in einer beliebigen Farbe. Dazu werden vom aufrufenden Skript Device Context, Breite, Höhe und Farbe übergeben. In Perseus kann jede DLL alles, was auch in GUI oder CUI Anwendungen möglich ist. Wir können hier die gesamte WinAPI und natürlich alle Perseus-Includes nutzen. Wir könnten sogar Objekte und Klassen in die DLL packen, aber das brauchen wir hier ganz sicher nicht.
Was wir aber brauchen sind die WinAPI und diverse Funktionen zur Datentyp-Konvertierung und zum Rechnen. So können wir Floats und Ints nutzen ohne weitere Variablen zu verwenden:
Dann deklarieren wir alle DLL-eigenen Variablen, in diesem Fall sind das zwei Puffer für die Koordinaten und ein Loopcounter. Könnten wir auch local machen, brächte aber nichts:
Jetzt kommen wir zur Hauptfunktion. Im Gegensatz zu PEs brauchen DLLs keinen Einsprungpunkt. Eine Basis-Adresse wird automatisch vom Compiler angelegt. Die Funktion nimmt vier Parameter auf (alles dwords) und gibt provisorisch "1" zurück (auch als dword). Der Header sieht dann so aus:
Jetzt rücken wir ein und schreiben den Code. Das ist einfache Mathematik und bedarf nicht viel Erklärung. Am Ende der Funktion steht wie immer ein end:
// Zeichenfunktion
export DrawSine(dword hdc, dword cxClient, dword cyClient, dword crColor) as dword;
// Querlinie
MoveToEx(hdc, 0, cyClient / 2, NULL);
LineTo(hdc, cxClient, cyClient / 2);
// Kurve
for (i = 0; i < 1000; i++) {
ptX = i * cxClient / 1000;
ptY = Sng2Int(Int2Sng(cyClient) / 2.0 * (1.0 - Sin(2.0 * Pi() * Int2Sng(i) / 1000.0)));
SetPixel(hdc, ptX, ptY, crColor);
}
return(1);
end;
Alles anzeigen
Damit ist der DLL Code schon fertig. Wir schmeißen ihm einfach den DC einer AutoIt GUI vor die Füße und den ganzen Rest übernimmt die DLL.
2 - AutoIt Test Code
GUI erstellen, DC auslesen, DLL aufrufen und das wars schon. Bei mir dauert das komplette neuzeichnen etwa 3.6ms (~280 FPS). Durch spielen mit den Variablen und durch besseren Perseus-Code kann man da noch ne Menge Speed rausholen, aber das ist ja nur eine Demonstration. Hier ist der AutoIt Code:
[autoit]#include <WinAPI.au3>
[/autoit][autoit][/autoit][autoit]; Standard BlaBla
$hGUI = GUICreate("Perseus Dll Test")
$hDC = _WinAPI_GetDC($hGUI)
GUISetBkColor(0xFFFFFF)
GUISetState()
; 1000x testen und durschn. Zeit ermitteln
$iTimer = TimerInit()
For $i = 1 To 10^3
; Dll wie jede andere DLL aufrufen
DllCall("Test.dll", "dword", "DrawSine", "dword", $hDC, "dword", 400, "dword", 400, "dword", 0x00A088FF)
Next
ConsoleWrite("-> Avg. time: " & Round(TimerDiff($iTimer) / 10^3, 2) & " ms." & @LF)
While GUIGetMsg()<>-3
WEnd
Exit _WinAPI_ReleaseDC($hGUI, $hDC) - 1
[/autoit]3 - Schon fertig
Ich hoffe es war anschaulich genug. Die Source-Files hänge ich an (auch die kompilierte DLL). Sicher lässt sich das für andere Zwecke sinnvoll einsetzen (Multithreading ist extrem einfach in Perseus. Damit lassen sich komplexe Routinen schön auslagern ). Vielleicht schreibe ich mal ein Mandelbrot-Beispiel o.ä.