Programmieren mit Delphi 10.3.2.


Mit Delphi 10.3. ist wieder eine super Entwicklungsumgebung verfügbar, die mich an die alten Delphi 5 - Zeiten erinnert. Die Hilfe lässt zwar ein wenig zu wünschen übrig, aber mit der Community Edition gibt es für den Privatbereich eine kostenlose Lizenz, die man erst nach einem Jahr (dann ebenfalls wieder) kostenlos erneuern muss. Ich habe das zum Anlass genommen, meine alten Quellen, in die in den letzten 20 Jahren viel Arbeit gesteckt wurde, nach noch brauchbarem Code zu durchforsten und mit Delphi 10 in die neuen Win10 - Zeiten zu retten. Und hier ist das Ergebnis: Eine Sammlung von Routinen in der Unit Amende.pas, die in dem folgenden Demo auszugsweise vorgestellt werden.

Hier kann das Demo kostenlos heruntergeladen werden. Die Quelltexte gibt es gegen ein milde Gabe ;-)

Hinweis: Nach dem Entpacken in ein beliebiges Verzeichnis auf C:\ die beiden .dam-Dateien jeweils in .exe umbenennen.

Hier einige der bereitgestellten Routinen im Überblick:

Für die meisten Beispiele muss nur die Unit "amende.pas" in das Projekt eingebunden werden und in der Uses-Klausel des Hauptformulars auftauchen. Einige Features lassen sich aber nicht in eine Unit auslagern, sondern sind nur in der Unit1 des Demoprogramms direkt nachvollziehbar.

Beispiele:

Anpassung der Kurzhinweise (Form1.OnCreate / OnMouseMove einiger Elemente zur Mitbewegung des Hints),

Umgang mit Ressourcen (Tipp: Suche nach "Image1" oder in Unit1 der Kommentar bei {$R *.res}) (Dazu zäh-

    len auch mehrere Mauscursor aus meinem CAD-Programm.),

Nutzung des Clipboards für den Listen-Export nach Excel,

Färbung und Sortierung von TListviews,  gezeigt in Form1.Listeview2 und in "Farben sortieren".

Drag&Drop - Funktionalität: anwendungsintern zum Tauschen von Items im Listview2 (Eigenschaft DragMode

    auf dmAutomatic stellen) und von außen (Dateinen aus dem Windows-Explorer auf Listview2 ziehen) usw.

 

Die Unit "amende.pas" bietet folgende Möglichkeiten:

 

"Drucker-Hilfsmittel", z.B. procedure prTextline(Zentrierung:byte;S:string;FA:tcolor;GR:byte);

Scalierung des Printer.Canvas und Möglichkeiten einfacher Listenerstellung (siehe unten: "Listendruck").

 

"Hilfesystem", procedure HILFE('Sinn des Programms');

Die Prozedur kann an verschiedenen Stellen eines Programm mit immer neuen Titeln in einem beliebigen Ereignis

benutzt werden. Eine neue '*.rtf'-Datei wird jeweils beim ersten Aufruf im Unterverzeichnis /HILFE automatisch er-

stellt. Hier wurde das OnKeyDown-Ereignis des Hauptformulars (if Key=vkF1 then Hilfe('Sinn des Programms');)

verwendet. Dafür sollte aber die Eigenschaft KeyPreview des jeweiligen Formulars auf true gesetzt sein.

Das Hilfesystem ist mit Suchfunktion und Index (wie unten zu sehen) ausgestattet, das Fenster kann mit der Maus

angefasst und verschoben werden.

 

"GIF laden", procedure TForm1.SpeedButton2Click();

Ein Timage wird - bereits bevor das Formular angezeigt wird - in Form1.OnShow mit "as" in ein GIFImage konver-

tiert. Vorher muss zur Designzeit ein .gif in das Image geladen worden sein. Wenn diese Typumwandlung später

durchgeführt wird, resultiert ein Fehler. Alle verwendeten Bilder (außer beim Download) wurden vorher als Res-

source eingebunden. Das Laden der Ressourcen kann mit Suche nach "Image1", "Image4" oder "Image5" nach-

verfolgt werden. Das Erstellen von Ressourcen kann in Unit1 nachgelesen werden.

 

"Bitmap gradweise drehen", procedure rotatebitmap();

Das läuft zwar auch unter W64, kann aber nur unter W32 kompiliert werden. Der Prozess verlangsamt alle ande-

ren Vorgänge in Abhängigkeit von der Größe des zu drehenden Bitmaps. Es braucht dazu ein (nicht sichtbares)

Ursprungs-Image, das das eigentliche Original-Bitmap enthält.

 

"Text-Files durchsuchen", function textinfile():boolean;

Beim Durchsuchen von Dateien sind *.pdf; *.htm; *.txt; *.pas; *.rtf; *.docx und *.xml - Files möglich. Umlaute sowohl

im Dateinamen als auch im Text sind erlaubt und werden gefunden, es wird aber Groß- u. Kleinschreibweise unter-

schieden. Dateien, die sich im aktuellen Laufwerk der Anwendung befinden, werden übergangen (Übergeordnete

und untergeordnete Verzeichnisse sind möglich.). Zum Testen können die Files im Verzeichnis "Beispieldateien

zum Durchsuchen" verwendt werden. Die Dateinamen enthalten Personennamen, die jeweils auch in den Dateien

vorkommen. Alle Funde können mit Doppelklick auf den ListView-Eintrag geöffnet werden [Bsp. für 'shellexecute()'].

Um dies in einem Programm einzubauen, muss diese Anwendung die "pdftotext.exe" mit sich führen. Dieses Hilfs-

programm läuft aber leider nicht unter Win7 32bit.

Im vorliegenden Beispiel sind alle zu durchsuchenden Dateien (nur eines Verzeichnisses!) zu markieren.

 

"Dongle erzeugen", function USBStick: boolean; function ISDONGLE: boolean; function GETSERIAL(): string;

                                   function MAKEDONGLE: boolean; procedure CODE();

                                   function ISAUTORUNON:boolean; procedure SETAUTORUN(boolean);

Beim Start dieses Demoprogramms wird der aktuelle AutoRun-Status abgefragt, ausgeschaltet und zum Schluss

wieder restauriert. Das sollte auch in der zu schützenden Anwendung passieren. So wird verhindert, dass beim

Einstecken eines USB-Sticks jedesmal der Explorer oder ein Dialog erscheinen.

[Hinweis: Seit Win10 Herbst 2019] können USB-Sticks einfach abgezogen werden. Allerdings schließt dabei der

Explorer, wenn er noch auf den Laufwerksbuchstaben des Sticks weist.]

Steckt ein USB-Stick, wird dessen Seriennummer ermittelt, codiert und als Datei "sys32.usb" auf den Stick ge-

schrieben. In MAKEDONGLE wird verschlüsselt, in ISDONGLE wird entschlüsselt - mit gleichem Passwort.

Dieses kann geändert werden, sollte aber in der zu schützenden Anwendung nicht als Klartext hinterlegt, sondern

an vielen, verschiedenen Stellen der Anwendung, die mit Sicherheit durchlaufen wurden, einzeln aus chr() zusam-

mengesetzt werden. Die Datei "sys32.usb" auf einen weiteren Stick zu kopieren, hilft natürlich nichts.

Für ISDONGLE können mehrere USB-Sticks stecken, nur einer von ihnen muss der korrekte Stick sein. MAKE-

DONGLE hingegen wird alle eingesteckten Sticks mit der jeweiligen Datei ausstatten.

Hinweis: Die Funktion USBStick erkennt auch USB-Festplatten, die als Dongle eher nicht geeignet sind.

 

"Verzeichnisstruktur kopieren", procedure COPDIR(); procedure MAKEROUNDED();

Die Prozedur kopiert sehr schnell eine ganze Verzeichnisstruktur mit allen Inhalten und darunterliegenden Unter-

verzeichnissen. Außerdem wird gezeigt, wie man ohne visuellen OpenDialog eine Verzeichnisauswahl macht.

Der Button liegt außerdem auf einem mit MAKEROUNDED() abgerundeten Panel. Das Verfahren wurde in dem

Ereignis Form1.OnShow auch auf dieses Hilfefenster angewendet: Das innenliegende beigefarbene Panel hier

erhält aber einen um 2px kleineren Radius, damit die Umrandungslinie der FormAmende (blau) parallel verläuft.

 

"Alphablending", procedure SETFORMTRANSPARENT();

Auf das schwarze Panel5 wird die ebenfalls schwarzeForm2 gelegt, deren transparentes Image1 ein Bild enthält.

Form2 wird mittels Timer4 und Timer5 von 0 auf 255 sichtbar und wieder unsichtbar gemacht.

 

"CD/DVD - Laufwerk öffnen / schließen", function CDDRIVE(): boolean; procedure MOVECD();

Es wird geprüft, welcher der Laufwerksbuchstaben A: - H: ein CD/DVD-Laufwerk ist und anschließend für dieses

Laufwerk das Fach geöffnet bzw. geschlossen. Das Betriebssystem prüft dabei, ob ein Datenträger eingelegt ist,

das kann die Ausführung des Befehls MCISendString('Set cdaudio door open', Nil, 0, 0); bis zu 30 sec verzögern

(Das animierte GIF links oben steht, solange das System beschäftigt ist.).

 

"Eine milde Gabe!", procedure BEZAHLEN();

Diese Prozedur ruft mit 'shellexecute();' den Paypal-Überweisungsdienst auf. Loggen Sie sich in Ihr Paypal-Konto

ein und autorisieren Sie eine Zahlung von 24,95 € an mich, dann erhalten Sie die Delphi 10 Quelltexte zu diesem

Demoprogramm. Natürlich nur, wenn Sie das auch möchten.

Betrag und Verkäufer-eMail können angepasst werden. Nach Abschluss des Paypal-Vorganges erhalten Käufer

und Verkäufer die eMail-Adressen des jeweils anderen und können Kontakt aufnehmen und der Verkäufer kannn

die Gegenleistung versenden.

 

"Fenster mit Ausschnitt", procedure SetWindowRgn();

Dieses Beispiel zeigt die Anwendung von SetWindowRgn();, um in einem bestimmtem Bereich eines Fensters den

Hintergrund sichtbar zu machen. Der Bereich kann mit Festlegung einer Reihe von Koordinatenpaaren durch die

API-Funktion 'CreatePolygonRgn();' definiert werden.

 

"Datei de- / codieren", procedure FASTCRYPT(FN:string;PW:ansistring);

Diese Prozedur verschlüsselt eine beliebige Datei. FASTCRYPT() erkennt dabei selbst, ob die Datei von ihr be-

reits codiert wurde (also zu entschlüsseln ist) oder nicht (also zu verschlüsseln ist). Die Datei wird dabei direkt

überschrieben. Verlust des Passwortes bedeutet Verlust der Datei!

 

"Drag&Drop", (im Demoprogramm integriert, nicht in 'amende.pas')

Ziehen Sie im Windows-Dateiexplorer markierte Dateien auf dieses Listview, sie werden dort eingetragen. Die

dazu notwendigen Passagen sind nicht in der Unit 'amende.pas' hinterlegt, aber im Quelltext des Beispielpro-

gramms mittels Suche nach "Drag&Drop" auffindbar.

 

"Doppelstart", function DOPPELSTART();

Mit dieser Funktion kann geprüft werden, ob die Anwendung bereits läuft und ggf. mit 'application.terminate;' oder

halt(0); beendet werden muss, falls sie nur einmal gestartet werden darf.

 

"Screenshot", procedure BARWEG; procedure BARAN; procedure SCREENSHOT();

Die Windows-Taskbar wird versteckt, ein Schreenshot vom gesamten Bildschirm angefertigt und in einem neuen

Fenster variabel groß dargestellt und danach wird die Windows-Taskbar wieder angezeigt. Die Taskbar zu ver-

stecken, ist für manche Programme wichtig, die den vollständigen Monitor benötigen.

 

"Verknüpfung", VERKNUPFUNG(); oder CREATSHORTCUT();

Hiermit können Sie einen Shortcut erstellen. VERKNUPFUNG(); tut das auf dem Desktop, im Quicklaunch-Bereich

und in der Registry, mit CREATSHORTCUT(); kann man dies einzeln auswählen.

 

"Neustart", procedure AUTOSTART(paramstr(0),extractfilename(paramstr(0)));WINEND(EWX_reboot);

Zuerst wird mit AUTOSTART() die Anwendung in der Registry unter dem Schlüssel HKEY_CURRENT_USER in

\Software\Microsoft\Windows\CurrentVersion\RunOnce das Programm für den nächsten Systemstart eingetragen

und danach mit WINEND() das Betriebssystem rebootet. Der nach dem Systemstart folgende Programmstart ver-

zögert sich um einige Sekunden.

 

"Lupe", procedure MAKELUPE(Form1,Panel4.Left+Label8.Left,Panel4.Top+Label8.Top,X,Y,200,2); (Bsp.)

Dieser Befehl findet in einem OnMouseDown-Ereignis Anwendung und ruft eine Lupe auf, die über die gesamte

Form1 der Anwendung bewegt werden kann. Im obigen Beispiel ist es das Ereignis Label8.OnMouseDown(). Es

ist dabei wichtig, bei den Left- u. Top-Angaben alle dazwischen liegenden Elemente aufzuführen: Hier liegt auf der

Form1 das Panel4 und auf dem Panel4 liegt das Label8. Die Lupe hat dabei einen Durchmesser von 200px und

einen Vergrößerungsfaktor von 2. Als X und Y sind die dem OnMouseDown-Ereignis mitgegebenen aktuellen

Mauskoordinaten einzutragen. Die Lupe funktioniert nur unter Windows 10 korrekt.

 

"Datei-Download", function ISCONNECTED:boolean; procedure DOWNLOADFILE(Q,Z:string):boolean;

Die Funktion ISCONNECTED prüft, ob eine Internet-Verbindung besteht. Wenn ja, dann wird mit der Prozedur

DOWNLOADFILE(); von der Website "www.detlef-Amende.de" ein Foto des norwegischen Geiranger Fjord he-

runtergeladen und im Bildrahmen darüber dargestellt. Der Download erfolgt in das aktuelle Programmverzeichnis

und wird anschließend wieder gelöscht. Man kann auch von beliebigen URL's die index.htm herunterladen und

nach Textbestandteilen durchsuchen. Hierzu werden von "www.tagesschau.de" die aktuellen Texte herunterge-

laden und in einem Memo (bereinigt) dargestellt. So sind beispielsweise automatisierte Textanalysen möglich.

 

"Test Datei-Upload", procedure UPLOADFILE(SERVER,USER,PASSWORT,QUELLE,ZIEL:string);

Die ersten drei Parameter dienen der Anmeldung am FTP-Server (z.B. 'ftp.detlef-amende.de'). Im Beispiel ist die-

se Funktion auskommentiert und wird stattdessen mit einer Meldung quittiert. QUELLE enthält den vollständigen

Pfad und Ziel muss mit führendem Slash beginnen ('/Unterverzeichnis/Dateiname').

 

"ImageLabel", procedure IMAGELABEL(Form1,460,20,'Hallo Welt!',A,4,clgray);

Diese Prozedur bietet schattierten Text mit einem Shadow-Offset von 1..8 px nach rechts unten (Mehr ist nicht

sinnvoll.). Der Parameter 'Form1' ist das Parent-WinControl, kann also nicht nur eine Form, sondern z.B. auch ein

Panel sein. Die Koordinaten sind die Relativ-Koordinaten auf dem Control. Mit var A: TFont; wird ein Font überge-

ben, in dem vorher Schriftart, -größe, -farbe, -style usw. festgelegt werden können. Im obigen Beispiel sind ein

Schattenoffset von 4px und die Schattenfarbe mit clgray angegeben. Breite und Höhe des Text-Rechteckes erge-

ben sich aus der Schriftgröße. Das Image, auf dem der auszugebende Text gezeichnet wird, liegt im Beispielpro-

gramm auf der Form1 und kann dort allerdings von sichtbaren Elementen (Edits. Panels usw.) auch überdeckt wer-

den. Es heißt 'LabelImage' und kann in Form1 mit 'LabelImage.visible:=false' ausgeschaltet und mit '.free' freige-

geben werden.

 

"Ausführbare Datei ?", function EXETYPE(const FileName: string): TExeFileKind;

Mit "Drag&Drop" können Dateien auf dieses Listview gezogen werden. Mit dem Button "Ausführbare Datei ?" kann

dann geprüft werden, ob sich darunter Programm-Dateien befinden, die man nicht an ihrer Namenserweiterung er-

kennen kann. Umbenannte .com / .exe / .dll - Files findet man im Unterverzeichnis "Beispieldateien zum Durchsu-

chen", ihr Eintrag wird nach der Prüfung in roter Schrift markiert. (.msi - oder .bat - Dateien werden nicht erkannt.)

Hinweis: Die Beispieldateien "UmbenannteEXE.pdf" usw. nicht zurück-benennen und starten, um zu prüfen, ob sie

auch wirklich ausführbar sind. Diese Dateien wurden irgendwoher kopiert und könnten Unfug anrichten!

 

"ListviewHeader", procedure LISTVIEWHEADERFONT();

Der Aufruf mit (LV: TListview;Fontname:string;HÖHE,BREITE,FETT,UNTER,DURCH,KURSIV:integer); ermög-

licht, die Beschriftung der Columns eines Listviews anzupassen, was mit Delphi-Standardmitteln so nicht ohne

weiteres möglich ist. Hintergrund- und Schriftfarbe dagegen lassen sich hiermit nicht verändern.

 

"Export über Clipboard", LISTVIEWTOCLIPBOARD(listview2);

Dieser Aufruf ermittelt zunächst das aktuelle Windows-Listentrennzeichen und schreibt dann mit dessen Hilfe alle

Zeilen und ihre Spalten des übergebenen Listviews in die Zwischenablage.

Im Demoprogramm wird die Zwischenablage danach an Excel übergeben (schreiben in eine 'listview.csv' im

aktuellen Programmverzeichnis und deren Aufruf mit EXECFILE();.

Hinweis: Nicht wundern über 3 Spalten in Excel - es gibt in Listview2 eine dritte Spalte der Breite = 0, in der stan-

dardmäßig eine 0 steht, wo aber eine 1 gesetzt wird, wenn der Listeneintrag auf eine aufrufbare Datei zeigt. Dies

wird in Listview2.OnCustomDrawItem zur Färbung des Textes genutzt.

 

"Farben vergleichen", function FARBABSTAND(C1,C2:TColor;RGBtoGR:byte): real;

Farben können im kubischen Raum als Vektoren mit den 3 Dimensionen Rot, Grün und Blau aufgefasst werden.

Die Helligkeit einer Farbe (Grau-Anteil) wird dabei durch die Länge des Vektors dargestellt. Die ähnlichste Farbe

wird durch die geringste Entfernung zwischen zwei Farbvektoren ermittelt. Dabei können aber zwei, in ihren

RGB-Anteilen exakt gleiche, jedoch unterschiedlich helle Farbvektoren mit ihren Endpunkten weiter von einander

entfernt sein, als unterschiedlichere Farben ähnlicher Helligkeit. Deshalb wird mit der Angabe RGBtoGR die

Wichtung des RGB-Anteils gegenüber dem Grau-Anteil angegeben. Mit dem im Demoprogramm voreingestellten

Standardwert 4 werden im Vergleich die RGB-Anteile 4x stärker berücksichtigt, als die Grau-Anteile. Dies erzielt

(nach subjektivem Empfinden natürlich unterschiedlich) die scheinbar besten Vergleiche.

Hinweis: Im Listview des Farben-Fensters (Unit5.pas) wird auch das auf- und absteigende Sortieren nach Spalten

gezeigt.

 

"Römische Zahlen", function dectoroman(integer):string;

Diese Funktion wandelt ganze (arabische) Zahlen in römische Zahlen um. Keine Ahnung, wozu das gut ist.

 

"Listendruck", verschiedene Prozeduren als Drucker-Hilfsmittel

Die Zeichenfläche des Druckers wird (bei printer.orientation := poPortrait) skaliert und eine 2seitige Beispielliste

mit 3farbigem Seitenkopf, 5spaltiger Tabelle und abschließender Seitenzahl gedruckt.

 

"Farbverlauf-Linie", GRADIENTLINE(Form1.Image8,XV,YV,XB,YB,Dicke,Startfarbe,Endfarbe,Mode);

Zeichnet eine Linie nicht einfarbig, sondern mit Farbverlauf vom Startpunkt (XV,YV) bis zum Endpunkt (XB,YB).

Mode gibt an, welche Art verwendet wird: 0: ersetzendes Zeichnen,  1: ergänzendes Zeichnen auf dem überge-

benen Image.

Der Button "Farbverlauf-Linie" kann für verschieden Beispiele mehrfach geklickt werden. Im letzten Beispiel sind

zwei transparente Images übereinander gelegt. Nur im vorderen wird mit Mode=0 gezeichnet, wobei das Bild da-

runter erhalten bleibt.

 

 

Hinweis zur Koordinatenumrechnung:

var A,B: TPoint;

A.X:=0;A.Y:=0;B:=Form1.clienttoscreen(A);  // Hier enthalten B.X und B.Y die Mauskoordinaten auf der Form.

form2.left:=B.X+panel5.left;form2.top:=B.Y+panel5.top;  // Form2 wird links oben genau auf das Panel5 gelegt.

Form2 liegt nun genau auf Form1.Panel5. Die Position der Form2 ist damit unabhängig davon, welcher Border-

style für Form1 gewählt wurde.

Die Umkehr-Operation: screentoclient(); um aus B wieder BS-Koordinaten zu machen.