Robert W.B. Linn´s Software, Beispielprojekte und Tipps zu TurboDB, TurboDB VCP, TurboDB Studio, Visual Data Publisher
   
Alle Tipps und Tricks
Alle Einträge  Stichworte  Alle Tipps und Tricks  Download Tipps und Tricks (html, hlp, rtf) 



Topic Restrukturierungsmeldungen bei der Tabellendefinition Kapitel Tabellen
Meldungen die erscheinen können, wenn eine Änderung an einer 
Tabellen-Definition vorgenommen wurde:

Meldung: "Restrukturierung erfolglos, unbekannter Bezeichner Feldname:Länge" 
Bedeutung:
Die Tabelle enthält einen ID-Index Feldname:Länge aber kein Feld namens Feldname.
Abhilfe:
Feld Feldname anlegen

Meldung: "REL-Datei schon vorhanden"
Bedeutung:
Sie versuchen eine neue oder geänderte Tabelle neu aufzubauen. Es handelt sich hier um eine oder mehrere Relationsfelder. Die WinTDB legt i.d.F. eine Relationstabelle.REL an. Diese Datei ist schon durch vorangegangene Operation vorhanden.
Abhilfe:
Um nicht von vorne mit der Tabellendefinition anzufangen (die WinTDB/VDP läßt sich nicht bewegen, diese Datei zu überschreiben), die Datei mit dem Dateimanager oder Explorer von Windows löschen. Vorher sollte WinTDB/VDP beendet werden.

Meldung: "Restrukturierung erfolglos, nur 8 Seiten erlaubt."
Bedeutung:
Diese Fehlermeldung erscheint u.A., wenn die zu  restrukturierende Tabelle in den Schreibrechten (NELI) beschränkt ist.
Abhilfe:     
1.Möglichkeit
Unter "Eigenschaften" der Tabelle alle Rechte geben, Projekt erneut öffnen und restrukurieren.
2.Möglichkeit
Tabelle exportieren
Bestehende Tabelle aus dem Projekt entfernen und Dateien löschen
Exportierte Tabelle umbenennen, d.h. alten Namen geben
Tabelle dem Projekt hinzufügen.


Topic Importfehler: Typen stimmen nicht überein Kapitel Tabellen
Der Fehler besteht darin, daß der Spaltentyp nicht mit dem übereinstimmt, was in der zu importierende Tabelle gefunden wurde. 
Beispiel:
Spaltentyp = Festkomma
In der zu importierende Tabelle wurde aber ein Alphazeichen (a,b,...) gefunden.


Topic Festhalten wann ein Datensatz das letzte Mal geändert wurde Kapitel Tabellen
Frage:
Wie kann festgehalten werden, wann ein Datensatz das letzte mal tatsächlich
geändert wurde?

Tipp 1
Die Funktion EDITREC liefert einen Wert anhängig von der Verarbeitung des Datensatzes zurück: 0 bei Abbruch und den Datensatznr, RecNr, bei Änderung.
Ist der zurückgegebenen Wert > 0, dann kann das Datum ermittelt und z.B. in den Datensatz gespeichert werden.

Beispiel:
Procedure Bearbeite_Datensatz;
Vardef nRNo : Real; ..Rückgabewert von EditRec
 DatensätzeBearbeiten("TABELLE.Formular");
 AnDenAnfangBlättern;
 nRNo := EditRec("Ändern Sie die Angaben.");
 If nRNo > 0
  ..der Satz wurde geändert, speichere Datum
  ReadRec(TABELLE, nRNo);
  TABELLE.Aenderungsdatum := Today;
  WriteRec(TABELLE, nRNo);
 End
 Schließen
 Return
Endproc

Tipp 2
Ein Feld Aenderungsdatum vom Typ Datum definieren. Dann in den Feld-Eigenschalften unter Eingabekontrolle, "Automatischer Eintrag" die Formel today an ("Formel" vorher ankreuzen) eintragen. 


Topic Suche nach den ersten Eintrag bei einen Index bestehend aus Laufende_Nummer + einen String Kapitel Tabellen
Index:
Suche nach den ersten Eintrag bei einen Index bestehend aus
Laufende_Nummer + einen String

ActivateForm("TABELLE.Formular");
Access(TABELLE, "TABELLE.ID");
Find("TABELLE.ID", Str(TABELLE2.Laufende_Nummer) +",");

Der Trick ist hinter dem Komma keine Angabe zu setzen


Topic Memofelder Inhalt löschen Kapitel Tabellen
Werden Datensätze mit Memofelder gelöscht, dann stellt sich immer wieder heraus,
daß die Memofelder ihren Inhalt beibehalten haben. Lediglich der Verweis ist gelöscht.
Auch die Ausführung von Indizes wiederherstellen, hat keinen Einfluß.
Um den Inhalt zu löschen muß die Tabelle restrukturiert werden.

Vorgang:
Tabellenstruktur editieren, keine Veränderungen vornehmen, OK klicken, die Tabelle wird
restrukturiert und dabei wird der nicht zugeordnete Inhalt der Memofelder gelöscht.


Topic Wie lässt sich ein Index anlegen, der nur die nicht gelöschten Sätze anzeigt? Kapitel Tabellen
Ist leider nicht machbar, weil die Datensätze sofort physikalisch gelöscht werden.
Damit ist die Konsistenz aller Indexdateien während der Löschung gewährleistet, die
gelöschten Datensätzen sind daher nicht mehr herstellbar.


Topic Import von verknüpften Tabellen Kapitel Tabellen
Import von verknüpfte Tabellen. 
Wenn Tabelle A ein Linkfeld auf Tabelle B hat, dann erst Tabelle B und
anschließend Tabelle A importieren.

Wenn eine Tabelle leer ist, (auch wenn die Einträge nur gelöscht wurden) und man importiert vorher exportierte Datensätze, dann werden exakt die selben Auto-Nummern vergeben.
VDP vergibt erst neue Auto-Nummern, wenn ein bereits angelegter Datensatz mit einer höheren Nummer existiert.
Grundsätzlich kann man also die Einträge importieren und anschließend muß auch die Zuordnung wieder stimmen.


Topic Zeitfeld Kapitel Tabellen
Ein Zeitfeld speichert die Uhrzeit in Anzahl Minuten nach Miternacht, also als reines
Zahlenfeld (max. Wert ca. 1460).
Aus diesem Grund kann man damit rechnen, wie mit einem anderen Zahlenfeld.
Beispiel:
ZeitFeld * DM
Hinweis:
Als Feldnamen nicht Zeit oder datum verwenden. Diese Angaben sind für VDP reserviert.


Topic Wiederherstellung einer Tabelle mit einem HexEditor Kapitel Tabellen
Vorgehensweise zur Wiederherstellung einer Tabelle mit Hilfe eines HexEditors

1.Tabelle sichern, damit man das mehrfach wiederholen kann.
2. attrib readonly von tabelle nehmen
3. Tabelle mit HexEditor aufmachen z.B. ultraedit
4. Die ersten 4 Byte auf die richtige Datengröße setzen.
Falls Wert nicht bekannt, dann experimentieren.
In diesem Fall ging es mit EE EE EE 00
Achtung: nicht größer, da ansonsten negativer Wert
5. Speichern und Tabelle mit VDP öffnen.
6. FileSize ansehen und restrukturieren.


Topic Datenzerstörung beim Versuch der Volltext-Indizierung Kapitel Tabellen
Datenzerstörung beim Versuch der Volltext-Indizierung

Problem:
Beim Versuch eine Volltext Indizierung zu erstellen ist VDP 3 abgestürzt.
Danach fehlen die in einer R-Feld verknüpften Felder (zB Artikel).

Lösung:
Die REL-Datei beinhaltet zwei Link-Felder mit dem Inhalt Laufende_Nummer der angekoppelten Tabelle.
Dieser Tabelle passiert einmal gar nichts, wenn man eine DAT-Datei indiziert.

Man muß jetzt erst einmal wissen, welche Tabellen noch welchen Inhalt haben.
1. ist Artikel.dat ok, ist die ursprüngliche Tabelle wieder ok?
2. ist das Rel-Feld noch vorhanden?

Wenn das Rel-Feld nicht mehr vorhanden:
1. rel-datei wegsichern.
2. rel-feld aus der ursprünglichen Tabelle entfernen, restrukturieren. 
Anschließend Rel-Feld wieder mit dem gleichen Namen anlegen. Rel-Datei wieder zurückkopieren.





Topic Datensätze einer Tabelle vergleichen Kapitel Tabellen
Datensätze einer Tabelle können verglichen werden, in dem das Kommando RELATION
verwendet wird.

Mit dem Kommando

RELATION temp=tabelle

wird einen zweiten Handle von der Tabelle "tabelle" mit einem eigenen Satzpuffer erzeugt.

Ein Satz aus Tabelle mittels readrec(tabelle,x) einlesen und
mit readrec(temp,y) den zu vergleichenden Satz einlesen.

Jetzt kann beispielsweise mit

diff:=$temp.Feld - $tabelle.Feld

auf die einzelnen Felder zugreifen.

Mit Dank an Ulrich Kern.


Topic Memofelder exportieren Kapitel Tabellen
Der Inhalt von Memofelder lassen sich mittels easy wie folgt exportieren:

Alle Memos einer Datei werden in getrennte Textdateien geschrieben. Die Namen der Textdateien sind "RECx", wobei x der physikalische Satznummer entspricht.

 Link(TABELLE, CopyMemo(MEMOFEL, "REC" + STR(RecNo(TABELLE))))


Topic Importproblem bei Feldnamen länger 30 Buchstaben Kapitel Tabellen
Beim Importieren von Textdateien in VDP Versionen tritt folgender Fehler auf:
Alle Felder die über 30 Buchstaben haben (in der Textdatei) werden nicht eingelesen.
Sind die Felder höchstens 30 Buchstaben lang, dann funktioniert es wie geplant. Die Felder in VDP 3.x können aber bis zu 255 Buchstaben lang sein.

Lösung:
Es ist ein Fehler in VDP und kann mittels folgendem Workaround umgangen werden:
Die Tabellenüberschriften in der CSV-Datei identisch mit der DAT-Datei machen und unbedingt die Reihenfolge einhalten.


Topic Serienbriefe mit Word für Windows Kapitel Serienbriefe
Es gibt mehrere Möglichkeiten Serienbriefe für WinWord aus dem 
Visual Data Publisher oder der Turbo Datenbank für Windows zu erstellen.

Tip 1:
Serienbriefe mit Microsoft Word für Windows mittels DDE

Vorgehensweise:
1. VDP starten und Formular öffnen
2. Word starten
3. <STRG> <F9> drücken
{} erscheinen
4. zwischen den beiden Klammern folgende Anweisungen schreiben

Syntax:
{DDEAUTO WINTDB "TABELLE.Formular" "Feld" *\ FORMATVERBINDEN}  

Beispiel:
{DDEAUTO WINTDB "ADRESSEN.Formular_ADRESSEN" "Name" *\ FORMATVERBINDEN}

5. rechte Maustaste drücken und Menü anwählen
<Feldfunktionen anzeigen ein/aus><RETURN>
6. <Feld aktualisieren><RETURN>

jetzt wird immer der Feldinhalt des aktuellen Datensatz aus TDB in Word angezeigt.

Tip 2:
Serienbriefe mit Word für Windows mittels Datenbankjob

Eine recht einfache besteht darin, eine Textdatei zu generieren, bei welcher die Felder durch
Semikolon getrennt sind. Über die Standard Exportfunktion geht das leider nicht, da für WinWord in der ersten Zeile der Textdatei die Feldlabels stehen müssen.
Über einen Datenbankjob ist die Sache schnell erledigt.
Die Methode hat auch noch mehrere Vorteile: 
Man kann nur die wirklich benötigten Felder exportieren. 
Man kann noch einige Feinheiten einbauen.

Hier ein Beispiel für einen entsprechenden Datenbankjob:
.REPORT
..Erstellt eine Textdatei zur Verwendung als Steuerdatei für 
..WinWord Serienbriefe.
.PROLOG
.PW 0
..Feldlabels in die erste Zeile der Ausgabedatei
Firma; Firma2; Name; Strasse; Ort
.DATA
$(Firma ";" Zusatz ";" xAnrede Titel +" "??(Titel) Vorname +""??(Vorname)  Name ";" xStrasse 
";" xPLZ " " Ort ")
.EPILOG
Im nächsten Beispiel wurden folgende Erweiterungen implementiert: 
Wenn eine Postfachpostleitzahl (PPLZ) angegeben ist, wird das Postfach und die PPLZ 
ausgegeben. 
Wenn keine Firma angegeben ist, wird in der ersten Zeile die Anrede und der Zusatz erst
nach dem Namen ausgegeben. 
Außerdem wird noch eine komplette Briefanrede zusammengesetzt.

.REPORT
..Erstellt eine Textdatei zur Verwendung als Steuerdatei für
..WinWord Serienbriefe.
.PROLOG
.PW 0
Firma; Firma2; Name; Strasse; Ort; Briefanrede
.DEF xAnrede = Choice(Geschlecht,"Herrn ", "Frau ", "")
.DEF xBAnrede = Choice(Geschlecht, "r Herr ", " Frau ", " Damen undHerren")
.DEF xStrasse = Choice(SEL(PPLZ), "Postfach "+Postfach, Straße)
.DEF xPLZ = Choice(SEL(PPLZ), PPLZ, PLZ)
.DATA
.IF Firma
$(Firma ";" Zusatz ";" xAnrede Titel+" "??(Titel) Vorname+""??(Vorname)  Name ";" xStrasse 
";" xPLZ " " Ort "; Sehr geehrte" xBAnrede Titel+" "??(Titel) Name)
.ELSE
$(xAnrede ";" Titel+" "??(Titel) Vorname+" "??(Vorname)  Name ";"Zusatz ";" xStrasse ";" xPLZ 
" " Ort "; Sehr geehrte" xBAnrede Titel+" "??(Titel) Name)
.END
.EPILOG


Topic Bekannte Probleme der verschiedenen VDP Versionen Kapitel Allgemeine Tipps
VDP 3.01

Das über ShowProgress eingeblendete Fenster verschwindet mit HideProgress nicht.
Das Problem tritt auf:
wenn den Aufruf aus onopenproject erfolgt
aus eine Prozedur aufgerufen wird, der einen Execdialog enthält. ExecDialog erlaubt keine weiteren Fenster.


Topic Fehlermeldungen: Tipps Kapitel Allgemeine Tipps
Hinweise zu VDP Fehlermeldungen

Fehlermeldung: "Illegale Indexdefinition"

Beispiel Anhand Datenbankjob:
.Sub TOPIC.Titel
$(TOPICS.tTitel)
.Do GotoXY(SYSTEM.sPrnPO...)
.Endsub TOPIC.Titel

Nach der Übersetzung erscheint die Fehlermeldung "Illegale Indexdefinition".
Die Ursache ist die Verwendung der Angabe SYSTEM.sPrnPO. 
Die SYSTEM-Tabelle stört VDP.

Lösung:
.Var nTmp = SYSTEM.sPrnPO
.Sub TOPIC
$(TOPICS.tTitel)
.Do GotoXY(nTmp, ...)
.Endsub TOPIC.Titel

Fehlermeldung: "Speicher reicht nicht aus" (Fehler 99)
Dieser Fehler tritt auf wenn zuviele Rekursionen vorliegen.

Beispiel:
..Modul001
Uses Modul002
Uses Modul003

Beim übersetzen des Modul001 kommt diese Meldung.

Lösung:
Abhilfe schaft die Verwendung von ExecMacro(Modul002, ProcedureAusModul002) und 
die Uses Anweisung weglassen.

Fehlermeldung "Tabelle nicht geöffnet"
Dieser Fehler tritt zum Beispiel auf bei der Übersetzung eines Datenbankjobs.

Überschrift Fehlermeldungsfenster: Compiler Error
Inhalt: Fehler im Modul poslj001.dbj Zeile 11 Spalte 13
.PRIMTABLEIS POSTION
Tabelle nicht geöffnet

Lösung:
Tabellenname wurde falsch geschrieben. I.d.F. muß die Tabelle POSITION heißen.

Fehlermeldung "Lesefehler"
Dieser Fehler tritt in einem Modul auf, wenn in eine Tabelle keine Datensätze vorhanden sind.
Überschrift Fehlermeldungsfenster: Fehler im Ausdruck
Inhalt: Lesefehler
ReadRec(SYSTEM.DAT,1)

Lösung:
Vorher prüfen ob Datensätze vorhanden sind. Beispiel:
If FileSize(SYSTEM) = 0
 Message("Keine Datensätze vorhanden!", "Fehler");
 Return
End



Topic Fehlermeldungen: Liste TDB/WinTDB/VDP Meldungen (unvollständig) Kapitel Allgemeine Tipps
Eine (unvollständige) Liste
Fehlermeldung Code Kapitel
Tabelle kann nicht geöffnet werden (Nr. 1)
Lesefehler (Nr. 2)
Schreibfehler (Nr. 3)
Fehler bei Indexerstellung (Nr. 4)
Fehler bei Indexlöschung (Nr. 5)
Index nicht vorhanden (Nr. 6)
Fehler in Selektion (Nr. 7)
Import-Fehler (Nr. 8)
Fehler in Ausgabeformat (Nr. 9)
Fehler beim Dateischließen (Nr. 10)
Indexschlüssel zu groß (Nr. 11)
Fehler beim Indexladen (Nr. 12)
Index paßt nicht zur Tabelle (Nr. 13)
Kein Datenfeld (Nr. 14)
illegales Unterverzeichnis (nur DOS-Version) (Nr. 15)
Illegale Tabellenverknüpfung (Nr. 16)
Tabelle ist offen (Nr. 17)
Keine Datei im aktuellen Verzeichnis (Nr. 18)
Datensatz nicht gefunden (Nr. 19)
Fehler in Kopfbereich (Nr. 21)
Indexdatei existiert bereits (Nr. 22)
Syntax-Fehler (Nr. 25)
Illegaler Dateiname (Nr. 26)
Fehler in Fußbereich (Nr. 27)
Indexbeschreibung zerstört (Nr. 28)
Falsche Programmversion (Nr. 29)
Doppelter Eintrag (Nr. 30)
MEMO nicht zu öffnen (Nr. 31 15.5)
MEMO hier nicht erlaubt (Nr. 32)
Fehler bei Memoschreiben (Nr. 33)
Illegale Operation (Nr. 34)
Tabelle bereits geöffnet (Nr. 35)
Zugriff nicht erlaubt (Nr. 36)
Tabelle nicht gefunden oder Zugriff verweigert (Nr. 37)
Falscher Code (Nr. 38)
Fehler in INCLUDE-Datei (Nr. 39)
Kein angekoppelter Datensatz (Nr. 40)
Ausdruck nicht komplett (Nr. 41)
Illegaler Operator (Nr. 42)
REAL-Überlauf (Nr. 43)
Typen stimmen nicht überein (Nr. 44)
Unbekanntes Zeichen (Nr. 45)
Illegale Zahlenkonstante (Nr. 46)
erwartet (Nr. 47)
Logischer Operand fehlt (Nr. 48)
Illegaler Operand (Nr. 49)
Unbekannter Bezeichner (Nr. 50)
Feldvariable erwartet (Nr. 51)
Unbekannter Fehler (Nr. 52)
Zu viele Variablen (Nr. 53)
fehlt (Nr. 54)
Zahl erwartet (Nr. 55)
erwartet (Nr. 56)
illegale Verknüpfung (Nr. 57)
Keine Tabelle (Nr. 58)
Zu viele Felder (Nr. 59)
Ausdruck zu komplex (Nr. 60)
nur Zahlenbereiche erlaubt (Nr. 61)
Fehler in Ausdruck (Nr. 62)
Datei kann nicht geöffnet werden (nur DOS-Version) (Nr. 63)
keine ADL-Datei (nur DOS-Version) (Nr. 64)
Datei nicht gefunden (nur DOS-Version) (Nr. 65)
nur 8 Seiten erlaubt (nur DOS-Version) (Nr. 66)
Zu viele Indizes (Nr. 67)
Auswahl ist leer (nur DOS-Version) (Nr. 68)
Formel nicht spezifiziert (nur DOS-Version)t (Nr. 69)
Bereich nicht festgelegt (nur DOS-Version) (Nr. 70)
Bezeichner doppelt definiert (Nr. 71)
REL-Tabelle existiert bereits (Nr. 72)
Zu viele R-Felder (Nr. 73)
Nur 15 Stellen erlaubt (Nr. 74)
String zu lang (Nr. 75)
nur ein N-Feld erlaubt! (nur DOS-Version) (Nr. 76)
zu wenig Platzhalter (nur DOS-Version) (Nr. 77)
zu viele Platzhalter (nur DOS-Version) (Nr. 78)
zu wenig Platz am rechten Rand (nur DOS-Version) (Nr. 79)
nur ein ID_Index erlaubt (nur DOS-Version) (Nr. 80)
Bereichsüberlauf (Nr. 81)
Unbekanntes Kommando (Nr. 82)
Label fehlt (nur DOS-Version) (Nr. 83)
kein ID-Index festgelegt (nur DOS-Version) (Nr. 84)
keine Definition (nur DOS-Version) (Nr. 85)
Illegale Textaufteilung (Nr. 86)
Illegaler Zugriff (Nr. 87)
Tabelle nicht geöffnet (Nr. 88)
Variable erwartet (Nr. 89)
Fehler beim Indexschreiben (Nr. 90)
Fehler beim Indexlesen (Nr. 91)
Ende des Unterreports nicht festgelegt (Nr. 92)
Illegale Operation (Nr. 93)
Zu viele Tabellen (Nr. 94)
Index defekt (Nr. 95)
BIS erwartet (Nr. 96)
END erwartet (Nr. 97)
Illegale Indexdefinition (Nr. 98)
Speicher reicht nicht aus (Nr. 99)
illegale Dateistruktur (Nr. 100)
Verschachtelung nicht erlaubt (Nr. 101)
ENDPROZ erwartet (Nr. 102)
weitere Anwender im Netz (Nr. 103 15.2)
Netzoperation abgebrochen (Nr. 104)
Datensatz wird bereits editiert (Nr. 105 15.2.2)
Fehler beim Einloggen (Nr. 106)
IPX-nicht aktiv (Nr. 107)


Topic Absturz WinTDB/VDP Kapitel Allgemeine Tipps
Sollte es vorkommen, das die Anwendung WinTDB.exe oder VDP.exe eine allgemeine Schutzverletzung liefert, m.a.w. abstürzt, dann reicht es nicht die Anwendung WinTDB/VDP
neu zu starten, aber Windows muß neu gestartet werden!

Das gilt für Windows 3.11 und Windows 95. Windows NT überlebt die Problematik.

Obiges gilt natürlich auch für fertige VDP-Anwendungen.

Warum (gilt für Windows 3.x und 95):
Wenn VDP abstürzt bleiben Teile der Anwendung im Hauptspeicher "hängen" oder belegt.
Das hängt mit der Hauptspeicherverwaltung von Windows zusammen. Zu erkennen ist das u.a. an der Große der verbleibende Kapazität der Windows Systemressourcen.
Wird die VDP gleich neu gestartet, kann es unter Umstände zu der Verwendung von falsche Hauptspeicher-Seiten führen. Ist eine sehr technische Angelegenheit.
Daher keine weitere Details.
Um absolut sicher zu gehen, ist es auch ratsam bei große Datenmengen, alle Tabellen der VDP-Anwendung zu restaurieren. Ich spreche da aus Erfahrung.


Topic Liste der Zuordnung für das Contextmapping. Kapitel Allgemeine Tipps
Hilfedatei erstellen
eine Liste der Zuordnung für das Contextmapping.
Stand: 24.03.1999 VDP Version 2.01

define ctxMptDatKopplung 10555
define ctxMptPrjNetzwerkEinrichten 12009
define ctxMptPrjDruckerEinrichten 12008
define ctxMptPrjProjektSchliessen 12007
define ctxMptPrjProjektOeffnen 12005
define ctxMptPrjNeuesProjekt 12004
define ctxMptPrjEntwicklerEinstellungen 12003
define ctxMptPrjBeenden 12002
define ctxMptPrjAnwenderEinstellungen 12001
define ctxMptPrjMakroAbbrechen 10436
define ctxMptPrjMakroStarten 10441
define ctxMptPrjAdlBaum 12006
define ctxMptPrjTabellenStruktur 1084
define ctxMptDatImport 10502
define ctxMptDatExport 10503
define ctxMptDatRueckgaengigDatensatzXxx 10570
define ctxMptDatNeueDatensaetzeEingeben 105 10
define ctxMptDatDatensaetzeAendern 105 11
define ctxMptDatDatensatzLoeschen 105 12
define ctxMptDatDatensatzDuplizieren 10513
define ctxMptDatMarkierteDatensaetzeLoeschen 10514
define ctxMptDatFeldinhalteKopieren 10515
define ctxMptDatAlleMarkierungenEntfernen 10517
define ctxMptDatMarkierteDatensaetzeSortieren 10518
define ctxMptDatAndere 10521
define ctxMptDatSequentiell 10522
define ctxMptDatWeitersuchen 10523
define ctxMptDatAnfangDerTabelle 10524
define ctxMptDatVorherigerDatensatz 10525
define ctxMptDatNaechsterDatensatz 10526
define ctxMptDatSatznummer 10528
define ctxMptDatNaechsteMarkierung 10529
define ctxMptDatVorherigeMarkierung 10530
define ctxMptDatDoppelteEintraegeMarkieren 10531
define ctxMptDatSuchenUndErsetzen 10532
define ctxMptDatVolltext 10533
define ctxMptDatNurMarkierteDatensaetze 10540
define ctxMptDatFormularsicht 10541
define ctxMptDatSpalteAendern 10542
define ctxMptDatSpalteErstellen 10543
define ctxMptDatSpalteLoeschen 10544
define ctxMptDatAnDenAnfangBlaettern 10545
define ctxMptDatAnDasEndeBlaettern 10581
define ctxMptDatWeiterblaettern 10546
define ctxMptDatZurueckblaettern 10547
define ctxMptDatAlleDatensaetze 10549
define ctxMptDatSchriftart 10550
define ctxMptDatStandardTabellenformat 10552
define ctxMptDatNetzMonitor 10553
define ctxMptDatVerknuepfteDatensaetze 10556
define ctxMptDatNeueVerknuepfteDatensaetzeEingeben 10557
define ctxMptDatSortierung 10561
define ctxMptDatStatistik 10551
define ctxMptTedZeileLoeschen 103 12
define ctxMptTedWiederholen 10308
define ctxMptTedAllesMarkieren 10307
define ctxMptTedWeitersuchen24328
define ctxMptTedErsetzen24327
define ctxMptTedSuchenNach 10304
define ctxMptTedSchriftart 10303
define ctxMptTedTabulator 10302
define ctxMptMedMenuestruktur 10 129
define ctxMptMedSchriftartenListe 10 121
define ctxMptMedEigenschaften 101 10
define ctxMptMedWeiterblaettern 10 122
define ctxMptMedZurueckblaettern 10 123
define ctxMptMedAktuelleSeite 10 127
define ctxMptMedNeueSeite 10 125
define ctxMptMedEpilog 10174
define ctxMptMedFussbereich 10173
define ctxMptMedDatenbereich 10172
define ctxMptMedKopfbereich 10171
define ctxMptMedProlog 10170
define ctxMptMedLinealeUndRaster 10132
define ctxMptMedRahmenVertikal 10147
define ctxMptMedRahmenHorizontal 10146
define ctxMptMedLinkeRahmenseite 10140
define ctxMptMedObereRahmenseite 10141
define ctxMptMedRechteRahmenseite 10142
define ctxMptMedUntereRahmenseite 10143
define ctxMptMedHorizontalZentrieren 10144
define ctxMptMedVertikalZentrieren 10145
define ctxMptMedTabellarisch 10154
define ctxMptMedBreitestesFeld 10150
define ctxMptMedHoechstesFeld 10151
define ctxMptMedSchmalstesFeld 10152
define ctxMptMedNiedrigstesFeld 10153
define ctxMptMedPaletteAnzeigen 10134
define ctxMptMedFormularTesten 10135
define ctxMptMedNumerierung 10131
define ctxPopMedAusrichten 10192
define ctxMptPedAnzeige 10800
define ctxMptPedBildEinlesen 10801
define ctxMptPedInformation 10802
define ctxMptPrjDruckvorschau 10432
define ctxMptPrjDrucken 10433
define ctxMptPrjDateiLoeschen 10450
define ctxMptPrjReparieren 10462
define ctxMptPrjIndizes 10453
define ctxMptPrjMenuepunktVolltextindex 10460
define ctxMptPrjVondBaseKonvertieren 1040
define ctxMptPrjNachdBaseKonvertieren 1041
define ctxMptPrjOnlineHilfeErstellen 10456
define ctxMptPrjInstallationsvorlageErzeugen 10457
define ctxMptPrjProjektfensterAnzeigen 120 20
define ctxMptTedFormel 10300
define ctxMptTedKompilieren 11 103
define ctxMptTedBedingung 10301
define ctxMptPrjProjektSpeichernUnter 1004
define ctxMptPrjDemProjektHinzufuegen 10415
define ctxMptPrjAusschneiden 104 20
define ctxMptPrjKopieren 10421
define ctxMptPrjEinfuegen 10422
define ctxMptPrjLoeschen 10423
define ctxMptPrjEntwerfen 10426
define ctxMptPrjEigenschaften 10427
define ctxMptPrjTabellenVerknuepfen 10443
define ctxMptPrjProjekteigenschaften 10444
define ctxMptPrjAdministratorPasswort 10446
define ctxMptPrjMasterPasswort 10451
define ctxMptPrjProgrammeigenschaften 10459
define ctxMptPrjDiskettenProduzieren 10458
define ctxMptPrjTabelleUmbenennen 10452
define ctxMptPrjNebeneinander24336
define ctxMptPrjUeberlappend24337
define ctxMptPrjSymboleAnordnen24335
define ctxMptPrjAlleSchliessen24338
define ctxMptPrjAlleIndizesWiederherstellen 10445
define ctxPopFrmHilfe 1099
define ctxDlgStdDruckerEinrichten2 2000
define ctxDlgAnwenderEinstellungen2 2004
define ctxDlgDatStatistik 20502
define ctxDlgDatSatznummer 20503
define ctxDlgDatVerknuepfteTabellen 20506
define ctxDlgDatSchnelleDirekteSuche 20507
define ctxDlgMedTastenkuerzel30003
define ctxDlgMedSchalterleiste30001
define ctxDlgMedMenuestrukturSeite30000
define ctxDlgMedSeiteFormularEigenschaften 20158
define ctxDlgMedBerichtEigVariablen 20552
define ctxDlgMedEigAllgMaskenelemente 20668
define ctxDlgMedBerichtEigDatenDefinition 20 116
define ctxDlgMedLinealeUndRaster 20156
define ctxDlgStdDateiOeffnen3 2050
define ctxDlgStdDateiSpeichern3 2051
define ctxDlgStdSchriftart3 2053
define ctxDlgStdAusdruck2 2003
define ctxDlgDialogfensterFuerDieVolltextSuche 205 12
define ctxDlgDatImportExport 20508
define ctxDlgDatSuchenUndErsetzen 20509
define ctxDlgPrjMakroAuswahl2 10 10
define ctxDlgStdAlphanumerischesFormat 20605
define ctxDlgStdNumerischesFormat 20606
define ctxDlgStdZeitFormat 20607
define ctxDlgStdAllgemeinesFormat 20609
define ctxDlgStdAuswahlFormat 206 10
define ctxDlgStdAdlFormat 206 11
define ctxDlgStdAutoNrFormat 20615
define ctxDlgPrjEigenschaftenProjektelement 20402
define ctxDlgPrjProjekteigenschaften 20400
define ctxDlgPrjAdministratorPasswort 20403
define ctxMptDatEndeDerTabelle 10527
define ctxDlgDatSucheMitBedingung 20504
define ctxDlgDatSuchenUeberIndex 20505
define ctxDlgMedSchriftartenliste 20 115
define ctxDlgMedMenuestruktur21400
define ctxDlgMedSeitennummer 20151
define ctxDlgMedTabellarischeAusrichtung 20153
define ctxDlgMedSeiteGruppierung 20155
define ctxDlgTedSuche42530
define ctxDlgTedErsetzung42531
define ctxDlgTedEinstellungen42532
define ctxDlgStdNetzwerkEinrichten2 2001
define ctxDlgStdFormelAssistent2 1001
define ctxDlgStdFehlerInFormeln2 1002
define ctxDlgStdVerknuepfenVonTabellen2 1003
define ctxDlgStdStrukturEditor 20000
define ctxDlgDatSpaltenBeschreibung2 1007
define ctxDlgStdStrukturAenderung 20401
define ctxDlgStdPasswortUndSchluessel30900
define ctxBerMaskenGestalten 100000
define ctxTecMaskenelementeSelektieren 100002
define ctxTecMaskenelementeAusrichten 100003
define ctxTecSchriftartEinesMaskenelementesAendern 100004
define ctxBrwBerichtSchritt 1223 20
define ctxBrwBerichtSchritt222321
define ctxBrwBerichtSchritt322322
define ctxBrwBerichtSchritt422323
define ctxBrwBerichtSchritt522324
define ctxBrwBerichtSchritt622325
define ctxBrwBerichtSchritt722326
define ctxBrwBerichtSchritt822327
define ctxBrwFormularSchritt 122300
define ctxBrwFormularSchritt222301
define ctxBrwFormularSchritt322302
define ctxBrwFormularSchritt422303
define ctxBrwFormularSchritt522304
define ctxBrwFormularSchritt622305
define ctxBrwFormularSchritt722306
define ctxBrwFormularSchritt822307
define ctxBrwFormularSchritt922308
define ctxBrwFormularSchritt 1022309
define ctxBrwProjektSchritt 122340
define ctxBrwProjektSchritt222341
define ctxBrwVolltextSchritt 122350
define ctxBrwVolltextSchritt222351
define ctxBrwVolltextSchritt322352
define ctxBrwVolltextSchritt422353
define ctxDlgPrjAdminPasswortEingeben 20405
define ctxDlgProgrammStart2 1202
define ctxDlgNeuesProjektelement 20404
define ctxMptMedBerichtEigenschaften 10 124
define ctxMptMedFormularEigenschaften 10 120
define ctxDlgMedFormularEreignisse 20553
define ctxDlgEntwicklerEinstellungen 20002
define ctxDlgDatSortierung 204 12
define ctxMptMedAuffrischen 10133
define ctxMptTedAllesloeschen24326
define ctxMptPrjWaehlen 10554
define ctxDlgMedEigAktivierungSeiten 20 117
define ctxDlgMedBerichtEigLayout 20150
define ctxDlgMedEigStilBeschriftung 206 20
define ctxDlgMedEigStilLogo 20621
define ctxDlgMedEigStilTabelle 20622
define ctxDlgMedEigStilMakro 20623
define ctxDlgMedEigStilFormel 20624
define ctxDlgMedEigStilAlpha 20625
define ctxDlgMedEigStilText 20627
define ctxDlgMedEigStilJaNein 20629
define ctxDlgMedEigStilRelation 20631
define ctxDlgMedEigStilMemo 20633
define ctxDlgMedEigStilReferenz 20642
define ctxDlgMedEigEingabekontrolle 20645
define ctxDlgMedEigAktivierungDatenelemente 20626
define ctxDlgMedEigStilBild 20661
define ctxDlgMedEigFormatBild 20662
define ctxDlgMedEigStilLinie 20665
define ctxDlgMedEigFormatTabelle 20666
define ctxDlgMedEigFormatMemo 20667
define ctxDlgMedEigAllgSeiten 20 112
define ctxDlgMedEigFormatElement 20669
define ctxDlgMedEigStilHTML 20670
define ctxDlgMedEigEreignisseDatenelement 20680
define ctxDlgMedEigEreignisseMakro 20681
define ctxDlgMedEigStilBerichtBereich 20 111
define ctxDlgPrjProgrammeigenschaften2 1200
define ctxDlgPrjWWWServerTesten22500


Topic Mehrere VDP Versionen auf einem Rechner Kapitel Allgemeine Tipps
Es können mehrere VDP Versionen, z.B. VDP 2 und VDP 3 auf einem Rechner installiert werden, wenn die VDP DLLs jeweils im VDP BIN Verzeichnis abgelegt werden.

Vorgehensweise:
1.VDP installieren
2.Folgende Batchdatei vom VDP BIN Verzeichnis (z.B. c:\prog\vdp2\bin) ausführen:
rem
rem Batchdatei: cleanvdp.bat
rem VDP DLL-Dateien aus dem Windows-System-Verzeichnis ins VDP BIN Verzeichnis verschieben.
rem
Copy C:\WINDOWS\SYSTEM\BWCC32.DLL 
Copy C:\WINDOWS\SYSTEM\CW3230.DLL 
Copy C:\WINDOWS\SYSTEM\Owl52f.dll 
Copy C:\WINDOWS\SYSTEM\Bds52f.dll 
rem
del C:\WINDOWS\SYSTEM\BWCC32.DLL 
del C:\WINDOWS\SYSTEM\CW3230.DLL 
del C:\WINDOWS\SYSTEM\Owl52f.dll 
del C:\WINDOWS\SYSTEM\Bds52f.dll 

Noch ein Tip:
Wenn Sie feststellen möchten, ob VDP die richtige TDBEngine verwendet, dann VDP starten und versuchen die tdbengine, z.B. tdbengin40.dll umzubenennen.


Topic Menüfunktionen Kapitel Allgemeine Tipps
Menüpunkte und easy-Funktionen
Für die meisten Menüpunkte gibt es entsprechende easy-Funktionen.
Probleme gibt es bei den Menüpunkten:
Bearbeiten|Einfügen
Der Inhalt der Zwischenablage läßt sich mit Clip2Text auslesen.

Ansicht|Alle Datensätze
Mit Sortierung oder SetSortOder

Menüpunkte in der generierte EXE-Datei
Es können mehr als 10 Menüpunkte angelegt werden, allerdings werden diese abhängig vom verfügbaren Speicher aufgebaut.
Der verfügbare Speicher ist wiederum abhängig von 
 a/ Anzahl der Prozeduren in dem Modul woraus die Menüpunkte aufgebaut werden und 
 b/ von der Länge der Prozedurnamen.

Fazit: Prozeduren die nicht in Menüpunkte verwendet werden mit einem dummy Parameter versehen (Procedur myProc(nB : Real) und Prozedurnamen so kurz (aber noch verständlich) halten.
und
werden neue Prozeduren erstellt und danach die Menüstruktur im Formular angepasst, kann es sein, daß abhängig vom verfügbaren Speicher, 
Prozeduren "wegfallen" ohne einen Hinweis dass der Speicher nicht mehr ausreicht. 
Der Menüpunkt ist aber noch da, allerdings ohne Funktion. also vorsicht!


Topic SELF - Schnittstellenentwicklungsleitfaden Kapitel Allgemeine Tipps
Wer mehr über Schnittstellenprogrammierung wissen möchte:
SELF - Schnittstellenentwicklungsleitfaden für Fremdanwendungen
Tel. 0911-3191545


Topic System-Tabelle verwenden Kapitel Allgemeine Tipps
System-Tabelle
Die Einrichtung einer System-Tabelle ist in fast allen größeren Projekte nützlich.
Mit einer System-Tabelle können:
o Globale Informationen ablegt werden, wie z.B.
Benutzer-Name, Einstellungen, Logo, Datum des letzen Starts, getätigte Eingaben usw.
o Daten zwischen Formularen oder Formularen und Datenbankjobsausgetauscht werden.
o Dialogfelder für Benutzereingaben realisiert werden.

Pro Anwendung braucht nur eine System-Tabelle eingericht zu werden der auch nur einen Datensatz enthält.
Wenn einmal eine System-Tabelle eingerichtet wurde, werden Sie sehrschnell erkennen, wie nützlich diese ist, und für wie viele Anwendungen die eingesetzt werden kann.

Wie kann eine System-Tabelle erstellt werden?
Eine System-Tabelle ist eine ganz normale Tabelle, die jedoch im Gegensatz zu den anderen Tabellen keine Daten aus dem Anwendungsbereich der Applikationenthält sondern
einfach nur Daten für die Applikation selbst.
Weil eine Systeme-Tabelle so ähnlichfunktioniert wie eine Sammlung von globalen Variablen, wird sie oft nur einen einzigen Datensatz enthalten.
Unter Umständen besitzt dieser allerdings einige Dutzend Felder.
Da einer System-Tabelle meist nur ein Datensatz enthält, sollte die Tabellen-Eigenschaft
auf nur Editieren gesetzt werden (Neueingabe und Löschen deaktivieren, nachdem der eine Datensatz angelegt wurde).

Gemerkte Eingaben
Als erstes Anwendungsbeispiel betrachten wir eine Applikation mit einem Schalter zum
Suchen nach dem Namen.
Der Schalter enthält das Makro:

INPUT("Anfangsbuchstaben der gesuchte Name?");
SUCHEN("KUNDEN.ID", T-Eingabe);

Wenn dieser Schalter mehrmals hintereinander betätigt wird, sieht der Anwender immer
seine letzte Eingabe als Vorschlag für die nächste. Wenn er öfter nach gleichen oder
ähnlichen Einträgen suchen muß, ist dies eine große Hilfe beim Eintippen.
Falls aber ein anderen INPUT dazwischen kommt, ist die letzte Such-Eingabe verloren,
da der Inhalt der Variablen T-Eingabe überschrieben wurde.
Um dieses Manko zu beheben, erstellen wir eine System-Tabelle mit einem Feld für die
letzte Such-Option:

1. Wählen Sie Datei/Dem Projekt hinzufügen im Projektfenster und selektieren Sie dann Neue Tabelle in der Liste.
2. Als Name der Tabelle wählen Sie SYSTEM. (Auch jede andere passende Bezeichnung ist möglich)
3. Fügen Sie in der Struktur ein einziges alphanumerisches Feld mit demNamen SucheName hinzu. Die Länge könnte z.B. 40 betragen.
4. Erzeugen Sie die Tabelle. Ein Formular benötigen Sie nicht.

Wie schon gesagt, ist die System-Tabelle eine Tabelle wie alle anderen auch.
Sie hat jedoch keine Verknüpfung zu den anderen Tabellen im Projekt und enthält im
Gegensatz zu diesen nur Verwaltungs-Information.
Die Anfangswerte für diese Verwaltungs-Information sollten Sie nun eintragen.
Öffnen Sie die neue Tabelle und erzeugen Sie mit "Bearbeiten/NeueDatensätze eingeben"
einen neuen Datensatz. Jetzt können Sie einen sinnvollen Vorgabewert für die Suche nach
dem Namen in der Spalte SucheName eintragen, z.B. *.
Beenden Sie die Neueingabe und schließen Sie die Tabelle.
Das Makro auf dem Such-Schalter muß nun so erweitert werden, daß es vor der Abfrage die
letzte Such-Einstellung aus der System-Tabelle holt und nachher den neuen Begriff
wieder in die System-Tabelle einträgt:

ReadRec(SYSTEM, 1);
T-Eingabe := SYSTEM.SucheName;
Input("Wie beginnt der gesuchte Name?");
Suchen("Kunden.id", T-Eingabe);
SYSTEM.SucheName := T-Eingabe

Somit retten Sie den Suchbegriff über alle eventuell folgenden Aufrufe von INPUT hinweg
und sogar beim nächsten Öffnen des Projektes ist er noch da.
Wenn Sie mit der Workgroup-Edition netzwerkfähige Anwendungen erstellen, sollten Sie
darauf achten, daß jeder Anwender seine eigene private System-Tabelle erhält.
Dies erreichen Sie, indem Sie bei den Eigenschaften der Tabelle unter Suchpfad
Lokaleintragen. Auch wenn das restliche Projekt auf dem Server installiert wird, legt diese
Option die System-Tabelle in das private Verzeichnis.

Datenaustausch
Wer anspruchsvolle Datenbankjobs einsetzt, kommt manchmal in die Verlegenheit,
dem Job für die Ausführung noch weitere Information zukommen zu lassen.
Alte DOS-Hasen benutzen dazu immer noch dem Befehl NOTE, obwohl es mit einer
System-Tabelle einfacher und komfortabler geht.

Als einfaches Beispiel wählen wir einen Datenbankjob, der die Kunden aus KFZ als
Liste ausdruckt:

.REPORT
.PO 5, MT 3
.PROLOG
Liste der Fahrzeuge *** Erstellt von: Datum: $heute
.DATA$(Name:30 Vorname:20 Fahrzeug.Bezeichnung:30)

Im Prolog des Jobs soll neben dem Titel auch das Erstelldatum und der Autor angegeben
werden. Aber auf welchem Weg kommt der Name in den Datenbankjob?
Mit einer System-Tabelle ist das gar kein Problem. Erweitern Sie diese einfach um eine
Spalte Autor und tragen Sie dort als Vorgabewert der Autor ein.
Diese Angaben fügen Sie ihrem Datenbankjob hinzu:

.REPORT
.PO 5, MT 3
.PROLOG
Liste der Kunden *** Erstellt von: $SYSTEM.AutorDatum: $heute
.DATA$(Name:30 Vorname:20 Fahrzeug.Bezeichnung:30)

Nun müssen Sie noch dafür sorgen, daß jeweils der richtige Autor in die
System-Tabelle eingetragen wird. Wahrscheinlich gibt es ja schon ein Prozedur, die
den Bericht ausführt. Die müssen Sie nur noch etwas erweitern:

Procedure Liste_drucken
 Input("Geben Sie Ihren Namen an:");
 ReadRec(SYSTEM, 1);
 SYSTEM.Autor := T-Eingabe;
 WriteRec(SYSTEM, 1);
 Run("KUNDEN.Liste", 2);
EndProc

Auf diese Weise können Sie nicht nur einfache Strings mit Datenbankjobs austauschen
sondern auch mehrere Informationen auf einmal inklusive Memos für Textbausteine oder
Bilder für Logos im Datenbankjob.
Natürlich ist diese Art des Datenaustausches nicht auf Datenbankjobsbeschränkt.
Das selbe funktioniert zwischen Formularen, z.B. wenn Sie ein modales Formular öffnen
oder zwischen Formular und Bericht.

Dialoge mit dem Anwender
In Kombination mit Fomularen und der Oberflächen-Funktion ExecDialog entfalten
System-Tabellen ihre ganze Mächtigkeit. Hierzu folgende Fragenstellungen:
Sind Ihnen die Möglichkeiten von Message und Input zu eingeschränkt?
Möchten Sie auch mal ein Datum oder zwei Zahlen oder noch mehr Eingabe beim Benutzer
abfragen?
Würden Sie die Gültigkeit seiner Eingaben gerne kontrollieren und eigene Fehlermeldungen
ausgeben?

Dies ist alles kein Problem, wenn Sie Formulare mit der System-Tabellekombinieren.
In Formularen können Sie ja nach belieben unterschiedliche Datentypenkombinieren,
Eingaben prüfen, Felder vorbesetzen, weitere Formulare ausführen usw. Es macht
keinen Unterschied, ob diese Daten "echte" Daten oder Verwaltungsdaten aus 
der System-Tabelle sind.
Damit sich auch das richtige Dialog-Feeling einstellt, verfügt easy über die Funktion
ExecDialog, die jedes Formular wie ein Dialogfeld ausführt.
Der Unterschied zu ähnlichen Funktionen wie z.B. EditRec besteht in folgenden Punkten:

  •  das Formular wird immer in seiner ganzen Größe zentriert auf dem Bildschirm angezeigt,
  •  der Dialog wird nicht mit einem ADL-Panel versehen,
  •  Menü- und Schalterleiste bleiben unverändert,
  •  die restliche Anwendung ist vollkommen gesperrt, solange der Anwender den Dialog nicht
    schließt,
  •  die Funktion ExecDialog liefert als Rückgabewert, ob es mit OK (CloseWnd) oder
    Abbruch (Cancel) beendet wurde.

    Um Ihnen die Vorgehensweise zu demonstrieren, erweiteren wir das vorherige Beispiel um
    die Möglichkeit, einen Altersbereich für die auszudruckenden Kunden anzugeben.

    Auch diese beiden Angaben werden in der System-Tabelle gespeichert.
    Sie muß also um die Spalten GeburtsdatumVon und GeburtsdatumBis ergänzt werden.
    Als nächstes fügen Sie dem Projekt ein neues Formular namens Bereich_eingeben für
    die System-Tabelle hinzu, das später als Dialogfeld dienen wird. Es sollte nur die beiden
    Datumsfelder und die zwei Schalter beinhalten.
    Am besten sieht es aus, wenn Sie für die Eingabefelder die Rahmenart 3-dimensional verwenden.
    Die Schalter werden mit OK und Abbruch beschriftet und führen die Makros CloseWnd und Cancel aus.
    Die Prozedur Liste_drucken wird so erweitert, daß zu Beginn das
    Anfangs- und Ende-Geburtsdatum abgebfragt wird:

    Procedure Liste_drucken
     If ExecDialog("SYSTEM.Bereich_eingeben") = 1
      Input("Geben Sie Ihren Namen an:");
      ReadRec(SYSTEM, 1);
      SYSTEM.Autor := T-Eingabe;
      WriteRec(SYSTEM, 1);
      Run("KUNDEN.Datenbankjob_Test", 2);
     End
    EndProc

    Nach dem Aufruf von ExecDialog stehen die Daten in der System-Tabelle
    und können vom Datenbankjob aus benutzt werden:

    .REPORT
    .PROLOG
    .SELECTION Geboren >= SYSTEM.GebdatumVon AND Geboren <= SYSTEM.GebdatumBis
    Liste der Kunden
    Erstellt von: $SYSTEM.Autor   Datum: $heute
    Geburtsdatum zwischen $SYSTEM.GebdatumVon und $SYSTEM.GebdatumBis
    ..
    .DATA$(Name:30 Vorname:20 Fahrzeug.Bezeichnung:30)


  • Topic tdbengine Kapitel Allgemeine Tipps
    Verschiedene Tipps wie die TDBengine unter VDP verwendet werden kann.

    tdbengine als Utility-Programm ausführen
    In easy kann die TDBengine easy-Programme ausführen mittels
    execute("tdbengine.exe test.prg");


    Topic Daten grafisch darstellen Kapitel Allgemeine Tipps
    Das Programm AUTOGRAPH kann Grafiken aus eine Datenbank generieren.
    Informationen:
    Martin Pflug
    Sachsenstrasse 26
    32130
    Hiddenhausen
    Tel:05223/84879
    Fax:05223/878436
    eMail:Pflug-@t-online.de


    Topic VDP Beschränkungen Kapitel Allgemeine Tipps
    VDP bis zu Version 2.03 Revision 90
    Maximal Anzahl Tabellen: 30
    Maximum Zeichen für die Beschreibung eines Index: 40


    Topic Import Tipps Kapitel Allgemeine Tipps
    Tipp 1
    Erweiterung der Datenstruktur bei einem VDP-Projekt, wobei VDP nicht am Rechner installiert ist:

    Die alte Tabelle in eine temporäre TDB-Tablle exportieren.
    Dann eine leere Tabelle mit der neuen Datenstruktur in das Projekt kopieren.
    Schließlich einen Import der temp. TDB-Tabelle durchführen; "Felder nach Name zuweisen" wählen und den Import starten.
    Dabei bleiben die alten Auto-Nummern erhalten.
     
    Dabei nicht vergessen, die Index-Dateien zu sichern (*.CIN !), ebenso die von der exportierten Datei benutzten Relationsdateien (falls Relationsfelder enthalten).

    Tipp 2
    Hat die IMPORT-Tabelle eine Volltextsuche mit der Position an erster Stelle, dann ist das Feld für die Volltextsuche (Begriffe) 
    an die letzte Stelle zu setzen. Erst dann können die Daten nach Reihenfolge importiert werden.

    Wenn das .REL-Feld die Reihenfolge stört, entsteht jeweils eine Verschiebung um 1 Feld ...

    Hat die IMPORT-Tabelle keine Volltextsuche muß beim Übernehmen auch die Reihenfolge der Zuweisung stimmen.

    TDB-Tabellen sollte man beim Import immer nach Feld-Namen zuweisen (Feld1 := Feld1 usw.).


    Topic Verschiedene Zusatzprodukte Kapitel Allgemeine Tipps
    tdbText
    Netzwerkfähigkeit
    tdbText wurde hinsichtlich Netzwerkfunktionalität nie speziell aufbereitet.
    Wenn zwei im Netz tdbText zum gleichen Datensatz aufrufen, dann kann dies durchaus kollidieren.
    Sie können jedoch versuchen, dies dadurch zu verhindern, daß man einfach einen temporären Dateinamen beim Aufruf verwendet.

    Verschiedenes
    Kopierschutz
    Tool zur Dateien-Verschlüsselungs-DLL für den VDP:
    Eine Möglichkeit ist www.mrk-soft.de (encryption, und auch in deutscher Sprache).


    Topic Kopierschutz Kapitel Allgemeine Tipps
    Kopierschutz wenn erstellten Programme auf CD weitergegeben werden
    Informationen zu Software: http://www.aladdin.de


    Topic Hilfreiche Formelfelder für Formularen Kapitel Formulare
    Folgende Formelfelder sind bei der Erstellung von Masken immer wiedernützlich.
    Tip: Übernahme direkt im Formular mittels der Windows-Zwischenablage

    Bearbeitungsmodus ermitteln
    "Modus: " + Choice(GetMode+1, 'betrachten', 'ändern', 'neu')

    Aktuelles Datum mit Zeit
    DateStr(Today) + " " + TimeStr(Now)

    Anzeige aktueller Datensatz und anzahl Datensätze
    Str(RecNo(TABELLE))+"/"+Str(FileSize(TABELLE))
    oder Tabellenunabhängig
    Str(RecNo(FileNr))+"/"+Str(FileSize(FileNr))
    Hinweis: FileNr enthält die aktuelle Tabellennummer

    Anzeige ob ein Memofeld leer ist oder Inhalt hat (wie bei derDOS-TDB)
    Choice(Sel(MemoLen(TABELLE.Memofeld)=0),"Leer","Inhalt")

    Letzte Änderung eine Tabelle feststellen
    "Letzte Tabellenänderung: " + FirstDir("TABELLE.DAT","")[27,18]


    Topic Bericht aus einem Formular aufrufen Kapitel Formulare
    Von einem Formular mittels eines Makros ein Bericht aufrufen, wobei als Selektion der
    aktuelle Datensatz übergeben wird.

    Makro im Formular:
    NOTE(STR($TABNAME.Nummer)); RUN("TABNAME.Bereicht_MEINBERICHT");

    Berichtsselektionskriterium:
    Nummer = VAL(NOTE)
    Nummer ist ein Auto_Nummer-Feld der Tabelle TABNAME.
    Berichte haben den Vorteil daß das Layout wesentlich besser ist als gegenüber
    Datenbankjobs und Serienbriefe.

    Weitere Hinweise: 
    NOTE kann auch verwendet werden um ein komplettes Selektionskriterium zu übergeben.
    Als Beispiel soll einen Bericht über den aktuellen Datensatz ausgegeben werden:

    Berichtsselektionskriterium: NOTE
    Wenn Sie in einem Formular ein Formelfeld mit dem Inhalt NOTE($Feldname) definieren,
    dann enthält dieses Feld immer den aktuellen Wert. Somit kann mittels Drucken,
    den aktuellen Datensatz-Bericht gedruckt werden
    (im Bericht oben aufgeführtes Bereichsselektionskriterium definieren).
    Vorteil ist, daß kein Makro definiert werden muß.


    Topic Bitmap Makros Kapitel Formulare
    Die Standardschalter(Buttons) der WinTDB/VDP können mit einem Bitmap versehen werden:
    Vorgehensweise:

    o Anzeigeelement "Logo" im Formular einfügen

    o Makro Schalter in gleicher Größe wie das Anzeigeelement "Logo" auf dem
    Anzeigeelement rübersetzen und als Rahmenstil unsichtbar wählen.


    Topic Laufende Nummer des Koppelfeldes in einem Formel anzeigen Kapitel Formulare
    Beispiel: Feld Kopplung gekoppelt mit ADRESSEN
    Formelfeld: ADRESSEN.Laufende_Nummer


    Topic Letzte Änderung eine Tabelle feststellen Kapitel Formulare
    Mittels FirstDir lassen sich Datei-Informationen ausgeben. An Position27 fängt das Dateidatum an. Die folgende 18 Zeichen enthalten Datum und Zeit.
    Mittels DBName und FileNr kann die Änderung für die aktuelle Tabelleausgegeben werden:
    "Letzte Änderung: " + FirstDir(DBName(FileNr),"")[27,18]

    Beispieltabelle: adressen.dat
    "Letzte Änderung: " + FirstDir("adressen.dat","")[27,18]


    Topic ExecMacro eine andere Tabelle Kapitel Formulare
    Wenn in einem Formular ein ExecMacro eine andere Tabelle ausgeführt wird, kann es 
    vorkommen, daß nachdem Datensätze markiert sind und ein Formular in Tabellensicht
    aufgerufen wird, keine Datensätze angezeigt werden. 

    Hierzu folgenden Tip wie die Datensätze angezeigt werden:

    Statt Makro-Befehl 
     EXECMACRO(Tabelle, Ausdruck...), 
    den Befehl
     ACTIVATEFORM(Formular);EXECMACRO(Tabelle, Ausdruck...)
    verwenden.


    Topic Inhalt geht beim Logo kopieren verloren Kapitel Formulare
    Ist ein Bild in einem Logo eingebettet, dann wird mittels Bearbeiten,Kopieren der Logo-Inhalt nicht kopiert.


    Topic Tabelle im Formular: aktuell angezeigtes Record aufrufen Kapitel Formulare
    Ist in einem Formular ein Anzeigeelement Tabelle definiert, dann ist esmanchmal sinnvoll auf den aktuell ausgewählte Datensatz (der angekoppelte Tabelle)zuzugreifen. 
    Im Tabellenmodul folgende Prozedur definieren:

    Procedure ZeigeGekoppeltesRecord
     Var nRNo = RecNr(ANGEKOPPELTETABELLE);
     ActivateForm("ANGEKOPPELTETABELLE.Formular);
     SetMark(ANGEKOPPELTETABELLE. NRNo);
     Attach;
     Sortierung("Markierung");
    Endproc

    Diese Prozedur durch folgendes Makro
    ExecMacro(TABELLE, ZeigeGekoppeltesRecord)
    aufrufen.


    Topic Ändern von Auswahlfelder Kapitel Formulare
    Beim Ändern von Auswahlfelder ist folgendes zu beachten:
    In ein bestehendes Formular das Auswahlfeld löschen, wieder neuhinzufügen und Numerierung der Objekte anpassen.
    WinTDB/VDP speichert die Auswahlmöglichkeiten im Formular mit ab.


    Topic Feldinhalt mit Leerzeichen am Anfang abfangen Kapitel Formulare
    Im Datenfeld unter Eingabekontrolle, Überprüfung folgende Bedingung setzen:
    Überprüfung: Links($Feld, 1) <> " "
    Meldung: Feld darf nicht mit einem Leerzeichen anfangen!


    Topic Umwandlung Großbuchstaben Kapitel Formulare
    Umwandlung in Großbuchstaben mittels:
    Deutsch: TABELLE.Feld := GROß(TABELLE.Feld);Refresh;
    Englisch: TABELLE.Feld := UPPER(TABELLE.Feld); Refresh;
    Hinweis: wichtig ist das Refresh benutzt wird!!!


    Topic Feld verlassen Befehl Kapitel Formulare
    Im Formulareditor kann ein Befehl ausgeführt werden, wenn das Feldverlassen wird.
    Es ist hier nicht notwendig bei der Änderung eines Feldinhaltes den Refresh-Befehl einzusetzen.
    Beispiel:
    Ausführen beim verlassen:
    $PreisMWST := $PreisNetto * 1,14;Refresh;
    Refresh ist NICHT notwendig, der $PreisMWST wird automatisch richtig gesetzt.


    Topic Formelfeld formatiert darstellen Kapitel Formulare
    Bei der Verwendung von numerischen berechneten Feldern in Formularen und Berichten
    kann es störend sein, daß immer zwei Nachkommastellen ausgegeben werden.
    Hier kann die Funktion STR Abhilfe schaffen: 

    Wenn Ihr bisheriger Ausdruck <Formel> war, sollten Sie STR(<Formel>, 0,n) 
    angeben, wobei n die gewünschte Anzahl von Nachkommastellen ist.

    Beispiel:
    STR(INT(Geburtstag),5,0)


    Topic Meldung "Fehlerhafte Gültigkeitsbedingung" Kapitel Formulare
    Die Gültigkeitsbedingung, die unter Eingabekontrolle eingegeben wurde,kann nicht berechnet werden.
    Beispiele:
    o Feldname falsch geschrieben
    o Makro hat sich geändert


    Topic Gezielt ausfüllen von Felder Kapitel Formulare
    Die Fragestellung habe ich schon ein paar Mal gehört und kann folgende Lösung dazu bieten:
    Beispiel:
    Das Feld LAND (Werte z.B. D, NL, B etc., Länderkennungen sindgespeichert in der Tabelle 
    TELLNDVW ) soll in die Felder TEL und FAX den jeweiligen Ländervorwahlsetzen. Weiterhin 
    enthält eine globale Systemtabelle SYSTEM die Option ob dieLänderkennung mit einem Plus 
    Zeichen oder mit 00 anfangen soll (Feld AdressenVorwahlPräfix).
    Für Holland währe es +31 oder 0031 und dann die Telefon- oderFaxnummer.
    Lösung:
    In der Eingabekontrolle für das Feld "LAND", Ausführen beim Verlassenfolgenden Befehl 
    einsetzen:
    ExecMacro(ADRESSEN, SetzeTelFaxVorgaben(0))
    Die Prozedur SetzeTelFaxVorgaben(0) (Dummy Parameter damit die Prozedurnicht in der 
    Werkzeug/Makroliste erscheint) aus dem Modul Adressenmakros hatfolgenden Aufbau:

    Procedure SetzeTelFaxVorgaben(nDummy : Real);
    ..anhand von der eingabe im feld land, werden aus der tabelle tellndvw
    ..die vorwahlnummern fuer tel und fax gesetzt
    ..lokale proc der via execmakro beim verlassen des feldes Landausgeführt wird
    Vardef sVorwahl : STRING;
    ReadRec(SYSTEM, 1); .. lese system record
    IF $SYSTEM.AdressenSetzeTelFaxVorgaben = 1 AND GetMode = 2
     ..suche Land aus der tabelle TELLNDVW
     nRNo := FindRec(TELLNDVW, $Land, "TEL-KENN.IND", 1);
     .. nichts gefunden, dann verlassen proc
     ?nRNo = 0 / Return
     ReadRec(TELLNDVW, nRNo);
     ..vorwahl setzen. präfix leer dann lasse wie es ist
     ?$SYSTEM. AdressenVorwahlPräfix = "" / sVorwahl := "" +$TELLNDVW.Vorwahl + " "
     ?$SYSTEM.AdressenVorwahlPräfix <> "" / sVorwahl :=$SYSTEM.AdressenVorwahlPräfix + 
     $TELLNDVW.Vorwahl[3, Length($TELLNDVW.Vorwahl) - 2] + " "
     ..abhängig von der sparte tel und fax setzen
     IF $ADRESSEN.Sparte = 6 .. privat
      $ADRESSEN.Tel-Privat := sVorwahl
      $ADRESSEN.Fax-Privat := sVorwahl
     End
     IF $ADRESSEN.Sparte = 3 .. geschaeft
      $ADRESSEN.Tel-Geschaeft := sVorwahl
      $ADRESSEN.Fax-Geschaeft := sVorwahl
     End
     Refresh
    End
    EndProc


    Topic Prüfung ob ein Memofeld Inhalt hat oder nicht Kapitel Formulare
    Definition eines Formelfeldes mit folgendem Inhalt :
    Choice(Sel(MemoLen(TABELLE.Memofeld)=0),"Leer","Inhalt") oder
    Choice(Sel(MemoLen(TABELLE.Memofeld)=0),"","vorhanden") 


    Topic Memos in der Tabellensicht anzeigen Kapitel Formulare
    Wird ein Memo-Feld in eine Tabellensicht angezeigt, dann wird das WortMEMO angezeigt. 
    Verwenden Sie die Funktion MemoStr(Memo-Feld) um die ersten 255 Zeichendes Memos anzuzeigen.
    Die gleiche Möglichkeit kann in eingebetteten Tabellen verwendetwerden.

    Beispiel:
    Feld: Aenderung, Typ: MEMO, Anzeige als MemoStr(Aenderung) stattAenderung


    Topic Strings in der Tabellensicht links oder rechtsbündig ausgeben Kapitel Formulare
    Um in der Tabellensicht Zeichenketten rechtsbündig auszugeben, öffnenSie das Dialogfenster mit dem Spaltenformat (Ansicht/Spalte ändern) und tragenunter Anzahl Nachkommastellen 0 ein. 

    Siehe da: Die Spalte wird rechtsbündig ausgerichtet.

    Für linksbündig wird im Nachkommastellen-Feld nichts eingetragen (leerlassen).


    Topic Sounddatei abspielen Kapitel Formulare
    Das Einlesen einer WAV-Datei geschieht genau wie das eines Bildes: DerSound erscheint als Schalter im Formular. Zuerst muß man den Editiermodus einschalten.Nach Drücken des Schalters wird ein Fenster geöffnet, in welchem ein Mikrofonsymbolenthält, fallsda
    Zum Abspielen eines Sounds braucht man auf jeden Fall die FunktionPlaySound. Plazieren Sie einfach einen Makroschalter in Ihr Formular und geben Sie alsMakrobefehl an:

    PlaySound(Klangfeld)

    Wobei "Klangfeld" das Label Ihres Soundfeldes ist.


    Topic Kompakte If-Abfragen mit der Choice-Funktion Kapitel Formulare
    Die mit Abstand am meisten benötigte Steuerstruktur ist mit Sicherheitdie IfThenElse-Abfrage. 
    Mit der Funktion Choice können einfache If-Abfragen realisiert werden.Diese Konstruktion kann man an den unterschiedlichsten Stellen nutzbringend einsetzen  vorallem da, wo nur Ausdrücke und keine Kommandos syntaktisch zulässig sind: inTabellenformaten,in
    Choice(Wahl, a1, a2, a3 ... an)
    Der erste Parameter der Choice-Funktion muß eine Zahl sein. Diesebestimmt, welcher der 
    nachfolgenden Ausdrücke das Funktionsergebnis bildet. Beträgt der Wertvon Wahl beispielsweise 2, ist das Funktionsergebnis der Ausdruck in a2. Wennder Wert des ersten Parameters nicht im Bereich von 1 bis n liegt, wird alsFunktionsergebnis von Choiceimmer
    Bei einer If-Abfrage gibt es für den Parameter Wahl nur zwei Werte,nämlich wahr und falsch. Ist Wahl wahr (Wert 1), wird der Parameter a1, zurückgegeben.Ist Wahl falsch (Wert 0), dann entspricht das Funktionsergebnis dem letzten Parameter(sinnvollerweisea

    Beispiel:
    Choice( Sel(Postfach < > ""), "Postfach: "+Postfach, Strasse)

    Erklärung: Mit der Funktion Sel wird die Bedingung geprüft:
    Postfach < > ""
    Ist das Feld Postfach nicht leer, trifft die Bedingung also zu, dannbildet der Eintrag in Postfach mit vorangestellter Konstante "Postfach: " dasFunktionsergebnis der Choice-Funktion. Ist das Feld Postfach hingegen leer, dann wird alsFunktionsergebnisderE
    Anmerkung:
    Die Angabe des bloßen Feldlabels bei einer Bedingung ist eine Abkürzungfür Feld < > "" daher kann der Funktionsaufruf auch lauten:

    Choice( SEL(Postfach), "Postfach: "+Postfach, Strasse)

    Weitere Beispiele sind:

    Nur einen Wert in eine Formel setzen wenn eine Bedingung erfüllt ist
    Setze im Formelfeld ALTER einen Wert wenn im Datenbankfeld GEBURTSTAGeinen Wert 
    eingetragen wurde.
    Lösung:
    Choice(INT(Geburtstag)+1, 0, (Today - Geburtstag) / 365.25)

    Noch eleganter (speziell für oben genannte Aufgabenstellung):
    Choice(INT(Geburtstag)+1, "", "Alter:"+STR(INT((Today - Geburtstag) /365.25),3,0))

    Gebe eine Informationszeile aus, wenn im Feld Ort einen Eintragvorhanden ist
    "A  Gebe das Wort Termin aus, wenn eine Bedingung erfüllt wurde 
    Choice(LINK(TERMLIST.AdressenRecNo = RecNo(ADRESSEN)), "Termin", "")


    Topic Zählen von angekoppelten Datensätzen Kapitel Formulare
    Die Funktion der Wahl lautet 'LinkCount', bzw. Link und Count. 

    Im Formular ein Formelfeld einfügen mit dem Inhalt LinkCount (TABELLE),wobei TABELLE der Name der angekoppelten Datei ist.
    Wenn es nicht funktioniert, gibt es Alternative folgende Formelverwenden:
    Link(TABELLE) * Count(TABELLE.Laufende_Nummer)!
    LinkCount geht auch über mehrere Distanzen hinweg, so dass auchZwischenkopplungen gezählt werden können. 


    Topic Eingebettete Tabellen in einem Formular bearbeiten Kapitel Formulare
    Folgende 3 Prozeduren ermöglichen eine direkte Bearbeitung von Datensätzen einer
    eingebettete Tabelle.
    Die Prozeduren können mittels Makro-Schalter auseinem Formular aufgerufen werden.

    Procedure DelSatz(nAktRec : Real);
    ..#Datensatz löschen
    ..#Parameter:
    ..#nAktRec = aktueller Datensatz
     If nAktRec > 0
      ?Message("Satz wirklich löschen?", "Satz löschen", 3) = 6 /DelRec(TABELLE, nAktRec);
     End
    Endproc

    Procedure EditSatz(nAktRec : Real) : Real;
    ..#Datensatz bearbeiten
    ..#Parameter:
    ..#nAktRec = aktueller Datensatz
     Vardef nRT : Real;
     If nAktRec = 0 / Return 0
     DatensätzeBearbeiten("TABELLE.Formular");
     Readrec(TABELLE, nAktRec);
     nRT := EditRec("Ändern Sie die Angaben. Abbruch mit ESC.");
     CloseWnd;
     Return nRT
    Endproc

    Procedure NewSatz(nDummy : Real);
    ..#Neuer Satz anlegen
    ..#Parameter:
    ..#nDummy = damit die Prozedur nicht in der Makroliste erscheint
     Vardef nRNo, nAktRec : Real; 
     nAktRec := ReadRec(PRIMTABELLE, RecNr(PRIMTABELLE));
     If nAktRec > 0
      ReadRec(TABELLE, 0);
      TABELLE.tFeld1 := "<Neu>";
      Writerec(TABELLE, 1 + FileSize(TABELLE));
     End
     nRNo := FindRec(TABELLE, Str(TABELLE.Laufende_Nummer), "TABELLE.INR",1);
     If nRNo > 0
      ?EditSatz(nRNo) = 0 / DelSatz(nRNo);
     End
    Endproc


    Topic POS Befehl bei Feldverlassen verwenden Kapitel Formulare
    Folgende Methode prüft das vorhanden sein einer Dateierweiterung.
    Ist keine Dateierweiterung vorhanden, dann wird eine Erweiterunggesetzt:

    Beispiel prüft ob eine Dateierweiterung HLP vorhanden ist:
    Choice(POS(".HLP", Upper(sHLPDateiname)) + 1, sHLPDateiname :=sHLPDateiname  + ".hlp", "");Refresh;

    Wird beim Befehl Feldverlassen eines Formulars verwendet.


    Topic Reihenfolge in Ausführen-Menü Kapitel Formulare
    Die Reihenfolge der Menüpunkte im Menü Ausführen ist im Entwurfsmodusanders als im Usermodus. Die Reihenfolge im Usermodus richtet sich nach derReihenfolge der Prozedureinträge ohne Parameter im ersten Formular, wogegen imEntwurfsmoduls die Prozedurenalph

    Sie müssen allerdings drauf achten, daß die Module in der richtigenReihenfolge übersetzt werden. Im Beispiel: erst Modul THELM003, dann THELM002 und THELM000

    Beispiel:
    Modul THELM000
    Prozedure Ausführen_Menüpunkt_1
    ExecMacro(THELM001, Menüpunkt1(Parameter));
    ..der Parameter kann auch ein Dummy Parameter sein
    Endproc

    Prozedure Ausführen_Menüpunkt_2
    ExecMacro(THELM003, Menüpunkt2(Parameter));
    ..der Parameter kann auch ein Dummy Parameter sein
    Endproc


    Topic Tabellenansicht löschen Kapitel Formulare
    Ist keine Tabellenansicht gewünscht dann ist es Möglich dieTabellenseite zu löschen. Hierzu erst die Tabelle selektieren und mit Bearbeiten|Löschen löschen.Die Seite läßt sich auch über Bearbeiten|Löschen löschen. Die Seite muß allerdings komplettleersein


    Topic Änderungsdatum festhalten Kapitel Formulare
    Das Änderungsdatum eines Datensatzes kann mit folgende Möglichkeit festgehalten
    werden:

    Für VDP:
    Legen Sie ein Datumsfeld an und geben Sie bei diesem im Formular unter
    Eigenschaften/Eingabekontrolle im Feld "Automatischer Eintrag" TODAY an
    ("Formel" vorher ankreuzen).

    Für TDB (DOS):
    Änderung am:_##########DF(heute) 

    Diese Formel reagiert nur beim Editieren. So kann bei einer nachfolgenden Auswertung einfach alle - und nur diese - Datensätze auswählt werden, die voher editiert wurden.


    Topic Formularseiten beim Aufruf steuern Kapitel Formulare
    Über die Eigenschaft Formular-Ereignisse | beim öffnen läßt sich u.a.auch die Seite die beim Aufruf des Formulars gezeigt werden soll steuern.
    Es gibt eine Reihe von Möglichkeiten.

    Tip 1:
    Via den Wert eines Feldes aus eine SYSTEM-Tabelle.
    Feld-Definition:
    SYSTEM.nPageNr, wobei nPageNr ein Byte-Feld ist
    Beispiel:
    procedure SetPage
     ..lese system record
     If ReadRec(SYSTEM, 1) > 0
      ..setze seitennummer
      ViewPage(SYSTEM.nPageNr);
     end
    endproc
    Aufruf im Ereignis-Feld:
    ExecMacro(SYSLM001, SetPage)
    SYSLM001.MOD ist ein Modul der SYSTEM-Tabelle.

    Tip 2:
    wie Tip 1 nur direkt mittels ViewPage.
    Beispiel:
    ViewPage(SYSTEM.nPageNr)
    Aufruf im Ereignis-Feld:
    ViewPage(SYSTEM.nPageNr)


    Topic Dynamische Schalterbeschriftung Kapitel Formulare
    Die Bezeichnung der Formularschalter sind standardmäßig starr aufgebaut, d.h.
    ein Formular wird erstellt. Die Felder und deren Bezeichnung definiert.
    Der Anwender hat keine Möglichkeit die Bezeichung zu ändern.
    Es gibt folgende Möglichkeit dynamische Schalterbezeichungen zudefinieren:

    Es gibt die Möglichkeit Formelfelder zu definieren.
    Anstatt eine feste Bezeichnung kann ein Formelfeld der einen Wert einer Tabelle
    dargestellt, verwendet werden.

    Beispiel:
    Es wird eine Tabelle SYSTEM angelegt.
    In der Tabelle werden alphanumerische Felder, z.B. 
    Feld Bezeichnung-Schalter1 mit 20 Zeichen 
    Feld Bezeichnung-Schalter2 mit 20 Zeichen 
    usw. angelegt.
    Dazu wird ein Formular, z.B. "Schaltereinstellungen" definiert.
    Im Formular kann der Benutzer die Bezeichnung eingeben.

    Im Hauptformular wie folgt vorgehen:
    1.Schalter definieren; Eigenschaften Farbe silber und Rahmen unsichtbar.
    2.Formelfeld mit als Inhalt: SYSTEM.Bezeichnung-Schalter1 definieren und als Rahmen-Eigenschaft hervorgehoben.
    Sollte das nicht klappen, dann gibt es noch folgende Möglichkeiten:
    Formelfeld: ReadRec(SYSTEM ,1);SYSTEM.Bezeichnung-Schalter1
    oder
    Formelfeld: SYSTEM.Bezeichnung-Schalter1[1, 255]

    3.Formelfeld ausschneiden (über Menü Bearbeiten | Ausschneiden)
    4.Formeld in Rahmen des Schalters einfügen (über Menü Bearbeiten |Einfügen)
    5.Maße der beiden Elemente (Schalter und Formelfeld) gleich setzen (über Menü Ausrichten)

    das wars.

    Siehe auch Dynamische Feldbeschriftung.


    Topic Dynamische Feldbeschriftung Kapitel Formulare
    Die Bezeichnung der Formularfelder sind standardmäßig starr aufgebaut, d.h. ein Formular
    wird erstellt. Die Felder und deren Bezeichnung definiert.
    Der Anwender hat keine Möglichkeit die Bezeichung zu ändern.
    Es gibt folgende Möglichkeit dynamische Feldbezeichungen zu definieren:

    Es gibt die Möglichkeit Formelfelder zu definieren.
    Anstatt eine feste Bezeichnung kann ein Formelfeld der einen Wert einer Tabelle dargestellt,
    verwendet werden.

    Beispiel:
    Es wird eine Tabelle SYSTEM angelegt.
    In der Tabelle werden alphanumerische Felder, z.B.
    FeldBezeichnung-Motiv mit 20 Zeichen usw. angelegt.
    Dazu wird ein Formular, z.B. "Feldeinstellungen" definiert.
    Im Formular kann der Benutzer die Bezeichnung eingeben.
    Im Hauptformular wird ein Formelfeld mit als Inhalt:
    SYSTEM.Bezeichnung-Motiv definiert.
    Daneben das Eingabefeld Motiv.

    Formelfeld: SYSTEM.Bezeichnung-Motiv
    Eingabefeld: Motiv

    Sollte das nicht klappen, dann gibt es noch folgende Möglichkeiten:
    Formelfeld: ReadRec(SYSTEM ,1);SYSTEM.Bezeichnung-Motiv
    oder
    Formelfeld: SYSTEM.Bezeichnung-Motiv[1, 255]

    Siehe auch Dynamische Schalterbeschriftung.


    Topic Unsichtbare Felder Kapitel Formulare
    Ein Feld kann als Eigenschaft unsichtbar erhalten. Wenn jetzt einVorgabewert für das unsichtbare Feld definiert werden soll, komt VDP mit der Fehlermeldung;Falscher Ausdruck für dieses Feld. Sobald das Feld wieder sichtbar gemacht wird, istalles ok.
    Es ist aber möglich ein festen Vorgabewert zu definieren.


    Topic Formeln in eingebettete Formulare Kapitel Formulare
    Eingebettete Formularen können bearbeitet werden, wenn die Optionenunter Tabelleneigenschaften gesetzt wurden. Es können Tabellen-Felder direktin der Tabellenzeile bearbeitet werden. Ist es notwendig Felder mitttelsFormeln mit einem Wert zu belegen, dannk
    Beispiel:
    Eingebette Tabelle (EINBETTAB) mit den Felder Feld1, Feld2
    Haupttabelle (TABELLE) mit dem Feld Summe. Summe soll das Produkt vonFeld 1 und Feld2 erhalten, also Summe := Feld1 * Feld2

    In der eingebettete Tabelle werden folgende Felder definiert:
    Feld1 (der Wert wird eingegeben)
    Feld2 := Feld1 * 1,16 (errechneter Wert, keine Eingabe möglich)

    Da Feld2 berechnet wird, wird diese nicht in der Datenbank geschrieben.Somit kann die Summe nicht berechnet werden.
    Was nun?
    Man kommt nicht drum rum ein EASY-Makro zu schreiben:
    Procedure SetSumme(nDummy : Real) : Real;
     ReadRec(EINBETTAB, RecNr(EINBETTAB));
     Feld2 := Feld1 * 1,16;
     WriteRec(EINBETTAB, RecNr(EINBETTAB));
     TABELLE.Summe := Feld1 * Feld2
     Return Feld2
    Endproc

    In der eingebette Tabelle kann anstatt Feld2 := Feld1 * 1,16, das MakroSetSumme(0) definiert werden. Zu beachten ist, daß SetSumme(0) mittelsExecMacro(MODUL, SetSumme(0)) aufgerufen werden muß.


    Topic Bedingter Formularzugang bei Mehrplatzbetrieb Kapitel Formulare
    Im Mehrplatzbetrieb können Formulare und Formularfelder mittels eine Benutzertabelle
    gezielt gesteuert werden.

    Tip 1:
    Die Formulare können über Ihre Eigenschaft | nur Aktiv falls oder über die
    Eigenschaft | beim öffnen gesteuert werden.
    Das gleiche gilt für Felder.

    Beispielmöglichkeit
    Der Benutzer meldet sich bei VDP mittels Benutzername und Passwort an.
    Diese befinden sich zum Beispiel in eine Tabelle USER.
    Die Tabelle hat den Felder
    Benutzername
    Passwort
    Rechte

    Die Möglichkeiten sind vielfältig.
    Wenn Rechte z.B. 2 ist, darf der Benutzer auf Tabelle A aber nicht auf Tabelle B zugreifen.
    Das kann in eine easy-Prozedur abgefragt werden.

    Anmeldeablauf
    1.Benutzername und Passwort beim Start der VDP-Anwendung abfragen.
    Aus der Tabelle USER
    2.Benutzername in eine SYSTEM-Tabelle zwischen speichern.
    Zum Beispiel in der Tabelle SYSTEM mit dem Feld AktUser.
    Die SYSTEM-Tabelle kann auch mit USER verknüpft werden.
    3.Bei jedes Formular etc. Benutzername und Rechte abfragen.
    Eintrag in nur Aktiv Falls:
    ExecMacro(SYSTEM, UserOK) = 1
    Procedure UserOK
     If SYSTEM.AktUser.Rechte = 2
      return 1
     else
     return 0
    Endproc
    4.Das Gleiche für Formularseiten, Felder etc.

    Tip 2:
    Von einem Unbekannten aus dem TDB-Forum. Vielen Dank.
    Es gibt im Projekt eine eigene Tabelle zur Userverwaltung in der für jeden User ein
    Datensatz besteht in dem für alle gewünschten Rechte Ja/Nein Felder definiert sind.

    Beim Programmstart muß sich jeder User über ein Modul in dieser Tabelle anmelden,
    der Datensatz des angemeldeten Users wird dabei in dieser Tabelle markiert und der Zugriff
    auf Markierung gesetzt.
    Über die Abfrage der Rechtefelder in der Usertabelle kann nun in allen Formularen und
    Tabellen mit userabhängigen feldbezogenen Rechten gearbeitet werden.
    Den userabhängigen Zugriff auf verschiedene Tabellen/Formulare wird über eine "Hauptmenü-Seite" in dieser Usertabelle gestaltet.
    Auf diese Seite gelangt man nach dem Anmelden automatisch. Von hier können alle anderen
    Tabellen/Formulare per Macro/Procedure abhängig von den Userrechten aufgerufen werden.
    Die standartmäßigen Menüpunkte wie Tabellenliste etc. müssen natürlich angepasst bzw.
    entfernt werden.


    Topic Beschriftung in einen Rahmen oben bzw. unten einbinden Kapitel Formulare
    Viele Formularmasken bekommen Ihren letzten Schliff erst durch Ihre Optik.
    Was leider noch nicht Version 2.01 vorhanden ist:
    Beschriftung in einen Rahmen oben bzw. unten einbinden.
    Die Beschriftung befindet sich z.Zz. nur über dem Rahmen.
    Mit einem kleinen Trick ist es doch möglich. Gewünschte Tabelle öffnen.
    Im Formulareditor das zu ändernde Formular öffnen. Es werden hier 2 Rahmen benötigt.
    Einen Hauptrahmen und einen Schriftrahmen.
    Gewünschten eigentlichen Hauptrahmen anlegen bzw. vorhandenen markieren.
    Beispiel:
    Breite 3.00 Höhe 2.00
    Eigenschaften des Rahmens wie folgt anlegen:
    Beispiel: 
    Farbe: Hintergrund , Rahmen: Rille. Wichtig : Rahmen nach hinten !!! 
    Einen zweiten Rahmen anlegen.
    Dieser zweite Rahmen ist nun für dieSchrift verantwortlich.
    Eigenschaften des zweiten Rahmens:
    Farbe: Hintergrund , Rahmen: Keiner!!! Wichtig :Rahmen nach vorne!!
    Unter Stil den gewünschten Text eingeben.
    Unter Format gewünschte Schriftart und Ausrichtung auf Zentriert einstellen.
    Hinweis:
    Hier sehen Sie unter "Ausrichtung" einen eingebunden Text "Ausrichtung " im Rahmen von VDP 2.01 selbst.
    Beispiel:
    Text 10 pt. Beschriftung: "Test". 
    Die Breite währe hier ca.0,83 Höhe 0,63 eventuell verkleinern.
    Der Text "Test" befindet sich nun über dem zweiten Rahmen.
    Der Trick dabei ist nun, daß dieser Text durch die oben genannten Einstellungen über den
    ersten Rahmen der oberen oder unteren Linie gelegt werden kann. Der zweite Rahmen
    verdeckt nun mit seiner Schriftzug die obere oder untere Linie. Dies hat den Effekt , als
    währe der Schriftzug in den Rahmeneingebunden. Der zweite  Rahmen ist in der
    Höhe so klein wie möglich zu halten, damit der Rest des Rahmens unter der Schrift nicht 
    die Felder im Formular stört.
    Natürlich können auch andere Rahmeneigenschaften Farbe und Hintergrund eingestellt
    werden. Wichtig ist nur das "nach vorne" und nach hinten "eingehalten" werden!

    Dieser Beitrag stammt von Georg Eisenbeiser. Vielen Dank.


    Topic Ein Formularfeld so formatieren, dass der erste Buchstabe immer ein Großbuchstabe ist Kapitel Formulare
    Mehrere Möglichkeiten:
    Tip 1
    Formular
    Im Formular|Feld Eigenschaften|Feld verlassen
    MeinFeld := Upper(MeinFeld[1,1]) + MeinFeld[2,255]; Refresh;

    Tip 2
    easy-Prozedur
    Procedure SetCapital(sStr : String) : String;
     ?sStr = "" / Return ""
     Return Upper(sStr[1,1]) + sStr[2,255]
    Endproc


    Topic Ein Feld vorbelegen, dass bei der Neuanlage automatisch die nächste Nummer eingetragen wird Kapitel Formulare
    Die Lösung läßt sich am Besten anhand eines Beispiels erklären.
    Beispielfelder:
    Kundennummer (Alpha 20)
    Laufende_Nummer (Auto-Nummer)

    1.easy-Prozedur definieren
    Procedure SetKundennummer : String;
    ..#setzt die nächste Kundennummer
    ..#es können auch komplexere Nummern vergeben werden. Zum Beispiel durch die
    ..#Verwendung einer Systemtabelle

     Return Str(Laufende_Nummer)
    ..oder
     Return "A" + Str(Laufende_Nummer,1,0)
    Endproc

    2.Unter Formulareigenschaften, beim Öffnen die Kundennummer setzen:
    $Kundennummer := SetKundennummer;


    Topic Ereignis Beim_Verlassen Kapitel Formulare
    Verschiedene Fragen und Antworten.

    Frage 1:
    Wie lässt sich eine Formular-Eigenschaft BEIM SPEICHERN programmieren?
    Antwort:
    Das Ereignis Beim_Verlassen wird aufgerufen, bevor der Datensatz gespeichert ist.
    Hier können Zuweisungen getroffen werden und mit Refresh in den Puffer geschrieben
    werden.
    Beispiel:
    PROCEDURE Beim_Verlassen;
     Eingabedatum := Today;
     Refresh;
    ENDPROC

    Das Ereignis Nach_dem_Verlassen bedeutet, daß der Eintrag bereits abgespeichert ist.
    Das Ereignis wird jedoch nur aufgerufen, wenn an dem Datensatz etwas geändert wurde
    (außer Änderungen in Memofeldern und Blobfeldern).
    In diesem Fall muß der Eintrag jedoch explizit abgespeichert werden.
    PROCEDURE Nach_dem_Verlassen
     ReadRec( FileNr, Recnr( FileNr));
     Eingabedatum := Today;
     WriteRec( FileNr, RecNr( FileNr));
    ENDPROC


    Topic Symbolleisten Kapitel Formulare
    Jedes Formular kann eine eigene Symbolleiste haben. Somit kann man fürz.B. Masken-und Tabellenmodus getrennte Formulare anlegen. 


    Topic Daten, wie Bilder einer Eingebettete Tabelle in ein Formular zeigen Kapitel Formulare
    Ein Formular enthält eine eingebettete Tabelle. Diese Tabelle enthält ein Bildfeld.
    Die Aufgabe lautet;
    wie kann das entsprechende Bild dargestellt werden,wenn duch die Tabelle gescrollt wird.
    Diese Aufgabe ist recht komplex. Die beschriebene Prozedur ist daherrecht aufwendig.

    Ein Hinweis:
    In ein Formelfeld können alpha, numerische Felder direkt ausgegeben werden.
    Beispiele:
    Str(BYTEFELD)
    ALPHAFELD

    Procedure ShowBildAusTab(nArt : Real);
    ..#gehe durch eine eingebettete tabelle
    ..#der Aufruf erfolgt mittels Schalter im Formular 
    ..#soll ein bild aus eine andere tabelle dargestellt werden, dann mußin der haupttabelle
    ..#auch ein bildfeld definiert werden. dieses bildfeld wird dann aulszwischenspeicher
    ..#verwendet. ich habe noch keine andere möglichkeit gefunden. einemöglichkeit wäre
    ..#das statische element logo zu verwenden. allerdings weiß ich nichtwie diese 
    ..#angesprochen wird.
    ..#Parameter:
    ..#nArt = 1 vorheriger satz, 2 nächster satz, 3 anfang, 4 ende
     Vardef nRNo : Real; 
     Vardef nBMPArt : Real; 
     Vardef sStr : String;
     Vardef Q : Object;
     Vardef X : Object;

     ..eingebettete tabelle im formular suchen
     Q := FindDataWnd("SYSTEM.SYSTEM", "EINTAB");
     Q.Use;
     ?nArt = 1 / Q.VorherigerDatensatz;
     ?nArt = 2 / Q.NächsterDatensatz;
     ?nArt = 3 / Q.AnfangDerTabelle;
     ?nArt = 4 / Q.EndeDerTabelle;
     ..lese aktuelles record aus der eingebettete tabelle
     If ReadRec(EINTAB, RecNr(EINTAB)) = 0
      Return
     End
     ..halte recordnummer und pfad zu grafik fest
     nRNo := Q.RecNr(EINTAB);
     sStr := GetLinkedFile(EINTAB.Bildx);
     IF Length(sStr) > 0
      ..suche hauptformular wieder (hat den namen SYSTAB)
      X := FindDataWnd("SYSTEM.SYSTEM", "SYSTAB"); 
      ..setze bearbeitungsmodus
      X.ModifyRecords;
      ..verbinde grafik; 1 = BMP Datei. für andere bitmaps entsprechendesetzen
      ?Upper(sStr) hat ".BMP" / nBMPArt := 1;
      ?Upper(sStr) hat ".DIB" / nBMPArt := 1;
      ?Upper(sStr) hat ".PCX" / nBMPArt := 2;
      ?Upper(sStr) hat ".WMF" / nBMPArt := 4;
      ?Upper(sStr) hat ".GIF" / nBMPArt := 5;
      ..setze link
      LinkBlob(SYSTEM.Bildx, sStr, nBMPArt);
      ..beende bearbeitungsmodus
      X.ModifyRecords;
     END;
     ..setze datenzeiger der eingebette tabelle wieder richtig
     Q.ShowRec(nRNo)
     Refresh;
    Endproc


    Topic Formular als modaler Dialog Kapitel Formulare
    Frage:
    Ich habe ein Formular modal als Dialog geöffnet und will aus ihm herauseinweites Formular (eine Hilfe) modal öffnen und erhalte die Fehlermeldung:
    Prozedur konnte nicht ausgeführt werden.
    Starte ich das Formular in der Entwicklerumgebung direkt, also nichtmodal, wird das Makro ausgeführt.

    Antwort:
    bei modalen Fenstern wird empfohlen, Makros nicht direkt, sondern überexecmacro(.. aufzurufen. 
    Dann wird die gesuchte Funktione auch gefunden, weil VDP weiß, inwelchem Modul er nachsehen muß.
    Dies sollte aber nur bei Bedarf angewendet werden, da der Aufruf über
    Execmacro dazu führt, daß das Modul komplett gelesen , die Funktionaufgerufen und anschließend sofort wieder aus dem Speicher geworfen wird.
    Sind viele Aufruf z.B. beim Verlassen eines Feldes vorhanden, kann diesdie Performance beinflußen.


    Topic Eingebettete Tabellen-Objekte in Formularen(1) Kapitel Formulare
    Folgende Prozeduren zeigen Beispiele zur Bearbeitung von eingebettete Tabellen
    in Formularen.

    procedure DoThemaPutStar;
    ..#setzt eine markierung
     Vardef RNo, nNoRecs, i : Real;
     VarDef oThemaTab : Object;
     oThemaTab := FindDataWnd("MLTTHEMA.Multi-Thema", "Thema");
     oThemaTab.Use;
     oThemaTab.PutStar;
     oThemaTab.Attach;
     Return
    endproc;

    procedure DoThemaLoop;
     Vardef RNo, nNoRecs, i : Real;
     VarDef oThemaTab : Object;

     oThemaTab := FindDataWnd("MLTTHEMA.Multi-Thema", "Thema");
     ?oThemaTab = 0 / Return
     oThemaTab.Use;
     oThemaTab.SetSortOrder("Markierung");
     ..gibt es markierte sätze
     nNoRecs := Link(THEMA) * Count(THEMA); 
     ?nNoRecs = 0 / Return
     ..Message(Str(nNoRecs));
     i := 1;
     ..lese die themen
     oThemaTab.TopOfTable
     Repeat
      RNo := ReadRec(THEMA, RecNr(THEMA));
      Message(Str(RNo) + "#" + THEMA.sThema, Str(i) + "/" + Str(nNoRecs));
      oThemaTab.NextRecord;
      i := i + 1;
     Until i > nNoRecs
     oThemaTab.SetSortOrder("THEMA.ID");
     Return
    endproc;

    procedure DoThemaGetStarNum : real;
    ..#liefert anzahl markierte datensätze
     VarDef oThemaTab : Object;
     oThemaTab := FindDataWnd("MLTTHEMA.Multithema", "Thema");
     oThemaTab.Use; 
     oThemaTab.SetSortOrder("Markierung");
     ..gibt es markierte sätze
     Return Link(THEMA) * Count(THEMA);
    endproc;

    procedure DoThemaSort;
    ..#setzt die sortierung auf standard.id
     VarDef oThemaTab : Object;
     oThemaTab := FindDataWnd("MLTTHEMA.Multithema", "Thema");
     oThemaTab.Use;
     oThemaTab.SetSortOrder("THEMA.ID");
     oThemaTab.TopOfTable;
     Return
    endproc;


    Topic Darstellung Link-Felder Kapitel Formulare
    Alle Datenfelder aus anderen Tabellen, die mit Koppelfelder verbunden sind, können auch 
    in der Tabellenansicht dargestellt werden.

    Die Syntax hierzu entspricht der sogenannten Link-Notation:
    Beispiel:
    Spalte 1: RechnungsNr
    Spalte 2: Kunde.Name
    Spalte 3: Kunde.Vorname
    Spalte 4: Währung.Währungskennzeichen

    Wenn das Linkfeld jedoch in der anderen Tabelle steht und auf die Primärtabelle zeigt,
    kann man die Information nicht in neben den Felder der Primärtabeledarstellen,
    sondern muß man für diese Tabelle eine eingebunde Tabelle ins Formulareinsetzen.


    Topic Eingebettete Tabellen-Objekte in Formularen(2) Kapitel Formulare
    Folgende Prozeduren zeigen wie auf eingebette Tabellen zugegriffenwerden kann.

    procedure ThemaTabGetStarNum(nDummy : real) : real;
    ..#liefert anzahl markierte datensätze der eingebettete tabelle thema
     VarDef oThemaTab : Object;
     VarDef nRNo, i, nNoRecs : Real;
     oThemaTab := FindDataWnd("MLTTHEMA.Multi-Thema", "Thema");
     ?oThemaTab = 0 / Return 0
     oThemaTab.Use;
     oThemaTab.SetSortOrder("Markierung");
     nRNo := ReadRec(THEMA, RecNr(THEMA));
     ?nRNo = 0 / nNoRecs := 0;
     ?nRNo > 0 / nNoRecs := Link(THEMA) * Count(THEMA);
     ..oThemaTab.SetSortOrder("THEMA.ID");
     ..oThemaTab.TopOfTable;
     Return nNoRecs
    endproc;

    procedure DoThemaPutStar;
    ..#setzt eine markierung
     Vardef RNo, nNoRecs, i : Real;
     VarDef oThemaTab : Object;
     oThemaTab := FindDataWnd("MLTTHEMA.Multi-Thema", "Thema");
     oThemaTab.Use;
     oThemaTab.PutStar;
     oThemaTab.Attach;
     Return
    endproc;

    procedure DoThemaTabLoop;
    ..#eine sehr umständliche procedure aber sie funktioniert
     Vardef RNo, nNoRecs, i : Real;
     VarDef oThemaTab : Object;
     ..gibt es markierte sätze
     nNoRecs := ThemaTabGetStarNum(0);
     oThemaTab := FindDataWnd("MLTTHEMA.Multi-Thema", "Thema");
     oThemaTab.Use;
     If nNoRecs = 0
      oThemaTab.SetSortOrder("THEMA.ID");
      oThemaTab.TopOfTable;
      return
     End
     oThemaTab.SetSortOrder("Markierung");
     i := 1;
     ..lese die themen
     oThemaTab.TopOfTable
     Repeat
      RNo := ReadRec(THEMA, RecNr(THEMA));
      ?RNo > 0 / Message(Str(RNo) + "#" + THEMA.sThema, Str(i) + "/" + Str(nNoRecs));
    ?i < nNoRecs / oThemaTab.NextRecord;
      i := i + 1;
     Until i > nNoRecs
     oThemaTab.SetSortOrder("THEMA.ID");
     oThemaTab.TopOfTable;
     Return
    endproc;

    procedure DoThemaTabGetStarNum : real;
    ..#liefert anzahl markierte datensätze
     VarDef oThemaTab : Object;
     oThemaTab := FindDataWnd("MLTTHEMA.Multithema", "Thema");
     oThemaTab.Use;
     oThemaTab.SetSortOrder("Markierung");
     ..gibt es markierte sätze
     Return Link(THEMA) * Count(THEMA);
    endproc;

    procedure DoThemaTabGetNoRecs : real;
    ..#liefert anzahl datensätze
     VarDef oThemaTab : Object;
     oThemaTab := FindDataWnd("MLTTHEMA.Multithema", "Thema");
     oThemaTab.Use;
     Return Link(THEMA) * Count(THEMA);
    endproc;

    procedure DoThemaTabSort;
    ..#setzt die sortierung auf standard.id
     VarDef oThemaTab : Object;
     oThemaTab := FindDataWnd("MLTTHEMA.Multithema", "Thema");
     oThemaTab.Use;
     oThemaTab.SetSortOrder("THEMA.ID");
     oThemaTab.TopOfTable;
     Return
    endproc;


    Topic Neuen Datensatz eingebettete Tabelle anlegen (Koppelfeld) Kapitel Formulare
    Ausgangsbasis
    Tabelle RECHNUNG
    Tabelle POSTEN
    POSTEN hat ein Koppelfeld Rechnung auf der Tabelle RECHNUNG

    Neben der eingebettete Tabelle im Formular soll ein Schalter NEU angelegt werden, der
    ein makro ausführt welches ein neuen Datensatz der Tabelle POSTEN anlegt.

    Procedure POSTENNEU
     Vardef nRNo, nRLN : Real;
     ..aktuelle rechung lesen
     nRNo := ReadRec(RECHNUNG, RecNr(RECHNUNG));
     ?nRNo = 0 / Return
     ..speichere rechnungs laufende nummer
     nRLN := RECHNUNG.Laufende_Nummer;
     ..lege neuen POSTEN Datensatz an
     ReadRec(POSTEN, 0);
     ..koppele POSTEN mit RECHNUNG
     POSTEN.Rechnung := nRLN;
     ..alternativ mittels
     POSTEN.Rechnung := RECHNUNG.Laufende_Nummer;
     ..speichere POSTEN
     WriteRec(POSTEN, FileSize(POSTEN) + 1);
     ..
     Message("Tabelle POSTEN: Datensatz angelegt.", "Hinweis");
    Endproc


    Topic Feldbeschriftungen Kapitel Formulare
    Tip 1:
    ja/nein-Feld mit Beschriftung Date&Time wird dargestellt als Date_Time.
    Das & wird von Windows bei Beschriftungen in Menüs und Controls als Unterstrich umgesetzt.
    Das ist von Windows so definiert, daran gibt es nichts zu ändern.


    Topic Felder auf Inhalt prüfen Kapitel Formulare
    Tipp 1
    Prüfen ob ein Datumsfeld Inhalt hat.
    Lösung:
    Choice(Sel(Datumsfeld = 0), "Leer", DateStr(Datumsfeld));
    oder in easy bzw. Datenbankjob
    If Datumsfeld = 0
     Message("dann ist es leer!")
    End


    Topic Anzeigeprobleme nach Änderung an Tabelle Kapitel Formulare
    Nach Änderung einer Tabelle (ein Koppelfeld wurde entfernt, neue Datenfelder hinzugefügt) erscheint in der Tabellenansicht immer noch das gelöschte Koppelfeld, 
    die neuen Felder (Spalten) sehe ich aber nicht.
    Diese Tabellensicht wird wie folgt aktualisiert:
    Menü: Ansicht -> Standard-Tabellenformat
    VDP speichert die Ansicht, wie es der User eingerichtet hat. Diese wird nicht automatisch geändert.
    Das Standard-Tabellenformat kann man aber über oben genannten Menüpunkt abrufen.


    Topic Fenster im Vollbild öffnen Kapitel Formulare
    Unter Programm Eigenschaften die Option Einfenster Anwendung wählen.


    Topic Felder aktivieren / deaktivieren Kapitel Formulare
    Unter Feld/Eigenschaften/Aktivierung kann unter Bedingung eine Abfrage definiert werden. Abhängig vom Ergebnis können Daten geändert werden oder nicht.
    Möglichkeit 1:
    In eine Systemtabelle ein numerisches Feld zur Steuerung definieren. Zum Beispiel: Feldzugriff
    Dann im Formular Feld Eingenschaften Bedingung setzen. Zum Beispiel: SYSTEM.Feldzugriff = 1 ermöglicht den Zugriff, wenn ungleich 1 dann kein Zugriff

    Möglichkeit 2:
    Mittels eine Ini-Datei und dann wie oben.


    Topic Reihenfolge der Bereiche in einem Datenbankjob Kapitel Datenbankjobs
    Nachfolgend eine klare Darstellung der Bereichsreihenfolge in einem Datenbankjob:

    .Report
    .Prolog
    ..Steuerzeichen
    .GP 1 etc.
    ..Zugriff
    .SetAccess MyTab.ind
    .Selektion $1=MySel
    .Kopf
    Ich bin eine Kopfzeile vom $heute      Seite $Seite
    .Fuß
    Ich bin die Fußzeile
    ..Gruppierung nach Feldname
    .Gruppe MyFeld[1]
    .Daten
    $1 $2
    .Epilog


    Topic Datenbereich in ein Datenbankjob Kapitel Datenbankjobs
    Ein Datenbereich muß immer eine Datenausgabe haben, damit Daten erscheinen.
    Wenn im Datenbereich nichts steht als ein Subreport, dann erhalten Sie keine Ausgabe.
    Daher immer:

    .DATEN
    $(<Mindestens ein Feld der Primärtabelle>)
    .SUB
    $(<Felder der angekoppelten Tabelle(n)>)
    .ENDSUB
    Header leitet übrigens eine Gruppendefinition ein, die Sie nichtbenötigen, wenn Sie SubReports verwenden.

    Wenn im Daten-Bereich nicht direkt ein Wert ausgegeben werden soll,gibt es folgenden Trick:
    Definition eine Dummy-Variable:
    .Var x = 0
    Im Datenbereich folgende Zuweisung:
    .DATEN
    .Do x := TABELLE.Laufende_Nummer
    ..


    Topic Kommando Report oder Serienbrief Kapitel Datenbankjobs
    Das Kommando .REPORT oder .SERIENBRIEF (.LETTER) muß immer in der ersten Zeile 
    des Jobs stehen. Ansonsten werden sie ignoriert.
    .REPORT
    oder
    .LETTER


    Topic Dialogfenster in Datenbankjobs Kapitel Datenbankjobs
    Bekanntlich verwendet easy Formulare von speziellen Hilfstabellen als
    Dialogfenster zur Benutzerinteraktion.
    Leider kann man in Datenbankjobs auf diese Methode nicht zurückgreifen, weil es sonst in der Druckvorschau zueinem Deadlock (Endlosschleife) kommt.
    Es geht dann nichts geht mehr.
    Will man also auf die Druckvorschau nicht verzichten hilft nur eines:
    Das Dialogfenster muß in eine Prozedur ausgelagert werden, welche anschließend den Datenbankjob ohne Dialogfenster mit der Menüfunktion Druckenstartet.


    Topic Ausgabe indirekt angekoppelter Informationen Kapitel Datenbankjobs
    Bei einem System mit zwei Dateien, die über ein Koppelfeld miteinanderverbunden sind, bietet die Benutzeroberfläche der Turbo Datenbank für Windows komfortable Funktionen zur
    Dateneingabe und zur Ansicht derverknüpften Informationen.
    Auch die Formulierungvon Ausgabejobs ist durch das ADL-System denkbar einfach. 
    Lediglich für die Ausgabe indirekt angekoppelter Informationen muß man wissen, daß es den
    Subreport gibt.
    Angenommen es gibt eine Tabelle mit den Datenfeldern
    Tabelle     FIRMEN
    Spalten     Firma, Straße, PLZ, Ort, Telefon

    und eine zweite Tabelle mit den Ansprechpartnern. 
    Tabelle     ANSPRECH
    Spalten     AName, AVorname, AAbteilung, ADurchwahl, AFirma (Koppelfeld auf die Firmentabelle)

    Diese Datenstruktur hat den großen Vorteil, daß beliebig viele Ansprechpartner mit einem 
    Firmeneintrag verknüpft sein können. Ein Ansprechpartner kann allerdings nur mit einem 
    Firmeneintrag verbunden sein. Hier liegt also eine 1:n-Verbindung vor.
    Diese Datenbank kann man nun von zwei Seiten aus betrachten.
    Bei aktiver Primärtabelle ANSPRECH (wenn z.B. ein Formular der Anprechpartner-Tabelle aktiv ist), ist der jeweilige Firmeneintrag (direkt) verknüpft und kann mit der Menüoption
    "Ansicht/Verknüpfte Datensätze" eingesehen werden. Wird die Primärtabelle gewechselt,
    beispielsweise durch Aktivierung eines Formulars der Firmen-Datei, sind nun die
    Ansprechpartner (indirekt) angekoppelt und lassen sich über "Ansicht/VerknüpfteDatensätze"
    einblenden und bearbeiten.

    Nun aber zur Datenausgabe innerhalb eines Datenbankjobs.
    Direkt verbundene Datensätze lassen sich meist ganz einfach, durch die Angabe des
    Spaltennamens ansprechen (sofern kein Konflikt durchgleichlautende Spaltennamen vorliegt).
    So kann man eine Adressliste füralle Ansprechpartner ganz einfach auf folgende Weise
    erstellen.

    .REPORT
    .PROLOGUE
    .PrimTableIs ANSPRECH
    .DATEN
    $Firma
    $AAbteilung
    $(AVorname+" "?(AVorname) AName)
    $Strasse

    $PLZ $Ort

    Nun das Ganze einmal von der anderen Seite.
    Für jede Firma sollen die Ansprechpartner aufgeführt werden. 
    In diesem Fall werden also indirekt angekoppelte Informationenausgewertet. 
    Das macht man immer mit einem Subreport:

    .REPORT
    .PROLOG
    .PrimTableIs FIRMEN
    .DATEN
    $(Firma:25 Telefon r 15)
    $Straße, $PLZ $Ort
    Ansprechpartner:
    .SUB
    $(AName:15 AVorname:10 AAbteilung:10 ADurchwahl r 15)
    .ENDSUB
    .EPILOG


    Topic Funktionsaufrufe in Datenbankjobs Kapitel Datenbankjobs
    Der Einsatz von Standardfunktionen innerhalb von Datenbankjobs ist problemlos möglich, wenn es sich um Funktionen handelt, die ein Ergebnis liefern (z.B. Today, SQRT etc.).
    Sie werden einfach innerhalb von Ausdrücken verwendet, z.B. bei Variablenzuweisungen 
    oder in einem Ausgabeformat.
    Zahlreiche Funktionen liefern nicht nur ein Ergebnis, sondern erfüllen in erster Linie eine
    Aufgabe, wie z.B. die Ausgabe einer Nachricht (Message) oder das Lesen eines bestimmten
    Datensatzes (ReadRec). Da auch diese Funktionen einen Wert liefern,kann man sie wie jede
    andere Funktion verwenden. 
    Quasi als Nebeneffekt wird der eigentliche Zweck der Funktion ausgeführt.
    Oft gibt der Rückgabewert der Funktion Aufschluß über den Erfolg der Aktion.
    Daher ist der Aufruf der Funktion innerhalb einer Variablenzuweisung oft sinnvoll.

    Beispiel für eine bedingte Ausgabe in einem Serienbrief:
    .VAR DruckeOrt = Message("Auch den Ortsnamen ausgeben?", "Anfrage", 3)
    $(Name, Vorname)
    .FALLS DruckeOrt = 6
    $(PLZ Ort)
    .ENDE

    (Zur Erinnerung: die Funktion Message liefert den Wert 6 zurück, wennder Anwender den Ja-
    Schalter gedrückt hat.)
    Wird der Rückgabewert nicht benötigt oder handelt es sich um eineselbst definierte Prozedur, welche gar keinen Wert zurück liefert, kann man die Funktion auch mittels
    des Kommandos .DO aufrufen.
    Beispiel:
    .DO ShowWait("Auswertung läuft. Bitte etwas Geduld...")
    ..Weitere Befehle
    .DO HideWait


    Topic Druckparameter aus Tabelle setzen Kapitel Datenbankjobs
    Es ist sinnvoll eine Tabelle mit Einstellungen für Ihr Projekt zudefinieren, z.B.
    Tabelle SYSTEM. 
    Diese Tabelle kann dann u.a. Einstellungen für Reports enthalten.
    Diese Einstellungen können innerhalb eines Datenbankjobs wie folgt gesetzt werden:

    .REPORT
    .PROLOG
    ..lese einzigster Datensatz aus der Tabelle SYSTEM
    .DO ReadRec(SYSTEM, 1)
    .DO SetPara(".PL"+STR(SYSTEM.EL)+", PO"+STR(SYSTEM.ER))
    ...


    Topic Schriftarten bei Listen und Jobs Kapitel Datenbankjobs
    Die Formatierung der Ausgabe erfolgt nur zeichenorientiert, d.h. es können keine 
    Proportionalschriften (s.g. TrueType Schriftarten) verwendet werden, aber nur Zeichensätze mit fester Breit, wie z.B. Courier.
    True Type Schriftarten sind am Zusatz New zu erkennen, z.B.
    Times NewRoman, Courier New.


    Topic Seitenlänge einstellen für Listen Kapitel Datenbankjobs
    Prinzipiell gilt für Listen und andere Ausdrucke, daß die Papierlänge unter dem
    Menüpunkt Datei | Drucker eingestellt wird.


    Topic Links und Rechtsbündige Kopf-/Fußzeilen Kapitel Datenbankjobs
    Folgende Darstellung in eine Fußzeile:

    TDBprov-Projektdetailbericht, ausgegeben am 31.12.96 um 09:00 Seite 1

    ist wie folgt in einem Job zu definieren:

    .Footer
    .HL
    $("TDBProv-Projektdetailbericht, ausgegeben am "+$heute+" um "+$jetzt)$("Seite "+$Seite 
    R_Form ToMargin )

    Die Plus Zeichen (+) nicht vergessen, da sonst die Leerzeichen nicht sauber dargestellt 
    werden.

    Für die Kopfzeile (Header) gilt Gleiches.
    Noch einen Hinweis:
    Sollte die Kopfzeile auf jede Seite erscheinen, dann das Punktkommando.HE 1 verwenden:

    .HE 1
    .Header
    $(...


    Topic Job (Liste) mit laufendem Numerierung Kapitel Datenbankjobs
    COUNT zählt intern die ausgegebenen Datensätze und kann am Ende des Berichtes für die
    Gesamtausgabe oder als Fußzeile (Footer) für einen Zwischenausgabe genutzt werden.

    Die Feldvariable in der Klammer muß ein vorhandenes Feld des Datensatzes sein.

    Beispiele
    Laufende Numerierung
    Count($1):5 " " $1:20 " " $2:50 " " $3:50  /

    Als Fußzeile in einem Datenbankjob oder Liste:
    .Footer
    $(COUNT(Name) " Name")           

    Hinweis:
    Die Funktion ZCOUNT gibt die Anzahl der Datensätze bei eine Gruppierungaus:
    .GP 1
    .GRUPPE Name[1]
    $(ZCOUNT(Name) " Name(n) gefunden")


    Topic Daten in Fußzeile ausgeben Kapitel Datenbankjobs
    Es können wie folgt Daten aus einer Tabelle in der Fußzeile (Footer) ausgegeben werden:

    .Report
    .Prolog
    .Header
    .Var sStr = TABELLE.Feld1 + " : " + Str(TABELLE.Laufende_Nummer)
    ..
    .Footer
    $(@a10n sStr C_Form ToMargin)


    Topic Job-Vorlage: Generelle Version Kapitel Datenbankjobs
    .Report
    ..#Datei:
    ..#TABLJxxx.JOB fuer Datenbank TABELLE.DAT
    ..#Hinweise:
    ..#TABELLE ersetzen durch richtige Tabellennamen
    ..#SELEKTION erweitern
    ..#HEADER ersetzen
    ..#Erstellt:
    ..#tt.mm.jjjj Autor
    ..
    .Prolog
    .MT 3, PO 5
    .FONT a8n = Arial, 8, n
    .FONT a10n = Arial, 10, n
    .FONT a10i = Arial, 10, i
    .FONT a10b = Arial, 10, b
    .FONT a10u = Arial, 10, u
    .FONT a12b = Arial, 12, b
    .FONT a12n = Arial, 12, n
    .FONT a14b = Arial, 14, b
    .FONT a14bu = Arial, 14, bu
    .FONT a16b = Arial, 16, b
    .FONT a16bi = Arial, 16, bi
    .FONT a24bi = Arial, 24, bi
    ..
    .PRIMTABLEIS TABELLE
    ..
    .ZUGRIFF TABELLE.ID
    .SELEKTION
    ..
    .. Header ohne Deckblatt
    .HE 1
    .Header
    $(@a10n "Projektname")
    ..HEADER ersetzen
    $(@a16bi HEADER C_Form ToMargin)
    .HL
    .Footer
    .HL
    $(@a10n "Detailinformationen, ausgegeben am " + $heute + " um " +$jetzt) $("Seite "+$Seite 
    R_Form ToMargin )
    ..
    .Daten
    $(/)
    .Epilog


    Topic Aktueller Datensatz ausgeben Kapitel Datenbankjobs
    Immer wieder kommt das Problem der Ausgabe des aktuellen Datensatzes. 
    Folgender Abschnitt im PROLOG-Teil ermöglich die Ausgabe des aktuellen Datensatzes im Formular (Beispiel Tabelle PROJEKT):

    ..Datenbankjob
    .Prolog
    .Do ReadRec(PROJEKT, RecNr(PROJEKT) )
    .Var nLN = PROJEKT.Laufende_Nummer
    .Selection Laufende_Nummer = nLN


    Topic Job-Vorlage: HTML-Job mit Tabellen Kapitel Datenbankjobs
    .Report
    ..#Datei: DBJxxx.JOB
    ..#Beschreibung:
    ..#HTML Tabellen-Gerüst.
    ..
    ..#Hinweise:
    ..#o DBTAB durch die richtige Tabelle ersetzen
    ..#o Feld1 bis Feld5 durch die richtige Felder ersetzen
    ..#o Zugriff und Selektion anpassen
    ..#o Width, Title und Head anpassen
    ..
    ..#Historie:
    ..#22.02.1997 R.W.B.Linn
    ..
    .Prolog
    ..MT 3, PO 5
    .Zugriff DBTAB.ID
    .Selection
    .Daten
    <!--- $DBTAB.Feld1 -->
    <!DOCTYPE HTML PUBLIC -//W3C//DTD HTML 3.2//EN>
    <!Datei: xyz.HTM>
    <html>
    <head>
    <title>DBTAB</title>
    </head>
    <body bgcolor=white>
    ..
    <table border>
    <caption>DBTAB</caption>
    ..
    ..heading setzen
    <tr>
    <th width=400 align=left>Feld1</th>
    <th width=400 align=left>Feld2</th>
    <th width=400 align=left>Feld3</th>
    <th width=400 align=left>Feld4</th>
    <th width=400 align=left>Feld5</th>
    </tr>
    ..felder ausgeben
    .sub
    <tr>
    <td width=400 align=left>$DBTAB.Feld1</td>
    <td width=400 align=left>$DBTAB.Feld2</td>
    <td width=400 align=left>$DBTAB.Feld3</td>
    <td width=400 align=left>$DBTAB.Feld4</td>
    <td width=400 align=left>$DBTAB.Feld5</td>
    </tr>
    .endsub
    </table>
    </body>
    </html>
    .Epilog


    Topic Job-Vorlage: HTML-Job mit Listeneinträge Kapitel Datenbankjobs
    .Report
    ..#Datei: jobname.job
    ..#Beschreibung: HTML-Datei mit Listeneinträge erstellen
    ..#Hinweise: Beim Drucken Ausgabe in Datei mit Windowstext wählen
    ..#Historie:
    ..#05.03.97 R.W.B.Linn
    ..
    .Prolog
    ..geht leider nicht
    ..WOHIN "C:\X.HTM"
    .PRIMTABLEIS PROJEKT
    .ZUGRIFF PROJEKT.ID
    ..aktueller Datensatz wählen
    .Do ReadRec(PROJEKT, RecNr(PROJEKT) )
    .Var nLN = PROJEKT.Laufende_Nummer
    .. Für Tests
    ..Var nLN = 64
    .Selection Laufende_Nummer = nLN
    ..
    .. Hauptteil
    .GROUP PROJEKT.ProjektName[1]
    .Daten
    <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
    <HTML>
    <HEAD>
    $("<TITLE>Projekthistorie " + PROJEKT.ProjektName + "</TITLE>")
    </HEAD>
    <BODY BGCOLOR=#00FFFF>
    $("<H1>Projekthistorie " + PROJEKT.ProjektName + "</H1>")
    $("<H2>Historie der Projekt&Auml;nderungen</H2>")
    .. Gibt es Einträge für das Projekt?
    .If LINK(HISTORIE) = 1
    <UL>
    .SUB ProjektVersion
    $("<LI> Version: " HISTORIE.ProjektVersion:10 " Datum: "HISTORIE.Wann:15 " Wer: " HISTORIE.Wer:15 "<BR>")
    ..Memofeld mit PRE ausgeben, weil sonst Umbrüche nicht mehr stimmen.
    $("<PRE>")
    $(HISTORIE.Aenderung:70)
    $("</PRE>")
    $("<P>")
    .ENDSUB
    .Else
    $("Keine Einträge vorhanden." C_Form ToMargin)
    .End
    </UL>
    ..
    $("<ADDRESS> Autor: " PROJEKT.AutorName ", " DateStr(ToDay)"</ADDRESS>")
    </BODY>
    .Epilog




    Topic Job-Vorlage: Aktueller Datensatz ausgeben Kapitel Datenbankjobs
    .Report
    ..Datei:
    ..TABLJxxx.JOB fuer Datenbank TABELLE.DAT
    ..Hinweise:
    ..TABELLE ersetzen durch richtige Tabellennamen
    ..SELEKTION erweitern
    ..HEADER ersetzen
    ..Erstellt:
    ..tt.mm.jjjj Autor
    ..
    .Prolog
    .MT 3, PO 5
    .FONT a8n = Arial, 8, n
    .FONT a10n = Arial, 10, n
    .FONT a10i = Arial, 10, i
    .FONT a10b = Arial, 10, b
    .FONT a10u = Arial, 10, u
    .FONT a12b = Arial, 12, b
    .FONT a12n = Arial, 12, n
    .FONT a14b = Arial, 14, b
    .FONT a14bu = Arial, 14, bu
    .FONT a16b = Arial, 16, b
    .FONT a16bi = Arial, 16, bi
    .FONT a24bi = Arial, 24, bi
    ..
    .PRIMTABLEIS TABELLE
    ..
    .ZUGRIFF TABELLE.ID
    .Do ReadRec(TABELLE, RecNr(TABELLE) )
    .Var nLN = TABELLE.Laufende_Nummer
    .. Für Tests
    ..Var nLN = 145
    .Selection Laufende_Nummer = nLN
    .If nLN = 0
    .Do Message("Kein Datensatz vorhanden!", "Fehler")
    .ST
    .End
    ..
    .. Header ohne Deckblatt
    .HE 1
    .Header
    $(@a10n "Projektname")
    $(@a16bi HEADER C_Form ToMargin)
    .HL
    .Footer
    .HL
    $(@a10n "Detailinformationen, ausgegeben am " + $heute + " um " +$jetzt) $("Seite "+$Seite 
    R_Form ToMargin )
    ..
    .Daten
    $(/)
    .Epilog


    Topic Job-Vorlage: HTML-Job mit gruppierte Ausgabe Kapitel Datenbankjobs
    .Report
    ..#Beispiel: Gruppierte Ausgabe von Datensaetze in HTML-Format
    ..#Autor: R.W.B.Linn 18.03.1997
    ..
    .Prolog
    .GP 1
    .Zugriff TEST2.ID
    ..Ruecksprungadresse setzen
    $("<A NAME='TOP'")
    ..aufbau des alphabetes
    .Var i = 0
    .While i < 26
    $("&#160<A HREF='#"+Chr(65 + i)+"'>"+Chr(65 + i)+"</a>")
    .Do i := i + 1
    .End
    $("<HR>")
    ..
    .Header
    ..
    .Footer
    .Gruppe Name[1]
    ..ausgabe der gruppen-buchstabe
    $("<A HREF='#TOP'>Zur&uuml;ck</A>")
    $("<A NAME='"+G_Neu+"'><H1>"+G_Neu+"</H1></A>")
    ..
    .Daten
    ..der eigentliche inhalt
    $(Name+"<BR>")



    Topic Subreport sortieren Kapitel Datenbankjobs
    Wenn die Ausgabe über SUB läuft, hinter ENDSUB eine Indexbeschreibung angeben.
    Beispiel:
    .Sub
    $Name, $Ort
    .Endsub "Name, Ort"


    Topic Schriftarten in Jobs definieren Kapitel Datenbankjobs
    Im Prolog werden Schriftarten mit dem Punktbefehl .FONT definiert.
    Verwendet werden die definierte Schriftarten mit .SETFONT.

    Beispiel:
    .Prolog
    .Font arial_klein = Arial,9,n
    .Font arial_gross = arial,16,b
    .Daten
    .SetFont arial_gross
    Hier eine Überschrift
    .SetFont arial_klein
    Hier normaler Text
    .Epilog


    Topic Zeilenumbruch wenn weniger als nn Zeilen frei Kapitel Datenbankjobs
    Anzahl Zeilen mit .LET in eine Variable ablegen und diese Variable dannan .CP übergeben.
    Da man Punktkommandos nicht mit Variablen aufrufen kann, gibt es die
    Funktion SETPARA.

    Beispiel:
    SETPARA("CP " + Str(nVar))
    wobei nVar die Variable ist.


    Topic Selektion eingeben Kapitel Datenbankjobs
    Über einen JOB oder MAKRO eine Liste drucken, bei der die Bedingung für
    die Selektion vom Anwender selbst eingegeben werden kann. 

    Makro schreiben: 

    Input ("Selektion:","Frage") 
    SUB _T-Eingabe 
     SetMark (FileNo, RecNo (FileNo)) 
    ENDSUB Name, Vorname 
    SetSortOrder ("Markierung") 
    Run ("Liste") 

    ...bzw. 'Liste' druckt nur markierte Datensaetze. 


    Topic Selektiver Listendruck Kapitel Datenbankjobs
    Frage:
    Wie kann ein selektiver Berichts- oder Listenausdruck erfolgen?

    Antwort:
    Im Bericht "Berichtsname" bei der Datensatzauswahl lediglich NOTE eingeben.
    Bericht dann speichern.
    Ein Makro erstellen: 

    Input("Kriterium eingeben")
    Note(T-Eingabe)
    Drucken("Berichtsname")


    Topic Abfrage der Funktion EINGABE Kapitel Datenbankjobs
    Frage:
    In Datenbankjobs kann man mit der Funktion EINGABE ein Fenster für dieEingabe einer Auswahl öffnen. Das Fenster hat zwei Funktionsknöpfe: OK / Abruch.
    Wie kann man den Abruch des Fensters abfragen ?

    Antwort:
    Folgendes Beispiel zeigt eine Möglichkeit:

    .Let T-Eingabe = "Voreinstellung" 
    .Let nRT = Input ("Bitte Text eingeben","Abfrage") 
    ..nRT auswerten, wenn 0 dann abbrechen, z.B. mittels ST (=Stop) Befehl
    .If nRT = 0 
    ..Abbruch 
    .ST
    .Else
    ..Hier weitermachen
    .End


    Topic Ausgabe von Bildfelder in Datenbankjobs Kapitel Datenbankjobs
    Ausgabe von Bildfelder in Datenbankjobs

    $(TABELLE.Bildfeld:Breite:Hoehe:Textversatz) 

    Höhe und Textversatz muessen nicht angegeben werden, dann wird das Bild
    automatisch angepasst. 

    Ist das Bild nicht vorhanden, erfolgt auch keine leere Ausgabe.


    Topic Fontdatei für Schriftarten in Datenbankjobs Kapitel Datenbankjobs
    Mittels dem Kommando Font können Schriftarten definiert werden.
    Beispiel:
    .FONT a10n = Arial, 10, n

    Es ist für die Entwicklung von Datenbankjobs hilfreich alle Fonts die benötigt werden in
    eine separate Textdatei abzulegen und diese mittels dem Include-Befehl als
    Textbaustein zu laden.

    Beispiel:
    INCLUDE FONTDEF.TXT

    Inhalt der Datei Fontdef.txt:
    ..Datei: fontdef.txt
    ..Definition von Standardfonts für Datenbankjobs
    .FONT a8n = Arial, 8, n
    .FONT a10n = Arial, 10, n
    .FONT a10i = Arial, 10, i
    .FONT a10b = Arial, 10, b
    .FONT a10u = Arial, 10, u
    .FONT a12b = Arial, 12, b
    .FONT a12n = Arial, 12, n
    .FONT a12bu = Arial, 12, bu
    .FONT a14n = Arial, 14, n
    .FONT a14b = Arial, 14, b
    .FONT a14bu = Arial, 14, bu
    .FONT a16b = Arial, 16, b
    .FONT a16bi = Arial, 16, bi
    .FONT a24bi = Arial, 24, bi


    Topic Druckziel festlegen Kapitel Datenbankjobs
    Bei der Ausführung von Datenbankjobs können verschiedene Druckziele, wie Druckvorschau, Drucker oder Ausgabe in eine Datei, festgelegt werden.
    Bei der Entwicklung von Datenbankjobs, kann mittels STRG-F9, der Job kompiliert und ausgeführt werden.
    Das Druckziel ist in der Regel, die Druckvorschau.
    Es besteht aber auch dieMöglichkeit, die Ausgabe in eine Datei oder direkt auf dem Drucker zu steuern.
    Hierzu muß der Datenbankjob einmal vom Hauptformular mittels "Ausführen, Jobname, Druckzielangeben", ausgeführt werden.


    Topic Eine erste Seite ohne Kopf und Fuß definieren Kapitel Datenbankjobs
    In einem Datenbankjob kann eine erste Seite ohne
    Kopf- (Header) und Fußzeile (Footer) definiert werden.

    Hierzu die Angaben vor dem .KOPF (.HEADING) und/oder .FUß (.FOOTER) setzen.
    Es können auch Punkbefehle, wie .PA (=Seitenumbruch) verwendet werden.
    Ebenso dieMöglichkeit von easy-Abschnitte, wie
    .Do Firstrec(TABELLE)
    .While ....
    $(TABELLE.Feld1)
    .Do NextRec(TABELLE)
    .End


    Topic Ausgabe in eine RTF-Datei Kapitel Datenbankjobs
    Nachfolgend ein Beispiel wie aus ein Datenbankjob eine RTF-Ausgabe erfolgt.
    Das Beispiel stammt aus der VDP Anwendung KAL.

    .Report
    ..#Datei: TOPLJ001.JOB fuer Datenbank TOPICS.DAT
    ..#Beschreibung:
    ..#ausgabe des aktuellen topics in eine RTF-Datei
    ..#Historie:
    ..#24.03.1999 R.W.B.Linn Erstellt
    ..
    .Include \daten\vdp\vdp2\kal\jobfonts.inc
    .Prolog
    ..
    .PRIMTABLEIS TOPICS
    .ZUGRIFF TOPICS.ID
    ..
    ..lese aktuelles record
    .Var nLN = 0
    .Var nRNo = 0
    .Do nRNo := ReadRec(TOPICS, RecNr(TOPICS))
    .If nRNo = 0
    .Do Message("Kein Topic gefunden!", "Fehler")
    .ST
    .End
    .Do nLN := TOPICS.Laufende_Nummer
    .Selection TOPICS.Laufende_Nummer = nLN
    ..
    .Var nRNo = 0
    .Do nRNo := ReadRec(SYSTEM, 1)
    .If nRNo = 0
    .Do Message("Keine Systemvorgaben gefunden!", "Fehler")
    .End
    ..
    ..//                                                            R T F -P R O C E D U R E N
    .Var nRT = 0 
    .Var sFile = "topic.rtf"
    .Do T-Eingabe := sFile
    .Do nRT := Input("Bitte RTF-Dateiname eingeben", "Frage");
    .If nRT = 0
    .ST
    .End
    .If Upper(T-Eingabe) hat ".RTF"
    .Else
    .Do T-Eingabe := T-Eingabe + ".rtf"
    .End
    .Do sFile := KAPITEL.kThema.sHTMLVerzeichnis + T-Eingabe
    ..#tempdatei für memos
    .Var sMemoFile = KAPITEL.kThema.sHTMLVerzeichnis + "memo.tmp"
    .Var nFH = 0
    ..
    .Procedure RTFFileCreate
    ..#legt die rtf-datei an
    .VarDef nFH : Real;
    ..
    .If nFH :=Rewrite(sFile)
    .Do WriteLn(nFH, "{\rtf1\ansi \deff0\deflang1024{\fonttbl{\f0\fmodernCourier New;}}")
    .Do WriteLn(nFH, "{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;}")
    .Do WriteLn(nFH, "{\info {\author r.w.b.linn}}")
    .Do WriteLn(nFH, "\paperw11906\paperh16838\margl1417\margr1417\margt1417\margb1134\gutter0")
    .Do Close(nFH)
    .Else
    .Do Message(sFile + " kann nicht erzeugt werden","Fehler",1)
    .End
    .Endproc
    ..
    .Procedure RTFFileAppend(sLine : String; nHdg : Real; nCRLF : Real)
    ..#hängt eine zeile oder zeichen an eine vorhandene rtf-datei
    .VarDef nFH : Real;
    .Do nFH := TAppend(sFile)
    .If nFH > 0
    .If nHdg = 1
    .Do WriteLn(nFH, "\f0\fs32\keepn \b " + sLine + " \b0 \par \pard\par\f0\fs20")
    .Else
    .If nCRLF = 0
    .Do Write(nFH, sLine)
    .Else
    .Do WriteLn(nFH, sLine + "\par")
    .End
    .End
    .Do Close(nFH);
    .End
    .Endproc
    ..
    .Procedure RTFFileAppendMemo
    ..#liest eine memo datei die vorher mittels
    ..#copymemo angelegt wurde
    .Vardef nFH, nFHM : Real;
    .Vardef c : String;
    ..
    .If IsFile(sMemoFile) = 0
    .Return
    .End
    .Do nFHM := Reset(sMemoFile)
    .Do nFH := TAppend(sFile)
    .If nFH > 0
    .While Not Eot(nFHM)
    .Do c := Read(nFHM, 1)
    .If Asc(c) = 10
    .Do Write(nFH, "\par ")
    .Else
    .If Asc(c) <> 13
    .Do Write(nFH, c)
    .End
    .End
    .End
    .Do Close(nFH);
    .Do Close(nFHM);
    .End
    .Endproc
    ..
    .Procedure RTFFileClose
    .VarDef nFH : Real;
    ..
    .Do nFH := TAppend(sFile)
    .If nFH > 0
    .Do WriteLn(nFH, "}")
    .Do Close(nFH);
    .End
    .Endproc
    ..
    ..//                                                            R T F -F I L E C R E A T E
    .Do RTFFileCreate
    ..//                                                            H E A DE R
    .Header
    .Do RTFFileAppend("Topic: " + TOPICS.tThema.sThema, 1, 1)
    ..
    .Footer
    ..Include \daten\vdp\vdp2\kal\jobftr.inc
    ..
    .Var x = 0
    .Daten
    .Do ShowWait("Bitte warten...")
    .Do x := TOPICS.Laufende_Nummer
    .Do RTFFileAppend("Thema:" + TOPICS.tThema.sThema, 0, 1)
    .Do RTFFileAppend("Kapitel:" + TOPICS.tKapitel.kKapitel, 0, 1)
    .Do RTFFileAppend("Datum:" + DateStr(TOPICS.tDatum), 0, 1)
    .Do RTFFileAppend("", 0, 1)
    .Do RTFFileAppend("Inhalt", 0, 1)
    .Do CopyMemo(TOPICS.tInhalt, sMemoFile)
    .Do RTFFileAppendMemo
    .Do DelFile(sMemoFile)
    .Do RTFFileAppend("", 0, 1)
    .Do RTFFileAppend("Stichworte", 0, 1)
    .Sub
    .Do RTFFileAppend(TOPICS.tStichwort.wStichwort, 0, 1)
    .Endsub
    ..
    .Epilog
    .Do RTFFileClose
    .Do DelFile(sMemoFile)
    .Do HideWait
    .If IsFile(sFile)
    .Do Message(sFile + " erstellt.", "Hinweis")
    .Else
    .Do Message(sFile + " konnte nicht erstellt werden.", "Hinweis")
    .End
    .ST
    ..


    Topic Job-Vorlage: Überweisungsformular Kapitel Datenbankjobs
    Beispiel eines Überweisungsformulars mit Vordrucken für Quicken/QuickenBooks.
    Mit Dank an Hr.Streibert (Konstanz)

    .REPORT
    ..Überweisungsformular drucken mit den Vordrucken fürQuicken/QuickenBooks
    .PROLOG
    .FONT a12n = Arial, 12, n
    .MM 10
    $(@a12n)
    ..Überweisungsauftrag
    .Do GotoXY(70, 22)
    $(SYSTEM.Firma)
    .Do GotoXY(70, 31)
    $(SYSTEM.Kto:96 SYSTEM.BLZ)
    .Do GotoXY(70, 39)
    $SYSTEM.Bank
    .Do GotoXY(70, 48)
    $("                                                  DM          "+ISS.gpm)
    .Do GotoXY(70, 56)
    Verwendungszweck vom $heute,
    .Do GotoXY(70, 65)
    für $ISS.Name, $ISS.Vorname

    ..Beleg für Kontoinhaber
    .Do GotoXY(70, 130)
    $(SYSTEM.Firma)
    .Do GotoXY(70, 138)
    $(SYSTEM.Kto:96 SYSTEM.BLZ)
    .Do GotoXY(70, 146)
    $SYSTEM.Bank
    .Do GotoXY(70, 154)
    $("                                                  DM          "+ISS.gpm)
    .Do GotoXY(70, 163)
    Verwendungszweck vom $heute,
    .Do GotoXY(70, 171)
    für $ISS.Name, $ISS.Vorname

    ___


    Topic Job-Vorlage: Generelle Version mit Include-Beispiele Kapitel Datenbankjobs
    .Report
    ..#Diese Vorlage verwendet drei Include-Befehle für die Fontdatei, den Header und Footer
    ..#Der Vorteil diese Methode ist, daß Sie nur Änderungen in den Include-Dateien
    ..#vornehmen müßen um alle Datenbankjobs anzupassen
    ..#Mittels eines easy-Moduls könne alle Jobs neu übersetzt werden.
    ..#Siehe <Job- und Module-Kompilierungsprozedure>
    ..#10.10.1999 R.W.B.Linn
    .Prolog
    .PRIMTABLEIS TABELLE
    .ZUGRIFF TABELLE.IND
    .Include \daten\vdp\projekt\jobfonts.inc
    ..
    ..Systemvorgaben lesen
    .Var nRNo = 0
    .Do nRNo := ReadRec(SYSTEM, 1)
    .If nRNo = 0
    .Do Message("Keine Systemvorgaben gefunden!", "Fehler")
    .ST
    .End
    ..
    ..#Seiteneinstellungen
    .DO SetPara(".MT "+STR(SYSTEM.JobMT)+", PO "+STR(SYSTEM.JobPO)+", MR"+STR(SYSTEM.JobMR))
    .Selection Ihre Selection
    ..
    ..#Definition der Variabelen
    .Var ULine20 = xMal("_",20)
    .Var ULine40 = xMal("_",40)
    .Var i = 0
    .Var j = 0
    ..
    .HE 1
    .Header
    .Include \daten\vdp\projekt\jobhdr.inc
    $(@a12b "Überschrift vom " + DateStr(ToDay) C_Form ToMargin)
    ..
    .Footer
    .Include \daten\vdp\projekt\jobftr.inc
    ..
    .Daten
    ..
    ..
    .Epilog
    ..


    Topic Prozeduren in Jobs definieren Kapitel Datenbankjobs
    In Datenbankjobs können easy-Prozeduren definiert werden.
    Folgendes Beispiel zeigt eine easy Routine der in einem Array nach ein Artikel sucht.
    Der Rückgabewert ist die gefundene Artikelnummer oder 0 wenn nicht gefunden.

    .Procedure SearchArtikel(nNo : Real) : Real;
    ..#sucht ein Artikel
    .Vardef i : Real
    .Do i := 1
    .While i <= nACnt + 1
    .If anArtikel[i] = nNo
    .Return i
    .End
    .Do i := i + 1
    .End
    .Return 0
    .Endproc
    ..

    ..#Aufruf im Datenbereich
    ..#Es wird anhand eines Artikelnummers in ein Array gesucht.
    ..#Das Ergebnis wird in ein zweidiemensionales Array übertragen.
    .Daten
    .Sub
    .Do i := SearchArtikel(FSArtikel.Laufende_Nummer)
    ..If i > 0 And j > 0
    .Do anKArtikel[i,j] := FSArtikel.VkPreis
    .Endsub
    ..
    .Epilog


    Topic Nummerierung bei Gruppenausgabe Kapitel Datenbankjobs
    Folgenden Abschnitt zeigt, wie eine fortlaufende Nummerierung bei einer 
    Gruppenausgabe erfolgen kann.
    Eine gruppierte Ausgabe mit fortlaufenden Nummerierung sieht wie folgt aus (Beispiel):

    Nr. Artikel Anzahl
    1 Artikel 1 5
    2 Artikel 2 8
    3 Artikel 3 10

    ..#Code im Datenbankjob
    ..#Tabelle POSTEN hält die Artikel. Die Artikel sind in eine TabelleARTSTAMM definiert
    ..#
    .GP 0
    .Var nCnt = 0
    .Var G_akt = ""
    .Var G_alt = ""
    .Var nSumArt = 0
    .Do G_akt := G_alt
    .Group POSTEN.PArtikelNr.Artikel
    ..
    .If G_alt <> G_akt
    .Do G_akt := G_alt
    .Do nSumArt := 0
    .End
    $(@a8n Str(nCnt := nCnt + 1, 1,0):10 + " " + "":20 + " " + G_alt:60! +" " + Str(ZSum(POSTEN.PMenge), 1, 2) r 20 + " " + "":20 + " " +Str(ZSum(POSTEN.PBrutto),1,2) r 20)
    .Do nSumArt := nSumArt + ZSum(POSTEN.PBrutto)


    Topic Ausgabe von Bitmaps die nicht in der Datenbank gespeichert sind Kapitel Datenbankjobs
    Die Ausgabe mittels ein Datenbankjob von Bitmaps (GIF und BMP) die nicht in der
    Datenbank gespeichert sind ist wie folgt möglich:

    1.In eine System-Tabelle muß ein Feld vom Typ Bild/Klang definiert werden.
    Beispiel: TempBMP

    2.Im Datenbankjob nachfolgendes Programmfragment definieren.
    Es könnte auch mittels eine Prozedur im Job erfolgen.

    ..Variabelen definieren
    ..Dateiname des Bitmaps speichern
    .Var sBild1 = ""
    ..für Tempstrings
    .Var sTmp1 = ""
    ..Filehandle für Bitmap-Datei
    .Var nFH1 = 0
    ..w1 = breite, h1 = höhe, t1 = textversatz
    .Var w1 = 0
    .Var h1 = 0
    .Var t1 = 0
    ..
    ..hier die Übergabe des Bildes beschreiben
    .Do sBild1 := "meinbild.gif"
    ..
    ..GIF = Compuserve-Format
    .If Upper(sBild1) Hat ".GIF"
    .Do LinkBlob(SYSTEM.TmpBMP, sBild1, 5)
    ..öffne gif-Datei und ermittle Width (an Pos 7) und Heigth (an Pos 9)
    .Do nFH1 := Reset(sBild1)
    .If nFH1 > 0
    .Do Read(nFH1, 6)
    .Do w1 := ASC(Read(nFH1, 1))
    .Do Read(nFH1, 1)
    .Do h1 := ASC(Read(nFH1, 1))
    .Do Close(nFH1)
    .End
    ..ende if bild ist GIF
    .End
    ..
    ..BMP = Bitmap
    .If Upper(sBild1) Hat ".BMP"
    .Do LinkBlob(SYSTEM.TmpBMP, sBild1, 1)
    ..öffne gif-Datei und ermittle Width (an Pos 19) und Heigth (an Pos 23)
    .Do nFH1 := Reset(sBild1)
    .If nFH1 > 0
    .Do Read(nFH1, 18)
    .Do w1 := ASC(Read(nFH1, 1))
    .Do Read(nFH1, 3)
    .Do h1 := ASC(Read(nFH1, 1))
    .Do Close(nFH1)
    .End
    ..bitmap
    .End
    ..
    ..für Tests
    ..Do Message(GetLinkedFile(SYSTEM.TmpBMP),Str(BlobSize(SYSTEM.TmpBMP)))
    ..gebe erst mal text aus (nur als Beispiel)
    .Do Print("Mein Bild:" + " ")
    ..Bitmap ausgeben, dabei ist der Textversatz 0
    ..die Ausgabe erfolgt dynamisch
    .Do _"Print(SYSTEM.TmpBMP:"+Str(w1)+":"+Str(h1)+":"+Str(t1)+ "' ')"
    ..berechne Anzahl Zeilenumbüche
    .Do sTmp1 := nTimes("/", h1 div 5)
    .Do _"Print("+sTmp1+")"


    Topic Datenbankjobausgabe in eine RTF-Datei Kapitel Datenbankjobs
    Beispiel eines Datenbankjobs dessen Ausgabe in eine RTF-Datei umgeleitet wird.

    .Report
    ..#Datei: KAPLJ002.JOB fuer Datenbank KAPITEL.DAT
    ..#Beschreibung:
    ..#ausgabe des aktuellen kapitels+topics in eine rtf-datei
    ..#Historie:
    ..#06.06.1999 R.W.B.Linn Erstellt
    ..
    .Include \daten\vdp\vdp2\kal\jobfonts.inc
    .Prolog
    ..
    .PRIMTABLEIS KAPITEL
    .ZUGRIFF KAPITEL.ID
    ..
    ..lese aktuelles record
    .Var nLN = 0
    .Var nRNo = 0
    .Do nRNo := ReadRec(KAPITEL, RecNr(KAPITEL))
    .If nRNo = 0
    .Do Message("Kein Kapitel gefunden!", "Fehler")
    .ST
    .End
    .Do nLN := KAPITEL.Laufende_Nummer
    .Selection KAPITEL.Laufende_Nummer = nLN
    ..
    .Var nRNo = 0
    .Do nRNo := ReadRec(SYSTEM, 1)
    .If nRNo = 0
    .Do Message("Keine Systemvorgaben gefunden!", "Fehler")
    .End
    ..
    ..//                                                            R T F -P R O C E D U R E N
    .Var nRT = 0 
    .Var sFile = "kapitel.rtf"
    .Do T-Eingabe := sFile
    .Do nRT := Input("Bitte RTF-Dateiname eingeben", "Frage");
    .If nRT = 0
    .ST
    .End
    .If Upper(T-Eingabe) hat ".RTF"
    .Else
    .Do T-Eingabe := T-Eingabe + ".rtf"
    .End
    .Do sFile := KAPITEL.kThema.sHTMLVerzeichnis + T-Eingabe
    ..#tempdatei für memos
    .Var sMemoFile = KAPITEL.kThema.sHTMLVerzeichnis + "memo.tmp"
    .Var nFH = 0
    ..
    .Procedure RTFFileCreate
    ..#legt die rtf-datei an
    .VarDef nFH : Real;
    ..
    .If nFH :=Rewrite(sFile)
    .Do WriteLn(nFH, "{\rtf1\ansi \deff0\deflang1024{\fonttbl{\f0\fmodernCourier New;}}")
    .Do WriteLn(nFH, "{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;}")
    .Do WriteLn(nFH, "{\info {\author r.w.b.linn}}")
    .Do WriteLn(nFH, "\paperw11906\paperh16838\margl1417\margr1417\margt1417\margb1134\gutter0")
    .Do Close(nFH)
    .Else
    .Do Message(sFile + " kann nicht erzeugt werden","Fehler",1)
    .End
    .Endproc
    ..
    .Procedure RTFFileAppend(sLine : String; nHdg : Real; nCRLF : Real)
    ..#hängt eine zeile oder zeichen an eine vorhandene rtf-datei
    .VarDef nFH : Real;
    .Do nFH := TAppend(sFile)
    .If nFH > 0
    .If nHdg = 1
    .Do WriteLn(nFH, "\f0\fs32\keepn \b " + sLine + " \b0 \par \pard\par\f0\fs20")
    .Else
    .If nCRLF = 0
    .Do Write(nFH, sLine)
    .Else
    .Do WriteLn(nFH, sLine + "\par")
    .End
    .End
    .Do Close(nFH);
    .End
    .Endproc
    ..
    .Procedure RTFFileAppendMemo
    ..#liest eine memo datei die vorher mittels
    ..#copymemo angelegt wurde
    .Vardef nFH, nFHM : Real;
    .Vardef c : String;
    ..
    .If IsFile(sMemoFile) = 0
    .Return
    .End
    .Do nFHM := Reset(sMemoFile)
    .Do nFH := TAppend(sFile)
    .If nFH > 0
    .While Not Eot(nFHM)
    .Do c := Read(nFHM, 1)
    .If Asc(c) = 10
    .Do Write(nFH, "\par ")
    .Else
    .If Asc(c) <> 13
    .Do Write(nFH, c)
    .End
    .End
    .End
    .Do Close(nFH);
    .Do Close(nFHM);
    .End
    .Endproc
    ..
    .Procedure RTFFileClose
    .VarDef nFH : Real;
    ..
    .Do nFH := TAppend(sFile)
    .If nFH > 0
    .Do WriteLn(nFH, "}")
    .Do Close(nFH);
    .End
    .Endproc
    ..
    ..//                                                            R T F -F I L E C R E A T E
    .Do RTFFileCreate
    ..//                                                            H E A DE R
    .Header
    ..Include \daten\vdp\vdp2\kal\jobhdr.inc
    .Do RTFFileAppend("Kapitel: " + KAPITEL.kKapitel, 1, 1)
    ..
    ..//                                                            F O O TE R
    .Footer
    ..Include \daten\vdp\vdp2\kal\jobftr.inc
    ..
    .Var x = 0
    .Daten
    .Do ShowWait("Bitte warten...")
    .Do x := KAPITEL.Laufende_Nummer
    .Do RTFFileAppend("Thema:" + KAPITEL.kThema.sThema, 0, 1)
    .Do RTFFileAppend("Inhalt:" + KAPITEL.kKapitel, 0, 1)
    .Do RTFFileAppend("Datum:" + DateStr(KAPITEL.kDatum), 0, 1)
    .Do RTFFileAppend("Inhalt:", 0, 1)
    .Do RTFFileAppend(KAPITEL.kInhalt, 0, 1)
    .Do RTFFileAppend("", 0, 1)
    .Do RTFFileAppend("Topic(s)", 0, 1)
    .Sub TOPICS
    .Do RTFFileAppend(TOPICS.tTitel, 0, 1)
    .Do CopyMemo(TOPICS.tInhalt, sMemoFile)
    .Do RTFFileAppendMemo
    .Do DelFile(sMemoFile)
    .Endsub
    ..
    .Epilog
    .Do RTFFileClose
    .Do DelFile(sMemoFile)
    .Do HideWait
    .If IsFile(sFile)
    .Do Message(sFile + " erstellt.", "Hinweis")
    .Else
    .Do Message(sFile + " konnte nicht erstellt werden.", "Hinweis")
    .End
    .ST
    ..


    Topic Rahmen im Druckjobs Kapitel Datenbankjobs
    Tip 1
    $(@a8b "Rahmen")
    ..150 ist die breite. Der Rahmen enthällt 3 Leerzeilen.
    .VL 150, VL, HL
    $(@a10n "")
    $(@a10n "")
    $(@a10n "")
    .HL
    .EVL
    ..

    Tip 2
    Folgender Druckjob zieht genau die gewünschten Linien zur Darstellung eines Rahmens.
    Im Datenbereich kann dann in die Rahmen hinein gedruckt werden.

    .REPORT
    .PROLOG
    .MM 1
    .MT 200, PO 100, MR 50
    .DEF Rahmenhöhe=450
    .DEF Rahmenbreite=600
    .PROCEDURE Rahmenziehen(x, y : REAL)
    .DO GotoXY(0,y)
    .Do SetPara("PO "+STR(150+x))
    .Do SetPara("VL "+STR(Rahmenbreite)+",VL "+STR(Rahmenbreite)+",VL                                         "+STR(Rahmenbreite)+",VL,HL")
    .REPEAT
    .DO GotoXY( x, WhereY +Rahmenhöhe)
    .HL
    .UNTIL WhereY > 2400
    .EVL
    .ENDPROC
    .DO Rahmenziehen(0, 150)
    .DO Rahmenziehen(0, 152)
    .DO Rahmenziehen(0, 154)
    .DO Rahmenziehen(1, 150)
    .DO Rahmenziehen(2, 150)
    .DO Rahmenziehen(3, 150)
    .DATEN
    .EPILOG


    Topic Ja/Nein-Felder in Berichten grafisch darstellen Kapitel Datenbankjobs
    Tipp 1
    In Berichten:
    Ein Element vom Typ FORMEL definieren.
    Das Element den Font z.B. WINGDINGS zuweisen.
    Die Formel wie folgt aufbauen:

    CHOICE(Ja_Nein_Feld,CHAR(0254),"o")
    oder
    CHOICE(Ja_Nein_Feld,CHAR(0231),"o")

    Das Ergebnis ist einen Kasten mit Haken bzw. einen leeren Kasten.

    Tipp 2
    In Datenbankjobs:
    Ein Font z.B. WINGDINGS erstellen.
    Ausgabe des Feldes:

    $(@myfont CHOICE(Ja_Nein_Feld,CHAR(0254),"o"))

    Das Ergebnis ist einen Kasten mit Haken bzw. einen leeren Kasten.

    Tipp 3
    In Datenbankjobs oder Berichten:
    In eine Systemtabelle zwei Bild-Felder für ein JA- und ein NEIN-Bitmap definieren.
    Beispiel: BildJA und BildNEIN
    Die Bildfelder mit Bitmap-Dateien einbetten. Empfehlung für die Bitmap-Dateien ist:
    Grösse: 10*10 Pixel, VGA 16 Farben

    Beispiel Datenbankjob:
    Ausgabe des Bildfeldes:
    .Prolog
    ..System Satz lesen. Die Systemtabelle enthält nur ein Datensatz.
    .Do ReadRec(System,1)
    .Daten
    .If JA
    JA:  $($SYSTEM.BildJA:2:1:0)
    .End
    .If NEIN
    NEIN:  $($SYSTEM.BildNEIN:2:1:0)
    .End


    Topic Verknüpfung in SUB-Reports Kapitel Datenbankjobs
    Bei geschaltelten SUB-Reports wird absolut nur der durch den SUB-Report vorgegebene
    Verknüpfung berücksichtigt.
    Wichtig ist allerdings, daß innerhalb des SUB-Report kein Zugriff auf eine andere
    Tabelle erfolgt, es sein denn über die Link-Notation.

    Verwende bei Feldzugriffen immer den vollen Pfad, also nicht Name sondern ADRESSEN.Name
    Oder nicht nur Betrag, sondern POSITION.Betrag

    Bei diesem Beispiel ist klar, welche Datensätze ausgegeben werden:

    ReadRec( ADRESSEN, RecNr(ADRESSEN))
    SUB RECHNUNG
    Showwait(RECHNUNG.RechNr)
    SUB POSITION
    n := n+POSITION.Betrag
    ENDSUB
    ENDSUB

    Hier wird es schon sehr diffus:

    ReadRec( ADRESSEN, RecNr(ADRESSEN))
    SUB RECHNUNG
    Showwait(RECHNUNG.RechNr)
    SUB POSITION
    n := n+POSITION.Betrag
    Showwait(KUNDEN.Rabatt)
    ENDSUB
    ENDSUB

    Hier erfolgt nämlich innerhalb des 2. SUP-Reports ein Zugriff auf eineexterne
                         Tabelle und in diesem Fall können Positionen zurAusgabe kommen, die überhaupt nicht zur Rechnung gehören.

    VDP weißt in diesen Fällen auch die Sortierung der Datensätze beiSUB-Reports ab.

    So ist es richtig:
    ReadRec( ADRESSEN, RecNr(ADRESSEN))
    SUB RECHNUNG
    Showwait(RECHNUNG.RechNr)
    SUB POSITION
    IF POSITION.Rechnung.Kunde.MwSt-Frei=0
    n := POSITION.Betrag* 1.16
    END
    n := n+POSITION.Betrag
    ENDSUB POSITION.Datum
    ENDSUB

    und so falsch:
    ReadRec( ADRESSEN, RecNr(ADRESSEN))
    SUB RECHNUNG
    Showwait(RECHNUNG.RechNr)
    SUB POSITION
    IF ADRESSEN.MwSt-Frei=0
    n := POSITION.Betrag* 1.16
    END
    n := n+POSITION.Betrag
    ENDSUB POSITION.Datum
    ENDSUB

    VDP wird in diesem Fall die SUP-Report Ausgabe über die Positioneventuell nicht
    korrekt ausgeben und außerdem dieSortieranweisung nach ENDSUB mit einer
    Fehlermeldung quitieren.


    Topic Seitenumbruch bei Gruppierung in einem Bericht Kapitel Datenbankjobs
    Problem:
    Wenn ein Datensatz kurz vor Seitenende beginnt, d.h. die Gruppierung kommt noch auf das Seitenende, aber die dazugehörigen Daten landen auf der nächsten Seite, ohne aber die
    Gruppierung zu wiederholen, oder ein Teil der Datensätze kommt noch auf das erste Blatt
    und der Rest wird ohne Gruppe auf der nächsten Seite gedruckt. 

    Lösungsmöglichkeiten:
    Tip 1
    In der Gruppendefinition den Punktbefehl .PA (neue Seite) verwenden
    .GP 1
    .Gruppe Upper(Name[1])
    .PA
    $(@a12b G_Neu Bold(0) )
    .Daten

    Tip 2
    In der Gruppendefinition den Punktbefehl .CP nn verwenden. Bei nn ist 10 findet ein Seitenumbruch wenn weniger als 10 Zeilen auf der Seite frei sind:
    .GP 1
    .Gruppe Upper(Name[1])
    .CP 10
    $(@a12b G_Neu Bold(0) )
    .Daten

    Tip 3
    .GP 1
    .Gruppe Upper(Name[1])
    ..Anzeige Anzahl Datensätze nach der Ausgabe des Gruppenteiles
    .If ZCount(Name) > 0
    $(@a12b + "Datensätze " + Str(ZCount(Name)))
    .End
    .CP 10
    $(@a12b G_Neu Bold(0) )
    .Daten

    Sie können auf mit dem VDP internen Befehl $Zeile arbeiten.


    Topic Zentrierter Text Kapitel Datenbankjobs
    Die Funktion C_Form ermöglicht eine zentrierte Darstellung in eine Zeile.
    Beispiel:
    $("Mein Text" C_Form 50)
    ergibt eine zentrierte Ausgabe von Mein Text in einem 50 Zeichen breiten Bereich.


    Topic Aufruf Prozeduren im Datenbankjob Kapitel Datenbankjobs
    Aufruf Prozeduren im Datenbankjob

    Frage:
    Kann eine Prozedur, die einen String zurückgibt, in einem Datenbankjob einsetzen werden, um den String ausgeben zu können?

    Antwort:
    Es funktioniert mit einem Aufrauf der externen Prozedur im Ausgabeformat:

    $(Procedur(Parameter):20)

    Prozeduren ohne Rückgabewert können mit

    .DO _"Procedur(Parameter)"

    aufgerufen werden.


    Topic Ausgabe Gruppensumme Kapitel Datenbankjobs
    Um eine Gruppensumme auszugeben ist der Berichtsaufbau wie folgt:
    Header
    Prolog
    Gruppen-Definition
    Datenbereich
    Footer

    Im Prolog Bereich eine Variable definiren und diese direkt einen Wert zuweisen.
    Beispiel Variable:
    .Prolog
    .Def nGruppensumme = Sum(TABELLE.Feld1)

    Die Variable im Footer Bereich ausgeben.
    Beispiel:
    .Footer
    $("Summe: " + Str(nGruppensumme)

    Weitere summierungen etc. sind auch möglich.
    Beispiel:
    .Prolog
    .Def nGruppeneintraege = Count(TABELLE.Feld1)
    .Footer
    "Anzahl Gruppeneinträge: " + Str(nGruppeneintraege)


    Topic Zählen von angekoppelte Datensätze Kapitel Datenbankjobs
    Beispiel: wobei BESTAND die angekoppelte Tabelle ist. Das Feld "material" der Haupttabelle ist ein Relationsfeld auf die Tabelle BESTAND
    $1
    .Var nCnt = 0
    .Sub BESTAND
    .Do nCnt := nCnt + 1
       $material.1
    .Endsub
     =========
     Total: $nCnt 


    Topic Moduldarstellung in der Makroliste Kapitel easy Allgemeine Hinweise
    In der Makroliste werden deshalb nur die Makros des ersten Moduls dargestellt, damit 
    Sie eine Auswahlmöglichkeit haben.
    Die Makros aus anderen Modulen können von den Makros des ersten Modulsaus aufgerufen werden.


    Topic Datensatz mittels Laufende Nummer suchen Kapitel easy Allgemeine Hinweise
    Beispiel:
    Vardef nSatz : Real;
    nSatz := FindRec(TABELLE, Str(Laufende_Nummer), "TABELLE.INR", 1);
    Ist nSatz > 0 dann wurde der Datensatz gefunden.
    Diese kann dann mit ReadRec(TABELLE, nSatz) gelesen werden.


    Topic Bilder/Sounds einlesen Kapitel easy Allgemeine Hinweise
    Vor allem bei Bilder ist es sehr schön, daß man sie statt über einen Button
    (der ein eigenes Bildfenster öffnet) direkt in das Formular integrieren kann.
    Der Nachteil besteht darin, daß sich Bilder nicht mehr so einfach einlesen lassen.
    Die einfachste Lösung:
    Plazieren Sie das Bildfeld einfach zwei mal indas Formular: einmal direkt und einmal als Button.
    Für eine noch elegantere Bild-Lesen-Funktion müssen Sie ein kleines Makro schreiben.
    Das könnte beispielsweise so aussehen:

    Procedure Bild_laden
     T-Eingabe:="*.BMP";
     IF ChooseFile("Vogelbild laden")
      IF T-Eingabe
       LinkBlob(Foto,T-Eingabe,1);
       Attach
      END
     END
    Endproc

    Erklärung:
    Mit ChooseFile wird ein komfortabler Dateiauswahl-Dialog aufgerufen. Das Ergebnis der
    Dateiauswahl wird in die Systemvariable T-Eingabe geschrieben. Zuvor kann man diese
    Variable initialisieren, sinnvollerweise mit der gesuchten Extension. Die Funktion LinkBlob
    verknüpft das Bilddatenfeld mit der ausgewählten Datei.
    Der dritte Parameter (hier 1) gibt an, um welchen Dateityp es sichhandelt. Analog funktioniert
    das natürlich auch bei Sounddateien.
    Vor allem in VDP-Anwendungen ist es wichtig, daß in den Datenfeldern für 
    verknüpfte Bilder- und Klangdateien nicht der absolute Pfad (also der komplette Pfadname
    mit Laufwerksangabe), sondern nur der relative Pfad zum Projektverzeichnis gespeichert
    wird. Damit bleibt der Endanwender flexibel und kann die Anwendung in jedes gewünschte
    Verzeichnis installieren.
    Um dies zu erreichen, ist es besser, die LinkBlob-Funktion ein wenig aufwendiger zu gestalten:

    LinkBlob(Foto, SubPath(DBDir(FileNo), T-Eingabe), 1)


    Topic Meldung "Falsche Programmversion" Kapitel easy Allgemeine Hinweise
    Die Meldung bedeutet, daß das kompilierte Modul nicht zur Programmversion von WinTDB/VDP paßt.

    Aktion: Modul neu übersetzen (kompilieren).


    Topic Report mit Deckblatt Kapitel easy Allgemeine Hinweise
    Bei grosse Reports ist es manchmal sinnvoll einen Deckblatt auszugeben.
    Folgender Abschnitt definiert einen Deckblatt:

    .Prolog
    .FONT a10a = Arial, 10, n
    .FONT a10b = Arial, 10, i
    .FONT a12a = Arial, 12, b
    .FONT a12b = Arial, 12, n
    .FONT a16a = Arial, 16, bi
    .FONT a24a = Arial, 24, bi..
    .. Header und Footer werden nur ausgegeben wenn Seite ungleich 1
    .HE 0
    .Header
    .If Seite > 1
    $(@a10a "TDBprov") $(@a16a PROJEKT.ProjektName C_Form ToMargin)
    .HL
    .End
    .Footer
    .HL
    .If Seite > 1
    $(@a10a "Projektdetailbericht, ausgegeben am "+$heute+" um "+$jetzt)$("Seite "+$Seite 
    R_Form ToMargin )
    .Else
    $(@a10b "TDBprov - TDB Projektverwaltung (c)R.W.B.Linn" C_FormToMargin)
    .End
    ..
    .Daten
    .. Erste Seite Deckblatt
    $(/)
    $(@a16a "Projektdetailbericht" C_Form ToMargin/)
    $(@a16a "für" C_Form ToMargin/)
    $(@a24a PROJEKT.ProjektName C_Form ToMargin/)
    .PA

    Hinweise: Seite ist eine TDB-Systemvariable.



    Topic Prozeduren nicht im Werkzeugmenü (Makrofenster) Kapitel easy Allgemeine Hinweise
    Sollen Prozeduren nicht im Werkzeugmenü (User Modus) oder im
    Makrofenster (Strg-O) erscheinen,  dann Prozeduren mit einem Dummy-Parameter
    definieren.

    Beispiel:
    Procedure MyLokal (Dummy : Real);

    Endproc

    Aufruf:
    MyLokal(0);


    Topic Hinzufügen Primärdatei Datensatz an angekoppelte Datei Kapitel easy Allgemeine Hinweise
    Die Lösung ist die laufende Nummer der Primärdatei direkt das Feld 
    Kopplung der angekoppelte Datei zuzuordnen.

    Beispiel:
    ADRESSEN ist Primärdatei, LETZTADR angekoppelte Datei
    If RecNo(ADRESSEN) > 0
     ReadRec(LETZTADR, 0);
     ..Kopplungsfeld bekommt ID Feld
     LETZTADR.Adresse := ADRESSEN.Nummer;
     WriteRec(LETZTADR, 1 + FileSize(LETZTADR));
     Refresh;
     Message("LETZTADR angepaßt mit AdresseNr. " + Str(ADRESSEN.Nummer));
    End


    Topic Hinzufügen Primärdatei Datensatz an Relationsdatei Kapitel easy Allgemeine Hinweise
    WinTDB setzt zur Auflösung eine n:m-Verbindung eine dritte Datei, die sg. Relationsdatei, ein. 
    Diese Datei (Dateiendung .REL) enthält die Laufende Nummern der verbundene Dateien.
    Mittels easy muß daher direkt die Relationsdatei bearbeitet werden. Hierzu ist es notwendig
    die Laufende_Nummern der Datensätze und der Name der Relationsdatei zu wissen.
    Name der Relationsdatei ist die Datei der das Relationsfeld enthält, allerdings mit der Endung .REL und ggf. eine Buchstabe am Ende des Dateinamens.
    Folgendes easy-Beispiel zeigt zwei Tabellen ADRESSEN und KORRESP.
    Eine Adresse kann mehrere Korrespondenzen enthalten, aber eine Korrespondenz kann
    auch an mehrere Adressen gerichtet sein. Das Relationsfeld befindet sich in der Tabelle
    KORRESP. Die Relationsdatei heißt KORRESPO.REL.
    Beim Öffnen des Projektes wird die Datei automatisch mit geöffnet. Es handelt sich wie gesagt um eine DAT-Datei.

    easy-Beispiel:
    ..adressen laufende nummer ermitteln
    ReadRec(ADRESSEN, RecNo(ADRESSEN) );
    ..neues korrespondez record erstellen
    ReadRec(KORRESP, 0);
    ..setze vorgaben
    SetField(KORRESP,3,DateStr(ToDay));
    ..speichere record
    WriteRec(KORRESP, 1 + FileSize(KORRESP));
    ..zweiter schritt
    ..korresp record lesen um laufende nummer zu ermitteln
    ReadRec(KORRESP, FileSize(KORRESP) );
    ..neues record in der relationsdatei erstellen
    ReadRec(KORRESPO, 0);
    ..laufende nummern zuordnen, hierbei ist feld 1 immer das feld mit den namen der
    ..tabelle der das relationsfeld enthält
    KORRESPO.1 := KORRESP.Nummer;
    KORRESPO.2 := ADRESSEN.Nummer;
    ..speichere record
    WriteRec(KORRESPO, 1 + FileSize(KORRESPO) );


    Topic Beim Programmstart eine Prozedur aufrufen (OnOpenProject) Kapitel easy Allgemeine Hinweise
    Oft möchte man eine Prozedur direkt beim Start einer Anwendung aufrufen.
    Entweder weil gleich zu Beginn eine Anwenderkommunikation nötig ist (z.B. Name des
    Anwenderseingeben), oder weil man bestimmte Datenfenster öffnen möchte, oder 
    um bestimmte globale Variablen (siehe nächster Abschnitt) initialisieren zu können.
    easy stellt Ihnen dazu die Prozedur OnOpenProjectzur Verfügung.
    Wenn das erste Modul einer Tabelle eine Prozedur mit dem Namen OnOpenProject enthält,
    wird diese beim Öffnen desProjektes ausgeführt. Dies gilt für jede Tabelle des Projektes.

    Beispiel:
    PROCEDURE OnOpenProject 
     If Message("Möchten Sie die Standardeinstellung laden?", "Start", 3) =6
      ActivateForm("KUNDEN.Kundenliste");    
      ActivateForm("RECHNUNG.Rechnung");
     End
    ENDPROC

    Hinweise:
    Zu beachten sei, daß die WinTDB beim Start alle OnOpenProject-Prozeduren aufruft,
    d.h. wenn es mehrere Tabellen mit Modulen gibt, die eine OnOpenProject-Prozedur enthalten, dann werden diese ausgeführt.
    OnOpenProject erscheint im User-Modus im Werkzeugmenü. Um das zu vermeiden, 
    könnte man OnOpenProject mit einem Parameter versehen.
    Ist im Modul auch möglich, aber beim Aufruf stürzt die WinTDB ab (WinTDB 1.02)!


    Topic Definition Globale Variablen Kapitel easy Allgemeine Hinweise
    Auf den ersten Blick fehlen in easyVariablen, die ihreGültigkeit über eine Prozedur hinaus
    bewahren. Dabei übersieht man leicht, daß es ja Variablen gibt, die nicht nur in allen
    Prozeduren gelten, sondern sogar auch beim nächsten Startder Anwendung noch ihre alten Werte haben: Tabellen.
    Angenommen, Sie möchten in einer Anwendung den Namen des Benutzersspeichern sowie das Datum und Uhrzeit des Programmstarts.
    Dazu legen Sie mit "Datei/NeueTabelle..." eine Tabelle namens SYSTEM mit z.B. den Spalten
    Benutzername (Typ Alphanumerisch:40)
    Startdatum (Typ Datum)
    Startzeit (Typ Zeit)
    an.
    Durch eine OnOpenProject-Prozedur können Sie die Werte beim Programmstart ermitteln
    und eintragen. Anschließend sind diese Daten an jeder Stelle im Programm bekannt:

    PROCEDURE OnOpenProject  
     ReadRec(SYSTEM, 1)
     Input(Geben Sie Ihren Namen an", Faktura");  
     GLOBVAR.BenutzerName := T-Eingabe; 
     GLOBVAR.StartDatum := today;  
     GLOBVAR.StartZeit := now
     WriteRec(SYSTEM, 1)
    ENDPROC

    Die Verwendung eine SYSTEM Tabelle sollte zum Standard für jedes Projekt werden.
    Zu der SYSTEM Tabelle kommen dann noch das SYSTEM Formular SYSTEMEINSTELLUNGEN (kann natürlich auch anders heißen) und das SYSTEM Modul.
    Alle Prozeduren die global in einem Modul eingesetzt werden, werden im SYSTEM Modul 
    definiert. Das SYSTEM Formular kann den verschiedensten Aufgaben haben,z.B.
    Seite 1 Allgemeine Einstellungen
    Seite 2 Drucker Parameter
    Seite 3 Hilfeseite

    Die Tabellenstruktur der Tabelle SYSTEM kann aus sehr unterschiedlichen Felder bestehen,
    eben abhängig von den eingesetzten Werte der im Projekt benötigten Werte.
    Die Tabelle SYSTEM enthält genau einen Datensatz, wo immer wieder aufzugegriffen wird;
    ReadRec(SYSTEM, 1).
    Neue Werte werden dementsprechend mir WriteRec(SYSTEM, 1) gespeichert.
    In dieses Dokument sind verschiedenen Tipps, die von der Tabelle SYSTEM gebrauch machen.


    Topic Dialogfenster für die Anwender Kommunikation Kapitel easy Allgemeine Hinweise
    Windows-Programme verwenden oft Dialogfenster zur Eingabe von Informationen durch den 
    Anwender.
    Mit easy können auch Ihre Anwendungen diese komfortable Eingabemöglichkeit benutzen.
    Denn was sind Dialogfenster anderes als modale Formulare?
    Erstellen Sie also eine Hilfstabelle namens DLGTAB (nur ein Beispiel) in Ihrem Projekt,
    welche für jede einzugebende Informationseinheit die passende Spalteenthält.
    In diese Tabelle müssen Sie per Hand einen Datensatz mit den Vorbelegungen des Dialogfensterseintragen.
    Anschließend entwerfen Sie ein oder mehrere Formulare für diese Tabelle. Zum Ausführen des Dialogfensters gehen Sie folgendermaßen vor:
    Diese Prozedur führt einen Dialog aus und gibt 1 zurück, wenn er mit OK bestätigt wurde, sonst 0.

    Procedure DialogAusführen(Dialogname: String; Kommentar: String): Real;
    ..#Datenfenster öffnen  OpenForm("DLGTAB."+Dialogname);  
    ..#Formular modal ausführen und Ergebnis auswerten  
     If EditRec(Kommentar)    
      Schließen    
      RETURN 1  
     Else
      Schließen    
     RETURN 0 
     End
    ENDPROC

    Als Beispiel soll eine Anwendung dienen, in deren Verlauf zwei Dialogfenster benötigt
    werden. In dem einen werden Vor- und Nachname des Anwenders sowie sein Geburtsdatum
    abgefragt, in dem anderen kann er Sortierung und Datensatz-Auswahl eines
    Berichtesfestlegen.
    Die Hilfetabelle DLBTAB erhält nun die folgende Struktur:
    Benutzername (Typ Alphanumerisch:40)
    Benutzervorname (Typ Alphanumerisch:20)
    BenutzerGeburtsdatum (Typ Datum)
    BerichtSortierung (Typ Auswahl aus (Bezeichnung, Hersteller, Modelljahr)
    BerichtAuswahl (Typ Integer)

    Zu dieser Tabelle entwerfen Sie zwei verschiedene Formulare. Das eine heißt z.B.
    BenutzerDlg und enthält die ersten drei Felder der Tabelle, während das andere BerichtDlg
    heißen könnte und die Felder vier und fünf beinhaltet.
    Zur Eingabe der Benutzerdaten rufen Sie einfach die obenstehende Prozedur auf:

    IF DialogAusführen("BenutzerDlg", "Geben Sie Ihre Daten an")
    ...
    END

    Wo die drei Punkte sind, können Sie die eingegebenen Daten verwenden:
    Message("Hallo, " + DLGTAB.BenutzerVorname + " " + DLGTAB.BenutzerName+ ".
    Sie sind " + Str(Year(today) - Year(DLGTAB.BenutzerGeburtsdatum)) + " Jahre alt.");


    Topic Projektverzeichnis ermitteln Kapitel easy Allgemeine Hinweise
    Die WinTDB bietet keine Möglichkeit das Projektverzeichnis eines Projektes direkt zu ermitteln. 
    Eine kleine easy-Abfrage schafft Hilfe:
    ?MaxFile > 0 / sProjektverzeichnis := DBDir(1);
    1 steht für die erste Tabelle im Projekt.
    MaxFile prüft ob es überhauptTabellen im Projekt gibt.

    Einsatzgebiet diese Möglichkeit ist das aufrufen von Prozeduren mittels
    ExecMacro, wobei das Modul in einem anderen Verzeichnis liegt.


    Topic Debugging Möglichkeit Kapitel easy Allgemeine Hinweise
    Während der Entwicklung von easy-Module ist es manchmal sinnvoll, Ergebnisse zwischen
    zu speichern (Debug-Informationen).
    Folgende Prozedur ermöglicht es Informationen ineine Logdatei (Textdatei) zu schreiben,
    welche dann z.B. mit dem Windows NotePadangezeigt werdenkann.

    PROCEDURE WriteToLog(sLogFile: STRING; s : STRING; nLogNeu : REAL)
    .. schreibt string s in einemlogdatei
    .. parameter:
    .. sLogFile - logdatei
    .. s - eintrag in der logdatei
    .. nLogNeu - 0 erstelle neue logdatei
    .. Beispiel:
    .. WriteToLog("Projekt.log", "START p.MyProc um " + DateStr(Today) + "" + TimeStr(Now), 0);

     DEF HEADING = "Debug";
     VARDEF nFH : Real;

     .. neue logdatei erstellen, wenn nLogFirst = 1
     IF nLogNeu = 1
      ?IsFile(sLogFile) = 1 / DelFile(sLogFile);
     END
     .. logdatei öffnen, erst prüfen ob logdatei vorhanden ist.
     IF IsFile(sLogFile) = 0 .. logdatei nicht da, erstelle neu
      IF nFH:=Rewrite(sLogFile) < 1
       Message("Kann Logdatei " + sLogFile + " nicht neu erstellen.",HEADING);
       Halt;
      END
     WriteLn(nFH,"Logstart um " + DateStr(ToDay) + " " + TimeStr(Now));
     Close(nFH);
     END
     .. logfile schon da?
     IF IsFile(sLogFile) = 1
      IF nFH:=TAppend(sLogFile) < 
       Message("Kann Logdatei " + sLogFile + " nicht öffnen...", HEADING);
       Halt;
      END
     END
     WriteLn(nFH,TimeStr(Now) + " : " + s);
     CLOSE(nFH);
    ENDPROC

    ..Beispiel: Eintragung in der Logdatei
    Procedur Test
     WriteToLog("Projekt.log", "Starte p. Test", 1); .. neue logdatei
     .. Schritt 1
     WriteToLog("Projekt.log", "Ende Schritt 1...", 0); .. hinzufügen
     .. Schritt 2
     WriteToLog("Projekt.log", "Ende Schritt 2...", 0);
    Endproc

    ..Aufruf Logdatei mittels Windows NotePad
    Procedure ZeigeLogDatei
     Execute("NotePad.exe Projekt.Log);
    Endproc


    Topic Datensätze aus Tabelle löschen Kapitel easy Allgemeine Hinweise
    Die sicherste Methode alle Datensätze einer Tabelle zu löschen, zeigen folgende 
    Modulfragmenten:

    Mögichkeit 1
    ..lösche alle Einträge der Tabelle FAX
    VARDEF nCount : Real;
    nCount := FileSize(FAX);
    IF nCount > 0
     nRNo:=LastRec(FAX);
     REPEAT
      DelRec(FAX, RecNo(FAX));
      nRNo:=PrevRec(FAX);
    UNTIL FileSize(FAX) = 0
    END

    Mögichkeit 2
    ..alle markierte Datensätze löschen
    ..die Markierung kann mittels SetMark erfolgen
    Access(TERMLIST, "Markierung");
    While ReadRec(TERMLIST, FirstRec(TERMLIST) )
     DelRec(TERMLIST, RecNr(TERMLIST) )
    End

    Möglichkeit 3
    Bei größeren Datenbanken (z.B. Größen zwischen 10.000 und 80.000 Datensätze) haben
    Möglichkeit 1 und 2 den entscheidenden Nachteil, daß das Löschen viele Minuten bzw. bei
    entsprechend kleinem Rechner sogar Stunden dauert.

    Besser geeignet ist i.d.F. die eingebaute Funktion "ClearDat(Tabelle:Real)".
    Hiermit werden schlagartig alle Datensätze ohne Rückfrage gelöscht. Eine Sicherheits-Rückfrage ließe sich problemlos über eine Prozedur einbauen:

    Procedure LöscheRecords
     If Message("Wirklich alle Datensätze löschen?", "Frage", 3) = 6
      ClearDat(TABELLE);
     End
    Endproc


    Topic Modul-Vorlage Kapitel easy Allgemeine Hinweise
    ..Modul für Tabelle TABELLE
    ..Datei:
    ..TABELLE.MOD
    ..Beschreibung:
    ..
    ..Historie:
    ..tt.mm.jjjj Autor

    INCLUDE ...

    Procedure OnOpenProject
    ..wird beim starten eines Projektes ausgeführt 
    Endproc



    Topic Arrays Kapitel easy Allgemeine Hinweise
    Verschiedenes zu Arrays

    Speicherplatz:
    Ein Array kann maximal 64 KB groß werden.
    Ein REAL benötigt 6 Bytes.
    Dadurch sind maximal 65536 / 6 = 10922 Einträge möglich.
    Ein String belegt übrigens nur 4 Byte (Es wird ein Zeiger auf denString gespeichert). 

    Definition:
    Vardef aFeld : String[5];
    Erzeugt wird ein ein-dimensionales Array mit 5 Elementen vom TypString.
    Array-Element mit einem Wert belegen:
    aFeld[1] := "Triathlon";
    Array-Element ausgeben:
    Message(aFeld[1]);

    Vardef aFeld : String[5, 5];
    Erzeugt wird ein zwei-dimensionales Array mit 5 mal 5 Elementen vom TypString.
    Array-Element mit einem Wert belegen:
    aFeld[1,1] := "Triathlon";
    Array-Element ausgeben:
    Message(aFeld[1,1]);

    Arrays und Prozeduren:
    Arrays werden als sogenannte Referenzparameter definiert.
    Procedure Test(Var aFeld : String[5] );
     Message(aFeld[1]);
    Endproc
    Procedure Test(Var aFeld : String[5, 5] );
     Message(aFeld[1,1]);
    Endproc

    falls die Arraydimensionen nicht bekannt sind, kann auch 0 übergebenwerden.
    Procedure Test(Var aFeld : String[0, 0] );
    Endproc

    Besondere Arrays:
    Ein String ist nichts anderes als Array von max. 255 Zeichen. Innerhalbdieses Arrays können Zeichen teil ausgebenen werden.
    Beispiel:
    Vardef sStr : String;

    sStr := "Triathlon ist cool";
    sStr[1, 9] liefert "Triathlon"


    Topic Umwandlung in Kleinbuchstaben Kapitel easy Allgemeine Hinweise
    Das Problem kann mit Hilfe der selbstdefinierten Funktion Lower gelößt werden.
    Diese nachstehend aufgeführte Funktion ist das Gegenstück zur vorh. Funktion UPPER:
    Hinweis: Lower ist ab VDP 3 als easy-Funktion standard enthalten.

    Procedure Lower(Wort:String):String
     Vardef Le, P : Real;
     Vardef W1 : String;
     Le:=Length(Wort);
     P:=1; W1:="";
     WHILE P <= Le
      IF ASC(Wort[P,1] >= 65 and ASC(Wort[P,1] <= 90
       W1:= W1+CHR(ASC(Wort[P,1])+32)
       ELSIF Wort[P,1]="Ä"
        W1:= W1+"ä"
       ELSIF Wort[P,1]="Ö"
        W1:=W1+"ö"
       ELSIF Wort[P,1]="Ü"
        W1:= W1+"ü"
       ELSE W1:=W1+Wort[P,1] 
      END
     P:= P+1
     END
     Return W1
    EndProc 

    Soll die Funktion in einem Datenbankjob aufgerufen werden, muß das Modul in dem sich
    diese Funktion befindet, mit dem Befehl USES eingebunden werden. Wennein Eingabefeld in einem Formular in Kleinbuchstaben umgewandelt werden soll, so istbei dem
    betreffenden Feld bei Eingabekontrolle/Ausführen beim Verlassenfolgendes einzugeben: EXECMACRO(<Modulname>,Feld := Lower(Feld); Refresh;


    Topic Word Importdatei aus einem Modul/Datenbankjob Kapitel easy Allgemeine Hinweise
    Frage:
    Eine Datei "adrliste.doc" soll als Quelldatei für  Word 97 benutztwerden.
    Die erste Zeile soll eine Titelzeile in folgender Form sein:
    "Name ;Vorname ; Adresse ; PLZ ; Telefon"
    danach die Daten.

    Antwort:
    In ein Modul:
    WriteLn (T,"Name;Vorname;Adresse;PLZ;Telefon"), dann die Daten ausgeben.
    Entweder mittels firstrec und nextrec Prinzip oder als Subreport.

    In ein Datenbankjob:
    .DATEN
    $("Name;Vorname...)
    .SUB
    $(Name, Vornaame...)
    .ENDSUB


    Topic Zwischenablage verwenden Kapitel easy Allgemeine Hinweise
    Die Windowszwischenablage kann mittels VDP ausgelesen bzw. beschrieben werden.
    Es gibt hierzu die folgende Funktionen:

    Tip 1
    Inhalt der Speicher-Datei in die Zwischenablage kopieren:
    Text2Clip

    Beispiel
    Die Prozedur kopiert den Inhalt des Memofeldes TABELLE.Bemerkung in die Zwischenablage.
    Procedure Memo2Clipboard;
     CopyMemo(TABELLE.Bemerkung, 'RAMTEXT');
     Text2Clip;
    EndProc;

    Tip 2
    Text-Inhalt der Zwischenablage in die Speicher-Datei kopieren:
    Clip2Text

    Beispiel
    Die Prozedur kopiert den Inhalt der Zwischenablage in das Memofeld Bemerkung des
    aktuellen Datensatzes.
    Procedure Clipboard2Memo;
     Clip2Text;
     ReadMemo(TABELLE.Bemerkung, 'RAMTEXT', 1);
    EndProc;

    Tip 3
    Zeichenkette an den vorhandenen Textinhalt der Zwischenablage hängen:
    AddStrToClipboard(Zeichenkette: String)

    Beispiel
    AddStrToClipboard(TABELLE.Feld + "," + TABELLE.Feld2)

    Tip 4
    Zeichenkette in die Zwischenablage kopieren:
    CopyStrToClipboard(Zeichenkette: String)

    Beispiel
    Die Adresse des aktuellen Kunden aus der Tabelle KUNDEN soll in dieZwischenablage kopiert werden:

    CopyStrToClipboard(KUNDEN.Vorname + ' ' + KUNDEN.Name + Chr(13) +Chr(10) + KUNDEN.Straße + Chr(13) + Chr(10) + KUNDEN.PLZ + ' ' + KUNDEN.Ort)

    Chr(13)+Chr(10) ist der String für einen Zeilenvorschub. Auf dieseWeise werden Name, Straße und Ort auf drei Zeilen verteilt.

    Tip 5
    Memofeld in die Zwischenablage kopieren

    Beispiel anhand TOPICS-Tabelle aus KAL:
    procedure Topic_zur_Zwischenablage
    ..#kopiert topic zur zwischenablage
     DEF CRLF = Chr(13) + Chr(10);
     DEF TMPFILE = DBDir(TOPICS) + "$$$.tmp";
     Vardef nTRNo, nFH : real;

     nTRNo := ReadRec(TOPICS, RecNr(TOPICS));
     If nTRNo = 0
      return
     End
     CopyStrToClipboard(TOPICS.tTitel + CRLF)
     AddStrToClipboard("" + CRLF);
     CopyMemo(TOPICS.tInhalt, TMPFILE, 1);
     If IsFile(TMPFILE) = 0
      Message("Abbruch: Temporäre Datei " + CRLF + TMPFILE + CRLF + "konntenicht angelegt werden!", "Fehler");
      return
     End
     nFH := Reset(TMPFILE);
     If nFH = 0
      Message("Abbruch: Temporäre Datei " + CRLF + TMPFILE + CRLF + "konntenicht geöffnet werden!", "Fehler");
      return
     End
     While Not EOT(nFH)
      AddStrToClipboard(ReadLn(nFH) + CRLF);
     End
     AddStrToClipboard("" + CRLF);
     AddStrToClipboard(SYSTEM.sKALVersion + CRLF);
     AddStrToClipboard("" + CRLF);
     Close(nFH);
     Message("Topic Inhalt von Topic " + CRLF + TOPICS.tTitel + CRLF  +"zur Zwischenablage kopiert.", "Hinweis");
    endproc


    Topic Zeichenumsetzung DOS <> Windows Kapitel easy Allgemeine Hinweise
    Immer wieder gibt es Probleme mit der Zeichenumsetzung zwischen DOS und Windows.
    DOS verwendet den sogenannten ASCII-Zeichensatz, Windows dagegen den
    ANSI-Zeichensatz.
    Da Beide nicht gleich sind, ist eine Umsetzung von Zeichen von DOS nach Windows undumgekehrt notwendig. Hierzu gibt es folgende Funktionen:

    1.Für die Umwandlung von DOS (=OEM) nach Windows:
    Windows-Zeichenkette := OEMToANSI(DOS-Zeichenkette)

    2.Für die Umwandlung von Windows nach DOS (=OEM):
    DOS-Zeichenkette := ANSIToOEM(Windows-Zeichenkette)

    Eine Zeichenkette kann auch ein einzelnes Zeichen sein.

    Um exportierte Daten aus der DOS-TDB in ein WinTDB- oder VDP-Projekt einlesen zu
    können, sollte die Funktion OEMToANSI verwendet werden.


    Topic Fehlerbehandlung für Datumseingabe etc. Kapitel easy Allgemeine Hinweise
    Eingabe eines Datums auf Gültigkeit prüfen:

     Vardef nTag : Real;
     T-Eingabe := Input("Bitte Datum eingeben!", "Frage");
     ?T-Eingabe = "" / Return
     nTag := Val(T-Eingabe)
     ..datestr wandelt eine Zahl in ein Datumstr mm.tt.jjjj um 
     T-Eingabe := DateStr(nTag))
    .EC 1
     If Val(T-Eingabe[7,2]) < 19 Or $Fehler > 0
      Message("Ungültiges Datum eingegeben (" + T-Eingabe + ").", "Fehler");
      Return
     End
     ..Fehlercheck wieder an VDP übergeben
    .EC 0


    Topic Datensatz mit Relations-Felder duplizieren Kapitel easy Allgemeine Hinweise
    Diese easy-Prozedur dupliziert ein Datensatz welches ein Relationsfeld enthält.

    Eine Relationsdatei, REL-Datei, enthält zwei Felder die auf Auto-Nummer Felder der zwei
    angekoppelte Tabellen verweisen.

    Die hier vorgeschlage Lösung verwendet ein Array zur Ablage der Koppelfelder.

    Procedure RELDuplizieren(nDummy : Real);
    ..Haupttabelle TABELLE enthält ein Relations-Feld Artikel welches
    ..auf die Tabelle ARTIKEL verweist. Die REL-Datei ist FSARTIKE

    Vardef i, nRNo, nLN, nCnt : Real;
    Vardef sFeld1, sFeld2 : String; ..die beiden staring felder der tabelleTABELLE
    Vardef anArtikel : Real[10000]; ..artikel array, speichert zeiger auf das auto-nummerfeld

    ..lese aktuellen datansatz
    nRNo := ReadRec(TABELLE, RecNr(TABELLE));
    ..kein gefunden, dann stoppe
    ?nRNo = 0 / Return
    ..speichere daten des aktuellen datensatzes in variabele
    sFeld1 := TABELLE.Feld1;
    sFeld2 := TABELLE.Feld2;
    ..
    ..speichere die zeiger auf die artikel im array anArtikel
    i := 0;
    Sub ARTSTAMM
     anArtikel[i] := TABELLE.Artikel.Laufende_Nummer;
     i := i + 1
    Endsub
    nCnt := i;
    ..
    ..neuen datensatz der tabelle TABELLE anlegen
    Readrec(TABELLE, 0);
    TABELLE.Feld1 := sFeld1;
    TABELLE.Feld2 := sFeld2;
    ..speichere datensatz
    WriteRec(TABELLE, 1 + FileSize(TABELLE));
    ..rufe den datansatz wieder auf um die Auto-Nummer zu ermitteln
    nLN := TABELLE.Laufende_Nummer;
    ..suche satz
    nRNo := FindRec(TABELLE, Str(nLN), "TABELLE.INR", 1);
    ..
    ..jetzt durch das array loopen und in der REL-Datei neue Datensätzehinzufügen.
    i := 0;
    While i <= nCnt
     ..neuen satz anlegen
     ReadRec(FSARTIKE, 0);
     FSARTIKE.R-TABELLE := nLN;
     FSARTIKE.R-ARTSTAMM := anArtikel[i]; ..übergabe der zeiger
     ..Message("Artikel: " + Str(nLN) + "/" + Str(anFSArtikel[i]), Str(i));
     ..speichere satz
     WriteRec(FSARTIKE, 1 + FileSize(FSARTIKE));
     i := i + 1;
    End
    ..
    ..ok das wars
    Return
    Endproc


    Topic Mittelteil eines Strings bearbeiten Kapitel easy Allgemeine Hinweise
    Es gibt in easy kann Befehl wie midstr bzw. substr um einen Mittelteileines Strings herauszufilten, aber in VDP besteht ein String aus eine Zeichenfolgevon max. 255 Zeichen. Es können Teile aus einem String herausgefiltert werden, indem dieStartpositionun
    Mittels Pos kann die Position eines Zeichens bzw. Zeichenketteermittelt werden. 

    Beispiel easy-Prozedur:

    Procedure Test
     Vardef sStr : String;
     Vardef i : Real;

     sStr := "fools garden ist toll";
     Message("Es wird garden ausgegeben: " + sStr[7, 6], "Test 1");
     Message("Es wird garden und der rest ausgegeben: " + sStr[7, 255],"Test 2");
     i := Pos("garden", sStr);
     Message("Es wird garden und der rest ausgegeben: " + sStr[i, 255],"Test 3");
     Message("Es wird garden ausgegeben: " + sStr[i, Length("garden")],"Test 4");
    Endproc


    Topic Definition von Zwischenvariablen Kapitel easy Allgemeine Hinweise
    Es gibt folgende VDP interne Möglichkeit Variablen zwischen zuspeichern:

    1.NOTE
    Funktion: Note(Zeichenkette: String) oder Note
    Legt die Zeichenkette in einem internen Speicher ab.
    Note ohne Parameter liefert den Inhalt des internen Speichers. Damit können Berichte oder Datenbankjobs vonMakros aus mit Informationen versorgt werden.

    2.T-Eingabe
    Die Funktionen Input und ChooseFile verwenden diese systemweite Variable vom
    Typ String.

    3.Windows Zwischenablage verwenden
    Funktion: Text2Clip
    Kopiert den Inhalt der Speicher-Datei in die Zwischenablage.

    Funktion: Clip2Text
    Kopiert den Inhalt der Zwischenablage in die Speicher-Datei, wenn es sich um einen
    Text handelt.

    4.VDP Zwischenspeicher RAMTEXT verwenden

    Beispiel Text aus der Windows Zwischenablage holen:
    Procedure AusZwischenablage : String;
     VarDef nFH : REAL
     VarDef sStr : STRING
     Clip2Text
     nFH := Reset("RAMTEXT");
     sStr := ReadLn( nFH);
     Close(nFH)
     Return sStr
    Endproc


    Topic Meldungssystem für Anwendungen Kapitel easy Allgemeine Hinweise
    Beschrieben wird ein eigenes Meldungssystem für VDP-Anwendungen.
    Das Meldungssystem besteht aus
    eine Textdatei mit Meldungen
    die drei Felder einer Systemtabelle
    ein Formular der Systemtabelle
    eine Prozedur definiert in ein Modul der Systemtabelle

    Hinweis: eine Systemtabelle ist eine VDP-Tabelle mit nur einenDatensatz. 

    Aufbau der Textdatei (=Meldungsdatei)
    Jede Zeile enthält eine Meldungs, die Meldung plus ein Aktionshinweis.
    Meldungsnummer und Meldung sind mittels Dollarzeichen getrennt.
    Die Meldung und Aktionshinweis sind mittels Raute (#) Zeichen getrennt. 
    Name der Datei ist beliebig. Im Beispiel wird kal.msg verwendet.
    Es können drei Parameter %s1, %s2 und %s3 verwendet werden.
    Siehe Beschreibung der Prozedur.
    Beispiel:
    1%Meine Meldung#mit entsprechender Aktion
    1003%Meine Meldung mit %s1 als Parameter#Keine Aktion.

    Felder der Systemtabelle
    Verwendet werden Beispielnamen
    Meldungstext, Feld: sKALMsgText , Alpha 125 Zeichen
    Aktionstext, Feld: sKALMsgToDo , Alpha 125 Zeichen
    MeldungsNr, Feld: nKALNr , Ganzzahl

    Formular der Systemtabelle
    Das Formular kann beliebig gestaltet werden.
    Die drei Felder sollten als Formelfelder definiert werden.
    Die Tabelle hat nur als Eigenschaft schließen, alle andereEigenschaften sind ausgeschaltet.

    Prozedur definiert in einem EASY-Modul
    Siehe nachfolgendem Beispiel.
    Erklärung der Parameter:
    nMsgNr : die Meldungsnummer. Entspricht die Zeilennummer derMeldungsdate.
    sP1 : 1. Parameter der in eine Meldungszeile ausgetauscht wird.
    sP2 : 2. Parameter der in eine Meldungszeile ausgetauscht wird.
    sP3 : 3. Parameter der in eine Meldungszeile ausgetauscht wird.

    procedure KALMessage(nMsgNr : real; sP1 : string; sP2 : string; sP3 :string);
    ..#
    ..#Parameter:
    ..#nMsgNr = Meldungsnummer
    ..#sP1 .. sP3 = Parameter
    DEF CRLF = Chr(13);
    Vardef nFH, nRT, nLineNr, nTMsgNr : real;
    Vardef sLine : string;

    ?nMsgNr = 0 / Return
    nLineNr := 0;
    sLine := "";
    ..öffne meldungsdatei und suche zeile
    nFH := Reset(DBDir(SYSTEM) + "kal.msg");
    If nFH > 0
     Repeat
      sLine := AnsiToOEM(ReadLn(nFH));
      nTMsgNr := Val(sLine[1, Pos("$", sLine) - 1]);
      nLineNr := nLineNr + 1;
     Until nTMsgNr = nMsgNr Or EOT(nFH)
    End
    ..zeile gefunden, dann tausche parameter aus
    If sLine <> ""
     sLine := sLine[Pos("$", sLine) + 1, 255];
     ?sP1 > ""/sLine := Exchange(sLine, "%s1", sP1);
     ?sP2 > ""/sLine := Exchange(sLine, "%s2", sP2);
     ?sP3 > ""/sLine := Exchange(sLine, "%s3", sP3);
     ReadRec(SYSTEM, 1);
     ..aktion vorhanden?
     If sLine hat "#"
      SYSTEM.sKALMsgText := sLine[1, Pos("#", sLine) - 1];
      SYSTEM.sKALMsgToDo := sLine[Pos("#", sLine) + 1, 255];
     Else
      SYSTEM.sKALMsgText := sLine;
      SYSTEM.sKALMsgToDo := ""
     End
     SYSTEM.sKALMsgNr := nMsgNr;
     WriteRec(SYSTEM, 1);
     ..gebe meldung aus
     nRT := ExecDialog("SYSTEM.KAL-Meldung");
     End
    Endproc

    procedure Test
    ..#Beispielaufruf
     KALMessage(2, "Mein Verzeichnis","", "");
    ..#oder
     ExecMacro(SYSLM001, KALMessage(3, $MeinFeld, "", ""))
    endproc

    Inhalt der meldungsdatei kal.msg
    Test von Rob#Tue was Du moechtest.
    Thema-Verzeichnis %s1 konnte nicht angelegt werden.#Bitte Angabenprüfen.


    Topic DLL Programmierung und Nutzung in easy Kapitel easy Allgemeine Hinweise
    Ab VDP 3.0 steht die Möglichkeit zur Verfügung DLLs in easy-Module einzubinden.
    Es stehen eine fast unbegrenzte Reihe von Möglichkeiten zur Verfügung. Allerdings gibt es Einiges zu beachten.
    DLLs können z.B. mittels C++ oder Borland Delphi erstellt werden.

    Syntax Deklaration in easy-Module:

    dllproc Funktionsname([Funktionsparameter: Parametertyp]): [Ergebnistyp] library DLL-Dateiname

    Folgende Hinweise bei der Entwicklung von DLLs (alle Beispiele in Borland Delphi):

    Tip 1
    Der Aufruf der Funktion oder Prozedure muss als stdcall und export definiert sein.

    Beispiel:
    procedure HelloWorld; stdcall; export;

    Tip 2
    Index Angabe der Export Klausel verwenden.

    exports
    HelloWorld index 1,

    Tip 3
    Definition der Funktion / Prozedure und Export Klausel müßen identisch sein, d.h. 
    auf die Groß/Kleinschreibung achten.

    Tip 4
    Bei der String-Verarbeitung PChar verwenden.

    Der "alte" Pacal-String-Typ ist nicht DLL konform. Das hat überhaupt nichts mit VDP zu tun.
    Verwenden Sie daher ausschließlich PChar oder beachten Sie den Hinweis,
    der von Delphi beim Erstellen jeder DLL im dpr-File angelegt wird.
    Es wird dringend empfohlen PChar zu verwenden-
    Rückgabe von Strings aus Delphi an VDP mittels der const Deklaration (siehe Beispiel Tip 5):

    Procedure RegGetValue(sKey : PChar; sValue : PChar; Const sResult : PChar) stdcall; export;

    Übergeben werden sKey und sValue. Zurück geliefert wird sResult. sResult ist als const deklariert!

    Tip 5
    Testmöglichkeit unter Delphi

    Bevor die DLL erstellt und unter VDP verwendet oder getestet wird, ist es einfacher erst mal eine EXE-Datei
    in Delphi für Testzwecke zu generieren. Wenn die Tests Ok sind, kann die DLL erzeugt werden.
    Weiterhin bei Tests rege gebrauch von ShowMessage() oder Debug Fenster machen.

    Beispiel anhand eine Delphi dpr-Datei:

    library WinReg;
    {
    für Tests
     die obere Anweisung library WinReg auskommentieren
     Anweisung exports am Ende auskommentieren:
    exports
           RegGetValue index 1;
     Am Ende zwischen Begin und End. eine ShowMessage Anweisung setzen
     ShowMessage(GetRegistryKey('Software | Microsoft|Internet Explorer|Main', 'Search Bar'));
    }

    uses
      Windows,
      SysUtils,
      Registry;

    Procedure RegGetValue(sKey : PChar; sValue : PChar; Const sResult : PChar) stdcall; export;
    var
      Registry: TRegistry;
      S1, S2, sTmp : String;
    begin
      S1 := String(sKey);
      S2 := String(sValue);
      Registry := TRegistry.Create;
      Registry.RootKey:=HKEY_LOCAL_MACHINE;
      Registry.OpenKey(S1, False);
      sTmp := Registry.ReadString(S2);
      StrPCopy(sResult, sTmp);
      {ShowMessage(S1 + '#' + S2 + '#' + sResult);}
      Registry.Free;
    end;

    {--für Tests Exports auskommentieren}
    Exports
      RegGetValue index 1;

    Var sTmp : String;
    Begin
     {--für Tests}
     {ShowMessage(RegGetValue('Software\Microsoft\Internet Explorer\Main', 'Search Bar', sTmp));}
    End.

    Tip 6
    Deklaration dllproc in easy für Beispiel in Tip 5.

    dllproc RegGetValue(sKey : String; sValue : String; Var sResult : String) library "c:\daten\delphi\vdpdll2\winreg.dll";

    Procedure TestRegistryDLL
    Vardef sKey, sValue, sResult : string;
    sKey := "Software\Microsoft\Internet Explorer\Main";
    sValue := "Search Bar";
    RegGetValue(sKey, sValue, sResult);
    Message(sResult);
    Endproc

    Tipp 7
    Noch ein Beispiel anhand GetPrivateProfileStringA

    DLLPROC GetPrivateProfileStringA(AppName :string; KeyName : string;
    Default : string; var ReturnedString : string; Size: Integer; FileName:
    string) : Integer library "kernel32.dll";

    Der Test

    procedure Test;
     vardef ReturnedStr: string;
     vardef Result: Integer;
     Result := GetPrivateProfileStringA('Datenbankjobs', 'Schriftart',
     'Verdana', ReturnedStr, 255, 'c:\vdp\kfz\kfz.ini');
     Message(ReturnedStr, Str(Result));
    endproc

    bringt die MessageBox, im Titel die Länge der zurückgegebenen Zeichenkette, diese selbst als Text. 


    Topic Bearbeitung angekoppelte Datensätze Kapitel easy Allgemeine Hinweise
    Tipp
    Funktionen zur Bearbeitung angekoppelte Tabellen:
    Die Funktionen
    AppendLinkedRec(), AppendLinkedRecs() und ViewlinkedRecs() 
    haben einen zusätzlichen dritten optionalen Parameter erhalten.
    Mit diesem Parameter kann den Titel des zu verwendenden Formulars angeben werden.
    Damit kann man die Formulare für Tabellen, die an mehrere andere Tabellen 
    angekoppelt sind, besser auf die jeweilige Herkunft des Ankoppelns 
    einstellen, v.a. bei den Initialisierungen.


    Topic eMail per DLL senden Kapitel easy Allgemeine Hinweise
    Eine Mail lässt sich per DLL verschicken.

    Im VDP3 Beispielprojekt Mailer ist eine DLL enthalten, der Mail-Funktionen
    enthält: ppweb.dll 

    Die eMail-Funktionen werden im Header des Moduls so eingebunden:

    ..E-Mail 
    DLLPROC SendMail(Host : String; Sender : String; UserId : String;
    Receiver : String; Subject : String; Body : String; Attachment : String) : INTEGER
    LIBRARY "ppweb.dll"; 

    DLLPROC SendPgpMail(KeyRing : String; CommentStr : String; 
    VersionStr : String; Host : String; Sender : String; UserId : String;
    Receiver : String; Subject : String; Body : String; Attachment : String) : INTEGER
    LIBRARY "ppweb.dll"; 

    DLLPROC GetMailError(VAR Msg : String; MaxLen : INTEGER) 
    LIBRARY "ppweb.dll";

    Der Aufruf erfolgt dann fast genauso wie bei einer eingebauten Funktion.


    Topic HTML-Form Analyse (Wissen) Kapitel Internet (HTML, Formulare, Wissen, ISAPI)
    HTML-Formulare generieren mittels Action= GET oder POST Dateien, die ausgewertet
    werden können.

    Alle Felder und Inhalte werden mittels & und sonstige Zeichen in der URL-Zeile dargestellt.
    Das passiert wenn der Benutzer den SUBMIT oder SENDEN - Button druckt.
    Auf dem Internet-Server läuft ein CGI-Programm der mit diese Zeichen umgehen muss.
    Hierzu gibt es eine Reihe von Moeglichkeiten.
    Ich habe die ersten Erfahrungen mit eine Programmiersprache PERL gemacht.
    PERL kann die Zeile analysieren und dann in eine lesbare Form ausgeben.
    Beispiel:
    Name=Linn
    Vorname=Robert
    Kommentar=Nette Homepage

    Im Formular steht hinter ACTION= welches Skript auf dem Serverausgefuehrt wird.
    URL koennte so aussehen: 
    http://../meinskript?Name=Linn&Vorname=Robert&Kommentar=Nette+Homepage

    Es gelten folgende Regeln:
    o Name/Werte werden durch Ampersandzeichen & getrennt
    o Name/Werte durch Gleichheitszeichen = getrennt
    o Alle nicht 7-bit Zeichen werden durch Hex-Zeichen mit Prozent %vorweg ersetzt (%NN)
    o Leerzeichen durch Pluszeichen +

    In PERL geht die Konvertierung sehr einfach, darum habe ich mich nicht drum gekummert,
    d.h. einmal einen Parser in PERL geschrieben und fertig war die Sache.

    C-Beispiel in http://www.hyperion.com/~koreth/uncgi.htm
    Vorgang:
    o Wertepaare trennen (&)
    o Trennung Name vom Wert (=)
    o Ersetzen + durch Leerzeichen
    o Ersetzen %NN durch ASCII Wert


    Topic Tipps zu ISAPI Kapitel Internet (HTML, Formulare, Wissen, ISAPI)
    Einfach ein paar Tipps und freie Gedanken.

    Tip 1
    easy-Routine der vorhandensein der isa-Datei (.isa) prüft:
    If IsFile("myisa.isa") = 0
     Message("Sorry, die Anwendung wurde nicht gefunden!", "Fehler");
     Return oder Halt
    End

    Tip 2
    Check ob Programmpfad für Webbrowser in der vdp32.ini eingetragen ist:
    [Werkzeuge]
    WWW-Browser=

    Tip 3
    Wenn die Anwendung mittels localisa.exe getestet wird, sollten die DLLs, wie owl...dllentweder ins Projekt- oder Windows-System Verzeichnis liegen.

    Tip 4
    Wird eine WWW-Anwendung erstellt, dann werden folgende Dateien generiert:
    anwendung.isa
    anwendungE.dll
    anwendungH.dll

    Das Programm anwendung.isa benötigt:
    owl52f.dll
    anwendunge.dll
    bds52f.dll
    kernel32.dll
    winspool.drv
    gdi32.dll
    user32.dll
    winmm.dll
    cw3230.dll
    vdp32cgi.dll

    Gilt für VDP 2.x


    Topic Web Server Anwendung testen Kapitel Internet (HTML, Formulare, Wissen, ISAPI)
    Wenn Sie eine VDP Web Server Anwendung erstellt haben, dann hat sich folgende Testmethode bewährt (VDP 2.03):

    1.VDP starten
    2.Applikationstyp setzen mittels
    Menüpunkt  Programm | Eigenschaften, als Applikationstyp Web Server (ISAPI) setzen
    3.Programm testen mittels
    Menüpunkt Programm | Programm testen
    In der Dialogbox z.B. folgende Werte eingeben:
    Abfrage (Query): Pruefaktion=Neu&AuftragNr=89
    Daten (Content): AuftragNr=89
    Hinweis:
    Es muß nicht eingegeben werden.
    4.Browser starten
    In der Dialogbox Schalten Browser starten klicken
    Hinweis:
    der Browser kann aber auch aktiv bleiben.

    Wichtig:
    Bei Updates auf Tabellen nur der Browser LOCALISE aktiv halten. VDP schließen.
    Die Daten werden sonst nicht in den Tabelle übernommen.


    Topic Ein Wort lesen welches durch die Zeichen blank, ( und ; abgegrenzt ist Kapitel easy Funktionsbibliothek
    Beschreibung:
    liest ein Wort welches durch die Zeichen blank, ( und ; abgegrenzt ist

    Procedure pReadWord(nPos : Real; sLine : String) : String;
    ..#liest ein Wort welches durch die Zeichen blank, ( und ; abgegrenztist
    ..#Returnwert:
    ..#Wort als String

     Vardef sTmp : String;
     Vardef i : Real;

     sTmp := "";
     ?i < 1 Or i > 255 / i := 1;
     ..gibt es Zeichen vor der Prozedur, dann haben wird mit Beispiel 2 zutun
     If i > 1 And Not sLine[i - 1] in ["=", ",", " ", "(", ")", ";", ":"]
      Return ""
     End
     i := nPos; ..setze anfangswert
     ?sLine = "" / Return ""
     Repeat
      sTmp := sTmp + sLine[i];
      i := i + 1;
     Until sLine[i] In [" ", "(", "=", ",", ":", ";"] Or i > Length(sLine)
     Return sTmp[1, i - 1]
    Endproc


    Topic HTML-Form Analyse (easy-Modul) Kapitel easy Funktionsbibliothek
    Beschreibung:
    verschiedene hilfreiche Routinen die immer wieder gebraucht werden für Internet
    Operationen sowohl in easy-Modulen als auch in Formulare

    Procedure pHexToStr(sHex : String) : String;
    ..#Umwandlung eines Hex-Wertes in ein String
    ..#Parameter:
    ..#sHex = Hex-Wert als String
     Vardef x : Real;
     x := xWert(Asc(sHex[2]) -48,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15) * 16 ;
     x := x + xWert(Asc(sHex[3]) -48,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15);
     Return AnsiToOEM( Chr(x) )
    Endproc

    Procedure pInetFormanalyse
    ..#einlesen der datei fb.txt. Diese Datei enthält den Output eineshtml-formulars
    ..#fb.txt analysieren und felder in eine datei ausgeben.
    ..#
    Var CRLF = Chr(13) + Chr(10);
    Var FIELDDELBEGIN = "&";
    Var FIELDDELEND = "=";
    Var BLANK = "+";
    Var HEXDEL = "%";
    Vardef nRT,i : Real; ..returncode versch. operationen
    Vardef nFHin, nFHout : Real; ..filehandle input- und outputdatei
    Vardef sInDatei, sOutDatei : String; ..dateinamen für in undoutputdatei
    Vardef sTmp : String;
    Vardef nFieldFound : Real;
    Vardef nFieldContentFound : Real;
    Vardef sFieldName : String;
    Vardef sFieldContent : String;

    ..Inputdatei abfragen
    ..checken ob datei schon existiert
    T-Eingabe:="fb.txt";
    REPEAT
    nRT := Input("Name der Formulardatei?", "InetFormanalyse");
    ?nRT=0/Return
    UNTIL IsFile(T-Eingabe)
    sInDatei := T-Eingabe;

    ..checken ob ausgabedatei schon existiert
    T-Eingabe:="x.txt";
    REPEAT
    nRT := Input("Name der Analysedatei", "InetFormanalyse");
    ?nRT=0/Return
    UNTIL NOT IsFile(T-Eingabe) OR nRT:=Message("Datei existiert bereits! 
    Überschreiben?","Achtung",3)=6
    ?nRT=2/RETURN
    sOutDatei := T-Eingabe;

    ..als erste neue datei erstellen
    IF nFHout := Rewrite(sOutDatei) = 0
    Message("Kann Analysedatei " + sOutDatei + " nicht erstellen.","Fehler");
    Return
    End
    ..formdatei öffnen
    IF nFHin := Reset(sInDatei) = 0
    Message("Kann Formdatei " + sInDatei + " nicht erstellen.", "Fehler");
    Close(nFHout);
    Delfile(sOutDatei);
    Return
    End
    ..analyse durchführen
    i:=0;
    nFieldFound := 0;
    nFieldContentFound := 0;
    sFieldName := "";
    sFieldContent := "";
    WHILE NOT Eot(nFHin)
     sTmp := Read(nFHin, 1); i := i + 1;
     ..ersetze blank
     ?sTmp = BLANK / sTmp := " ";
     ..EOL abfangen und durch "" ersetzen
     ?Asc(sTmp) = 13 / sTmp := "";
     ?Asc(sTmp) = 10 / sTmp := "";
     ..hexzahl gefunden
     If sTmp = HEXDEL
      sTmp := sTmp + Read(nFHin, 2);
      sTmp := pHexToStr(sTmp);
     End
     ..feld gefunden?
     If sTmp = FIELDDELBEGIN
      nFieldFound := 1; ..setze flag on
      ?nFieldContentFound = 1/WriteLn(nFHout, "Inhalt: " + sFielContent);
      nFieldContentFound := 0; ..setze flag off
      sFieldName := ""; ..init felder
     End
     ..feldende gefunden
     If sTmp = FIELDDELEND And nFieldFound = 1
      nFieldFound := 0; ..setze flag off
      nFieldContentFound := 1; ..setze flag on
      sFieldContent := "";
      WriteLn(nFHout, "Feld: " + sFieldName);
     End
     ..erweitere feldname
     If nFieldFound = 1
      ?sTmp <> FIELDDELBEGIN And sTmp <> FIELDDELEND/sFieldName:=sFieldName+sTmp;
     End
     ..erweitere feldinhalt
     If nFieldContentFound = 1
      ?sTmp <> FIELDDELBEGINAndsTmp<>FIELDDELEND/sFieldContent:=sFieldContent+sTmp;
     End
     ShowWait("Feld " + sFieldName + CRLF + "Inhalt: " + sFieldContent);
     END
     ?nFieldContentFound = 1/WriteLn(nFHout, "Inhalt: " + sFieldContent);
     ..schliessen
     Close(nFHin);
     Close(nFHout);
     Message("Bin fertig...");
    Endproc


    Topic Datensatz bearbeiten beenden Kapitel easy Funktionsbibliothek
    Beschreibung:
    Abfangen der beiden Möglichkeiten
    Datensätzeändern (ModifyRecords) und 
    Neuedatensätze (AppendNewRecords)
    eingeben, ab:

    Procedure EndeBearbeiten
    ..#umschalten der Bearbeitungsmodi
     ?GetMode = 1/Datensätzeändern
     ?GetMode = 2/NeueDatensätzeEingeben
    Endproc


    Topic Alternative Message-Funktion für Meldungen Kapitel easy Funktionsbibliothek
    Beschreibung:
    Ein eigenes Meldungsfenster als Alternative für die Funktion Message. 
    Warum:
    o Fenstergrösse Message ist begrenzt,
    o Anzahl Textzeichen begrenzt,
    o Vordefinierte Makros nur für Ja, Nein und Abbruch

    Vorgehensweise:
    In eine globale Tabelle SYSTEM zwei Felder definieren
    (siehe auch Topic Globale Variablen):
    MeldungsHeader (String 40) und Meldungstext (String 255).

    Weiterhin wird ein Formular SYSTEM.Systemmeldung erstellt.
    Es enthält die beiden Felder und ein OK Makro (führt CloseWnd aus).
    In der Objekt Reihenfolge den OK Button an erste Stelle.

    Im System Modul wird folgende Prozedur definiert:

    Procedure SystemMeldung(sText, sHdg : String);
    ..#Ausgabe eine Systemmeldung
     ReadRec(SYSTEM, 1);
     ?$SYSTEM.MeldungsHeading <> "" / $SYSTEM.MeldungsHeading := sHdg;
     ?$SYSTEM.MeldungsText <> "" / $SYSTEM.MeldungsText := sText;
     WriteRec(SYSTEM,1);
     ActivateForm("SYSTEM.Systemmeldung");
    Endproc

    Aufruf der Prozedur in Makros, Module etc.:
    ExecMacro(System, SystemMeldung("Keinen Speicherplatz","Fehler") );

    Noch folgenden Tip:
    Es ist nicht möglich Variablen zu übergeben:

    Var sMsg = "Hallo, wie geht"s..."
    ExecMacro(System, SystemMeldung(sMsg,"Fehler") );

    WinEASY laßt diese Möglichkeit nicht zu. 

    Es gibt ein Ausweg, in dem der Meldungstext und Heading erst in der Tabelle SYSTEM geschrieben werden.

    Var sPanaMod = "\daten\wintdb\utils\uti-pana.prg"
    ReadRec(SYSTEM, 1);
    $SYSTEM.MeldungsHeading := "Hinweis";
    $SYSTEM.MeldungsText := "Projektanalysemodule " + sPanaMod + " nichtgefunden.";
    WriteRec(SYSTEM, 1);
    ExecMacro(System, SystemMeldung("","") );
    Prozedur SystemMeldung mit leeren Felder übergeben, da diese schonvorher geschrieben wurden.

    Hinweis:
    Sind in eine Tabelle mehrere Formulare definiert und ist schon eine aktiv (z.B. 
    TAB.Form1), dann wird beim Aufruf von ActivateForm("TAB.Form2") TAB.Form1 aktiviert, 
    anstatt von TAB.Form2.
    (Fehler in WinTDB 1.02?)


    Topic Umsetzung Memo- in String-Feld Kapitel easy Funktionsbibliothek
    Beschreibung:
    Die Memo-Voranzeige unter WinTDB ist nicht so elegant, wie unter DOS-TDB.
    Ich habe daher ein zusätzliches Feld aufgebaut, was das Memo-Feld ersetzen soll.
    Wenn Memos verwendet werden die kleiner 256 Zeichen sind, dann ist es sinnvoller
    diese in einem mehrzeiligem String-Feld zu setzen.
    Folgende Routine setzt ein Memo-Feld in ein Stringfeld um.

    PROCEDURE BemerkungToNotiz

    VARDEF nCount : Real
    VARDEF nRNo : Real
    VARDEF I : Real
    VARDEF sTmpFile : STRING;
    VARDEF nHandle : Real;
    VARDEF sTmp : String;
    VARDEF sNotiz : String;

    sTmpFile := "TEMP.TXT";
    IF Access(ADRESSEN,"ADR_NR.IND") > 0
       Message("Ich arbeite...");
       ..gehe zum ersten record
       nRNo:=FirstRec(ADRESSEN);
       I:=0;
       WHILE nRNo>0
    .. record lesen
    ReadRec(ADRESSEN,nRNo);
    ..If IsFile(sTmpFile) = 1 DelFile(sTmpFile)
    .. memo in texfileschreiben
    CopyMemo($ADRESSEN.Bemerkung,sTmpFile);
    .. textfile in string kopieren
    sNotiz := "";
    IF nHandle := Reset(sTmpFile) > 0
    While not eot(nHandle)
      sTmp  := ReadLn(nHandle);
    sNotiz := sNotiz + sTmp;
    End
     Close(nHandle)
                    SetField(ADRESSEN,LabelNr(ADRESSEN,"Notiz"), sNotiz);
                    WriteRec(ADRESSEN,nRNo);
    ELSE
     Message(sTmpFile+" kann nicht erzeugt werden","Fehler",1)
    END
                   .. nächstes record
                   nRNo:=NextRec(ADRESSEN);
                   I := I + 1;
         END
       END
    ENDPROC

    Hinweis:
    Ab der Version 1.04 gibt es eine Easy-Funktion HTML2STR.


    Topic Ein einfachen Datenbankjob generieren Kapitel easy Funktionsbibliothek
    Beschreibung:
    Generiert ein einfachen Datenbankjob.

    Procedure JobGen
    ..#generiert einen einfachen job. ideal für die erstellung eines ersten jobs

     VAR nDatenbank = 1; ..erster datenbank oder 
     VAR nDatenbank = FileNr; ..aktuelle datenbank
     VAR sDBName = DBName(nDatenbank);
     VAR sJobname = sDBName[1,Pos(".",sDBName)] + "JOB";
     VAR sAutor = "R.W.B.Linn";

     VARDEF nRT,i : Real; ..returncode versch. operationen
     VARDEF nHandle : Real; ..filehandle
     VARDEF nAusgabe : Real; ..ausgabedatei

     ..checken ob datei schon existiert
     T-Eingabe:=sJobname;
     REPEAT
      nRT := Input("Name des Datenbankjobs","JobGen");
      ?nRT=0/Return
     UNTIL NOT IsFile(T-Eingabe) OR nRT:=Message("Datei existiert bereits! Überschreiben?","Achtung",3)=6
     ?nRT=2/RETURN
     sJobname := T-Eingabe;

     ..als erste datei öffnen
     IF nAusgabe:=Rewrite(sJobname)
      ..jetzt wird der job erstellt
      WriteLn(nAusgabe,".Report");
      WriteLn(nAusgabe,"..Datei: "+sJobname+" fuer Datenbank"+DBName(nDatenbank));
      WriteLn(nAusgabe,"..Erstellt: "+DateStr(ToDay)+" "+sAutor); 
      WriteLn(nAusgabe,".."); 
      WriteLn(nAusgabe,".var Linie=XMal('_',72)");
      WriteLn(nAusgabe,".Prolog");
      WriteLn(nAusgabe,".Header");
      WriteLn(nAusgabe,"Liste von $heute");
      WriteLn(nAusgabe,"$Linie");
      WriteLn(nAusgabe,".Footer");
      WriteLn(nAusgabe,"$Linie");
      WriteLn(nAusgabe,"Seite -$(Seite)- Report: "+sJobname);
      WriteLn(nAusgabe,".Daten");
      ..ausgabe der datenfelder
      WHILE i:=i+1 <= MaxLabel(nDatenbank)
       WriteLn(nAusgabe,"$"+Label(nDatenbank,i))
      END
      WriteLn(nAusgabe,"..Jobende");
      Close(nAusgabe);
      ..
      Message("Job "+sJobname+" generiert...");
     ELSE
      Message(sJobname+" kann nicht erzeugt werden","Fehler",1);
     END
    Endproc


    Topic Ein Wert aus eine Windows Ini-Datei lesen Kapitel easy Funktionsbibliothek
    Beschreibung:
    Die Prozedur LeseIniWert liest aus eine Windows Ini-Datei (z.B.win.ini) eine Wert.
    Einsatzgebiete diese Prozedur können z.B. sein:
    o aktueller Drucker ermitteln (Datei: win.ini, Sektion: Windows,Eintrag: Device)
    o eigene Projekt Ini-Datei erstellen, um dann Werte auszulesen:
    definierte Meldungen, Auswahlmöglichkeiten
    Diese Möglichkeit kann auch in einem Formelfeld verwendet werden.

    Prozeduraufruf:
    Der Aufruf erfolgt via der Funktion ExecMacro. 
    Beispiel für einen Formelfeld in einem Formular:
    Standard Drucker ermitteln
    ExecMacro(SYSTEM, LeseIniWert("c:\windows\win.ini", "windows","device") )

    Procedure LeseIniWert (sIniDatei, sSektion, sEintrag : String) : String
    ..#liest einen wert aus eine windows ini-datei und liefert diese zurück.
    ..#ini-datei aufbau
    ..#[sektion]
    ..#eintrag=wert
          
     Vardef sWert : String;..wert der zurückgeliefert wird
     Vardef nFH : REAL;.. filehandle
     Vardef sLine : String;.. ini-zeile
     Vardef sTempLine : String;.. tempzeile
     Vardef nFound : Real;.. sektion gefunden?
         
     ..init
     ?sSektion[1] <> "["/sSektion := "[" + sSektion + "]";
     sSektion := Upper(sSektion);
     sEintrag := Upper(sEintrag);
     nFound := 0;
     ..inidatei vorhanden
     IF IsFile(sIniDatei) = 0
      Message(sIniDatei + " nicht gefunden.", "Fehler", 1);
      Return
     END
     ..öffne inidatei
     IF nFH := Reset(sIniDatei) > 0
      WHILE NOT Eot(nFH)
       sLine := ReadLn(nFH)
       sTempLine := sLine;
       sLine := Upper(sLine);
       ?sLine = sSektion / nFound := 1
       IF nFound = 1
        IF sLine[1, Pos("=", sLine) - 1] = sEintrag
         Close(nFH)
         Return sTempLine[Pos("=", sLine) + 1, Length(sTempLine) - Pos("=", sLine) ]
        END
       END
      END
     ELSE
      Message(sIniDatei + " nicht gefunden.", "Fehler", 1);
     END
     Close(nFH);
    Endproc
          
    Beispielaufruf:
    Procedure ATest
     ..#test, gibt der aktuelle Drucker. aus.
     Message(LeseIniWert ("c:\windows\win.ini", "Windows", "Device") );
    Endproc


    Topic Ein Wert in eine Windows Ini-Datei schreiben Kapitel easy Funktionsbibliothek
    Beschreibung:
    Die Prozedur SchreibeIniWert schreibt in eine Windows Ini-Datei (z.B.win.ini) eine Wert. 
    Einsatzgebiete diese Prozedur können z.B. sein:
    o eigene Projekt Ini-Datei erstellen, um dann Werte auszulesen:
    o definierte Meldungen, Auswahlmöglichkeiten


    Procedure SchreibeIniWert (sIniDatei, sSektion, sEintrag, sWert : String) : Real
    ..#schreibt einen wert aus eine windows ini-datei und liefert diese zurück.
    ..#ini-datei aufbau
    ..#[sektion]
    ..#eintrag=wert
    Vardef nFHin, nFHout : REAL;.. filehandle
    Vardef sLine : String;.. ini-zeile
    Vardef sTempLine : String;.. tempzeile
    Vardef nFound : Real;.. sektion gefunden?
    Vardef nChanged : Real; .. wert geändert
    Vardef sIniDateiNeu : String;
    Vardef sOrgSektion, sOrgEintrag : String;
    ..init
    ?sSektion[1] <> "["/sSektion := "[" + sSektion + "]";
    ..speichere originalwerte
    sOrgSektion := sSektion; sOrgEintrag := sEintrag;
    sSektion := Upper(sSektion); sEintrag := Upper(sEintrag);
    nFound := 0; nChanged := 0;
    ..inidatei vorhanden?
    IF IsFile(sIniDatei) = 0
     Message(sIniDatei + " nicht gefunden.", "Fehler", 1);
     Return 0
    END
    ..öffne inidatei
    IF nFHin := Reset(sIniDatei) > 0
     ..erstelle neue inidatei
     sIniDateiNeu := sIniDatei[1, pos(".", sIniDatei) - 1] + ".rob";
     ..tempinidatei löschen
     ?IsFile(sIniDateiNeu) = 1/ DelFile(sIniDateiNeu);
     IF nFHout := Rewrite(sIniDateiNeu) < 1
      Message(sIniDatei + " kann nicht erstellt werden.", "Fehler", 1);
      Return 0
     END
     .. inidatei lesen bis ende
     WHILE NOT Eot(nFHin)
      sLine := ReadLn(nFHin);
      sTempLine := sLine;.. original zeile zwischenspeichern
      sLine := Upper(sLine);
      ?sLine = sSektion / nFound := 1.. sektion gefunden
       ..noch nicht gefunden, schreibe originalzeile
       ?nFound = 0 / WriteLn(nFHout, sTempLine);
        ..sektion gefunden, aber eintrag nicht, schreibe originalzeile
        ?nFound = 1 AND sLine[1, Pos("=", sLine) - 1] <> sEintrag / WriteLn(nFHout, sTempLine);
         ..sektion und eintrag gefunden, wert ändern
         IF nFound = 1 AND sLine[1, Pos("=", sLine) - 1] = sEintrag
           WriteLn(nFHout, sOrgEintrag + "=" + sWert);
            nChanged := 1; nFound := 0;
         END .. if
          ..neue sektion erreicht?
          IF nFound = 1 AND sLine[1] = "[" AND sLine <> sSektion
           ..eintrag nicht gefunden, schreibe einen neuen
           IF nChanged = 0
             ..schreibe neuen eintrag
             WriteLn(nFHout, sOrgEintrag + "=" + sWert);
             nChanged := 1; nFound := 0;
             ..nicht vergessen, die gelesene zeile zu schreiben
             WriteLn(nFHout, sTempLine);
           END .. if
          END .. if
         END .. while not eot
         ..dateiende erreicht, wurde der wert geändert?
         ..sektion gefunden, aber eintrag nicht (dh sektion ist am dateiende): eintrag neu
         IF nFound = 1 AND nChanged = 0
          WriteLn(nFHout, sOrgEintrag + "=" + sWert);
           nChanged := 1;
         END
         .. sektion und eintrag nicht gefunden: neue sektion
         IF nChanged = 0
           WriteLn(nFHout, "");
           WriteLn(nFHout, sOrgSektion);
           WriteLn(nFHout, sOrgEintrag + "=" + sWert);
         END .. if
         ELSE
          Message(sIniDatei + " nicht gefunden.", "Fehler", 1);
          Return 0
         END
         Close(nFHin);
         Close(nFHout);
         ..
         .. dateien umbenennen
         ?IsFile(sIniDateiNeu) = 1/ DelFile(sIniDatei);
         IF Rename(sIniDateiNeu, sIniDatei) = 0
          Message("Kann Datei nicht umbennen.");
          Return 1
         ELSE
          Return 0
         END
    EndProc
         
    Beispielaufruf:
    Procedure ATest
     ..#schreibt Werte in eine test.ini
     SchreibeIniWert ("c:\daten\wintdb\test.ini", "Linn", "Sport", "Triathlon");
     SchreibeIniWert ("c:\daten\wintdb\testini", "Kim", "Sport", "Tennis");
     Execute("notepad x.ini");
    Endproc


    Topic Projektanalyse Modul Kapitel easy Funktionsbibliothek
    Beschreibung:
    Projektanalyse Prozeduren
    Prozeduren in Projekten einbinden durch hinzufügen folgende Prozeduren:

    ProjektAnalyse
    Erstellt die Datei projektname.ana, der eine komplettenProjektbeschreibung liefert,
    d.h. Tabellenname, Felder, Indices etc.

    Zeige_ProjektAnalyseReport
    Run den Windows Notepad auf und zeigt die Analyse Dateiprojektname.ana.

    Procedure ProjektAnalyse
    ..#Erstellt die Datei projektname.ana, der eine komplettenProjektbeschreibung liefert, d.h.
    ..#Tabellenname, Felder, Indices etc.

    Var CRLF = Chr(13) + Chr(10)
    Var HEADING = "Projektanalyse";
    Var BLANK = " ";
    Vardef sRepName : String;
    Vardef nFH : Real;
    Vardef i, j, k, l, nRT : REAL
    Vardef s : String;
    Vardef asFelder : String[100];      .. max 100 felder lesen
    Vardef sProjektName : String;
    Vardef nAnzahlTabellen : Real;
    Vardef nAnzahlIndices : Real;
    ..sind db's vorhanden
    If MaxFile = 0 
     Message("Fehler - Keine Tabellen gefunden.", HEADING);
     Return
    End
    ..ermittle projektdatei, projektverzeichnis angeben, weil uti-panaprojektverzeichnis ..unabhängig ist
    ..hier wird einen trick verwendet
    IF MaxFile < 1
     Message("Keine Tabellen gefunden, Prozedur wird abgebrochen.",HEADING);
     Return
    END
    ..hole projektverzeichnis, verwender dbdir(1), erste tabelle, fürprojektdir
    If s := FirstDir(DBDir(1) + "*.TDB", "") 
     sProjektName := DBDir(1) + s[1, Pos(".", s) - 1]
    End
    sRepName := sProjektName + ".ANA" ;
    DelFile(sRepName); ..loesche analysereport
    i:=j:= 0;
    nAnzahlTabellen:=nAnzahlIndices:=0;
    .. öffne reportdatei
    If nFH := Rewrite(sRepName) > 0
    ShowWait("Bitte warten..." + CRLF + "analysiere Projekt " +sProjektName);
    WriteLn(nFH, "WinTDB - Projektanalyse fuer Projekt " + sProjektName);
    WriteLn(nFH, "");
    WriteLn(nFH, "analysiert am " + DateStr(Today) + " um " + TimeStr(Now) );
    While j:=j+1 <= MaxFile
      i:=0;
      Writeln(nFH, "");
      WriteLn(nFH, "*** Tabelle " + Str(j) +" : " + DBName(j)  );
      nAnzahlTabellen := nAnzahlTabellen + 1;
      Writeln(nFH, "Felder:");
      ..liste label auf
      WHILE i:=i+1 <= MaxLabel(j)
       asFelder[i] := Label(j, i) + nTimes(" ", 40 - Length(Label(j,i) ) ) + GetType(j, i) ;
      END
     StrSort(asFelder, MaxLabel(j));
     NLoop(i, MaxLabel(j), WriteLn(nFH, BLANK + asFelder[i] ) );
     Writeln(nFH, "Anzahl Felder: " + Str(MaxLabel(j)) );
      ..liste index auf
     Writeln(nFH, "Indizes:");
     k:=l:=0;
      Repeat
       k:=k+1 ..MaxIndex
       ..Message(Str(MaxFile) + "/" + Str(j) +  ": Tabelle " + DBName(j) );
       ?IndName(j, k) <> ""/WriteLn(nFH, BLANK + "Index " + Str(k) + ": " + IndName(j, k) + 
       nTimes(" ", 20 - Length(IndName(j,k) ) ) + IndDef(j, k) );
       nAnzahlIndices:=nAnzahlIndices+1;
      Until IndName(j,k) = ""
      WriteLn(nFH, "Statistik:");
      WriteLn(nFH, BLANK + "Anzahl Records: " + Str(FileSize(j)) );
      W i e n nFH,BLANK+"Dateiinfos(Name,Groesse,Datum,Zeit,Attribut,Verzeichnis):");
      WriteLn(nFH, BLANK + FirstDir(DBDir(j) + DBName(j), "") );
     End
     WriteLn(nFH, "");
     WriteLn(nFH, "Gesamt Statistik:");
     WriteLn(nFH, "Insgesamt besteht dieses Projekt aus ");
     WriteLn(nFH, Str(nAnzahlTabellen)+" Tabellen und " +Str(nAnzahlIndices)+" Indices.");
     WriteLn(nFH, "");
     WriteLn(nFH, "Hinweise:");
     WriteLn(nFH, "Feldtypen: S)tring xx, N)umerisch, M)emo, A)uswahl...")
    WriteLn(nFH, "mehr Info siehe TDB - Hilfe oder Handbuch.")
     Close(nFH)
     HideWait;
     ?IsFile(sRepName) = 1/Message("Projektanalysereport " + sRepName + " erstellt.", "Utility");
    HideWait;
    End
    Endproc

    Procedure Zeige_ProjektAnalyseReport
     Vardef sRepName : String;
     Vardef s : String;
     ..ermittle projektdatei
     If s := FirstDir(DBDir(1) + "*.TDB", "") <> ""
     sRepName := DBDir(1) + s[1, Pos(".", s) - 1] + ".ANA" ;
     End
     Execute("NotePad " + sRepName);
    Endproc


    Topic Datum- und Zeitfunktionen Kapitel easy Funktionsbibliothek
    Beschreibung:
    In den folgenden Prozeduren sind eine Reihe von Möglichkeiten im Bezug auf
    Datum und Zeit aufgeführt.
    In der Prozedur DatumsInfo sind ein paar Spielereien mit dem Datum und Zeit zu sehen.
    Sind viele Berechnungen nötig, dann können einzelnen Berechnungen als easy-Funktion
    definiert werden.

    Procedure WoTagNr (sDatum : String) : Real;
    ..#Wochentagnr. ermitteln
    ..#Parameter:
    ..#sDatum = Datum als String
     Return  (Pos(DayOfWeek(Val(sDatum))[1, 2],"MoDiMiDoFrSaSo") + 1) / 2 ;
    Endproc
    Procedure MonatsName(nMnt : Real): String;
    ..#Monatsname ermitteln
    ..#Paramter:
    ..#nMnt = Monatsnummer
     Vardef nTmp  :  String;
     nTmp := "";
     ?(nMnt > 0) AND (nMnt < 13) / nTmp := Choice(nMnt, "Januar","Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November","Dezember")
     Return nTmp
    Endproc

    Procedure MonatsNameAusDatum(sDatum : String) : String;
    ..#Monat als String Jan, Feb ..
    ..#Parameter:
    ..#sDatum = Datum als String
     Vardef nTmp : String;

     Return Choice(Month(Val(sDatum)), "Jan", "Feb", "Mär", "Apr", "Mai","Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez");
    Endproc

    Procedure Date2Real(sDatum : String) : Real
    ..#Umwandlung Datum als String in Real
    ..#Parameter:
    ..#sDatum = Datum als String
     Return Val(sDatum)
    Endproc

    Procedure Time2Real(sTime : String) : Real
    ..#Umwandlung Zeit als String in Real
    ..#Parameter:
    ..#sTime = Zeit als String
     Return Val(sTime)
    Endproc

    Procedure DatumsInfo
    ..#Beispiel mit oben beschriebene Prozeduren und vieles mehr
     DEF CRLF = Chr(13) + Chr(10)
     Vardef nTotZeit : Real;
     Vardef nTmp : String;
     Vardef nWoTagNr : Real;
     Vardef nNoMntTage : Real;
     Vardef nJahresTagNr : Real;
     Vardef sDatum : String;
     Vardef sMonat : String;
     Vardef nKalWoche : Real;
     Vardef nSchaltJahr,  nTageImJahr : Real;
     Var sInfo = "";

     .. datum speichern, ermöglicht flexibele berechnungen
     sDatum := DateStr(Today); .. oder z.B. "09.8.1996"

     ..wochentagnummer
     nWoTagNr := (Pos(DayOfWeek(Val(sDatum))[1, 2],"MoDiMiDoFrSaSo") + 1) /2 ;

     ..jahrestagnummer
     nJahresTagNr := (Week(Val(sDatum)) * 7) - (7 - nWoTagNr);
     ..anzahl tage im Jahr 
     nTmp := (Pos(DayOfWeek(Val("31.12." +sDatum[7,4]))[1,2],"MoDiMiDoFrSaSo") + 1) / 2 ;
     nTageImJahr := (Week(Val("31.12." + sDatum[7,4])) * 7) - (7 - nTmp);

     ..anzahl monatstage
     nNoMntTage := 31;
     IF sDatum[4,2]<>"12"
      nNoMntTage :=Val(DateSt(Val("01."+Str(VAL(sDatum[4,2])+1)+"."+sDatum[7,4])-1)[1,2] );
     END
     .. schaltjahr ?
     nSchaltJahr := 0; .. nein oder doch
     IF DateStr( VAL("01.03." + sDatum[7,4]) - 1)[1,2] = "29" ..eb 29 dannschaltjahr
      nSchaltJahr := 1; .. ja
     END

     .. monat als string Jan, Feb ..
     sMonat := Choice(Month(Val(sDatum)), "Jan", "Feb", "Mär", "Apr","Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez");

     .. welche kalenderwoche
     nKalWoche := Week(Val(sDatum));

     .. info zum test ausgeben
     sInfo := sInfo + "Tag: " + DayOfWeek(Val(sDatum)) + " Nr: " +Str(nWoTagNr) + " JTagNr: " +  Str(nJahresTagNr) + CRLF;
     sInfo := sInfo + "Monat: " + sMonat + " Nr:" + Str(Month(Val(sDatum)))+ " Tage: " + Str(nNoMntTage) + CRLF;
     sInfo := sInfo + "Woche Nr:" + Str(nKalWoche);

     Message(sInfo, "Heute ist " + DateStr(Val(sDatum)) );

     ..zeit addieren
     nTotZeit := Val("05:22") + Val("58:44");
     Message("Totale Spieldaur: " + Str(nTotZeit DIV 60) + ":" + Str(nTotZeit MOD 60));

    Endproc

    Procedure Monate_Seit_Heute
    Vardef nDatum, nMonthCount : Integer;
     T-Eingabe := DateStr(Today);
     Input("Datum");
     SetPara('ec 1');
     nDatum := VAL(T-Eingabe);
     SetPara('ec 0')
     IF nDatum >= 1.1.1900 And nDatum <= 31.12.2099
    nMonthCount := Month(today)-Month(nDatum)+((Year(today)-Year(nDatum))*12)
    Message("Monate seit '" + T-Eingabe + "' = " + Str(nMonthCount));
     ELSE 
    Message("Datum '" + T-Eingabe + "' ist NICHT gültig...")
     END
    EndProc;


    Topic Tabelleninhalt löschen und Autonummer zurücksetzen Kapitel easy Funktionsbibliothek
    Beschreibung:
    aktuelle Datenbank komplett löschen und anschließen die
    Autonummer(=Laufende_Nummer) auf 1 setzen.

    Procedure ResetDat
    ..#aktuelle Datenbank komplet löschen und die Autonummer auf 1 setzen
     ClearDat(FileNr)
     SetAuto(Filenr,1)
    Endproc

    ..#zweite variante mit parameter
    Procedure ResetDat(nFileNr : Real);
    ..#Datenbank komplet löschen und die Autonummer auf 1 setzen
    ..#Parameter:
    ..#nFileNr = Datenbanknummer

     ClearDat(nFileNr)
     SetAuto(nFilenr,1)
    Endproc


    Topic Taschenrechner Kapitel easy Funktionsbibliothek
    Beschreibung:
    Eine kleine Spielerei mit VAL

    Procedure Taschenrechner : Real;
     Vardef sFrage : String;
     sFrage := "";
     Input(sFrage, "Taschenrechner");
     Return Val(T-Eingabe)
    Endproc

    Eine kleine Rechenspielerei.
    Procedure Taschenrechner(A, B : Real)
     Vardef sFrage : String;
     sFrage := Str(A) + " mal " + Str(B) + " ist?";
     Input(sFrage, "Rechentest");
     If Val(T-Eingabe) ist A * B
        Message("Sehr gut!")
     Else
        Message("Ist leider nicht richtig!");
     End
    Endproc


    Topic Fortschreitungsanzeige (Progessbar) Kapitel easy Funktionsbibliothek
    Beschreibung:
    Ausgabe eine Fortschreitungsanzeige

    Procedure UProgressbar(nArt : Real; sMeldung : String; nMax : Real; nAct : Real);
    ..#Darstellung ein Fortschreitungsanzeige
    ..#Parameter:
    ..#nArt: 1 = balken, 2 = %
     DEF CRLF = Chr(13) + Chr(10);
     DEF nPMax = 100;
     DEF sDEL = Chr(219)
     Vardef sTmp : String;
     Vardef i, k, f : Real;

     f := nMax / nPMax;
     ?f = 0 / f := 1;
     k := Int(nAct / f);
     If nArt = 1
      sTmp := "";
      nLoop(i, k, sTmp := sTmp + Chr(219));
      ShowWait(sMeldung + CRLF + sTmp);
     End
     ?nArt = 2/ShowWait(sMeldung + CRLF + Str(k,1,0) + "%");
    Endproc


    Topic Direkte Bearbeitung von Datensätze einer angekoppelte Tabelle in einem Formular Kapitel easy Funktionsbibliothek
    Beschreibung:
    Folgende 3 Prozeduren ermöglichen eine direkte Bearbeitung von Datensätze einer
    eingebettete Tabelle.
    Die Prozeduren können mittels Makro-Schalter aus einem Formular aufgerufen werden.

    Procedure DatensatzLöschen(nAktRec : Real);
    ..#Datensatz löschen
    ..#Parameter:
    ..#nAktRec = aktueller Datensatz
     If nAktRec > 0
      ?Message("Satz wirklich löschen?", "Satz löschen", 3) = 6 /DelRec(TABELLE, nAktRec);
     End
    Endproc

    Procedure DatensatzBearbeiten(nAktRec : Real) : Real;
    ..#Datensatz bearbeiten
    ..#Parameter:
    ..#nAktRec = aktueller Datensatz
     Vardef nRT : Real;
     If nAktRec = 0 / Return 0
     DatensätzeBearbeiten("TABELLE.Formular");
     Readrec(TABELLE, nAktRec);
     nRT := EditRec("Ändern Sie die Angaben. Abbruch mit ESC.");
     CloseWnd;
     Return nRT
    Endproc

    Procedure DatensatzNeu(nDummy : Real);
    ..#Neuer Satz anlegen
    ..#Parameter:
    ..#nDummy = damit die Prozedur nicht in der Makroliste erscheint
     Vardef nRNo, nAktRec : Real; 
     nAktRec := ReadRec(PRIMTABELLE, RecNr(PRIMTABELLE));
     If nAktRec > 0
      ReadRec(TABELLE, 0);
      TABELLE.tFeld1 := "<Neu>";
      Writerec(TABELLE, 1 + FileSize(TABELLE));
     End
     nRNo := FindRec(TABELLE, Str(TABELLE.Laufende_Nummer), "TABELLE.INR",1);
     If nRNo > 0
      ?EditSatz(nRNo) = 0 / DelSatz(nRNo);
     End
    Endproc


    Topic Verschiedene Prozeduren die Dateioperationen durchführen Kapitel easy Funktionsbibliothek
    Beschreibung:
    Verschiedene Prozeduren die Dateioperationen durchführen.

    Procedure pAskForFile(sFrage, sHeading, sVorgabe : String) : String;
    ..#Datei abfragen
    ..#Parameter:
    ..#sFrage = Fragenstellung, welche Datei
    ..#sHeading = Fensterüberschrift
    ..#sVorgabe = Vorgabe Dateiname
    ..#Returnwert:
    ..#Dateiname

     Vardef  nRT : Real;
     T-Eingabe:= sVorgabe;
     REPEAT
      nRT := Input(sFrage, sHeading);
      If nRT = 0 .. abbruch im input fenster
       Return ""
      End
      If IsFile(T-Eingabe) = 1        .. datei vorhanden
       nRT := Message("Datei existiert bereits! Überschreiben?","Achtung",4)
       ?nRT = 6 / nRT := 0     .. Ja
       If nRT = 2      .. Abbruch
        Return ""
       End
      End
      ?IsFile(T-Eingabe) = 0 / nRT := 0;      .. datei nicht vorhanden
     UNTIL nRT = 0
     Return T-Eingabe
    Endproc

    Procedure pSelectTDBFile(nDummy : Real) : String;
    ..#Auswahl eines tdb-Projektes
    ..#Parameter:
    ..#nDummy = 0 damit diese Prozedur nicht in der Liste der Prozedurenerscheint.
    ..#Returnwert:
    ..#TDB-Projektdateiname

     T-Eingabe := "*.TDB";
     If ChooseFile("TDB-Projekt auswählen") = 1
      Return T-Eingabe;
     Else
      Return "";
     End
    Endproc

    Procedure pFileOfDir(sPath:STRING) : STRING;
    ..#Dateiname aus dem kompletten Pfad auslesen
    ..#Parameter:
    ..#sPath = Pfadangabe
    ..#Returnwert:
    ..#Dateiname
     Vardef sSep : STRING;

     sSep:=Choice(Sel(sPath:=Exchange(sPath," ","") HAT "\"),"\",":")
     Repeat
     Until Not sPath:=Right(sPath,Length(sPath) - POS(sSep,sPath)) Hat sSep
     Return sPath
    Endproc

    Procedure pDirOfPath(sPath:String) : String;
    ..#Verzeichnis aus dem kompletten Pfad auslesen
    ..#Parameter:
    ..#sPath = Pfadangabe
    ..#Returnwert:
    ..#Verzeichnisname
     Return sPath[1, Length(sPath) - Length(pFileOfDir(sPath)) ] ;
    Endproc

    Procedure pFileFromPath(sPath:String):String
    ..#Dateiname aus dem kompletten Pfad auslesen
    ..#Parameter:
    ..#sPath = Pfadangabe
    ..#Returnwert:
    ..#Dateiname aus Pfadangabe

     Vardef sSep : String;

     sSep:=Xwert(Sel(sPath:=Exchange(sPath," ","") Hat "\"),"\",":")
     Repeat
     Until Nicht sPath:=Right(sPath,Length(sPath) - Pos(sSep, sPath)) HatsSep
     Return sPath
    Endproc

    Procedure pCurDrive(nDummy : Real) : String;
    ..#Dateiname aus dem kompletten Pfad auslesen
    ..#Parameter:
    ..#nDummy = 0 damit diese Prozedur nicht in der Liste der Prozedurenerscheint.
    ..#Returnwert:
    ..#aktuellen Laufwerks
     Return GetDir(0)[1,2]
    Endproc

    Procedure pDrivePath(sDrive : String) : String;
    ..#gesetzen Pfades für Laufwerk sDrive
    ..#Parameter:
    ..#sDrive = Laufwerk A, B, C ...
    ..#Returnwert:
    ..#gesetzen Pfades für Laufwerk sDrive

     Vardef nDrive : Real;

     Xwert(Sel(nDrive:=ASC(GROß(LTRIM(sDrive)[1])) VON 65 BIS90),nDrive:=nDrive - 64,nDrive:=0)
     sDrive := GetDir(nDrive);
     Return XWERT(Sel(RECHTS(sDrive,1)="\"), sDrive, XWERT(SEL(sDrive),sDrive + "\",""))
    Endproc

    Procedure pFileDate(sFile : String) : String;
    ..#Dateidatum und Zeit ermitteln
    ..#Parameter:
    ..#sFile = Dateiname
    ..#Returnwert:
    ..#Dateidatum und Zeit
     Return FirstDir(sFile, "")[27, 17]
    Endproc

    Procedure pCheckPath(sPath : String) : String;
    ..#Pfades mit \ abgeschlossen zurückgeben
    ..#Parameter:
    ..#sPath = Pfadangabe
    ..#Returnwert:
    ..#Pfades mit \ abgeschlossen

     If sPath[Length(sPath)] <> "\"
      Return sPath + "\"
     Else
      Return sPath
     End
    Endproc


    Topic Hex-Wert in ein String umwandeln Kapitel easy Funktionsbibliothek
    Beschreibung:
    Hex-Wert in ein String umwandeln.

    Procedure pHexToStr(sHex : String) : String;
    ..#Umwandlung eines Hex-Wertes in ein String
    ..#Parameter:
    ..#sHex = Hex-Wert als String
    ..#Returnwert:
    ..#Hex-Wert als String

     Vardef x : Real;

     x := xWert(Asc(sHex[2]) -48,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15) * 16 ;
     x := x + xWert(Asc(sHex[3]) -48,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15);
     Return AnsiToOEM( Chr(x) )
    Endproc


    Topic Projektanalyseprozeduren Kapitel easy Funktionsbibliothek
    Beschreibung:
    Die Prozeduren erstellen eine komplette Projektanalyse. Die Prozedureneinbinden in Projekten durch hinzufügen derProzeduren:
    ProjektAnalyse:  Erstellt die Datei projektname.ana, der einekompletten Projektbeschreibung liefert, d.h. Tabellenname, Felder, Indices etc.
    Zeige_ProjektAnalyseReport: Zeigt Analyse Datei projektname.ana imNotepad

    Procedure ProjektAnalyse
    ..#analysiert ein bestehendes projekt

     Var CRLF = Chr(13) + Chr(10)
     Var HEADING = "Projektanalyse"
     Var BLANK = " "
     Vardef sRepName : String;
     Vardef nFH : Real;
     Vardef i, j, k, l, nRT : REAL
     Vardef s : String;
     Vardef asFelder : String[100];.. max 100 felder koennen gelesen werden
     Vardef sProjektName : String;
     Vardef nAnzahlTabellen : Real;
     Vardef nAnzahlIndices : Real;

     ..sind db´s vorhanden
     If MaxFile = 0 
      Message("Fehler - Keine Tabellen gefunden.", HEADING);
      Return
     End
     ..ermittle projektdatei
     ..projektverzeichnis angeben, weil uti-pana projektverzeichnisunabhängig ist
     ..hier wird ein trick verwendet
     IF MaxFile < 1
      Message("Keine Tabellen gefunden, Prozedur wird abgebrochen.",HEADING)
      Return
     END
     ..hole projektverzeichnis, verwender dbdir(1), erste tabelle, fürprojektdir
     If s := FirstDir(DBDir(1) + "*.TDB", "") 
      sProjektName := DBDir(1) + s[1, Pos(".", s) - 1]
     End
     sRepName := sProjektName + ".ANA" ;
     DelFile(sRepName); ..loesche analysereport
     i:=j:= 0;
     nAnzahlTabellen:=nAnzahlIndices:=0;
     ..öffne reportdatei
     If nFH := Rewrite(sRepName) > 0
      ShowWait("Bitte warten..." + CRLF + "analysiere Projekt " +sProjektName);
      WriteLn(nFH, "WinTDB - Projektanalyse fuer Projekt " + sProjektName);
      WriteLn(nFH, "");
      WriteLn(nFH, "analysiert am " + DateStr(Today) + " um " +TimeStr(Now) );
      While j:=j+1 <= MaxFile
       i:=0;
       ..Message(Str(MaxFile) + "/" + Str(j) +  ": Tabelle " + DBName(j) );
       Writeln(nFH, "");
       WriteLn(nFH, "*** Tabelle " + Str(j) +" : " + DBName(j)  );
       nAnzahlTabellen := nAnzahlTabellen + 1;
       Writeln(nFH, "Felder:");
       ..liste label auf
       WHILE i:=i+1 <= MaxLabel(j)
        asFelder[i] := Label(j, i) + nTimes(" ", 40 - Length(Label(j,i) ) )+ GetType(j, i) ;
       END
       StrSort(asFelder, MaxLabel(j));
       NLoop(i, MaxLabel(j),  WriteLn(nFH, BLANK + asFelder[i] ) );
       Writeln(nFH, "Anzahl Felder: " + Str(MaxLabel(j)) );
       ..Liste index auf
       Writeln(nFH, "Indizes:");
       k:=l:=0;
       Repeat
        k:=k+1 .. MaxIndex
        ..Message(Str(MaxFile) + "/" + Str(j) +  ": Tabelle " + DBName(j));
        If IndName(j, k) <> ""
         WriteLn(nFH,BLANK + "Index " + Str(k) + ": " + IndName(j, k) +nTimes(" ", 20 - Length(IndName(j,k) ) ) + IndDef(j, k) );
        End
        nAnzahlIndices:=nAnzahlIndices+1;
       Until IndName(j,k) = ""
       WriteLn(nFH, "Statistik:");
       WriteLn(nFH, BLANK + "Anzahl Records: " + Str(FileSize(j)) );
       WriteLn(nFH, BLANK + "Dateiinformationen (Name, Groesse, Datum,Zeit, Attribut, Verzeichnis):");
       WriteLn(nFH, BLANK + FirstDir(DBDir(j) + DBName(j), "") );
      End
      WriteLn(nFH, "");
      WriteLn(nFH, "Gesamt Statistik:");
      WriteLn(nFH, "Insgesamt besteht dieses Projekt aus: ");
      WriteLn(nFH, Str(nAnzahlTabellen) + " Tabellen und " +Str(nAnzahlIndices) + " Indices.");
      WriteLn(nFH, "");
      WriteLn(nFH, "Hinweise:");
      WriteLn(nFH, "Feldtypen: S)tring xx, N)umerisch, M)emo, A)uswahl...")
      WriteLn(nFH, "mehr Info siehe TDB - Hilfe oder Handbuch.")
      Close(nFH)
      HideWait;
      If IsFile(sRepName) = 1
       Message("Projektanalysereport " + sRepName + " erstellt.","Utility");
      End
      HideWait;
     End
    Endproc

    Procedure Zeige_ProjektAnalyseReport
    ..#zeigt die erastellte Datei mittels Notepad
    Vardef sRepName : String;
    Vardef s : String;

     ..ermittle projektdatei
     If s := FirstDir(DBDir(1) + "*.TDB", "") <> ""
      sRepName := DBDir(1) + s[1, Pos(".", s) - 1] + ".ANA" ;
     End
     Execute("NotePad " + sRepName);
    Endproc



    Topic E-Mail-Adresse auf Richtigkeit hin überprüfen Kapitel easy Funktionsbibliothek
    Beschreibung:
    Diese Funktion stammt aus dem Beispiel WEBGAST, welches dem Produkt VDP 2.0 beiliegt.
    Der Funktion ValidEmail wird ein String mit der zu überprüfenden Mailadresse übergeben.
    Die Funktion liefert 0 (null) zurück, wenn die Minimalanforderungen erfüllt sind.
    Ansonsten werden je nach Problem die Werte 1 bis 4 zurückgegeben
    (nähere Erläuterung siehe "Rückgabewerte").

    PROCEDURE ValidEmail(EMAIL:String):REAL
     ..#Beschreibung:
     ..#Test auf gültige E-Mail Adresse
     ..#Es wird dazu die Minimalanforderung geprüft.
     ..#1. nur ein @-Zeichen und dieses nicht als erstes Zeichen
     ..#2. es ist mindestens ein Punkt nach dem @-Zeichen, wobei der erste
     ..#Punkt nicht direkt nach dem @ folgen darf
     ..#Rückgabewerte:
     ..#0 - Adresse gültig
     ..#1 - kein @ oder an erster Stelle
     ..#2 - zweites @ im String
     ..#3 - kein Punkt oder direkt nach dem @
     ..#4 - letztes Zeichen ist @ oder Punkt
      VARDEF AT:REAL;

      AT:= Pos("@", EMAIL);
      IF AT << 2
        .. Kein @ oder an erster Stelle
        RETURN 1
      END

      .. Teilstring nach dem @
      EMAIL:= RightStr(EMAIL, Length(EMAIL) - AT);
      IF  Pos("@", EMAIL) <> 0
        .. Zweites @ vorhanden
        RETURN 2
      END

      IF  Pos(".", EMAIL) << 2
        .. Kein Punkt oder an erster Stelle
        RETURN 3
      END

      EMAIL:= RightStr(EMAIL, 1);
      IF  EMAIL = "." or EMAIL ="@"
        .. letztes Zeichen ist Punkt oder @

        RETURN 4
      END

      .. Minimalanforderung erfüllt
      RETURN 0

    ENDPROC


    Topic Debug-Prozedur für Module Kapitel easy Funktionsbibliothek
    Beschreibung:
    die Prozedur WriteToLog in Module einbinden.
    Es wird eine Datei erstellt, welche dann mit Strings beschrieben werden kann.

    PROCEDURE WriteToLog(sLogFile: STRING; sStr : STRING; nLogNeu : REAL);
    ..#schreibt String sStr in eine Logdatei sLogFile
    ..#Parameter:
    ..#sLogFile = Logdatei
    ..#sStr = Eintrag in der Logdatei
    ..#nLogNeu: 0 = erstelle neue Logdatei
    ..#Beispielaufruf:
    ..# WriteToLog("Projekt.log", "START p.MyProc um " + DateStr(Today) + "" + TimeStr(Now), 0);

     DEF HEADING = "Debug";
     VARDEF nFH : Real;

     ..#neue logdatei erstellen, wenn nLogFirst = 1
     IF nLogNeu = 1
      ?IsFile(sLogFile) = 1 / DelFile(sLogFile);
     END
    ..#logdatei öffnen, erst prüfen ob logdatei vorhanden ist.
     IF IsFile(sLogFile) = 0 .. logdatei nicht da, erstelle neu
      IF nFH:=Rewrite(sLogFile) < 1
       Message("Logdatei " + sLogFile + " kann nicht neu erstellt werden.",HEADING);
       Halt;
      END
      WriteLn(nFH,"Logstart um " + DateStr(ToDay) + " " + TimeStr(Now));
      Close(nFH);
     END
    ..#logfile schon da?
     IF IsFile(sLogFile) = 1
      IF nFH:=TAppend(sLogFile) < 1
       Message("Kann Logdatei " + sLogFile + " nicht öffnen...", HEADING);
       Halt;
      END
     END
     WriteLn(nFH,TimeStr(Now) + " : " + sStr);
     CLOSE(nFH);
    ENDPROC

    PROCEDURE BeispielWriteToLog(nDummy : Real);
     ..#Beispiel: Eintragung in der Logdatei
     WriteToLog("Projekt.log", "Starte p. Test", 1); .. neue logdatei
     ..#Schritt 1
     WriteToLog("Projekt.log", "Ende Schritt 1...", 0); .. hinzufügen
     ..#Schritt 2
     WriteToLog("Projekt.log", "Ende Schritt 2...", 0);
    ENDPROC

    PROCEDURE ZeigeLogDatei(nDummy : Real);
    ..#Aufruf Logdatei mittels Windows NotePad
     Execute("NotePad.exe Projekt.Log");
    ENDPROC


    Topic Paßwort Abfrage Kapitel easy Funktionsbibliothek
    Beschreibung:
    Es gibt eine Reihe von Möglichkeiten Passworte abzufragen.
    Nachfolgend eine einfache Lösung.
    Die Benutzernamen und Passworte sind in der Tabelle SYSUSER gespeichert.
    Felder sUsername und sPasswort.

    Procedure BenutzerZulassen(nAktRNo : Real) : Real;
    ..#Benutzer zulassen
    ..#Parameter:
    ..#nAktRNo = aktueller Datensatz
    ..#Returnwert:
    ..#liefert 1 wenn Ok, sonst 0
    ..#Aufrufbeispiel:
    ..#BenutzerZulassen(RecNo(KASSE))

     Vardef nRT, nRNo : Real;
     Vardef nUsername, nPasswort : String;

     nRT := INPUT("Geben Sie Ihre Benutzername ein.","Benutzername", 0);
     ?nRT = 0 / Return 0
     nUsername := T-Eingabe;
     nRT := INPUT("Geben Sie Ihr Passwort ein.","Passwort", 1);
     ?nRT = 0 / Return 0
     nPasswort := T-Eingabe;
     nRNo := FindRec(SYSUSER, nUsername + "," + nPasswort,"SYSUSER.IND",1);
     If nRNo = 0
       Message("Passwort oder Benutzername nicht richtig!", "FehlerAnmeldung");
       Return 0
     End
     nRNo := ReadRec(SYSUSER, nRNo);
     If nRNo > 0
       nName := SYSUSER.sUsername;
       ReadRec(KASSE, nAktRNo);
       KASSE.Einnehmer := nName
       Writerec(KASSE, nAktRNo);
       Attach
       Return 1
     Else
      Message("Falscher Code", "Fehler");
      Return 0
     End
    Endproc


    Topic Beispiel zu MitBedingung Kapitel easy Funktionsbibliothek
    Beschreibung:
    ein Beispiel für kombinierte MitBedingung-Suche

    PROCEDURE Starte_Suchassistent
    ..#ein Beispiel für kombinierte MitBedingung-Suche
    ..#Parameter:
    ..#keine
    ..#Returnwert:
    ..#keine
     VarDef nCount : REAL;
     IF EXECDIALOG("DIALOG.Suchassistent")=1
      SetSortOrder("ADRESSEN.ID")
      ReadRec( DIALOG,1)
      If DIALOG.ID-Name#""
       DIALOG.ID-Name := UPPER(DIALOG.ID-Name)
       IF MitBedingung("UPPER(ADRESSEN.ID-Name)
        "+CHOICE(DIALOG.A-ID-Name,"=","hat","wie","ungleich")+"
        '"+DIALOG.ID-Name+"'",1,2)>0
        SetSortOrder("ADRESSEN.ID",2)
       ELSE
        Message("Keine passenden Einträge gefunden", "ID-Name"+DIALOG.ID-Name)
       END
      END
      If DIALOG.Firma#""
       DIALOG.Firma := UPPER(DIALOG.Firma)
       IF MitBedingung("UPPER(ADRESSEN.Firma)
        "+CHOICE(DIALOG.A-Firma,"=","hat","wie","ungleich")+"
        '"+DIALOG.Firma+"'",1,2)>0
        SetSortOrder("ADRESSEN.ID",2)
       ELSE
        Message("Keine passenden Einträge gefunden","Firma "+DIALOG.Firma)
       END
      END
      If DIALOG.Name#""
       DIALOG.Name := UPPER(DIALOG.Name)
       IF MitBedingung("UPPER(ADRESSEN.Name)
        "+CHOICE(DIALOG.A-Name,"=","hat","wie","ungleich")+"
        '"+DIALOG.Name+"'",1,2)>0
        SetSortOrder("ADRESSEN.ID",2)
       ELSE
        Message("Keine passenden Einträge gefunden","Name "+DIALOG.Name)
       END
      END
      If DIALOG.Straße#""
       DIALOG.Straße := UPPER(DIALOG.Straße)
       IF MitBedingung("UPPER(ADRESSEN.Straße)
        "+CHOICE(DIALOG.A-Straße,"=","hat","wie","ungleich")+"
        '"+DIALOG.Straße+"'",1,2)>0
        SetSortOrder("ADRESSEN.ID",2)
       ELSE
        Message("Keine passenden Einträge gefunden","Straße"+DIALOG.Straße)
       END
       END
       If DIALOG.Ort#""
        DIALOG.Ort := UPPER(DIALOG.Ort)
        IF MitBedingung("UPPER(ADRESSEN.Ort)
         "+CHOICE(DIALOG.A-Ort,"=","hat","wie","ungleich")+"'"+DIALOG.Ort+"'",1,2)>0
         SetSortOrder("ADRESSEN.ID",2)
        ELSE
         Message("Keine passenden Einträge gefunden","Ort "+DIALOG.Ort)
        END
        END
        If DIALOG.Land#""
         DIALOG.Land := UPPER(DIALOG.Land)
         IF MitBedingung("UPPER(ADRESSEN.Land)
          "+CHOICE(DIALOG.A-Land,"=","hat","wie","ungleich")+"
          "+DIALOG.Land+"'",1,2)>0
          SetSortOrder("ADRESSEN.ID",2)
         ELSE
          Message("Keine passenden Einträge gefunden","Land "+DIALOG.Land)
         END
        END
        If DIALOG.Branche#""
         DIALOG.Branche := UPPER(DIALOG.Branche)
          IF MitBedingung("UPPER(ADRESSEN.Branche)
          "+CHOIE(DIALG.A-Branche,"=","hat","wie","ungleich")+"'"+DIALOG.Branche+"'",1,2)>0
       SetSortOrder("ADRESSEN.ID",2)
      ELSE
      Message("Keine passenden Einträge gefunden","Branche"+DIALOG.Branche)
      END
      END
      IF nMarks(FileNr)=0
      Message("Keine passenden Einträge gefunden")
      END
     END
    ENDPROC


    Topic Felder von Tabelle zu Tabelle kopieren Kapitel easy Funktionsbibliothek
    procedure CopyMemoTab2Tab
    ..#kopiert ein Memofeld von Tabelle1 zu Tabelle2
    ..#Tabelle 2 ist mittels ein Koppelfeld (Tabelle2.Koppelfeld) mit Tabelle 1 verbunden.
    ..#es könne auch andere Felder kopiert werden. dann die suchroutineanpassen.

     DEF TMPMEMO = DBDir(TABELLE1) + "memo.tmp";
     vardef nRNoT1, nRNoT2 : real;
     vardef nLNT1, nLNT2 : real; ..aufende_nummer der tabelle

     ..zugriff tab1 auf laufende_nummer setzen
     Access(TABELLE1,  "TABELLE1.INR");
     ..loope durch die tabelle1
     nRNoT1 := FirstRec(TABELLE1);
     WHILE nRNoT1 > 0
      ..lese record und speichere laufende_nummer der tabelle 1
      ReadRec(TABELLE1, nRNoT1)
      nLNT1 := TABELLE1.Laufende_Nummer;
      ..suche zugehörige record in tab2
      ..möglichkeit 1:
      ..hierbei wird als der index mit koppeldfeld information verwendet
      nRNoT2 := FindRec(TABELLE2, Str(nLNT1), "TABELLE2.IN1", 1);
      If nRNoT2 > 0
       ReadRec(TABELLE2, nRNoT2);
       ?IsFile(TMPMEMO) / DelFile(TMPMEMO);
       CopyMemo(TABELLE2.Tab2Memo, TMPMEMO);
       ReadMemo(TABELLE1.Tab1Memo, TMPMEMO, 0)
       WriteRec(TABELLE1, nRNoT1)
       ?IsFile(TMPMEMO) / DelFile(TMPMEMO);
      End
      ..möglichkeit 2:
      ..hierbei wird durch die tabelle 2 gelooped
      nRNoT2 := FirstRec(TABELLE2);
      WHILE nRNoT2 > 0
       ReadRec(TABELLE2, nRNoT2);
       If TABELLE2.Koppelfeld = nLNT1
        ?IsFile(TMPMEMO) / DelFile(TMPMEMO);
        CopyMemo(TABELLE2.Tab2Memo, TMPMEMO);
        ReadMemo(TABELLE1.Tab1Memo, TMPMEMO, 0)
        WriteRec(TABELLE1, nRNoT1)
        nRNoT2 := NextRec(TABELLE2);
        ?IsFile(TMPMEMO) / DelFile(TMPMEMO);
       End
      End
      nRNoT1 := NextRec(TABELLE1);
      END .. WHILE Stamm
    endproc



    Topic Job- und Module-Kompilierungsprozeduren Kapitel easy Funktionsbibliothek
    Beschreibung:
    Verschiedene Prozeduren um Module und Jobs neu zu übersetzen (kompilieren).

    Procedure XCompile(sMod : String);
    ..#kompiliert ein Module
    ..#Parameter:
    ..#sMod = Modulname

     Vardef nRT : Real;

     ?IsFile(sMod) = 0 / Return
     ShowWait( "Compiliere " + sMod + "...");
     IF nRT := Compile( sMod) <> 0
       IF Message( 'Fehler ' + Str(nRT,1,0) + "/" + Str($Fehler) + ' inModul/Job: ' + sMod, 'Compile', 2) = 2 
         HideWait;
         Return
      END
     Else
       ..Message(sMod+ ' erfolgreich übersetzt.', "Hinweis");
       Return
     END;
    Endproc

    Procedure DoCompileAllMods
    ..#kompiliert alle Module im aktuellen Projektverzeichnis
     Vardef sTmp: String;
     sTmp := FirstDir("*.MOD", "");
     WHILE sTmp <> ""
       XCompile(sTmp[1, 12]);
       sTmp := NextDir;
     END
    Endproc

    Procedure DoCompileAllJobs
    ..#kompiliert alle Jobs im aktuellen Projektverzeichnis

     Vardef sTmp: String;
     sTmp := FirstDir("*.JOB", "");
     WHILE sTmp <> ""
       XCompile(sTmp[1, 12]);
       sTmp := NextDir;
     END
    Endproc

    ..#die beiden module können auch in ein zusammengefaßt werden
    Procedure DoCompileAll(sPath : String)
    ..#kompiliert alle Jobs im aktuellen Projektverzeichnis
    ..#Parameter:
    ..#sPath = Pfadangabe, zB *.JOB oder *.MOD

     Vardef sTmp: String;
     sTmp := FirstDir(sPath, "");
     WHILE sTmp <> ""
       XCompile(sTmp[1, 12]);
       sTmp := NextDir;
     END
    Endproc


    Topic Updates mit Strukturänderung durchführen Kapitel easy Funktionsbibliothek
    ..Info
    ..für alle, die beim Kunden Projekte laufen haben und Updates mit Strukturänderung
    ..durchführen wollen:
    ..Diese Routine geht davon aus, daß im Unterverzeichnis eine komplette Kopie aller
    ..Dateien liegen. Ob das Update durchgeführt wird, entscheidet die Existenz einer Datei
    ..namens UPDATE.INI
    ..Update.ini beinhaltet in der 2. Zeile die Revisionsnummer des Updates
    ..Aufbau UPDATE.INI
    ..[Update]
    ..Rev=1
    ..Update.ini wird noach dem Update umbenannt.
    ..Importiert werden alle Felder, auch die Memofelder, auch kaputte Quelldateien mit
    ..Laufende_Nummer=0 werden dabei korrigiert.
    ..viel Spaß H. Götz

    ..Modul für Tabelle EINSATZ
    ..01.12.1999
    ..procedure Daten_einlesen
    ..falls die Quelldatei Laufende_Nummer=0 enthält muß 
    ..mit einer vereinfachten Importroutine gearbeitet werden
    ..ob die Importroutine korrekt arbeitet, wenn man nur über dieRecord-Nummer 
    ..geht anstelle der Lfd weiß ich derzeit nicht sicher.
    ..Bei einfacheren Strukturen sicherlich, bei komplexen Verknüpfungenmuß 
    ..noch getestet werden
    .NB 1
    PROCEDURE Datensatz_anhängen(nDat, nDB : REAL)
     VarDef c : STRING
     VarDef j, nF : REAL
     ReadRec( nDat,0)
     j := 1
     REPEAT
      c := Label( nDat,j)
      IF LabelNo( nDB, c)>0
       IF GetType( nDat, j)[1] # "M"
        SetField( nDat, j, GetField( nDB, LabelNo( nDB,c)))
       END
      END
      j := j+1
     UNTIL j > MaxLabel(nDat)
     nF := FileSize( nDat)+1
     WriteRec( nDat, nF)
     ReadRec( nDat, nF)
     j := 1
     REPEAT
      c := Label( nDat,j)
      IF LabelNo( nDB, c)>0
       IF GetType( nDat, j)[1] = "M"
        PrimFile( nDB)
        DO _'CopyMemo('+c+' ,"RAMTEXT")'
        PrimFile( nDat)
        DO _'ReadMemo( '+c+',"RAMTEXT",1)'
        PrimFile( nDB)
       END
      END
      j := j+1
     UNTIL j > MaxLabel(nDat)
    ENDPROC

    PROCEDURE Daten_einlesen( nDat : REAL; cDat : STRING)
    ..01.12.1999 / Götz
     VarDef nF, nDB, nRec, nFI,j,i : REAL
     VarDef aLfd : REAL[5000]
     VarDef c : STRING
     Showwait("Programmupdate wird durchgeführt"+CHR(13)+DBNAME(nDat) +"wird
     zurückgelesen")
     nDB := OpenDB(cDat,"",0,0)
     IF nDB >0
      PrimFile( nDB)
      ACCESS( nDB, IndName( nDB,0))
      ReadRec( nDB, FirstRec( nDB))
      ..falls die Quelldatei Laufende_Nummer=0 enthält muß 
      ..mit einer vereinfachten Importroutine gearbeitet werden
      ..ob die Importroutine nicht korrekt arbeitet, 
      ..wenn man nur über die Record-Nummer geht anstelle der Lfd weiß ich 
      ..derzeit nicht sicher.
      ..Bei einfacheren Strukturen sicherlich, bei komplexen
      ..Verknüpfungen muß noch getestet werden
      IF FileSize( nDB)>0, GetField( nDB, LabelNo( nDB,"Laufende_Nummer"))="0"
       Message("Die Backupdatei erhält einen Eintrag mit
       Laufender_Nummer=0"+CHR(13)+"Die Einträge werdenkorrigiert","Warnhinweis zu
       "+DBNAME(nDB))
       nRec := FirstRec( nDB)
       WHILE nRec >0
        ReadRec( nDB, nRec)
        Datensatz_anhängen(nDat, nDB)
        nRec := NextRec( nDB)
       END
      ELSE
       nRec := FirstRec( nDB)
       i := 0
       WHILE nRec >0
        ReadRec( nDB, nRec)
        aLfd[i] := VAL( GetField( nDB, LabelNo( nDB, "Laufende_Nummer")))
        i := i+1
        nRec := NextRec( nDB)
       END
       aLfd[i] := 0
       i := 0
       WHILE aLfd[i] >0
        ReadRec( nDB, FindRec(nDB, STR( aLfd[i]),IndName( nDB, 0)))
        Datensatz_anhängen(nDat, nDB)
        i := i+1
       END
       CloseDB(nDB)
      END
     ELSE
      Message("kann Datei nicht öffnen",cDat)
     END 
    ENDPROC

    PROCEDURE Alte_Einträge_löschen( nDat : REAL)
    ..01.12.1999 / Götz
     Showwait("Alte Einträge werden entfernt")
     ClearDat( nDat )
     WHILE FileSize( nDat )>0
      Delrec( nDat , FirstRec( nDat ))
     END
     SetAuto( nDat ,1)
    ENDPROC

    procedure Programm_aktuallisieren
    ..01.12.1999 / Götz
     VarDef nRev, nDatei, nRec, nFI,j : REAL
     VarDef nMaxFile : REAL
     VarDef aLfd : REAL[5000]
     VarDef c : STRING
     nMaxFile := Maxfile
     IF ISFILE("UPDATE.INI")=0
      HALT
      Message("UPDATE.~NI wird zurück in UPDATE.INI umbenannt","Update wird
      fortgesetzt")
      Rename("UPDATE.~NI","UPDATE.INI")
     END
     nFI := Reset("UPDATE.INI")
     c := ReadLn(nFI)
     c := LTRIM(RTRIM( c[5,10] ))
     nRev := VAL(c)
     Close(nFI) 
     Showwait("Ihr Programm wird aktuallisiert"+CHR(13)+"Revision"+STR(nRev))
     nDatei := 1
     REPEAT
      Showwait("Aktuallisiere "+DBNAME( nDatei))
      IF ISFILE(BaseDir+"BACKUP\"+DBNAME(nDatei))=1
       Alte_Einträge_löschen(nDatei)
       Daten_einlesen( nDatei, BaseDir+"BACKUP\"+DBNAME(nDatei))
      END
      nDatei := nDatei+1
     UNTIL nDatei > nMaxFile
     Rename("UPDATE.INI","UPDATE.~NI")
     Hidewait
    endproc

  • **

    PROCEDURE Editieren( cField : STRING)
    ..01.12.1999 / Götz
    ..ermöglicht die Bearbeitung des Datenfeldes, welches als cFieldübergeben wird
     ReadRec( FileNr, RecNr(FileNr))
     T-Eingabe := GetField(FileNr, LabelNo( FileNr,cField))
     IF Input(cField)=1
      SetField(FileNr, LabelNo( FileNr,cField),T-Eingabe)
      WriteRec( FileNr, RecNr(FileNr))
      ATTACH
     END
    ENDPROC

    PROCEDURE Neueingabe
    ..01.12.1999 / Götz
     VarDef nRec : REAL
     T-Eingabe := ""
     VarDef cField, cLfd : STRING
     cField := IndDef(FileNr,1)
     cField := cField[1,POS(":",cField) -1]
     ReadRec( FileNr, 0)
     IF Input( cField,"Neueingabe")=1
      SetField( FileNr, LabelNo( FileNr, cField),T-Eingabe)
      IF GetField( FileNr,LabelNo( FileNr, cField))#""
       nRec := FileSize( FileNr)+1
       WriteRec( FileNr, nRec)
       SetSortOrder( IndName( FileNr,1))
       ShowRec( nRec)
      END
     END
    ENDPROC

    PROCEDURE Datensatz_Löschen
    ..01.12.1999 / Götz
    ..Löscht den aktuellen Datensatz nach Rückfrage
    ..als Feldinhalt wird der Inhalt des ersten Feldes aus den ID-Indexangezeigt
     VarDef nRec : REAL
     VarDef cField, cLfd : STRING
     ReadRec( FileNr, RecNr( FileNr))
     nRec := RecNr( FileNr)
     cField := IndDef(FileNr,1)
     cField := cField[1,POS(":",cField) -1]
     cLfd := GetField( FileNr, LabelNo( FileNr, "Laufende_Nummer"))
     IF Message(cField+" : "+GetField(FileNr,LabelNo(FileNr,cField)),"Eintrag wird
      unwiderruflich entfernt!",3)=6
      DelRec( FileNr, FindRec( FileNr,cLfd, IndName( FileNr, 0)))
      SetSortOrder( IndName( FileNr,1))
      ShowRec( nRec)
     END
    ENDPROC


  • Topic Verzeichnis mit Unterverzeichniss erstellen Kapitel easy Funktionsbibliothek
    Beschreibung:
    Ein Verzeichnis mit Unterverzeichniss wird in in Zwischenschritte erstellt.

    Procedure MakeNewDir(sDir : String) : Real;
    ..#erstellt ein Verzeichnis mit Unterverzeichniss in Zwischenschritte
    ..#Parameter:
    ..#sDir : Verzeichnis welches erstellt werden soll
    ..#Returnwert:
    ..#0 = Ok, 1 = Fehler
    ..#Bespielaufruf:
    ..#Message(Str(MakeNewDir("D:\XXX\YYY\Z\123")));

     Vardef nRT, i : Real;
     Vardef sTmpDir : String;

     ..keine angabe
     ?sDir = "" / Return 1
     ?sDir[Length(sDir)] <> "\"/ sDir := sDir + "\";
     sTmpDir := "";
     i := 1;
     While i <= Length(sDir)
      ..Zwischenverzeichnis erstellen
      If sDir[i] = "\"
       nRT := MakeDir(sTmpDir);
       sTmpDir := sTmpDir + sDir[i];
      Else
       sTmpDir := sTmpDir + sDir[i];
      End
      i := i + 1;
     End
     If IsFile(sTmpDir + "NUL")
      ..Message(sTmpDir + " ist da.");
      Return 0
     Else
      ..Message(sTmpDir + " ist NICHT da.");
      Return 1
     End
    Endproc


    Topic Löschen angekoppeler Daten Kapitel easy Funktionsbibliothek
    Beschreibung:
    Löschen angekoppelte Datensätze.

    Procedure LöscheKoppeldaten;
    ..#
     Link(TABELLE, SetMark(TABELLE, RecNr(TABELLE)));
     If NMarks(TABELLE) > 0
      Access(TABELLE, "Markierung");
      While ReadRec(TABELLE, RecNr(TABELLE))
       DelRec(TABELLE, RecNr(TABELLE));
      End
     End
    Endproc


    Topic EURO Kalkulator Kapitel easy Funktionsbibliothek
    Beschreibung:
    Ein einfachen Euroumrechner. Hierzu muß in eine System-Tabelle das Feld UmrechnungsfaktorZuEURO definiert sein.

    Procedure EUROKalk
    ..#ein einfachen euro <> dm Umrechner
     Vardef nRT, nWertEin : Real;
     Vardef sStr : String;

     ReadRec(SYSTEM, 1);
     T-Eingabe := "";
     nRT := Input("Zahl eingeben. Beenden mit EUR oder DM","EUROKalk");
     ?nRT = 0 / Return
     ?T-Eingabe = "" / Return
     T-Eingabe := Upper(T-Eingabe)
     ..#euro zu dm
     If T-Eingabe hat "EUR"
      sStr := T-Eingabe[1, Pos("EUR", T-Eingabe) - 1];
      sStr := RTrim(sStr);
      nWertEin := Val(sStr) * SYSTEM.UmrechnungsfaktorZuEURO;
      Message(T-Eingabe + " = " + Str(nWertEin, 1,5) + " DM", "EUROKalk");
      Return
     End
     ..#dm zu euro
     If T-Eingabe hat "DM"
      sStr := T-Eingabe[1, Pos("DM", T-Eingabe) - 1];
      sStr := RTrim(sStr);
      nWertEin := Val(sStr) / SYSTEM.UmrechnungsfaktorZuEURO;
      Message(T-Eingabe + " = " + Str(nWertEin, 1, 5) + " EUR","EUROKalk");
      Return
     End
     ..#dm zu euro wenn keine währung angegeben
     sStr := RTrim(T-Eingabe);
     nWertEin := Val(sStr) / SYSTEM.UmrechnungsfaktorZuEURO;
     Message(T-Eingabe + " = " + Str(nWertEin, 1, 5) + " EUR", "EUROKalk");
     Return
    Endproc


    Topic Zeile in Worte trennen und als Parameter zurückgeben Kapitel easy Funktionsbibliothek
    ..#
    ..#Prozedur "ParseInWords"
    ..#ersten Parameter den String aufnimmt, der analysiert werden soll
    ..#zweiten Paramter einen String mit all den Zeichen, die als Worttrenner gewertet werden sollen
    ..#dritten Parameter einen Array von Strings, der mit den gefundenen Wörtern gefüllt wird.
    ..#(c)Lüko Willms

    PROCEDURE ParseInWords(zuAnalysieren, Trennzeichen : STRING; VAR Wörter : STRING[]) : REAL
    VARDEF nWords, nChars : REAL
    VARDEF Ist_im_Wort : REAL

    ClrArray(Wörter)
    nWords := 0
    nChars := 1
    Ist_im_Wort := Falsch

    WHILE nChars 0
    IF Ist_im_Wort 
    Ist_im_Wort := Falsch
    END IF
    ELSE
    IF NOT Ist_im_Wort
    Ist_im_Wort := Wahr
    nWords := nWords + 1
    END IF
    Wörter[nWords] := Wörter[nWords] + zuAnalysieren[nChars]
    END IF 
    nChars := nChars + 1
    END WHILE 
    RETURN nWords
    ENDPROC


    Topic Strings bearbeiten Kapitel easy Funktionsbibliothek
    Beschreibung:
    Prozeduren um Strings zu bearbeiten:

    Kapitalschreibweise
    PROCEDURE SetCapital(sStr : STRING) : STRING;
    ..#erste Buchstabe als Grossbuchstabe
    ..#Parameter:
    ..#sStr = String der bearbeitet werden soll
    ..#Returnwert:
    ..#angepasster String
     ?sStr = "" / RETURN ""
     RETURN Upper(sStr[1,1]) + sStr[2,255]
    Endproc

    Umwandlung in Grossbuchstaben
    PROCEDURE SetUpper(sStr : STRING) : STRING;
    ..#Umwandlung in Großbuchstaben
    ..#Parameter:
    ..#sStr = String der bearbeitet werden soll
    ..#Returnwert:
    ..#angepasster String
     RETURN Upper(sStr)
    Endproc

    Umwandlung in Kleinbuchstaben
    PROCEDURE SetLower(sStr : STRING) : STRING;
    ..#Umwandlung in Kleinbuchstaben
    ..#Parameter:
    ..#sStr = String der bearbeitet werden soll
    ..#Returnwert:
    ..#angepasster String
     VARDEF Le, P : REAL;
     VARDEF W1 : STRING;
     Le:=Length(sStr);
     P:=1; W1:="";
     WHILE P <= Le
      IF ASC(sStr[P,1]) >= 65 and ASC(sStr[P,1]) <= 90
       W1:= W1+CHR(ASC(sStr[P,1])+32)
       ELSIF sStr[P,1]="Ä"
        W1:= W1+"ä"
       ELSIF sStr[P,1]="Ö"
        W1:=W1+"ö"
       ELSIF sStr[P,1]="Ü"
        W1:= W1+"ü"
       ELSEIF W1:=W1+sStr[P,1] 
       ..ELSE W1:=W1+sStr[P,1] 
      END
     P:= P+1
     END
     RETURN W1
    EndProc 

    Mittelteil eines STRINGs herausfiltern
    Es gibt in EASY kann Befehl wie midstr bzw. substr um einen Mittelteileines STRINGs herauszufilten, aber in VDP besteht ein STRING aus eine Zeichenfolgevon max. 255 Zeichen. Es können Teile aus einem STRING herausgefiltert werden, indemdie Startpositionun
    Mittels Pos kann die Position eines Zeichens bzw. Zeichenketteermittelt werden. 
    Beispiel Easy Prozedur:

    PROCEDURE MidStr(sStr : STRING; nPos : REAL; nLen : REAL) : STRING;
    ..#Teil aus String rausfiltern
    ..#Parameter:
    ..#sStr = String der bearbeitet werden soll
    ..#nPos = Anfangsposition
    ..#nLen = Länge des Strings der raus gefiltert werden soll
    ..#Returnwert:
    ..#angepasster String

     ?sStr = "" / RETURN sStr
     ?nPos <= 0 / RETURN sStr
     ?nLen <=0 Or nLen > 255 / RETURN sStr
     RETURN sStr[nPos, nLen]
    Endproc

    STRING mit Leerzeichen füllen
    PROCEDURE FillStr( sStr : STRING; n : REAL) : STRING;
    ..#String mit n Leerzeichen füllen
    ..#Parameter:
    ..#sStr = String der bearbeitet werden soll
    ..#n = Anzahl Leerzeichen
    ..#Returnwert:
    ..#angepasster String

     sStr := sStr + nTimes(" ",n)
     RETURN sStr[1,n]
    ENDPROC

    Sucht den xten Teilstring aus einem String mit Trennzeichen(=Delimiter)
    PROCEDURE TakeString(sStr, cSep : STRING; nIndex:REAL) : STRING;
    ..#xten Teilstring aus einem String mit Trennzeichen (=Delimiter)suchen
    ..#Parameter:
    ..#sStr = String der bearbeitet werden soll
    ..#cSep = Trennzeichen
    ..#nIndex = Position
    ..#Returnwert:
    ..#angepasster String

     VARDEF x,y,z : REAL
     x := 1;
     z := 1; 
     y := SCAN(cSep, sStr) + 1;
     WHILE z:=z+1 <= nIndex UND z <= y
       x:= x + POS(cSep, sStr[x,255])
     END
     RETURN sStr[x,POS(cSep, sStr[x,255]) - 1]
    ENDPROC

    Ersetzt Umlaute in einem String (1.Möglichkeit)
    Procedure ReplaceUmlaute(sStr : String) : String
    Vardef sTmp : String;
    Vardef i : Real;

    i:=1; sTmp:="";
    While i <= Length(sStr)
    If sStr[i] in ["Ä","Ö","Ü","ä","ö","ü","ß","|"]
    ?sStr[i] = "Ä" / sTmp := sTmp + "AE"; 
    ?sStr[i] = "Ö" / sTmp := sTmp + "ÖE";
    ?sStr[i] = "Ü" / sTmp := sTmp + "ÜE";
    ?sStr[i] = "ä" / sTmp := sTmp + "ae";
    ?sStr[i] = "ö" / sTmp := sTmp + "oe";
    ?sStr[i] = "ü" / sTmp := sTmp + "ue";
    ?sStr[i] = "ß" / sTmp := sTmp + "sz";
    Else
    sTmp := sTmp + sStr[i];
    End
    i := i + 1;
    End
    Return OemToAnsi(sTmp)
    Endproc

    Ersetzt Umlaute in einem String (2.Möglichkeit)
    Procedure ReplaceUmlaute(sStr : String) : String
    sStr := Exchange(sStr, "Ä", "AE");
    sStr := Exchange(sStr, "Ö", "ÖE");
    sStr := Exchange(sStr, "Ü", "ÜE");
    sStr := Exchange(sStr, "ä", "ae");
    sStr := Exchange(sStr, "ö", "oe");
    sStr := Exchange(sStr, "ü", "ue");
    sStr := Exchange(sStr, "ß", "sz");
    Return OemToAnsi(sStr)
    Endproc


    Topic Verzeichnis erstellen Kapitel easy Funktionsbibliothek
    Beschreibung:
    Verzeichnis erstellen. Diese Prozedure bietet die Möglichkeit Unterverzeichnisse zu
    erstellen, wo bei das Rootverzeichnis nicht vorhanden sein muß.
    Das im Gegensatz zu der Standardfunktion MakeDir.

    Procedure MakeNewDir(sDir : String) : Real;
    ..#erstellt ein Verzeichnis in Zwischenschritte
    ..#Parameter:
    ..#sDir : Verzeichnis welches erstellt werden soll
    ..#Rückgabe:
    ..#1 = Ok, 0 = Fehler
     Vardef nRT, i : Real;
     Vardef sTmpDir : String;

     ..keine angabe
     ?sDir = "" / Return 1
     ?sDir[Length(sDir)] <> "\"/ sDir := sDir + "\";
     sTmpDir := "";
     i := 1;
     While i <= Length(sDir)
      ..Zwischenverzeichnis erstellen
      If sDir[i] = "\"
       nRT := MakeDir(sTmpDir);
       sTmpDir := sTmpDir + sDir[i];
      Else
       sTmpDir := sTmpDir + sDir[i];
      End
      i := i + 1;
     End
     If IsFile(sTmpDir + "NUL")
      ..Message(sTmpDir + " ist da.");
      Return 1
     Else
      ..Message(sTmpDir + " ist NICHT da.");
      Return 0
     End
    Endproc


    Topic Prüfen ob eine Tabelle schon geöffnet wurde Kapitel easy Funktionsbibliothek
    Beschreibung:
    Prüft ob eine Tabelle schon geöffnet wurde.

    PROCEDURE IsDBOpen(sDBName : STRING) : REAL;
    ..#check ob eine Tabelle schon geöffnet ist, wenn ja Rückgabe desfilenr
    ..#Parameter:
    ..#sDBName = Verzeichnis und Name der Tabellendatei
    ..#Retrunwert:
    ..#0 = DB ist nicht geöffnet, sonst FileNr des DBs

     VARDEF i, nIsOpen : REAL;
     i:=0;
     nIsOpen := 0;
     While i:=i+1 <= MaxFile
      ?Upper(sDBName) hat Upper(DBDir(i) + DBName(i)) / nIsOpen := i
     End
     RETURN nIsOpen
    ENDPROC


    Topic Alle Einträge einer Tabelle mit angekoppelter Tabelle(n) löschen Kapitel easy Funktionsbibliothek
    Beschreibung:
    Löscht alle Einträge einer Tabelle mit angekoppelter Tabelle.

    Procedure DeleteAllEntries
    ..#alle Einträge einer Tabelle löschen
    ..#Parameter:
    ..#Returnwert:

     ..erst mal alle demarkieren
     DelMarks(TABELLE);
     ..Beispiel: alle Felder
     Link(TABELLE , SetMark(TABELLE, RecNr(TABELLE) ) );
     ..Beispiel:markiere alle angekoppelte Datensätze
     Link(TABELLE.koppelfeld = TABELLE2.Laufende_Nummer , SetMark(TABELLE,   RecNr(TABELLE) ) );
     nCnt := NMarks(TABELLE);
     ..setze zugriff auf markierung
     If nCnt > 0
      Access(TABELLE, "Markierung")
      WHILE ReadRec(TABELLE, FirstRec(TABELLE) )
       DelRec(TABELLE, RecNr(TABELLE) );
      END
      If NMarks(TABELLE) = 0
       Message("Alle Prozeduren vom Modul " + TABELLE.Modulname.Dateiname +" gelöscht.", "Hinweis");
      End
     End
    Endproc



    Topic Tempverzeichnis auf das Windowsverzeichnis setzen Kapitel easy Funktionsbibliothek
    Beschreibung:
    setzt das Tempverzeichnis auf das Windowsverzeichnis.

    Procedure pSetTMPDir(nDummy : Real) : String;
    ..#setzt ein Tempverzeichnis auf dem Windowsverzeichnis.
    ..#Ist WINDIR nicht vorhanden, dann auf BaseDir, welches 
    ..#das Homeverzeichnis des Projektes ist
    ..#Beispiel: DEF TMPFILE = pSetTMPDir(0) + "tempfile.txt";
    ..#Returnwert:
    ..#Windows oder Projektverzeichnis

    ?GetEnv("WINDIR") <> "" / Return GetEnv("WINDIR")
    ?GetEnv("WINDIR") = "" / Return BaseDir
    Endproc


    Topic Ein links abgeschnittenen String in ShowWait zeigen Kapitel easy Funktionsbibliothek
    Beschreibung:
    Zeigt ein links abgeschnittenen String. Wird für Showwait verwendet.
    Abgeschnittener Teil wird als ... gezeigt.

    Procedure pShowLine(sLine : String; nMaxLength : Real) : String;
    ..#Zeigt ein links abgeschnittenen String. Wird für Showwait verwendet.
    ..#Abgeschnittener Teil wird als ... gezeigt.
    ..#Parameter:
    ..#sLine = dargestellte Information
    ..#nMaxLength = max. Länge des Strings
    ..#Returnwert
    ..#angepasster String

     ?nMaxLength < 0 Or nMaxLength > 255 / nMaxLength := 255
     If Length(sLine) > nMaxLength
      Return "..." + sLine[Length(sLine) - nMaxLength, 255]
     Else
      Return sLine
     End
    Endproc


    Topic Eine Dateiname in den Teilen Pfad, Name und Erweiterung aufsplitten Kapitel easy Funktionsbibliothek
    Beschreibung:
    Eine Dateiname in den Teilen Pfad, Name und Erweiterung aufsplitten

    Procedure SplitFilename(sFilename : String; Var sPath, sName, sExt :String);
    ..#Dateiname in den Teilen Pfad, Name und Erweiterung aufsplitten
    ..#Parameter:
    ..#sFilename = kompletter Dateiname
    ..#Returnwert:
    ..#sPath = Pfad
    ..#sName = Dateiname
    ..#sExt = Dateierweiterung
     Vardef i, j : Real;
     nLoop(i, Length(sFilename) - 1, Sel(sFilename[i + 1] = "\", j := i+1))
     sPath := sFilename[1, j];
     sName := sFilename[j + 1, 255]; 
     sExt := ""
     j := Pos("