Rainer Becker
Deutsche FoxPro User Group
Reportparameter
Schliessen von Fenstern
Programmkopfzeilen
Clipboard löschen
Fehlerbehandlung setzen
Freier Hauptspeicher
Schaltjahrberechnung
Wertübergabe Taschenrechner
Fehlermeldung zum Eingabefeld
Nächster Arbeitstag
Drucker prüfen
Mehrere Apps generieren
Weiter mit Escape
Doppelte Programmnamen
Felder ohne Alias
Temporäre Dateien des Linkers
Escape bei Memofeldern
Wahrheitskonstanten
Quartalsanfang
Effektive Dateigrösse
Aufruf von Druckertreibern
Ausklammern aus dem Projekt
Inhalt Resourcedatei
Resourcedatei im Netzwerk
Was alles im EXE fehlt
Resource Exhausted
Netzwerk-Konfiguration
Gelöschte Sätze suchen
Drucker nicht bereit
FP-Umgebungsvariable
Praktisches Arbeiten
Wie oft haben Sie sich schon geärgert, daß Sie bei neuen Masken, Menüs und Reports ständig die selben Standardeinstellungen vornehmen müssen (z.B. Farbschemas, Seitenlänge, Zeilenbreite usw.)? Es wäre doch schön, wenn man diese Grundeinstellungen abspeichern könnte, so daß sie z.B. bei jedem neuen Report automatisch vorhanden sind. Öffnen Sie ganz einfach einen neuen Report mit "CREATE REPORT". Nun definieren Sie alle Einstellungen, wie Rahmen, Kopf- und Fußzeilen, Seitennummern und Datumsfelder. Und nun wählen Sie im Menü "DATEI" die Funktion "SPEICHERN UNTER..." und geben als Namen "NEU" an. Das war's! Denn jedesmal, wenn Sie CREATE REPORT eingeben, erstellt FoxPro eine Zwischendatei mit dem Namen NEU. Und wenn diese schon vorhanden ist, wird sie natürlich wie jeder andere Report auch eingelesen. Bei Verwendung der englischen Version müssen Sie unter dem Namen "UNTITLED" abspeichern. Wichtig ist auch, daß diese Vorgaben immer nur für das laufende (SET DEFAULT) Verzeichnis gelten.
In Abwandlung des Tricks eine kurze zusätzliche Erläuterung. Der Trick mit der Vorgabedatei funktioniert natürlich nicht nur bei Berichtsdateien sondern genauso auch bei den anderen Werkzeugen von FoxPro. Insbesondere praktisch ist das Anlegen eines Programmes NEU.PRG im aktuellen Verzeichnis mit Hilfe eines einfachen Texteditors. Hier hinein schreibt man seinen Standardprogrammkopf (siehe die Programmbeispiele hier im Newsletter) mit Copyright, Autorenname und so weiter. Bei jedem Neuanlegen eines Programmes hat man dann automatisch einen entsprechenden Programmkopf und muß nicht jedesmal die Zeilen aus einem anderen Dokument hineinkopieren oder gar neu eintippen.
Wenn man die Standardmenüleisten von FoxPro zum Teil in seine eigene Anwendung übernimmt, stehen dem Programmbenutzer viele kleine nette Funktionen wie der Kalender, ASCII- und Sonderzeichentabelle und ein umwerfendes Puzzle zur Verfügung. Leider kostet jedes dieser Fensterchen 10 Kilobyte Hauptspeicher, außer die Hilfemaske, welche fast 40 KB verbraucht. Wenn ein Benutzer alle der zur Verfügung stehenden Systemfenster öffnet und verkleinert in eine Ecke stellt, weil das so praktisch ist, fehlen der Anwendung glatte 100 KB Speicherplatz. Außerdem kann es bei der Programmbeendung passieren, daß man zwar alles aufgeräumt hat, aber immer noch eines dieser Systemfenster offen ist und von daher die Applikation nicht terminiert (außer bei QUIT). Vor dem Aufrufen von speicherhungrigen Funktionen wie BROWSE, SELECT oder RUN sowie vor dem Beenden der Programmes frage ich deshalb bei meinen Anwendungen nacheinander alle Systemfenster mit der Funktion WEXIST ab und schließe die Systemfenster ggfs. mit der Funktion DEACTIVATE WINDOW. In der englischen Version und in der Dokumentation von FoxPro sowie ab 2.5b werden die Bezeichnungen "Calendar", "Filer", "Special", "Help", "ASCII" und "Puzzle" verwendet. Die Systemfensternamen lauten in der deutschen Version 2.5a "Kalender", "Puzzle", "Dateimanager","Hilfe", "Sonderzeichen", "ASCII Tabelle" und "Rechner". Man muß also nacheinander IF WEXIST("<Fenster>") + DEACTIVATE WINDOW <Fenster> mit den korrekten deutschen Bezeichnungen aufrufen, um die Systemfenster wirklich wegzubekommen.
Die Systemspeichervariable _CLIPTEXT enthält das "Clipboard". Alle mit Textfunktionen (Ausschneiden, Kopieren, Einfügen) bearbeiteten Textabschnitte werden in dieser Variablen abgespeichert. Die abgespeicherten Textabschnitte werden nur durch den zu diesem Zeitpunkt vorhandenen freien Speicher von FoxPro begrenzt. Leider kennt das Clipboard keine andere Größenbegrenzung und kann vom Programmierer auch nicht limitiert werden. Da es außerdem keine temporären Dateien verwendet, sondern nur im Hauptspeicher läuft, kann es beim Ausschneiden oder Kopieren von sehr großen Textabschnitten in die Ablage durch den Anwender zu ernsthaften Speicherproblemen kommen. Deshalb sollte man bei allen Funktionen, die auch nur ein Minimum an Speicher benötigen, die Zeile "_CLIPBOARD=LEFT(CLIPBOARD,1000)" einfügen, welches die Clipboardgröße auf ein Kilobyte beschränkt. Natürlich kann man noch viele andere Sachen mit dem Clipboard anstellen. Beispiele wären das Umwandeln von Groß- in Kleinbuchstaben und umgekehrt oder das Ersetzen von Zeichen durch andere. Diese Funktionen kann man dann in einem erweiterten Textmenü dem Benutzer anbieten.
Fast jeder verwendet in seinen Programmen eine Fehlerbehandlungsroutine - und sei es nur eine rudimentäre. Notfalls kann man immer noch von CompuServe die Datei FOX2EROR laden, welche eine einfache Fehlerbehandlungsroutine zur Verfügung stellt. Bei bestimmten Funktionen allerdings ist es sinnvoll, eine eigenständige Fehlerroutine zu verwenden, statt die allgemeine Fehlerbehandlung aufzurufen. Insbesondere wenn man dem Benutzer erlaubt, Berichtsdateien zu verändern oder gar neu zu erstellen, sollte man beim Ausführen dieser Berichtsdateien alle Fehler grundsätzlich abfangen und den Anwender höflich um Überarbeitung seiner Berichtsdatei bitten. Damit ein reibungsloses Umschalten zwischen spezieller und allgemeiner Fehlerbehandlung möglich ist, sollte der allgemeine Aufruf in eine eigene Prozedur getan und beim Programmstart aufgerufen werden. Diese kleine Routine könnte wie folgt aussehen:
Mit "ON ERROR DO <SpezialFehler>" ruft man dann die spezielle Fehlerbehandlung auf und setzt sie hinterher mit "=SETERROR()" wieder zurück. Dann kann man später ohne Probleme die Aufrufparameter für die Fehlerroutine ändern ohne an tausend Stellen im Programm nach "ON ERROR" suchen zu müssen.
Unter dem Namen "RamAvail" lasse ich mir von einer Mini-Funktion den Wert "val(sys(1001))-val(sys(1016))" zurückgeben. Dies ist der tatsächlich noch freie Hauptspeicher innerhalb von FoxPro. Die normale "MEMORY()"-Funktion gibt leider nur den freien DOS-Speicher unterhalb von 640 Kilobyte zurück und nützt einem meist überhaupt nichts. Mit folgender Funktion prüfe ich dann den vorhandenen Hauptspeicher vor dem Aufrufen von Speicherplatzaufwendigen Funktionen:
Natürlich kann man sich den freien Speicherplatz auch gleich mit 1024 multiplizieren lassen um von Vorneherein Kilobytes statt Bytes zu erhalten.
Es gibt bereits tausende von Schaltjahr-Routinen. In FoxPro kann man es sich allerdings etwas einfacher machen, weil es intern bereits Schaltjahre berechnen kann. Aus unbekannten Gründen wurde aber die eigentliche Schaltjahrabfrage nicht als Funktion zur Verfügung gestellt. Der nachfolgende Routine kann man wahlweise ein Datum, eine Jahreszahl oder nichts (=Tagesdatum) übergeben - sie liefert ein .T. für ein Schaltjahr zurück:
Die letzten drei Zeilen der Routine kann man natürlich in eine einzige Zeile mit dem "Return" zusammenfassen.
Der Taschenrechner im Systemmenü von FoxPro läßt sich sehr leicht in eigene Anwendungen einbauen, in dem man eine entsprechende Leiste mit dem Systemmenünamen des Rechners in sein eigenes Menü integriert. Zusätzliche Funktionalität erhält man aber durch nachfolgende kurze Routine. Sofern der Benutzer in einer Maske ist und gerade auf einem numerischen Feld steht, wird der Wert des Feldes automatisch in den Taschenrechner übernommen:
Zusätzlich könnte man unter einer weiteren Menüposition das Kopieren des Taschenrechnerwertes in das Clipboard _CLIPTEXT anbieten. Dann kann der Benutzer den berechneten Wert zurück in das numerische Feld in der Maske übernehmen.
Häufig arbeiten viele Menschen am Wochenende - viele Programmierer können davon ein Liedchen singen. Auf Rechnungen, Lieferscheinen und diversen offiziellen Ausdrucken, Listen und Formularen ist es aber dennoch unerwünscht, ein Wochenenddatum auszudrucken. Bei der Erfassung von Zahlungseingängen wiederum ist es völlig unmöglich, daß ein Geldeingang am Wochenende erfolgt. Von daher wird eine kleine Funktion zur Berechnung des nächsten Werktages sowohl in Masken als auch in Berichten häufig benötigt. Hier die einfache Version zum Einbau in eine Berichtsdatei:
Wenn Sie zum Beispiel ein Feld Rechnungsdatum RECHNUNG.RECHDATUM haben, verändern Sie das Ausdruckfeld im Report in NXTWORKDAY(RECHNUNG.RECHDATUM). Die Funktion kann man noch erweitern mit einem Zugriff auf eine Feiertagsdatei.
Bei der Ausgabe von Berichten muß man mit "PRINTSTATUS" die Druckbereitschaft abfragen. Wenn der Drucker während der Berichtsausgabe auf einmal nicht mehr druckbereit ist, muß man in einer Fehlerroutine warten, bis der Drucker bereit ist oder der Benutzer den Vorgang abbricht. Nachfolgende Funktion prüft alle zwanzig Sekunden den Drucker und liefert .T. zurück, sofern weitergedruckt werden soll. Ist der Drucker nicht bereit und bricht der Benutzer mit <Escape> ab, wird .F. zurückgegeben:
Bei Arbeiten an mehreren Projektdateien oder an einem auf mehrere Projektdateien verteilten Programm, spart der Befehl BUILD ausgesprochen viel Zeit. Zwar kann man sich alle Applikationen in einer eigenen Projektdatei zusammenfassen und dort jeweils anwählen und neu erstellen lassen. Wesentlich einfacher aber ist das Erstellen einer Datei mit allen zusammengehörenden Projekten oder mit einem Mini-Programm welches nacheinander die folgenden Zeilen aufruft:
Diese kleine Funktion kann man natürlich noch um einen Parameter und ein paar Zeilen für das automatische Erstellen von EXE-Dateien erweitern (BUILD EXE mit dem Zusatzparameter EXTENDED oder STANDALONE).
Häufig ist der einfache "WAIT WINDOW"-Befehl zum Anzeigen einer Erläuterung nicht ausreichend. Denn leider reagiert dieser Befehl auf alle Tastendrücke. Möchte man den Benutzer also auf etwas hinweisen, während er gerade bei der Eingabe ist, muß man schon auf selten benutzte Tasten ausweichen, damit der Text gelesen und nicht versehentlich gleich wieder "weggedrückt" wird. Man könnte dafür z.B. die Escape-Taste verwenden:
Man sollte vorher "SET ESCAPE OFF" gesetzt haben. In meinen eigenen Anwendungen ist dies prinzipiell der Fall. Außerdem könnte man vor der eigentlichen Textanzeige noch einen Ton mit "CHR(7)" einbauen.
Sofern man nicht in der Konfigurationsdatei von FoxPro einen sofort auszuführenden Befehl oder ein sofort auszuführendes Programm festlegt, befindet man sich nach dem Start im aktuellen FoxPro-Verzeichnis. Da man seine Projekte und Programmdateien aber normalerweise in einem anderen Verzeichnis hat, erleichtert es die tägliche Arbeit ungemein, wenn man sich für jedes Projekt eine kleine Startdatei schreibt. Dieses Startprogramm setzt dann die Pfade und ähnliches für das Projekt und ruft es ggf. auch gleich auf. Vermeiden sollte man allerdings, daß dieses Hilfsprogramm den gleichen Namen hat wie eine der Programmdateien des angewählten Projekts. Ruft man erst das Hilfsprogramm auf und möchte dann gleich danach eine andere Programmdatei im neuen Verzeichnis mit dem gleichen Namen aufrufen, wird statt dem neuen Programm das alte nochmals gestartet. Selbst wenn zwischendurch das Verzeichnis gewechselt oder CLEAR ALL bzw. CLOSE ALL eingegeben wurde, ist der Programmpufferspeicher von FoxPro immer noch in Betrieb und enthält die alte Programmdatei. Erst wenn man MODI COMM eingibt oder ein anderes Programm startet, wird der Pufferspeicher wieder geleert und der nächste Versuch startet dann das richtige Programm. Dieses Verhalten kann man mit dem Befehl CLEAR PROGS umgehen - dadurch wird nämlich der Pufferspeicher gelöscht.
Vielleicht ist es Ihnen auch schon einmal passiert. Sie sind in einer Maske und ganz plötzlich tritt der Fehler auf "Variable nicht gefunden" - und zwar mit einer Variablen die in der aktuellen Maske überhaupt nicht enthalten ist. In diesem Fall ist folgendes passiert: In Ihrer aktuellen Maske wurde in einer VALID-Funktion der Befehl SHOW GETS aufgerufen. Dieser ruft für alle auf dem Bildschirm befindlichen Masken die SHOW-GET-Routine auf. In dieser Routine wiederum werden vom Maskengenerator alle SAY-Befehle wiederholt, für die Sie bei dem Maskenentwurf das Feld "[ ] Aktualisieren" angekreuzt haben. Haben Sie auch nur bei einem einzigen SAY in irgendeiner Maske vergessen, den Datenbankalias mitanzugeben, so wird diese Variable als (wahrscheinlich nicht definierte) Speichervariable interpretiert, sofern nicht alle Masken mit der gleichen Datenbank arbeiten und Sie nicht für jede offene Datenbank ein SCATTER MEMVAR aufgerufen haben. Sofern man nicht mit SCATTER MEMVAR arbeitet, sondern immer direkt mit den Datenbankfeldern, darf man in keinem SAY-Feld den Datenbankalias vergessen.
In der Konfigurationsdatei "CONFIG.FP" kann man verschiedene Pfade für temporäre Dateien von FoxPro einstellen. Der Linker des Distribution Kits allerdings nimmt auf diese Einstellungen keinerlei Rücksicht. Er verwendet stattdessen die Umgebungsvariable TMP, welche Sie z.B. mit "SET TMP=C:\TEMP" in Ihrer AUTOEXEC.BAT-Datei definieren sollten. Dabei sind mehrere Feinheiten zu beachten. Zum einen schneidet der Linker keine Leerzeichen ab. Haben Sie also noch ein oder zwei Leerzeichen hinter dem Verzeichnisnamen eingegeben, so ist der Linker nicht lauffähig. Gleiches gilt, wenn die Umgebungsvariable auf ein nicht mehr existentes oder ein vorübergehen nicht erreichbares Laufwerk (z.B. im Netzwerk) zeigt. Sofern der Linker nicht arbeitet, sollten Sie also zuerst die Umgebungsvariable TMP mit GETENV("TMP") abfragen. Bei Nichtvorhandensein des genannten Verzeichnisses bei Pfadangaben in CONFIG.FP kommt übrigens auch FoxPro selbst ins Stolpern und bringt ggf. den Rechner zum Stillstand.
Im Maskengenerator kann man ganz elegant Memofelder einbauen. Über die Funktion ( ) EDIT kann man Memofelder mehrzeilig mit einer Rolleiste darstellen und TABs ein- oder ausschalten. Zusätzlich kann man eine Maximalzahl an zulässigen Zeichen festlegen. Alle Klauseln stehen zur Verfügung. Mit einer kleinen Ausnahme. Die VALID-Klausel funktioniert bei Memofeldern ein klein wenig anders. Zwar kann man auch hier das Feld eigentlich nur verlassen, wenn die VALID-Klausel .T. zurückgibt - aber da muß man das "eigentlich" betonen. Drückt ein Benutzer in diesem Fall die Taste ESCAPE so wird das Verbot der VALID-Klausel, daß Feld zu verlassen, einfach ignoriert! Wenn man sicher mit Memofeldern arbeiten möchte, muß man vor Betreten des Memofeldes, also spätestens in der WHEN-Klausel, den Befehl "ON ESCAPE *" eingeben. Sonst kann der Endanwender die VALID-Klausel umgehen und Daten eingeben, die Sie eigentlich nicht zulassen wollten.
Bei WHEN-Klauseln und VALID-Klauseln von Maskenfeldern möchte man häufig eine kurze Aktion oder Berechnung ausführen und trotzdem .T. zurückgeben. Damit man nicht extra eine Prozedur für diesen Zweck anlegen muß, kann man auch einfach folgende Funktion mit der gewünschten Berechnung oder Aktion als Parameter aufrufen:
Bei "FALSE" muß natürlich ".F." zurückgegeben werden. Ich verwende diese Primitivfunktionen auch gerne an Stellen im Sourcecode, an denen noch die korrekten Funktionsaufrufe fehlen - dann kann man immer gleich sehen, wo man noch weiterarbeiten muß.
Viele Berichte im Rechnungswesen und für die Geschäftsführung basieren auf quartalsweisen Berechnungen. Die nachfolgende Funktion ermittelt den Quartalsanfang für ein übergebenes Datum bzw. für das aktuelle Datum:
Die Funktion lebt von der richtigen Einstellung von DATE, nämlich "SET DATE GERMAN". Deshalb wird der alte DATE-Wert gesichert und später wieder zurückgesetzt. Man könnte über einen zusätzlichen Parameter noch das vorige und nächste Quartal bzw. das Quartalsende ermitteln lassen.
Sofern eine Datenbankdatei kopiert werden soll, benötigt man zur Überprüfung des freien Speicherplatzes auf dem Speichermedium die Größe der Datenbankdatei. Diese kann man durch folgende Formel berechnen:
Es wird der Datenbankkopf zu der Größe eines Datensatzes mal der Anzahl der Datensätze addiert. Dies gilt leider nur für Datenbanken ohne Indexdatei und ohne Memofelder.
Im Unterverzeichnis GOODIES\PDRIVERS von FoxPro wird die Applikation GENPD.APP mitgliefert. Mit diesem Programm kann man schnell und ohne Probleme den aktuellen Druckertreiber wechseln oder neue Druckertreiber definieren. Das Programm muß mit zwei Parametern aufgerufen werden. Der erste Parameter kann eine "1" oder eine "2" sein, der zweite Parameter kann leer sein oder den Namen eines Druckersets beinhalten. Die Fälle im Einzelnen:
1. Der Aufruf von DO GENPD.APP WITH 1,"" bringt eine Auswahlbox zum Setzen eines Druckersets. Der Cusorbalken steht auf dem Defaultdruckerset. Man kann Druckersets anlegen, bearbeiten, setzen und zum Default-Druckerset erklären. Letzteres wird in der Resource-Datei vermerkt.
2. DO GENPD.APP WITH 1,"LASER" lädt das Druckerset "LASER" in den Speicher und setzt es gleichzeitig als Default-Druckerset in der Resource-Datei. Auf dem Bildschirm wird nichts angezeigt.
3. Beim Aufruf DO GENPD.APP WITH 2,"" erscheint ebenfalls eine Auswahlbox mit den bei 1. genannten Möglichkeiten - allerdings kann man keine Defaulteinstellung speichern.
4. DO GENPD.APP WITH 2,"LASER" läßt ebenfalls die Auswahlbox wie bei 3. erscheinen. Allerdings steht der Cursorbalken nicht auf dem Defaultdruckerset sondern auf dem Set "LASER".
In den Fällen zwei bis vier kann man zusätzlich zur einfachen Auswahl in eine weitere Bearbeitungsmaske verzweigen. Für den Fall, daß die Resourcedatei "FPUSER.DBF" nicht vorhanden ist oder "SET RESOURCE OFF" gesetzt wurde, verhält sich "GENPD.APP" wie folgt:
5. Bei Übergabe von "1" erscheint statt dem Auswahldialog für Druckersets eine Maske zum Auswahl des effektiven Druckers und zum Einstellen einiger Druckerparameter. Wird im zweiten Parameter ein Name übergeben, wird dieser angezeigt, was aber ohne weitere Bedeutung ist.
6. Bei DO GENPD.APP WITH 2,"" erscheint die Meldung "Resource-Datei nicht verfügbar" unabhängig vom zweiten Parameter.
Das Programm GENPD.APP ist im Alltag außerordentlich nützlich. Man kann es in eine Projektdatei mit einbinden und beim Erstellen von EXE-Programmen sogar mit an den Endkunden ausliefern.
Alle in einem Programm aufgerufenen Menüs, Masken und Berichte werden automatisch in die Projektdatei mit aufgenommen. Mit Hilfe des Befehls EXTERNAL kann man auch in einer Makrosubstitution (mit "&<variable>", also nicht im Code erkennbar) aufgerufene Masken, Berichte, Menues usw. dem Projektmanager mitteilen. Daraufhin bindet der Projektmanager diese Dateien ebenfalls in das jeweilige Projekt mit ein. Häufig möchte man jedoch gerade das Gegenteil erreichen, damit das Projekt nicht überquillt von Standardmasken, Libraries und Funktionen, die man überall oder zumindest sehr häufig verwendet. Zum Beispiel kann man Libraries aus dem Projekt weglassen und stattdessen alle in der Library enthaltenen Funktionen als EXTERNAL ARRAY definieren. Wenn man jedoch Masken und Menüaufrufe von der Aufnahme ausklammern möchte, muß man DO ("MASKE.SPR") oder DO ("MENU.MPR") im Code verwenden. Da es sich dabei nicht um eine Makrosubstition sondern um eine - wesentlich schnellere - Auswertung eines Klammerausdrucks (siehe EVALUATE) handelt, ist der Geschwindigkeitsverlust sehr gering.
In der Resource-Datei "FOXUSER.DBF" werden alle Einstellungen des Benutzers verwaltet. Sofern "SET RESOURCE OFF" gesetzt wurde, kann man diese Datei wie jede andere Datenbank auch mit den normalen FoxPro-Befehlen öffnen und bearbeiten. Alle wesentlichen Daten erhält man mit dem Befehl "BROWSE FOR TYPE=[DATA] OR ID=[COLORSET]" angezeigt. In der Satzart "COLORSET" werden die Farbdefinitionen aufbewahrt. In der Satzart "PDSETUP" werden aller Druckerdefinitionen gespeichert. Die Default-Definition, die beim Start automatisch geladen wird, hat ein vorangestelltes "-" vor dem Namen. Unter "LBLLAYOUT" findet man alle Standarddefinitionen für Etiketten. Unter "DIARYDATA" werden alle Kalendereinträge gespeichert. Insbesondere wichtig ist noch der einmalig auftretende Datensatz "PROJDEFAULT". In diesem ist die Entwickleranschrift festgehalten, welche in jedes neue Projekt automatisch eingetragen wird. Ein gelegentliches Aufräumen der Resourcedatei kann nicht schaden. Sofern man die BROWSE- und Fenstereinstellungen nicht unbedingt benötigt, kann man mit dem folgenden Befehl alle nicht so wichtigen Datensätze entfernen: "DELETE FOR TYPE !=[DATA] AND ID !=[COLORSET]". Danach kann man mit "PACK" die Datei komprimieren.
Im Netzwerk gibt es erhebliche Probleme mit EXCLUSIVE geöffneten Dateien. Eine exklusiv geöffnete Datei steht nur einem einzigen Benutzer zur Verfügung. Die Hilfstextdatei FOXHELP.DBF wird von FoxPro im Nur-Lesen-Modus geöffnet und bearbeitet. Mehrere Benutzer können also gleichzeitig im Netzwerk die Hilfsfunktion benutzen. Anders sieht es bei der Resource-Datei FOXUSER.DBF aus. Diese wird exklusiv geöffnet und steht somit nur dem ersten Benutzer von FoxPro zur Verfügung. Alle anderen Benutzer bekommen eine Fehlermeldung beim Programmstart sowie bei jedem Zugriff auf die Resourcedatei. Schaltet man jetzt mit dem Befehl SET RESOURCE OFF die Resourcenverwaltung einfach ab, hat man keinen Zugriff mehr auf Termine im Kalender, Farbsets oder Druckersets, Voreinstellungen für BROWSE-Fenster usw. Ohne Resourcedatei sind viele Möglichkeiten stark eingeschränkt. Die einzig akzeptable Lösung ist folgende: Man kann mit dem DOS-Befehl ATTRIB die FoxPro-Resourcedatei als Nur-Lese-Datei markieren. Geben Sie am DOS-Prompt einfach ATTRIB FOXUSER.DBF +R ein (gleiches für die FOXUSER.FPT-Datei). Ab jetzt können beliebig viele Benutzer auf die Resourcedatei zugreifen. Nur die voreingestellte Farbe und den voreingestellten Drucker können Sie nicht mehr ändern. Außerdem beschwert sich die Kalenderfunktion jedesmal, daß sie nicht speichern kann. Ab FoxPro/DOS 2.5 bekommen Sie leider zusätzlich das Problem, das GENPD.APP auf jeden Fall in die Foxuser-Datei schreibt.
Das Erstellen von EXE-Dateien funktioniert mit dem Distribution Kit eigentlich ohne wirklich nennenswerte Probleme. Ärgerlich ist nur, daß soviele Funktionen stillschweigend unter den Tisch fallen. In EXE-Programmen stehen folgende wesentliche Funktionen grundsätzlich nicht zur Verfügung und sollten deshalb auch in APPs weggelassen werden:
1. Der Dateimanager kann weder über den Befehl FILER noch über die Leistenbezeichnung aufgerufen werden. Funktionen zur Dateimanipulation müssen entweder mühselig selbst geschrieben werden oder man weicht auf "RUN COMMAND.COM" aus.
2. Der Makrodefinitionsdialog im Systemmenü unter "Makro..." erscheint in EXE-Programmen als Leiste nicht. Hingegen stehen die Tastenkombinationen SHIFT+F10 zum Definieren und ALT+F10 zum Abrufen von Makros zur Verfügung. Theoretisch könnte man sich die Makro-Maske also selbst zusammenbauen.
3. Das Erstellen von RQBE-Abfragedateien ist dem Endanwender bei EXE-Programmen nicht möglich. Man kann nur vorgefertigte Queries ablaufen lassen. Dies ist ausgesprochen schade, da die Such- und Abfragefunktionen von einem Endanwender sehr häufig benötigt werden. Man muß sich mit externen Programmen wie "FOXFIRE!" begnügen.
Wie nicht anders zu erwarten, kann man natürlich keine Masken in einem EXE-Programmen bearbeiten. Erfreulich hingegen ist, daß Endanwender den vollständigen Report-Generator erhalten! Die Befehle "CREATE REPORT" und "MODIFY REPORT" samt Zusatzmenüleiste sind auch im kompilierten Programm voll funktionsfähig. Einfach in das Menü "CREA REPO ?" und "MODI REPO ?" einbinden.
Irgendwann einmal sind alle Resourcen verbraucht. Komisch nur, wenn einem das gleich beim Programmstart passiert. Die Fehlermeldung "Resource Exhausted" oder "Keine Resourcen" kann bei der Verwendung des DOS-Hilfsprogrammes SHARE.EXE auftreten. FoxPro verbraucht beim Starten sowie beim Öffnen jeder Programm-, Menü- oder Maskendatei ein Dateihandle. Das Öffnen von Datenbankdateien kostet beim Vorhandensein einer Index- und einer Memodatei gleich drei Dateihandles. Die Handles werden in der CONFIG.SYS-Datei mit dem Befehl FILES festgelegt. Meistens kommt man mit FILES=80 aus. Das Hilfsprogramm SHARE.EXE verwaltet jedoch intern nochmals die bereits bei FILES angegebenen Dateihandles - diesmal jedoch incl. logischer Dateisperren. Der Default-Wert ist bei SHARE.EXE nur 20 - sobald mehr als 20 Dateien geöffnet werden, sind die Resourcen auch schon verbraucht. Man muß über den Zusatzparameter "/l:" die Anzahl hochsetzen. Der Aufruf innerhalb der CONFIG.SYS-Datei sieht dann so aus: "INSTALL=C:\DOS\SHARE.EXE /f:4096 /l:80". Sofern man SHARE.EXE nicht benötigt, kann man natürlich den Aufruf ganz aus der CONFIG.SYS-Datei löschen.
FoxPro verbraucht beim Starten sowie beim Öffnen jeder Programm-, Menü- oder Maskendatei ein Dateihandle. Das Öffnen von Datenbankdateien kostet beim Vorhandensein einer Index- und einer Memodatei gleich drei Dateihandles. Darüberhinaus benötigt FoxPro selbst mindestens fünf eigene Handles. Die Handles werden in der CONFIG.SYS-Datei mit dem Befehl FILES festgelegt. Meistens kommt man mit FILES=80 aus. Dies gilt aber nur für einen Einzelplatzrechner. Im Netzwerk müssen Dateihandles darüberhinaus zusätzlich in der SHELL.CFG bzw. NET.CFG der Arbeitsstation definiert werden. Die CFG-Datei legt verschiedene Startparameter für den Netzwerkbetrieb fest. Unter anderem gibt es den Parameter "FILE HANDLES", welchen man ebenfalls mindestens auf 80 setzen sollte. Zwei weitere Besonderheiten sind dabei zu beachten. Die Summe der Dateihandles von FILES und FILE HANDLES darf 240 nicht überschreiten und es gilt der niedrigere Wert von beiden. FoxPro selbst kann bis zur Version 2.0 nicht mehr als 99 File-Handles gleichzeitig verwalten, ein Wert von 120 für FILES und FILE HANDLES ist also ausreichend. Schwierig wird es bei den neuen Versionen von FoxPro, welche bis zu 225 Arbeitsbereiche zur Verfügung stellen - dies wird im Netzwerk durch FILE HANDLES ganz drastisch beschnitten werden.
Nach gelöschten Sätzen wird normalerweise nicht gesucht. Sie werden nicht benötigt und man setzt einfach SET DELETED ON. Leider bremst diese Vorgehensweise die Rushmore-Optimierung von FoxPro, da nicht mehr eine reine Indexsuche erfolgen kann, sondern zusätzlich von allen Datensätzen die Löschmarkierung aus der Datenbank geladen werden muß. Außerdem ist die Wiederverwendung von alten Datensätzen mit LOCATE FOR DELETED() (ggf. SCATTER MEMVAR BLANK und GATHER MEMVAR) bei großen Datenbanken unzumutbar langsam. Deshalb ist es sinnvoll, einen zusätzlichen Index bei allen größeren Datenbanken mitzuführen, welcher nur die gelöschten Datensätze enthält. Diesen Index legen Sie mit INDEX ON DELETED() TAG GELOESCHT (oder wiederum DELETED) an. Den Geschwindigkeitsunterschied können Sie in der extremen Variante feststellen, wenn Sie TALK ON setzen und ein COUNT FOR DELETED() vor und nach der Indizierung durchführen. Der Unterschied sollte (ausreichend Datensätze vorausgesetzt) jeden überzeugen.
Auf manchen Computern erscheint die Meldung "Drucker nicht bereit!" allzu häufig. Da nützt es auch nichts, diesen Fehler mit einer eigenen Fehlerroutine abzufangen. Das häufige Auftreten liegt in einem Koordinatinsproblem zwischen dem PC und der Peripherie begründet und tritt nach meinen Erfahrungen besonders häufig bei Laserdruckern auf (während dem Seitenvorschub). Diesem Problem muß man von zwei Seiten zugleich zu Leibe rücken. Zum einen gibt es in der Konfigurationsdatei CONFIG.FP von FoxPro den Parameter "TIME=". Normalerweise startet FoxPro 6000 Kontaktversuche mit dem Drucker - die Variable TIME kann aber Werte zwischen 1 und 1 Million annehmen. Also setzt man in der CONFIG.FP-Datei einfach "TIME=1000000" und schon hat man ziemlich viele Versuch, bis die Fehlermeldung erscheint. Sofern dies allein immer noch nicht ausreichen sollte, kann man zusätzlich eine Zeile in die AUTOEXEC.BAT-Datei des Rechners einfügen: "MODE LPT1,,p". Diese Zeile setzt DOS auf endlose Wiederholungsversuche und unterdrückt die "Drucker nicht bereit"-Meldung restlos. Allerdings bekommt man dann überhaupt keine Fehlermeldung mehr und kann den Berichtsausdruck auch nicht mehr abbrechen, bis der Drucker wenigstens einige weitere Zeichen empfangen konnte.
Bekannt ist wahrscheinlich die Umgebungsvariable FOXPROCFG mit welcher man den Pfad zur Konfigurationsdatei CONFIG.FP festlegen kann. Darüberhinaus kann man FoxPro beim Start vier verschiedene Parameter übergeben. Weniger bekannt ist die Umgebungsvariable "FOXPROSWX", welche alternativ die Parameter aufnehmen kann, die beim Start von FoxPro gelten sollen. Die vier Parameter sind:
Die Konfigurationsdatei CONFIG.FP kann mit <-C> festgelegt werden. Mit <-E> wird die Benutzung des expanded Memory abgeschaltet - ähnlich wie bei EMS=OFF. Mit <-K> wird die Benutzung der erweiterten Funktionstasten wie bei F11F12=OFF abgeschaltet. Und <-T> schaltet die Startmaske von FoxPro aus - entsprechend dem Logo-Schalter bei Projektdateien.
Bei EXE-Programmen kommt diesen Parametern eine gewisse Bedeutung zu. Eine mit in das Projekt aufgenommen CONFIG.FP-Datei mit den Konfigurationsangaben kann durch die Übergabe dieser vier Parameter beim Aufruf oder via FOXPROSWX überschrieben werden. Man kann also die CONFIG.FP includen, um Änderungen zu verhindern, und kann über Schalter im Notfall eine neue CONFIG.FP definieren.
Folgende drei kleine Tricks helfen bei der täglichen Programmierarbeit mit FoxPro:
Sehr praktisch ist ein kleines Startprogramm, welches SET DEFAULT, SET PATH, SET HELP und SET RESOURCE für verschiedene Projekte korrekt einstellt. Zusätzlich füge ich noch ein "KEYBOARD "MODI PROJ <PROJECT>" und ein KEYBOARD "{ENTER}" in das jeweilige Startprogramm ein, um gleich das entsprechende Projekt zu öffnen und den Cursor reinzusetzen. Häufig lebensrettend hat sich ein einfaches "ON ERROR CLOSE ALL" erwiesen. Leider gibt es ab und zu (z.B. beim Ändern von großen Masken bei gleichzeitiger Dateistrukturänderung) Fehler mit Endlosschleifen in FoxPro. Der ON ERROR-Aufruf fängt den Fehler ab und sichert erstmal alle offenen Dateien. Danach kann man dann beruhigt RESET drücken. Häufig stellen Programme ihre eigene Umgebung ein. Wenn man ein Programm unterbrechen muß, ist man evtl. auf der falschen Hilfe- und Resource-Datei und ein paar SETs stimmen auch nicht. Außerdem kann man bei pausierten Programmen keine Projekte neu erstellen lassen (Knopf nicht wählbar). Dafür habe ich ein kleines Standardprogramm, welches alles zurücksetzt (ähnlich wie Start-Programm) und zusätzlich ein KEYBOARD "CANCEL{ENTER}" aufruft, sofern PROGRAM(2) nicht leer ist.