=============================================================================
PowerBASIC.GER-FAQ für die Versionen 3.00, 3.10, 3.20 & 3.50
deutsche Version (DOS)
(c) 1995/2005 von Thomas Gohel, Alle Rechte vorbehalten
Stand: 29.09.2005 - Version 1.00
Tips, Tricks, Bugs und andere mehr oder weniger wichtige Sachen
=============================================================================
=====================
Vorwort zu dieser FAQ
=====================
Die in dieser FAQ aufgeführten Hinweise erfolgen ohne Berücksichtigung
eventueller Copyright-Verletzung und ohne Rücksichtname eventuell
einge-
tragener Warenzeichen.
Des weiteren garantiert der Autor nicht für Richtigkeit der hier ange-
führten Probleme, Tips & Bugs etc. Sollten Sie Anregungen oder Ver-
besserungsvorschläge haben, so stehe ich diesen Sachen offen gegenüber
und werde dies in zukünftigen Versionen der FAQ mit einfliessen
lassen.
Ich möchte weiter darauf hinweisen, das einige der hier unter dem
Abschnitt 'Fehler' aufgeführten Probleme im weiteren Sinne keine Bugs
darstellen. Diese Ungereimtheiten bzw. verschwiegenen Einschränkungen
gilt es hier für die Allgemeinheit zu dokumentieren (das es in Zukunft
ein besseres PowerBASIC gibt).
=======================
Verbesserungsvorschläge
=======================
Verbesserungsvorschläge können Sie jederzeit an den Autor dieser FAQ
richten, die aktuellen Netmail-Adressen lauten:
Thomas Gohel@[EMAIL PROTECTED]
(FidoNet)
pbfaq@[EMAIL PROTECTED]
(InterNet und Unternetze)
Des weiteren besteht die Möglichkeit sich OnLine in eine Mailbox
einzu-
loggen, in der der Autor dieser FAQ erreichbar ist:
****t 1: (030) 473 00 910 (PBSOUND HQ, Berlin - 64.0, ISDN, X75,
V42B)
****t 2: (030) 473 00 910 (PBSOUND HQ, Berlin - 33.6, VFC, V34,
FAX)
Hier können Sie Ihre Vorschläge und Probleme los werden. Bitte
schreiben
Sie dazu Ihre Nachricht in der PBSOUND-Nachrichten-Area. Eine Antwort
sollten Sie spätestens nach 48 Stunden erhalten.
======================================
Bezug der aktuellen PowerBASIC.GER-FAQ
======================================
Die aktuelle PowerBASIC.GER-FAQ können Sie jederzeit aus meiner
Stammbox
Online downloaden. Die Telefonnummern lauten:
****t 1: (030) 473 00 910 (PBSOUND HQ, Berlin - 64.0, ISDN, X75,
V42B)
****t 2: (030) 473 00 910 (PBSOUND HQ, Berlin - 33.6, VFC, V34,
FAX)
Wechseln Sie nach dem Login in die 'PowerBASIC: FAQ'-Filearea.
Des weiteren finden Sie hier noch 16 weitere 'PowerBASIC-Fileareas'
PowerBASIC: PBSOUND
PowerBASIC: Sound Blaster
PowerBASIC: FAQ
PowerBASIC: Sourcen (allgemein)
PowerBASIC: Sourcen (Deutschland)
PowerBASIC: Sourcen (Netherlands)
PowerBASIC: Toolkits (allgemein)
PowerBASIC: Toolkits (Deutschland)
PowerBASIC: Toolkits (Netherlands)
PowerBASIC: Grafik (allgemein)
PowerBASIC: Grafik (Deutschland)
PowerBASIC: Grafik (Netherlands)
PowerBASIC: DFÜ, BBS und FidoNet Sourcen
PowerBASIC: allgemeine Pakete und Info's
PowerBASIC: Demos
PowerBASIC: User Uploads / Incoming
Viele in dieser FAQ erwähnten Sourcen und Toolboxen können Sie hier
Online oder auch per FidoNet downloaden.
InterNet-Teilnehmer können die PowerBASIC.GER-FAQ jederzeit via World
Wide Web (WWW) unter:
- http://www.gohel.de
erreichen.
Ein Request der FAQ über das FidoNet ist unter dem Magic 'PBFAQ'
möglich!
****t 1: (030) 473 00 910 (PBSOUND HQ, Berlin - 64.0, ISDN, X75,
V42B)
****t 2: (030) 473 00 910 (PBSOUND HQ, Berlin - 33.6, VFC, V34,
FAX)
Weiter PowerBASIC-Magics sind: PBSOUND und PBFILES.
============
Gesamtinhalt
============
1. Bezug, Toolboxen, Preise und Info's zu PowerBASIC
2. Fehler/Ungereimheiten in den PowerBASIC-Versionen 3.0, 3.1 & 3.2
3. PowerBASIC und der CoProzessor
4. Standard-Probleme
5. Tip's in Verbindung mit dem InLine-Assembler
6. Tip's in Verbindung mit Pointern
7. Tip's in Verbindung mit Turbo-C bzw. Borland C++
8. Tip's bei der Konvertierung von Sourcen von PDS nach PowerBASIC
3.x
9. vorhandene Shareware & Public Domain-Lösungen
10. Die PowerBASIC-Leute
====================================================
1. Bezug, Toolboxen, Preise und Info's zu PowerBASIC
====================================================
1.1. Die aktuelle Version von PowerBASIC
1.2. Der Originalhersteller von PowerBASIC
1.3. Deutschsprachiger Raum
1.4. deutsche PowerBASIC-Preise
1.5. Dänemark, Norwegen, Schweden und Finnland
1.6. Neuigkeiten in der PowerBASIC 3.1 Version
1.7. Neuigkeiten in der PowerBASIC 3.2 Version
1.8. Neuigkeiten in der PowerBASIC 3.5 Version
1.9. PowerBASIC 4.0 - The next Generation / Wishlist
1.1. Die aktuelle Version von PowerBASIC
----------------------------------------
Die aktuelle Version von PowerBASIC in Deutschland (seit Januar 1998)
ist die Version 3.50. In den USA und in anderen Staaten ist diese
Version bereits seit Dezember 1997 verfügbar.
1.2. Der Originalhersteller von PowerBASIC
------------------------------------------
PowerBASIC wird und wurde in den USA entwickelt und es befinden sich
natürlich auch diverse Möglichkeiten mit diesen Leuten in Kontakt zu
treten. Hier die aktuell bekannte Kontaktadresse von PowerBASIC Inc.:
Addresse:
PowerBASIC, Inc.
1978 Tamiami Trail S.#200
Venice, FL 34293
Bestellung : +1 (800) 780-7707
Kundendienst : +1 (941) 408-8700
Fax : +1 (941) 408-8820
InterNet:
World Wide Web : www.powerbasic.com
Liste der InterNet Addressen : info@[EMAIL PROTECTED]
Bestellung : order@[EMAIL PROTECTED]
Verkauf und Marketing : sales@[EMAIL PROTECTED]
Technischer Sup****t : sup****t@[EMAIL PROTECTED]
Anregungen für zukünftige
PowerBASIC Versionen : suggest@[EMAIL PROTECTED]
FTP- & WWW-Sites:
http://pbsound.basicguru.com
http://www.gohel.de
http://www.xlsior.org
http://www.basicguru.com
http://www.uni-jena.de/~p6sepa/rshp.html
http://home/t-online.de/home/mstadler/homepage.htm
http://www.leo.org/pub/comp/platforms/pc/msdos/programming/pbasic/
http://www.fys.ruu.nl/~bergmann/basic.html
http://www.zephyrsoftware.com
http://www.blarg.net/~future/shareware.html
http://www.cdrom.com/simtel.net/msdos/basic.html
http://www.cyberbox.north.de/FILES/DOS/dos106.html
ftp.global2000.net/pub/pbasic
Newsgroups (englisch):
alt.lang.powerbasic
comp.lang.powerbasic
| Newsgroups (deutsch):
| news.kannofant.de/de.comp.lang.powerbasic
| Hinweis: Nur nach Authentifizierung mit User/Password!
| (jeweils "basic")
1.3. Deutschsprachiger Raum
---------------------------
In Deutschland wird PowerBASIC vom deutschen Distributor: "Kirschbaum
Software GmbH" vertrieben. Die aktuelle Adresse lautet:
Kirschbaum Software GmbH
Kronau 15
83550 Emmering
Tel.: 08067/9038-0
Fax.: 08067/903898
Die derzeit aktuelle Version von PowerBASIC ist die Version 3.50. Als
aktuelle Toolboxen bietet Kirschbaum für PowerBASIC folgende Pakete
an:
PB/DLL - PowerBASIC DLL-Compiler für Windows
PowerGRAPH - für grafische Menüoberflächen (PCX, Fonts, etc.)
PowerISAM - Datenbanken (ebenfalls verfügbar in Englisch bei
PowerBASIC Inc.)
PowerTOOLS - SAA-Oberfläche, Hilfesystem, nützliche Routinen
PB/xtra - Sammlung von Sharewareprogrammen und Sourcecode
Kirschbaum besitzt keine Mailbox bzw. offizielle EMailadressen!
Allerdings
existieren für die Mitarbeiter bzw. für die Toolbox-Entwickler eigene
EMail-Adressen und Sup****t-Foren bzw. nicht öffentliche Newsgroup etc.
In diesem Fall sehen Sie bitte in dem Handbuch der betreffenden
Toolbox
nach.
1.4. deutsche PowerBASIC-Preise
-------------------------------
Alle hier genannten Preise sind nicht verbindlich! Änderungen oder Ab-
weichungen können jederzeit auftreten! Eine aktuelle und gültige
Preis-
liste kann jederzeit bei Kirschbaum Software per FAX angefordert
werden.
Vollversion: 199,-DM
Vollversion 3.5 für Studenten, Schüler: 150,-DM
Update von VOBIS-Basisversion 2.10f auf V3.2: 149,-DM
Update von V2.10 auf V3.5: 149,-DM
Update einer 3.x-Version auf V3.5: 36,80DM
| 1.5. Dänemark, Norwegen, Schweden und Finnland
| ----------------------------------------------
| In einigen europäischen Ländern (incl. Deutschland und Östereich)
| wird PowerBASIC von:
|
| Berggreen Service
| Lodsgaarden A 111
| DK-2791 Dragoer
| DENMARK
| info@[EMAIL PROTECTED]
| http://www.berggreen.dk
|
| vertrieben.
1.6. Neuigkeiten in der PowerBASIC 3.1 Version
----------------------------------------------
- Benutzerdefinierte TYPE- und UNION-Variablen können nun direkt
verglichen werden.
- Konstanten im Binaer-, Hex- oder Oktalformat (&B, &H, &O) können
einem bestimmten Datentyp zugeordnet werden, indem man den ent-
sprechenden Identifier anhängt.
Beispiel:
A?? = &HFFFF?? '= 65535
B% = &HFFFF% '= -1
- Konstanten (%Test) können ab dieser PowerBASIC-Version Werte im
64-Bit-Wertebereich (vorzeichenbehaftet) annehmen.
Beispiele :
%MaxAnzahl = 500000
%Konst1 = &HFFFF '= -1 (Integer)
%Konst2 = &H0FFFF '= 65535 (Long)
Bei Angaben Binaer-, Hexadezimal oder Oktalformat kann man durch
Angeben oder Weglassen einer führenden Null festlegen, ob der
erzeugte Wert vorzeichenbehaftet ist oder nicht.
- BIN$, HEX$ und OCT$ können jetzt Werte bis zu 32bit Long-Integer
ausgeben.
- Ab PB 3.10 können Sie alternative Namen für SUBs oder FUNCTIONs
vergeben, unter denen Sie dann diese Unterroutinen aus OBJ-Routinen
(mit Assenbler oder C erzeugt) aufrufen koennen.
Beispiel:
SUB MySub ALIAS "_my_sub" (Var1%,Var2$) PUBLIC
PRINT "Hallo", Var1%, Var2$
END SUB
- Das Schlüsselwort ANY in einer Prozedurdefinition erlaubt die
Übergabe eines Parameters beliebigen Typs. Der Parameter wird
per REFERENCE als 32bit-Adresse übergeben. Damit das aufgerufene
Programm weiss um welchen Typ es sich handelt sollten Sie einen
Typecode als ersten Parameter mit übergeben. Wird die Routine
in PowerBASIC codiert so muss zur Übernahme des Parameters der
Inline-Assembler genutzt werden.
Beispiel:
i% = 11
CALL TestAny(0,i%) 'die freien Parameter müssen
'Variablen sein
s$ = "Hallo"
CALL TestAny(1,s$)
SUB TestAny(ParamType AS INTEGER, ANY)
DIM Int.Param AS INTEGER
DIM String.Param AS STRING
SELECT CASE ParamType
CASE 0 'Integer
! les bx, [bp+6] :Offset der Var. in BX laden
! mov ax, es:[bx] ;Wert der Var. in AX laden
! mov Int.Param, ax ;Variable mit AX (Wert)
laden
PRINT Int.Param
CASE 1 'String
;Offset der Stringkennung
! les bx, [bp+6] ;in BX laden
! mov ax, es:[bx] ;Stringkennung in AX laden
! mov String.Param,AX
PRINT String.Param
END SELECT
END SUB
- Rückgabewerte von FUNCTIONs die mit dem Inline-Assembler geschrieben
wurden, können jetzt auch ohne eine Zwischenvariable mit einem Wert
belegt werden. Dazu dient das Schlüsselwort FUNCTION.
Beispiel:
PRINT AsmTest(2)
FUNCTION AsmTest(BYVAL int.param AS INTEGER) AS INTEGER
! mov ax, int.param
! inc ax
! mov FUNCTION, ax ;der Wert wird zurückgeliefert
END FUNCTION
(siehe auch Tips mit dem Inline-Assembler)
- Die Verwendung von FUNCTION anstelle des Funktions-Namens ist auch
bei BASIC-Codierten FUNCTIONs möglich.
Beispiel:
PRINT FuTest(2)
FUNCTION FuTest(BYVAL int.param AS INTEGER) AS INTEGER
FUNCTION = int.param + 1
END FUNCTION
- Die Funktion FRE() wurde erweitert :
FRE(-3) gibt den freien Speicherplatz für den Stack zurück
FRE(-4) gibt die maximale Länge für dynamische Strings zurück, die
mit $STRING gesetzt wurde
FRE(-5) gibt die Anzahl der belegten Stringsegmente zurück
FRE(-6) gibt die Anzahl der unbenutzten Blöcke im aktuellen String-
segment zurück
FRE(-7) gibt die Größe des unbenutzten Speichers im aktuellen
Stringsegment zurück
1.7. Neuigkeiten in der PowerBASIC 3.2 Version
----------------------------------------------
- Data Pointers
- Code Pointers
Es können nun folgende Sprünge direkt in Basic ausgeführt werden:
"CALL DWORD x", "GOTO DWORD x" und "GOSUB DWORD x" . "x" ist in
diesem Fall der 32bit Zeiger auf die SUB/FUNCTION oder das Label.
(Zu den neuen Pointer-Funktionen existiert ein DIR$-Demo)
- 32-Bit Umsetzung von:
STRPTR32, VARPTR32 und CODEPTR32
- Zeiger/Pointer auf Strukturen können an eine SUB/FUNCTION mit dem
Schlüsselwort "BYVAL" übergeben werden.
Beispiel:
DECLARE SUB MySUB(x AS INTEGER)
DIM z AS INTEGER PTR
z = &HB8000000
CALL MySUB(BYVAL z)
- 16550 UART Unterstützung
- Die LEN() Funktion liefert nun auch die Länge von User-definierten
Strukturen zurück.
- Label und Variablen können nun zur besseren Unterscheidung auch so-
genannte Underlines '_' enthalten.
1.8. Neuigkeiten in der PowerBASIC 3.5 Version
----------------------------------------------
- einige wichtige Bugfixes.
- ASCIIZ Strings: DIM xyz as ASCIIZ * 100.
- Arrays als dürfen als Benutzertyp nun 1 oder 2 statische Dimensionen
enthalten.
- & Operator wird erkannt als STRING Verbindung.
- STRING PTR ist jetzt eine legale Strutur in TYPE/UNION
- $ELSEIF metastatement.
- ASC(x$,n) Funktion und Befehl bieten eine optionale Anfangsposition.
- REDIM PRESERVE nur an den äußeren Grenzen von dynamischen und HUGE
Arrays.
- RND() ist ein zuläßiger Ersatz fuer RND.
- RND(x,y) liefert ein LONG INTEGER im Bereich x -> y zurück.
- TRIM$() ist eine Kombination aus LTRIM$() und RTRIM$().
- Indexed pointers: @[EMAIL PROTECTED]
- DIM VIRTUAL x(1000000) reserviert Arrayspeicher im EMS, darf aber
nicht
als dynamischer String oder als BYREF Parameter benutzt werden.
- HUGE und VIRTUAL Arrays dürfen LONG INTEGER Indexe verwenden. Mit
dieser Erweiterung kann man einen leichten Anstieg bei der Größe
des generierten Codes bemerken. Wenn ein Segment nun sehr nahe zum
64k Limit ist, benötigt es evtl. das $SEGMENT Metastatement um
verschoben zu werden.
- ERRCLEAR Befehl setzt das Errorflag auf Null.
- ERRCLEAR Funktion gibt ERR zurück, und setzt dann das Errorflag auf
Null.
- ERRCLEAR ist ein synonym fuer die alte Funktion ERRTEST.
- CVI(x$[,n]), CVL... bieten eine optionale Startposition innerhalb
des Strings.
- CVL(X$,3) extrahiert das dritte bis sechste Byte von x$ und
konvertiert die 4 Byte in die entsprechende LONG INTEGER
Zahl. In diesem Fall muss x$ mindestens 6 Byte lang sein.
- SIZEOF(var) Funktion gibt die physikalische Größe einer Variable
zurück,
- besonders nützlich beim Feststellen der maximalen Länge
eines fixed-length String, ASCIIZ String oder einer User
definierten TYPE Struktur
- Gibt immer 2 für einen dynamischen String zurück.
- STDIN x, y$ liest bis zu x Zeichen vom Standard Eingabegerät,
(welches
umgeleitet werden kann), und weist sie der Stringvariable zu. Wenn
weniger als x Zeichen sofort bereit sind, dann wird ein String
kürzer
als x Byte zurück gegeben.
- STDIN LINE, y$ liest eine Zeile Text direkt vom Standard
Eingabegerät,
(welches umgeleitet werden kann) und weist sie der Stringvariable
zu.
Wenn EOF erreicht wird, wird ein 1 Byte langer String mit CHR$(26)
zurück gegeben.
- STDOUT x$ [;] gibt den Stringausdruck x$ auf dem Standard
Ausgabegerät
aus, (welches umgeleitet werden kann), gefolgt von einem CR/LF. Wenn
das optionale angehängte Semikolon hinzugefügt wurde, dann wird das
CR/LF unterdrückt.
- SETEOF #1 Befehl wurde hinzu gefügt, um eine offene Datei an ihrer
momentanen Position abzuschneiden.
- FRE(-11) gibt die Anzahl der nicht allokierten Bytes im EMS Speicher
zurück.
1.9. PowerBASIC 4.0 - The next generation / wishlist
----------------------------------------------------
So kurz nach einer aktuellen Release V3.5 des Compilers ist es
natürlich
sehr, sehr schwer Punkte für Verbesserungen zu finden, aber es gibt
sie
natürlich trotzdem.
- XMS Sup****t für VIRTUAL Arrays
- SORT ARRAY Sup****t für VIRTUAL Arrays
- 32bit Inline-Assembler
- Syntax Highlighting in der IDE
- eine bessere IDE
====================================================================
2. Fehler/Ungereimtheiten in den PowerBASIC-Versionen 3.0, 3.1 & 3.2
====================================================================
Kurzübersicht:
2.0. PowerBASIC-Fehlerbibliotheken
2.1. Das NUMERIC/OVERFLOW-Problem in PowerBASIC 3.0
2.2. Das NUMERIC/OVERFLOW-Problem in PowerBASIC 3.1/3.2
2.3. Kein Overflow-Fehler beim Doubleword
2.4. Absturz der PowerBASIC IDE und fertiger EXE's beim Laden
2.5. unterschiedlich große EXE-File beim Komplieren mit PB/PBC
2.6. unterschiedliche EXE-Files bei gleicher Kompilation
2.7 Probleme mit der Maus innerhalb der IDE
2.8. Das Fixup Overflow Syndrom
2.9. Die Sache mit dem ASCII-154 nach einen REMARK im Inline-ASM
2.10. Fehler 454: END FUNCTION expected
2.11. Noch ein REMARK-Problem bei $ALIAS
2.12. Der Fehler CDWRD in der deutschen OnLine-Hilfe
2.13. Der Fehler CVDWRD in der deutschen OnLine-Hilfe
2.14. Absturz bei Betätigen von CNTRL-C
2.15. Fehler bei Verwenden der Ausgabe über "CONS:" und CNTRL-C
2.16. Die Sache mit dem Fehler 244 in einer Stand Alone EXE-Datei
2.17. Probleme bei Verkettung mehrerer Zeilen Sourcecode
2.18. Probleme mit dem WATCH-Fenster und mehrdimensionalen Arrays
2.19. Fehlerhafte interne Funktion/Variable: pbvScrnCols
2.20. unkorrekte interne Funktion/Variable: pbvHost
2.21. Ein kleiner Unterschied im neuen InLine-Assembler der V3.1/3.2
2.22. Das dd-Problem bei PowerBASIC 3.1/3.2
2.23. undokumentierte interne Variablen in PowerBASIC 3.0/3.1/3.2
2.24. Der PRINT-Bug in PowerBASIC 3.2
2.25. Der Fehler "File not found" nach Verwendung von NAME
2.26. Rechenfehler bei der Verwendung von Konstanten
2.27. falsches "Bit schieben" bei ROTATE
2.28. Overflow bei Verwendung von FOR/NEXT-Schleifen
2.29. Overflow bei Verwendung von STEP -1 in FOR/NEXT-Schleifen
2.30. Der Bug im VARPTR32-Befehl
2.31. Der "KEY ON" Bug
2.32. Absturz der PowerBASIC IDE im Pick-Menü
2.33. Absturz der PowerBASIC IDE bei fehlerhaften Syntax
2.34. falsches Vertauschen der Variablen bei Verwendung von SWAP
2.35. Der Multiplexer Interrupt Fehler im REG-Befehl
2.36. Inhalt eines Verzeichnis wird mit KILL gelöscht
2.37. Die Sache mit der Zeichenkette "USR"
2.38. Laufzeitfehler im PowerBASIC Helpcompiler
2.39. Der Fehler Truncating im PowerBASIC Helpcompiler
2.40. Absturz der PowerBASIC-IDE nach Aufruf der eigenen Hilfe
2.0. PowerBASIC-Fehlerbibliotheken
----------------------------------
Zur besseren Sicherheit Ihrer eigenen Programme empfehle ich
prinzipiell
die Einbindung aller Fehlerbibliotheken. Nur so können Sie sicher
sein,
das PowerBASIC auch den wahren Fehler anzeigt und z.B. nicht bei:
SELECT CASE pbvrevision
mit einem unerklärlichen Fehler aussteigt. Im fertigen Programm
könnnen
Sie die Bibliotheken wieder entfernen, da sie eigentlich nur während
der
Programmentwicklung wirklich benötigt werden.
Die $ERROR-Bibliotheken können Sie innerhalb der IDE ständig einbinden
oder direkt in Ihrem Sourcecode definieren. Die Einstellungen im
Sourcecode haben gegenüber den Einstellungen der IDE Vorrang!
Die $ERROR-Bibliotheken binden Sie wie folgt ein:
$ERROR NUMERIC ON
$ERROR OVERFLOW ON
$ERROR BOUNDS ON
$ERROR STACK ON
Achtung: Einige der hier aufgezeigten Ungereimtheiten können nur mit
diesen Bibliotheken aufgedeckt werden!
2.1. Das NUMERIC/OVERFLOW-Problem in PowerBASIC 3.0
---------------------------------------------------
Versionen: 3.0
bekannt : teilweise in Version 3.10 beseitigt
Die hier aufgeführten Probleme beziehen sich nur auf die Verwendung
von
vorzeichenlosen Variablen und werden an Variablen vom Typ WORD
aufgeführt:
Beispiel 1:
Demo?? = &hA000
führt zu einem Overflow, da PowerBASIC dies als vorzeichenbehaftete
Variable versucht zu interpretieren. Dieser Fehler kann nur durch
Angabe
einer Realzahl umgangen werden.
Ähnliche Effekte lassen sich im $NUMERIC-System auch bei Verwendung
des
REG()-Befehles nachvollziehen:
Beispiel 2:
Demo?? = REG(1)
kann unter Umständen ebenfalls zu einem Überlauf führen, sofern der
übergebene Wert als INTEGER negativ wäre. Den Fehler können Sie um-
schiffen, sofern sie bei der Verwendung von REG() nur Variablen vom
Typ
INTEGER verwenden, die NUMERIC-Bibliothek beim Kompilieren entfernen.
Noch viel besser ist es allerdings, den alten BASIC-Unsinn über Bord
zu
werfen und die Geschichte gleich im InLine-Assembler sauber zu pro-
grammieren! ;-)
Interessant ist auch das 'Verschleppen' von Fehlern bei
ausgeschalteter
$ERROR NUMERIC Bibliothek. Der Fehler tritt dann etwas später im
Programm auf, komischerweise aber ebenfalls bei Variablen vom Typ
WORD.
Eigenartigerweise läßt sich dies am besten mit den internen
PowerBASIC-
Variablen vom Typ WORD nachvollziehen.
Ein weiterer Overflow-Effekt verbirgt sich in den
PowerBASIC-Funktionen
STRSEG/STRPTR, VARSEG/VARPTR, CODESEG/CODEPTR. Im Gegensatz zum REG()
Befehl müssen die Variablen definitiv vom Typ WORD sein, ansonsten
droht wiederum ein Überlauf in größeren Programmen.
2.2. Das NUMERIC/OVERFLOW-Problem in PowerBASIC 3.1/3.2
-------------------------------------------------------
Versionen: 3.1/3.2
bekannt : Nachbesserung bei PowerBASIC Inc. verlangt
Man soll nicht denken, das eine neue Version auch die ganzen alten
Fehler
in Vergessenheit geraten läßt ;-).
Beispiel 1:
Demo?? = &hA000
kann weiterhin zu einem Überlauf führen. Leider läßt sich dieser
Fehler
nicht mehr in einer Zeile demonstrieren, da er gelegentlich in sehr
komplexen Programmen weiterhin auftritt. Das hat sich mit PowerBASIC
in der Version 3.20 leider immer noch nicht geändert.
Im Gegensatz zur Version 3.00 kann der Fehler aber durch explizente
Unsigned-Angabe beseitigt werden:
Demo?? = &h0A000
Sollten Sie Toolbox-Entwickler sein und auf Nummer sicher gehen
wollen,
dann geben Sie in folgene Zeile ein, sofern Ihre Sourcen auch unter
PowerBASIC 3.0 laufen sollen:
! mov ax, &hA000
! mov Demo??, ax
Beispiel 2:
Demo?? = REG(1)
führt meines Erachtens nicht mehr zu einem Overflow, ganz
ausschliessen
kann ich dies aber nicht. Trotzdem sollte man bei der Verwendung von
REG
weiterhin nur Variablen vom Typ INTEGER verwenden. Viele PowerBASIC-
Funktionen funktionieren jetzt besser, andere bereiten trotzdem
Probleme.
Dies betrifft wieder diverse spezielle Routinen welche nur für
Integer-
Variablen ausgelegt sind, aber trotzdem mit Variablen vom Typ WORD
funktionieren.
Das Overflow-Problem bei STRSEG/STRPTR, VARSEG/VARPTR und
CODESEG/CODEPTR
ist weiterhin existent.
2.3. Kein OVERFLOW-Fehler beim Doubleword
------------------------------------------
| Versionen: 3.0/3.1/3.2/3.5
| bekannt : ja
Für Variablen vom Typ Doubleword ist in PowerBASIC kein Overflowtest
integriert. Dies können Sie an einem kleinen Beispiel testen.
Beispiel:
i??? = -1
PRINT i???
Die Ursache für diesen Mangel liegt in der Intel CPU selbst begründet,
denn dort gibt es keinen Overflow den der Compiler auswerten könnte.
2.4. Absturz der PowerBASIC IDE und fertiger EXE's beim Laden
-------------------------------------------------------------
Versionen: 3.0/3.1 (3.2 nicht getestet)
bekannt : nein (teilweise)
Ein Absturz der IDE beim Laden tritt eigentlich recht selten auf und
ist
im Prinzip immer auf folgende Ursachen zurückzuführen:
- QEMM Speicherverwaltungsmanager (bis Version 7.03)
- extrem wenig verfügbarer Arbeitsspeicher
- Sie haben versucht die IDE mit dem Befehl LOADHIGH zu laden
- 4DOS
In den meisten Fällen wird die IDE während des Ladevorganges mit einem
Grafikfehler (Cursor innerhalb der IDE) auf die Kommandozeile zurück-
kehren.
Ebenfalls betroffen von diesem Effekt sind alle fertigen
PowerBASIC-EXE
Files. Wollen Sie diesen Effekt auf alle Fälle umgehen, so müssen Sie
die PowerBASIC-EXE mit einem EXE-Packer wie PKLITE komprimieren.
2.5. unterschiedlich große EXE-File beim Komplieren mit PB/PBC
--------------------------------------------------------------
Eigentlich ist dies kein Fehler, da es nur einen kleinen Unterschied
in
der Wirkungsweise des IDE-Compilers zu dem Kommandozeilencompiler
gibt,
welche die unterschiedlich großen EXE-File erklärt.
Die IDE compiliert die EXE-Datei immer nach den Einstellungen in der
IDE,
das heißt wenn Sie dort zum Beispiel die VGA-Lib nicht mit compilieren
wollen, so geben sie das als Standard in der IDE an. Der PBC
compiliert
dagegen die VGA-Lib immer mit, sofern sie das nicht als Metastatment
anderweitig deklariert haben.
Die Metastatment-Einstellung haben immer Vorrang vor den Einstellungen
in der IDE!
2.6. unterschiedliche EXE-Files bei gleicher Kompilation
---------------------------------------------------------
Versionen: 3.0/3.1
bekannt : anscheinend
Einen netten Effekt gibt es zu berichten, sofern Sie Sourcen mehrmals
compilieren und diese dann mit einem Filevergleich-Utility einer
genauen
Betrachtung unterziehen. Sofern sich Ihr verfügbarer freier Speicher
geändert hat, werden die erstellten EXE-Files unterschiedlich sein.
Meines Erachtens speichern die beiden PowerBASIC Compiler auch
Ursprungsinformationen mit ab, welche vom Typ Integer/Word sind und
sich
immer an den Offset's &h9C/&hA0 befinden (PB3.1). Dieser Effekt läßt
sich mit der PB-IDE und auch dem PBC nachvollziehen.
Nach einigen Auskünften sollen PB-EXE-Files, welche unter einer
PowerBASIC-SHELL mit PBC compiliert wurden zum Abstürzen neigen.
Da ich aber selbst seit ca 2 Jahren alle meine Projekte auf ähnliche
Weise compiliere, kann ich diesen Effekt nicht nachvollziehen oder
bestätigen. In Version 3.0 des PowerBASIC-Compilers schien allerdings
der SHELL-Befehl anderweitige Effekte bei großen EXE-File auszulösen.
Die Probleme lösten sich damals mit der Verwendung eines alternativen
PBSHELL-Befehls.
2.7 Probleme mit der Maus innerhalb der IDE
--------------------------------------------
Versionen: 3.0
bekannt : anscheinend in Version 3.1 behoben
Sollten Sie innerhalb der IDE mit der Maus arbeiten damit Sie
komfortabel
Sourcecode Einfügen und Ausschneiden können, so kann dies beim
Markieren
längerer Texte (welche den rechten Bildschirmrand überschreiten) zu
einem
Teilabsturz führen. Des weiteren markiert der Maus-Cursor die Texte
nicht
richtig. Sie erkennen das daran, das Sie in der Regel eine längere
Zeile
nicht markieren können.
Des weiteren scheint es vereinzelt Probleme mit der Mausunterstützung
zu
geben, Sofern sie den 80*43/50'er Textmodus verwenden.
2.8. Das Fixup Overflow Syndrom
-------------------------------
Versionen: 3.0/3.1/3.2
bekannt : Nachbesserung bei PowerBASIC Inc. verlangt
So jetzt kommen wir zu meinem Lieblingsfehler, zumal er eigentlich
durch
einen ernsthaften Programmierfehler seitens des PowerBASIC Anwenders
ausgelöst wird. Die Beschreibung im Handbuch, sowie der OnLine-Hilfe,
ist leicht irreführend dennoch prinzipiell richtig.
Ich persönlich würde den Fehler wie folgt beschreiben:
<neue Fehlerbeschreibung>
PowerBASIC konnte die angegebene Sprungadresse nicht finden. Eine
mögliche Ursache ist ein SHORT-Sprung zu einem Label der nicht im
gültigen Bereich für einen SHORT-Sprung liegt. Bitte Überprüfen Sie
alle
Sprungbefehle auf Ihren Gültigkeitsbereich.
<Ende>
Leider hat sich gerade bei dieser Fehlermeldung in beiden PowerBASIC
Versionen ein Fehler eingeschlichen. Da die menschliche Natur
prinzipiell
nicht so recht glauben will was da so steht, wird die Source eben
nochmals (ohne Änderung) kompiliert. Die IDE quittiert das sofort mit
einem Absturz.
Eine genauere Beschreibung des Zusammenspiels der einzelnen Assembler-
Befehle, vor allem die verschiedenen Adressierungsarten in
Abhängigkeit
von der CPU, erspare ich mir hier. Dafür gibt es jede Menge Assembler-
Bücher, meines Erachtens eh eine Voraussetzung zur sinnvollen
Programmierung mit dem InLine-Assembler.
2.9. Die Sache mit dem ASCII-154 nach einen REMARK
--------------------------------------------------
Versionen: 3.0/3.1/3.2
bekannt : Fehler in Version 3.50 beseitigt
Eine nette Sache kann Sie zum Beispiel in Verbindung mit einer guten
Kommentierung Ihrer InLine-Assembler Source schlichtweg zum Wahnsinn
treiben: Die Sache mit dem Sonderzeichen ASCII-154 nach einem REMARK
(REM bzw. ; ):
Beispiel:
CLS
PRINT "1"
! nop ; Ü <- (ASCII-154)
PRINT "2"
PowerBASIC wird in diesem Fall die Programmausführung bis zu der Zeile
mit dem Sonderzeichen (nach dem REM) fortsetzen und dann stoppen. Die
hartgesottenen können diese Sache auch einmal mit dem Debuger
verfolgen.
In diesem Fall werden Sie feststellen, das PowerBASIC nach dem REMARK
einfach nur noch sieben ASCII-Nullen an den Code anhängt und das
weitere
Compilieren einstellt.
2.10. Fehler 454: END FUNCTION expected
----------------------------------------
Versionen: 3.0/3.1/3.2
bekannt : Fehler in Version 3.50 beseitigt
Diese Fehler kann auftreten, sofern der kommentierte Text einer
Inline-
Assemblerzeile das ASCII-154 Zeichen enthält. Lesen Sie sich bitte
auch
den vorherigen Absatz durch.
2.11. Noch ein REMARK-Problem bei $ALIAS
----------------------------------------
Versionen: 3.0/3.1/3.2/3.5
bekannt : Fehler in Version 3.50 beseitigt
Der Fehler ist wieder recht einfach zu beschreiben. Sie dürfen bei der
Verwendung von $ALIAS kein ':' (ASCII 58) nach einem REMARK verwenden,
da dies PowerBASIC mit einem Fehler 462 (nicht definierte
SUB/FUNCTION)
interpretiert. Dieses Problem tritt nur Aufgrund der GWBASIC Abwärts-
kompatibilität auf!
Beispiel:
$ALIAS DATA AS "_DATA" ': C-Segmente an PowerBASIC anpassen
^
führt zum Fehler 462
2.12. Der Fehler CDWRD in der deutschen OnLine-Hilfe
----------------------------------------------------
Versionen: 3.0 (nur deutsche Version)
In der OnLine-Hilfe hat sich ein Tipfehler eingeschlichen, statt dem
richtigen Befehl 'CDWD' wird der Befehl mit 'CDWRD' beschrieben. In
den
deutschen Handbüchern ist der Syntax aber korrekt erklärt.
Beispiel:
i??? = 1
PRINT CDWRD(i???) : 'falscher Syntax
PRINT CDWD(i???) : 'richtiger Syntax
2.13. Der Fehler CVDWRD in der deutschen OnLine-Hilfe
-----------------------------------------------------
Versionen: 3.0 (nur deutsche Version)
Analog wir bei dem Syntaxfehler 'CDWRD' hat sich auch hierbei ein
Fehler
in der OnLine-Hilfe eingeschlichen, der Syntax lautet wie im deutschen
Handbuch korrekt beschrieben 'CVDWD'.
2.14. Absturz bei Betätigen von CNTRL-C
---------------------------------------
Versionen: 3.0
bekannt : Fehler in Version 3.10 beseitigt
Dieser Fehler ist im allgemeinen bekannt und tritt nur auf wenn Sie
die
Compileroption $OPTION CNTLBREAK OFF verwenden, während das BREAK-Flag
auf DOS-Ebene auf ON gesetzt ist (normalerweise ist dies aber von
MS-DOS
eh auf OFF gesetzt). Betätigen Sie unter diesen Vorrausetzungen nun
die
Tastenkombination CNTL-C, dann stürzt Ihr fertiges Programm gelinde
gesagt ab.
Abhilfe schafft das Sperren des BREAK-Flag's per eigener PowerBASIC-
Funktion. Dies können Sie zum Beispiel durch folgende Routinen
erreichen:
SHARED BreakFlag%
FUNCTION BreakAus public
'Controll-Break-Interrupt sichern und abschalten
! mov ax, &h3300
! int &h21
! mov BreakFlag%, dx
! mov ax, &h3301
! mov dx, 0
! int &h21
END FUNCTION
FUNCTION BreakReset public
'Control-Break-Interrupt restaurieren
! mov ax, &h3301
! mov dx, BreakFlag%
! int &h21
END FUNCTION
In einigen Mailboxen befindet sich auch eine Datei namens CNTL.ZIP,
welche den offiziellen BugFixed darstellt.
2.15. Fehler bei Verwenden der Ausgabe über "CONS:" und CNTRL-C
---------------------------------------------------------------
Versionen: 3.0
bekannt : Fehler in Version 3.10 beseitigt
Dieser Fehler ist ebenfalls eine Auswirkung des CNTRL-C Bugs, während
der Ausgabe über "CONS:" kann es zu Nebeneffekten kommen. Näheres ist
mir pesönlich nicht bekannt.
2.16. Die Sache mit dem Fehler 244 in einer Stand Alone EXE-Datei
-----------------------------------------------------------------
Versionen: 3.0
bekannt : Fehler in Version 3.10 beseitigt
Sollten Sie PowerBASIC 3.0 nutzen und öfters im InLine-Assembler
programmieren, so kann es in Verbindung mit den beiden internen
PowerBASIC-Funktionen:
GetStrLoc
GetStrAlloc
zu dem oben genannten Fehler 244 (Bibliothek nicht vorhanden) kommen.
Dieser Fehler tritt nur in einer Stand-Alone-EXE Datei auf und nicht
innerhalb der PowerBASIC-IDE. Als Voraussetzung müssen sich die beiden
internen PowerBASIC-Funktionen innerhalb einer PowerBASIC Unit (PBU)
befinden. Als Abhilfe müssen Sie die beiden PowerBASIC-Funktionen
STRSEG/STRPTR benutzen, die Werte dann zwischenspeichern und danach
auf
die betreffenden Prozessorregister schieben.
2.17. Probleme bei Verkettung mehrerer Zeilen Sourcecode
--------------------------------------------------------
Versionen: 3.0/3.1
bekannt : Fehler in Version 3.20 beseitigt
Die PowerBASIC-IDE, sowie der Kommandozeilen-Compiler, haben
allgemeine
Probleme, wenn Sie Sourcecode über mehrere Zeilen verteilen, welcher
normalerweise in eine Zeile gehört.
Beispiel:
C$ = CHR$( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)+_
CHR$( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
Gerade in Verbindung mit großen Projekten hat sich gezeigt, das der
Compiler zu einer falschen Interpretation neigt, sprich: An
irgendeiner
Stelle im Sourcecode meldet der Compiler einen für Sie unerklärlichen
Fehler. In vielen Fällen bleibt der Cursor aber an richtigen Stelle
stehen.
2.18. Probleme mit dem WATCH-Fenster und mehrdimensionalen Arrays
-----------------------------------------------------------------
Versionen: 3.0/3.1
bekannt : Fehler in Version 3.2 beseitigt
Das WATCH-Fenster kann keine mehrdimensionalen Arrays korrekt dar-
stellen.
2.19. Fehlerhafte interne Funktion/Variable: pbvScrnCols
--------------------------------------------------------
Versionen: 3.0/3.1/3.2
bekannt : nein
Diese interne Variable soll Ihnen die Anzahl der angezeigten
Bildschirm-
spalten zurückliefern. In Verbindung mit allen Modies welche nicht die
40'er bzw. 80'er Spaltenanzahl verwenden, wird nicht die korrekte
Anzahl
der Bildschirmspalten zurück geliefert. Solche Modies können Sie auf
jeder VGA-Karte einstellen und diverse Tools (u.a. Disk Command
Center)
unterstützen dies sogar!
Abhilfe schafft hierbei wieder eine eigene Funktion:
DIM fixScrnCols AS BYTE
! mov ah, &h0f
! int &h10
! mov fixScrnCols, ah
2.20. unkorrekte interne Funktion/Variable: pbvHost
---------------------------------------------------
Versionen: 3.0/3.1/3.2
bekannt : nein
Das Bit 8 ist unter Microsoft Windows(NT) 3.x nicht gesetzt.
2.21. Ein kleiner Unterschied im neuen InLine-ASM der V3.1/3.2
--------------------------------------------------------------
Versionen: 3.1/3.2
bekannt : Nachbesserung bei PowerBASIC Inc. verlangt
Dieser Fehler ist recht einfach erklärt, während PowerBASIC 3.0 im
Inline-Assembler folgende Zeile zuläßt:
! mov ax, &h0A000
verweigert PowerBASIC 3.1/3.2 an dieser Stelle die Zusammenarbeit,
obwohl das Feature in der Version 3.1/3.2 neu ist.
2.22. Das dd-Problem bei PowerBASIC 3.1/3.2
-------------------------------------------
Versionen: 3.1/3.2
bekannt : Feature in Version 3.5 beseitigt
Dieser Fehler ist recht schnell beschrieben, da die neuen 32Bit
&h...., &o.... &b Anweisungen als bekannt vorrausgesetzt werden.
PowerBASIC Inc. hat in Verbindung mit dem InLine-Assembler einfach die
Umsetzung vergessen!! Sie glauben mir nicht, dann probieren Sie doch
einfach folgendes:
! dd &h12345678
Diese kleine Ungereimtheit wird seitens PowerBASIC Inc. mit dem 8bit
Inline Assembler begründet, aber der Inline-Assembler der Version 3.50
wurde erfreulicherweise trotzdem in dieser Richtung überarbeitet.
2.23. undokumentierte interne Variablen in PowerBASIC 3.0/3.1/3.2
-----------------------------------------------------------------
Folgende interne Variablen sind in PowerBASIC 3.0 bereits vorhanden,
aber nicht dokumentiert:
pbvBinBase
pbvDefSeg
pbvHost
pbvScrnBuff
pbvSwitch
pbvVTxtX1
pbvVtxtX2
pbvVTxtY1
pbvVtxtY2
Folgende internen Varibalen sind ab V3.1 nicht mehr dokumentiert, aber
noch in Version 3.2 vorhanden:
pbvRestore
Die Lage im Datensegment ist bei PowerBASIC 3.0 mit der Lage in
PowerBASIC 3.1/3.2 identisch.
2.24. Der PRINT-Bug in PowerBASIC 3.2
-------------------------------------
bekannt : ????
In der Version 3.2 werden Variablen vom Typ DWORD nicht mehr korrekt
beim PRINT-Befehl dargestellt:
Beispiel:
Demo??? = 1234567890
PRINT Demo???
führt zu folgender Ausgabe:
PowerBASIC 3.0/3.1: 1234567890
PowerBASIC 3.2 : 1.234568+E
Abhilfe schafft das Verwenden von PRINT USING ...
2.25. Der Fehler "File not found" nach Verwendung von NAME
----------------------------------------------------------
Versionen: 3.0/3.1/3.2
bekannt : Fehler in Version 3.50 beseitigt
Ein sehr merkwürdiger Fehler in der Behandlung PowerBASIC-interner
Filehandles hat sich bei der Verwendung des Befehles "NAME" einge-
schlichen.
Beispiel:
OPEN "B",1,"DATEI1.TMP" ' Öffnen der 1. Datei
OPEN "B",2,"DATEI2.$$$" ' Öffnen
CLOSE 2 ' ... und sofort schliessen
OPEN "B",3,"DATEI3.TMP" ' Öffnen
CLOSE 3 ' ... und sofort schliessen
KILL "DATEI2.$$$" ' 2. Datei löschen
NAME "DATEI3.TMP" AS "DATEI2.$$$"
' 3. Datei -> 2. Datei umbenennen
CLOSE 1 ' ... Schliessen der 1. Datei
END
2.26. Rechenfehler bei der Verwendung von Konstanten
----------------------------------------------------
Versionen: 3.0/3.1/3.2
bekannt : nein
PowerBASIC rechnet bei der Verwendung von Konstanten gelegentlich
nicht korrekt. Es sei natürlich die Frage in den Raum gestellt, warum
man nicht gleich das Rechenergebnis einsetzt, da es sich hierbei um
eine reine Formsache handelt.
Beispiel:
i% = -20-4 : %k= -20-4
PRINT i% , %k
2.27. falsches "Bit schieben" bei ROTATE
----------------------------------------
Versionen: 3.0/3.1
bekannt : Fehler in Version 3.20 beseitigt
Der ROTATE-Befehl hat in PowerBASIC 3.0/3.1 einen Fehler sofern
Variablen
vom Type QUAD verwendet werden.
Beispiel:
i&& = 1
ROTATE RIGHT i&&, 1
ROTATE LEFT i&&, 1
PRINT i&&
2.28. Overflow bei Verwendung von FOR/NEXT-Schleifen
----------------------------------------------------
Versionen: 3.0/3.1/3.2/3.5
bekannt : ja
PowerBASIC erlaubt es nicht in FOR/NEXT-Schleifen den maximal gültigen
Wertebereich einer Variablen auszuschöpfen. Der maximal mögliche Wert
wird intern von PowerBASIC verwendet, da PowerBASIC m.E. erst intern
die Variable erhöht und dann abfragt. Logischerweise kommt es dabei
zu einem Überlauf, sofern Ihr Wert bereits den maximal möglichen
Wert erreicht hat.
Der Fehler betrifft m.E. alle Variablentypen.
Beispiel:
FOR Demo? = 1 TO 255
PRINT Demo?
NEXT Demo?
Sollten Sie nicht die "$ERROR NUMERIC" Bibliothek verwenden, so
befindet
sich diese FOR/NEXT Konstruktion in einer Endlosschleife.
Dieser Effekt ist begründet aufgrund der Abwärtskompatibilität zu
anderen
BASIC Compilern und der Wirkungsweise der Intel CPU.
2.29. Overflow bei Verwendung von STEP -1 in FOR/NEXT-Schleifen
---------------------------------------------------------------
Versionen: 3.0/3.1/3.2/3.5
bekannt : ja
In PowerBASIC müssen alle Variablen vom gleichen Typ (signed/unsigned)
sein, sofern sie in FOR/NEXT Schleifen verwendet werden. Folgendes
Bei-
spiel ist also nicht zuläßig:
Beispiel:
FOR Demo?? = 10 TO 2 STEP -1
NEXT Demo??
oder
FOR Demo??? = 10 TO 2 STEP -1
PRINT Demo???
NEXT Demo???
Sollten Sie nicht die "$ERROR NUMERIC" Bibliothek verwenden, so
befindet
sich diese FOR/NEXT Konstruktion in einer Endlosschleife.
2.30. Der Bug im VARPTR32-Befehl
--------------------------------
Versionen: ab 3.2
bekannt : Fehler in Version 3.50 beseitigt
Im Gegensatz zu den Befehlen STRPTR32 und CODEPTR32 hat sich im
VARPTR32-Befehl ein Bug eingeschlichen. Leider ist es mit diesem
Befehl nicht möglich gleichzeitig eine mathematische Operation
auszuführen.
Beispiel:
DIM Demo AS STRING * 10
Wert1??? = VARPTR32(Demo) + 1
Wert2??? = VARPTR32(Demo)
Wert2??? = Wert2??? + 1
PRINT Wert1???, Wert2???
2.31. Der 'KEY ON' Bug
----------------------
Versionen: 3.0/3.1/3.2
bekannt : nein
Laut PowerBASIC Benutzerhandbuch und BASIC Spezifikation des
KEY-Befehls
stellt der 'KEY ON'-Befehl in Zeile 25 die aktuelle
KEY-Tastaturbelegung
in 'Norton Commander' ähnlicher Form dar. Ist dieses der Fall, sollte
PowerBASIC jeden Zugriff des Programmierers auf die Zeile 25 durch
LOCATE mit einem 'Error 5: Illegal Function' unterbinden. Ebenso
sollte
die Zeile 25 durch ein versehentliches Scrollen geschützt sein.
Seit PowerBASIC V3.x (im Gegensatz zur V2.10) ist dieses nicht mehr
der
Fall!
Beispiel:
KEY OFF
FOR i% = 1 TO 10
READ A$
KEY i%, A$ + CHR$(13)
NEXT i%
KEY LIST
COLOR 3, 0
KEY ON
COLOR 7, 0
LOCATE 25, 1: PRINT " Dieser Text sollte abgefangen werden!!
";
WHILE NOT INSTAT
WEND
KEY OFF
END
DATA "Hilfe", "Return"', "Edit", "Wechseln", "Re****t"
DATA "PRINT", "Setup", "DOS", "Kopie", "Quit"
Mir stellt sich nun die Frage ob dieses ein Fehler im
PowerBASIC-Handbuch
oder ein Bug im Compiler ist. Auf alle Fälle können Sie diesen Effekt
aber durch die Verwendung von:
VIEW TEXT (1,1)-(80,24)
umgehen.
2.32. Absturz der PowerBASIC IDE im Pick-Menü
---------------------------------------------
Versionen: 3.0/3.1/3.2/3.5
bekannt : nein
Die PowerBASIC IDE stürzt ab, wenn sie zum ersten Mal nach dem Start
der IDE im Menü "File\Pick", anstatt der RETURN-Taste die DEL-Taste
betätigen. Sollten Sie bereits während der Sitzung das Menü "Pick"
einmal
mit RETURN geöffnet haben, so wirkt sich der Fehler nicht mehr aus.
Ich persönlich halte den Fehler für sehr ernsthaft, liegen doch die
beiden Tasten auf der Tastatur eng zusammen.
2.33. Absturz der PowerBASIC IDE bei fehlerhaften Syntax
--------------------------------------------------------
Versionen: 3.0/3.1/3.2
bekannt : Fehler in Version 3.50 beseitigt
Die PowerBASIC IDE stürzt ab, sofern Sie versuchen folgende Zeile
zu compilieren:
PRINT Test1$ XOR Test2$ XOR Test3$
Über den Sinn der Zeile möchte ich lieber nicht diskutieren. <g>
2.34. falsches Vertauschen der Variablen bei Verwendung von SWAP
----------------------------------------------------------------
Versionen: 3.0/3.1/3.2/3.5
bekannt : nein
Bei Verwendung des SWAP-Befehl in Verbindung mit TYPE-Strukturen und
der
Indizierung des Feldes über eine Variable (im Beispiel "a(c%).x")
werden
die Felder falsch miteinander getauscht (geswappt). Wird das Feld über
einen fest definierten Wert (z.B. "a(1).x") indiziert, dann arbeitet
der
SWAP-Befehl korrekt.
Beispiel:
TYPE SwapTest ' Benutzerdefinierter Datentyp
x AS INTEGER
y AS INTEGER
END TYPE
DIM a(1 TO 2) AS SwapTest ' Array anlegen
c% = 1
d% = 2
a(1).x = 1 ' Felder initialisieren
a(1).y = 2
a(2).x = 3
a(2).y = 4
CLS
PRINT "vor SWAP: "; a(c%).y, a(d%).y
SWAP a(c%).y, a(d%).y
PRINT "nach SWAP: "; a(c%).y, a(d%).y
2.35. Der Multiplexer Interrupt Fehler im REG-Befehl
----------------------------------------------------
Versionen: 2.x/3.0/3.1/3.2
bekannt : Fehler in Version 3.50 beseitigt
Erstaunlicherweise gibt es selbst einige Ungereimtheiten sofern Sie
mit dem REG-Befehl den Multiplexer-Interrupt &h2F aufrufen. In der
Regel hat es den Anschein das der Aufruf vom System abgewiesen wird.
Ein Gegentest beweist aber das es mit dem Inline-Assembler
funktioniert!
Beobachtet wurde dieser Effekt bei der Programmierung des MSCDEX, der
Abfrage der Windows-Version und der Timeslice-Funktion des
Multiplexer-
Interrupts.
Abhilfe schafft nur konsequentes Programmieren mit dem
Inline-Assembler.
Beispiel:
! mov ax, &h1680
! int &h2F
! mov Taskfreigabe%, ax
Taskfreigabe% = Taskfreigabe% AND 255
SELECT CASE Taskfreigabe%
CASE &h80 : PRINT "Taskfreigabe nicht unterstützt"
CASE &h0 : PRINT "Taskfreigabe wird unterstützt"
CASE ELSE : PRINT "unerwarteter Wert"
END SELECT
REG 1, &h1680
CALL INTERRUPT &h2F
Taskfreigabe% = REG(1)
Taskfreigabe% = Taskfreigabe% AND 255
SELECT CASE Taskfreigabe%
CASE &h80 : PRINT "Taskfreigabe nicht unterstützt"
CASE &h0 : PRINT "Taskfreigabe wird unterstützt"
CASE ELSE : PRINT "unerwarteter Wert"
END SELECT
Die Ursache für diesen Effekt liegt in der Wirkungsweise des
REG-Befehls
begründet, allerdings hat QuickBASIC diese Probleme nicht. <g>
2.36. Inhalt eines Verzeichnis wird mit KILL gelöscht
-----------------------------------------------------
Versionen: 3.0/3.1/3.2
bekannt : nein
Ein nettes Feature verbirgt sich in dem KILL-Befehl von PowerBASIC.
Sollten Sie die Pfadangabe mit einem Backslash (ohne weitere Wildcards
oder Dateinamen abschliessen), dann wird das komplette Verzeichnis
gelöscht.
Beispiel:
KILL "C:\TEMP\" ' löscht alle Dateien im TEMP-
' Verzeichnis
2.37. Die Sache mit der Zeichenkette "USR"
------------------------------------------
Versionen: 3.0/3.1/3.2
bekannt : Fehler in Version 3.50 beseitigt
Ein völlig unerklärliches Verhalten in der PowerBASIC-IDE und dem
Kommandzeilen-Compiler ist zu beobachten, wenn die Zeichenkette 'USR'
in der Source vorkommt. Da der Compiler im ersten Beispiel abstürzt,
ist definitiv von einem Bug zu sprechen.
Beispiel:
PRINT USR ' PB/PBC stürzt ab
Test% = USR ' Error 477
2.38. Der GOTO DWORD Bug
------------------------
Versionen: 3.2
bekannt : beseitigt in Version 3.50
PowerBASIC vergißt ganz simpel den Segmentanteil der Adresse, that's
all.
Beispiel:
Demo??? = CODEPTR32(TestLabel)
GOTO DWORD c???
$SEGMENT
TestLabel:
PRINT "Test"
END
2.39. Der 'ON LOCAL ERROR' Bug
------------------------------
Versionen: 3.0/3.1/3.2
bekannt : beseitigt in Version 3.50
Bei Verwendung von 'ON LOCAL ERROR' in einer PBU kann zu einem Absturz
des Programms führen.
Beispiel:
'Main file
$COMPILE EXE
$LINK "TEST.PBU" 'oder PBL
FileName$ = "TEST.DOC"
CALL ResumeDemo(Demo%)
PRINT "Error", Demo%
END
'Unit file
$COMPILE UNIT
SUB ResumeDemo (Demo%) PUBLIC
ON LOCAL ERROR RESUME NEXT
' Zum Test dieses File mit Winword etc. erstellen und
einmal
' abspeichern
OPEN "TEST.DOC" FOR BINARY AS #1
Demo% = ERRTEST
END SUB
2.40. ... und nochmal 'ON LOCAL ERROR'
--------------------------------------
Versionen: 3.0/3.1/3.2/3.5
bekannt : nein
PowerBASIC stürzt ab, wenn in einer SUB/FUNCTION mit "ON ERROR"
anstatt
mit "ON LOCAL ERROR" gearbeitet wird. In diesem Fall kann es zu einem
Stack bzw. Stringspeicher Problem kommen, sofern der erwartete Fehler
auch eintritt.
Natürlich ist dies ein eindeutiger Programmierfehler, aber der
Compiler
sollte dieses bereits beim compilieren erkennen.
2.41. Laufzeitfehler im PowerBASIC Helpcompiler
-----------------------------------------------
Versionen: 3.0 (Helpcompiler)
bekannt : nein
Der Helpcompiler (bzw. Encoder) scheint irgendwie reichlich Fehler zu
enthalten. Vor allem Anfängern bereit der Laufzeitfehler 9 an der
Adresse 10095 bestimmt viel Ärger. Dies ist ein interner Fehler des
Helpcompilers, der durch das Nichtvorhandensein des Befehls '/LOOKUP'
ausgelöst wird.
2.42. Der Fehler Truncating im PowerBASIC Helpcompiler
------------------------------------------------------
Versionen: 3.0 (Helpcompiler)
Der Fehler 'Truncating ... to 76 characters' wird des öfteren
irrtümlich
angezeigt, da die Steuerzeichen nicht berücksichtigt werden.
2.43. Absturz der PowerBASIC-IDE nach Aufruf der eigenen Hilfe
--------------------------------------------------------------
Versionen: 3.0 (Helpcompiler)
Bei der Programmierung bzw. eigentlich dem Schreiben der Hilfe müssen
Sie aufpassen, das die effektive Länge der darzustellenden Textzeile
nicht größer als die wirklich vorhandene Zeilenbreite des PowerBASIC-
Hilfefensters ist, da die PowerBASIC-IDE in diesem Fall mit einem
Grafikfehler abstürzt.
Dieser Fehler tritt nur in der Endwicklungsphase einer selber
geschriebenen Hilfedatei (*.PBH) auf!
=================================
3. PowerBASIC und der CoProzessor
=================================
3.1. Unterstützt PowerBASIC einen CoProzessor?
3.2. Welche Fließkommabibliothek ist für mich die optimale?
3.3. Macht sich der CoProzessor auch bei $FLOAT PROCEDURE bemerkbar?
3.4. Welche PowerBASIC-Funktionen sind betroffen?
3.5. mögliche Ursachen für den CoProzessor-Effekt
3.6. PowerBASIC-Benchmark Source
3.1. Unterstützt PowerBASIC einen CoProzessor?
----------------------------------------------
Die Antwort lautet ganz einfach JA. Bereits in den Compiler-Optionen
haben Sie die Möglichkeit drei verschiedene Fließkommabibliotheken
auszuwählen. Aber mit dieser Unterstützung des CoProzessors sind unter
PowerBASIC einige Haken verbunden, die es hier aufzuzeigen geht damit
sie schnellere und hoffentlich nur sauber funktionierende Programme
entwickeln.
3.2. Welche Fließkommabibliothek ist für mich die optimale?
-----------------------------------------------------------
PowerBASIC bietet insgesamt drei Fließkommabibliotheken an:
a) $FLOAT EMULATE
Dieses ist die DEFAULT-Bibiothek und dadurch in der Regel bei ca
95%
der Anwender im Einsatz. Sie zeichnet sich durch automatische
Unter-
stützung des i87 aus, sofern ein solcher CoProzessor gefunden
wurde.
Der enorme Nachteil liegt aber sofort auf der Hand. PowerBASIC
testet ständig auf einen CoProzessor und wird dadurch erheblich
langsamer sofern wirklich kein i87 installiert ist.
b) $FLOAT PROCEDURE
Diese Bibliothek ist mit Abstand die schnellste, sofern kein Co-
Prozessor installiert ist.
c) $FLOAT NPX
Mit Abstand liegt diese Bibliothek vorne, sofern jedenfalls ein
i87 vorhanden ist.
3.3. Macht sich der Coprozessor auch bei $FLOAT PROCEDURE bemerkbar?
--------------------------------------------------------------------
Auch hier ist die Antwort ganz klar: JA. Obwohl PowerBASIC keine
Coprozessorunterstützende Fließkommabibliothek eingebunden hat, läßt
sich dies anhand der beiliegenden Source sehr deutlich beweisen.
Des Rätsels Ursache liegt in der PowerBASIC-Runtime-Bibliothek, diese
unterstützt schon von Hause aus einen i87. Deshalb lassen sich auch
die
Geschwindigkeitsauswirkungen der verschiedenen Fließkommabibliotheken
nicht verallgemeinern.
3.4. Welche PowerBASIC-Funktionen sind betroffen?
-------------------------------------------------
Als betroffende internen PowerBASIC-Funktionen wäre da vorallem
SELECT CASE zu nennen. Messungen haben gezeigt das SELECT CASE mit i87
5 Sekunden braucht. Unter den gleichen Voraussetzungen (aber ohne i87)
bis zu 200 Sekunden benötigen kann ($FLOAT EMULATE). Enorme Ver-
besserungen waren bereit mit $FLOAT PROCEDURE zu erreichen (jetzt
nur noch 35 Sekunden).
Im allgemeinen kann gesagt werden: SELECT CASE hat nichts in zeit-
kritischen Routinen zu suchen.
Ebenso, aber bei weitem nicht so extrem, ist die PRINT-Ausgabe von
nummerischen Ausdrücken betroffen.
3.5. mögliche Ursachen für den CoProzessor-Effekt
-------------------------------------------------
Meines Erachtens hat dieser Effekt recht natürliche Ursachen, da alle
betroffenden Befehle mit dem neuen 80-stelligen Zahlensystem umgehen
können müssen. Anscheinend haben die Programmierer von PowerBASIC ver-
sucht den zusätzlichen Rechenaufwand durch Einsatz des CoProzessors
wieder wettzumachen. Wobei Ihnen dies bei vorhandenem CoProzessor
auch recht gut gelungen ist.
Andererseits kann man sich fragen, warum der Compiler dies nicht
besser
optimiert sofern nur normale 16/32bit Zahlen eingesetzt werden.
3.6. PowerBASIC-Benchmark Source
--------------------------------
Die hier beigefügte Source soll Ihnen die Zusammenhänge der vorherigen
Abschnitte besser demonstrieren. Am besten Sie compilieren die Source
und testen einfach ein wenig herum.
Source:
REM
*****************************************************************
REM
REM PBBENCH.EXE - Performance-Meßprogramm für PowerBASIC
REM
REM Zum Feststellen der Geschwindigkeitsunterschiede einzelner
REM PowerBASIC-Befehle in Verbindung der verwendeten Fließkomma-
REM bibiothek bei vorhanden bzw. nichtvorhandensein eines
REM Coprozessors.
REM
REM Copyright: Thomas Gohel & Andras Hoeffken Version
2.10
REM Alle Rechte vorbehalten
REM
REM
-----------------------------------------------------------------
REM
REM Wichtige Hinweise:
REM Für halbwegs reale Meßungen muß sich der Prozessor im REAL-
REM Mode befinden. Es dürfen keine TSR-Treiber installiert sein,
REM also kein KEYB.COM, SMARTDRV.EXE oder ähnliches.
REM Wichtig:
REM Für eine halbwegs genaue Meßung muß das Programm mehrmals
REM aufgerufen und dann Mittelwerte gebildet werden.
REM
REM Besitzer von 486'er/586'ern bzw. 286/386'ern mit
REM installiertem x87'er Prozessor können den CoProzessor für
REM PowerBASIC mit dem in dieser Source beigefügtem Listing
REM Ein/Aus schalten. Das muß allerdings die IDE bzw. das
fertige
REM EXE-File erneut gestartet werden!
REM
REM
*************************************************************
REM
$COMPILE EXE "PBBENCH.EXE"
$CPU 80386
$LIB ALL OFF
REM $FLOAT NPX ' für Rechner mit CoProzeßor (am
' schnellsten)
REM $FLOAT PROCEDURE ' für Rechner ohne CoProzeßor (von mir
' empfohlen)
REM $FLOAT EMULATE ' automatisch unterstützen (ohne
' Coprozessor extrem langsam!!
REM $DEBUG MAP OFF
PRINT
PRINT "Performance-Messprogramm fuer PowerBASIC";:
PRINT TAB(58); "(c) A.Hoeffken/Th.Gohel";:
PRINT TAB(68); "Version 2.10";:
PRINT STRING$(80,"-");
PRINT
a% = 1 ' diverse Variablen
i% = 1234 ' -"-
e& = 12345678 ' -"-
REM Zc1! für 5000000-Schleifen ; zum Herausrechnen der Zeiten
REM Zc2! für 2000000-Schleifen ; für die FOR/NEXT-Schleifen
REM Zc3! für 100000-Schleifen
REM Zc4! für 2000-Schleifen
IF pbvnpx > 0 THEN
PRINT "CoProzessor " + CHR$(pbvnpx+48) + "87 gefunden!"
PRINT
PRINT "Soll der CoProzessor für die nächste Messung ";
PRINT "ausgeschaltet werden (J/N)?"
BEEP
A$ = UCASE$(INPUT$(1))
IF A$ = "J" THEN CoPro "AUS"
ELSE
PRINT "kein CoProzessor gefunden!"
PRINT
PRINT "Soll der CoProzessor für die nächste Messung ";
PRINT "wieder eingeschaltet werden (J/N)?"
PRINT
PRINT "Hinweis: Einschalten dieses Testes bei nicht ";
PRINT "installiertem Coprozessor führt"
PRINT " zum Absturz!"
BEEP
A$ = UCASE$(INPUT$(1))
IF A$ = "J" THEN CoPro "EIN"
END IF
PRINT
GOSUB HoleZeitKonstanten
GOSUB MesseFORNEXT
GOSUB MesseIFTHEN
GOSUB MesseSELECTCASE
GOSUB MesseMATHEMATIK
GOSUB MesseSTRING
GOSUB MesseNUMPRINT
GOSUB MesseSTRPRINT
PRINT
END
'********************************************************************
' Holen der einzelen Zeitkonstanten für die einzelnen Messungen
'********************************************************************
HoleZeitKonstanten:
PRINT "Messung der Zeitkonstanten ";
t1! = TIMER
FOR i& = 1 TO 2000 ' Zeit für 2000-Schleifen ausmessen
NEXT i&
t2! = TIMER
Zc4! = t2! - t1!
PRINT ".";
t1! = TIMER
FOR i& = 1 TO 5000000 ' Zeit für 5-Mio-Schleifen ausmessen
NEXT i&
t2! = TIMER
Zc1! = t2! - t1!
PRINT ".";
t1! = TIMER
FOR i& = 1 TO 100000 ' Zeit für 100000-Schleifen ausmessen
NEXT i&
t2! = TIMER
Zc3! = t2! - t1!
PRINT "."
t1! = TIMER
FOR i& = 1 TO 2000000 ' Zeit für 2-Mio-Schleifen ausmessen
NEXT i&
t2! = TIMER
Zc2! = t2! - t1!
RETURN
'********************************************************************
'
' Hier nun die einzelnen Routinen zur Zeitmessung der einzelnen
' Befehle. Im Prinzip ist die Messung immer abhängig vom
verwendeten
' Computersystem und dem installiertem Betriebssytem. Gerade aber
in
' Verbindung mit PowerBASIC, der verwendeten Fließkommabibiliothek
' und dem Vorhandensein eines CoProzessors lassen sich erhebliche
' Unterschiede bei der Performance einzelner Befehle ermitteln.
'
'********************************************************************
MesseFORNEXT:
PRINT "Messe FOR/NEXT : ";
t1! = TIMER
FOR i& = 1 TO 5000000 '5-Millionen-Schleife ausmessen,
NEXT i& 'i = long integer
t2! = TIMER
PRINT t2! - t1!; "sec "
RETURN
MesseIFTHEN:
PRINT "Messe IF/THEN : ";
t1! = TIMER
FOR i& = 1 TO 5000000
IF a% = 0 THEN 'IF THEN Methode
ELSEIF a% = 2 THEN
ELSE
END IF
NEXT i&
t2! = TIMER
PRINT t2! - t1! - Zc1!; "sec "
RETURN
MesseSELECTCASE:
PRINT "Messe SELECT CASE: ";
t1! = TIMER
FOR i& = 1 TO 2000000
SELECT CASE A% 'SELECT CASE Methode
CASE 0
CASE 1
CASE ELSE
END SELECT
NEXT i&
t2! = TIMER
PRINT t2! - t1! - Zc2!; "sec "
RETURN
MesseMATHEMATIK:
PRINT "Messe MATHEMATIK : ";
t1! = TIMER
FOR i& = 1 TO 2000000
i% = i% + 100 'extrem einfache Aufgaben
e& = e& * 2
e& = e& \ 2
i% = i% - 100
NEXT i&
t2! = TIMER
PRINT t2! - t1! - Zc2!; "sec "
RETURN
MesseSTRING:
PRINT "Messe STRING's : ";
t1! = TIMER
FOR i& = 1 TO 2000
A$ = STRING$(20000, 32)
A$ = RIGHT$(A$, 10000) + "Test"
e% = INSTR(A$, "Test")
A$ = ""
NEXT i&
t2! = TIMER
PRINT t2! - t1! - Zc4!; "sec "
RETURN
MesseNUMPRINT:
PRINT "Messe NUM-PRINT's ";
t1! = TIMER
FOR i& = 1 TO 100000
LOCATE , 1
PRINT "Messe NUM-PRINT's: "; i&;
NEXT i&
t2! = TIMER
LOCATE , 20
PRINT t2! - t1! - Zc3!; "sec "
RETURN
MesseSTRPRINT:
PRINT "Messe $$$-PRINT's ";
t1! = TIMER
FOR i& = 1 TO 100000
LOCATE , 1
PRINT "Messe $$$-PRINT's: ";
NEXT i&
t2! = TIMER
LOCATE , 20
PRINT t2! - t1! - Zc3!; "sec "
RETURN
'*****************************************************************
' Hier nun die Routine zum Ausschalten des Coprozessors
'*****************************************************************
SUB Copro(Switch$)
SELECT CASE UCASE$(Switch$)
CASE "AUS", "OFF", "-"
! mov ax, &h0040
! mov es, ax
! mov ax, word ptr es:[&h10]
! and ax, &b1111111111111101
! mov word ptr es:[&h10], ax
CASE "EIN", "ON", "+"
! mov ax, &h0040
! mov es, ax
! mov ax, word ptr es:[&h10]
! or ax, &b0000000000000010
! mov word ptr es:[&h10], ax
END SELECT
END SUB
====================
4. Standard-Probleme
====================
4.1. Kompatibilität der PBU's & LIB's zwischen den 3'er Versionen
4.2. Zu wenig Speicherplatz innerhalb der PowerBASIC-IDE
4.3. Ermitteln des eigenen Dateinamens und dem Pfad zum Dateinamen
4.4. Kein Speicherplatz verfügbar bei ENVIRON$
4.5. Keine Errorcode-Zurückgabe bei SHELL
4.6. Kürzen von Files
4.7. Fehler 502/514 bei Verwendung von C-OBJ-Files
4.8. Warmboot über STRG-ALT-ENTF verhindern
4.9. Öffnen von mehr als 15 Files mit PowerBASIC und/oder mit DOS
4.10. HEX$-DWORD Routine für PowerBASIC 3.1/3.2
<Hier fallen mir einfach keine mehr ein>
4.1. Kompatibilität der PBU's & LIB's zwischen den 3'er Versionen
-----------------------------------------------------------------
Im Gegensatz zum PowerBASIC-Update von der V2.10 auf die V3.00 sind
die PBU/LIB's der PowerBASIC 3'er Versionen untereinander abwärt-
kompatibel. Das heißt, sie können eine mit PowerBASIC 3.0 erstellte
PBU/LIB unter den beiden höheren PowerBASIC Versionen weiterverwenden.
Eine mit PowerBASIC 3.1 erstellte PBU/LIB können Sie dagegen
allerdings
nicht mehr in der älteren Version nutzen.
Zwischen den Versionen 3.0-3.1 gibt es aber Aufgrund des erweiterten
Zahlensystems eventuell Unterschiede beim Austausch von Sourcen unter-
einander. In diesem Fall lesen Sie sich bitte auch den Abschnitt
'Fehler ...' durch.
4.2. Zu wenig Speicherplatz innerhalb der PowerBASIC-IDE
--------------------------------------------------------
Für das 'ständig vorhandene' Speicherplatzproblem innerhalb der
integrierten Entwicklungsumgebung wurde von Bob Zale selbst ein Tool
entwickelt, welches die Bereiche des VGA-Grafik-RAM's, sowie den
Bereich
der monochromen Herculeskarte für PowerBASIC erschliesst. Obwohl das
Tool 'PBPLUS96' (96kByte mehr RAM) für die PowerBASIC Version 2.00
entwickelt wurde, funktioniert es ebenso unter PowerBASIC Version
3.10.
4.3. Ermitteln des eigenen Dateinamens und dem Pfad zum Dateinamen
------------------------------------------------------------------
Oft stehen Sie vor dem Problem das Sie zwar Ihr Programm über einen
Pfad-Befehl aufrufen können, dieses dann aber die eigenen Daten und
INI-Files nicht mehr findet. Die Lösung ist recht einfach: DOS
speichert diese Informationen im PSP bzw. im zum PSP gehörigen
Environmentblock.
--- Cut --------------------------------------------------------------
'*********************************************************************
'
' Pfad und Dateiname des aktuellen Programm ermitteln in
' PowerBASIC 3.0/3.2
'
' von Thomas Gohel
'
'*********************************************************************
$COMPILE EXE
! mov ax, &h6200
! int &h21
! mov es, bx
! mov ax, word ptr es:[&h2C]
! mov pbvDefSeg, ax ; undokumentiert in PowerBASIC 3.0
FOR i% = 0 TO 1024
IF PEEK$(i%, 4) = CHR$(0,0,1,0) THEN EXIT FOR
NEXT i%
WHILE PEEK(i% + 4) <> 0
Temp$ = Temp$ + CHR$(PEEK(i% + 4))
i% = i% + 1
WEND
DEF SEG
FOR i%=LEN(Temp$) TO 1 STEP -1
IF RIGHT$(MID$(Temp$,1,i%),1) = "\" THEN EXIT FOR
NEXT i%
ExeDir$ = MID$(Temp$,1,i%)
ExeName$ = MID$(Temp$,i%+1)
PRINT ExeDir$; " "; ExeName$
--- Cut End ----------------------------------------------------------
4.4. Kein Speicherplatz verfügbar bei ENVIRON$
----------------------------------------------
Dieser Absatz ist zwar teilweise im Handbuch beschrieben, doch möchte
ich einige weiterführende Tips geben, da dieses Thema immer wieder zu
Mißverständnissen führt. Der Aufbau des Environmentblockes in
Verbindung
mit dem Programm Segment Prefix wird nicht weiter beschrieben, ist
allerdings von enormer Bedeutung zum besseren Verständnis dieses
Fehlers.
Zusammenfassend sei gesagt, das Sie nur das vorhandene Environment
modifizieren und nicht durch neue Einträge erweitern können!! Wollen
Sie
nun trotzdem Einträge hinzufügen, so können Sie 3 Wege beschreiten:
a) Teile des Environment löschen und dann den neuen Eintrag hinzufügen
oder bereits vorher einen Dummy-Environmenteintrag anlegen und
diesen
dann per ENVlRON-Befehl löschen bzw. modifizieren.
b) Wenn Sie z.B. eine DOS-SHELL mit einer Information starten wollen:
OldEnv$ = ENVIRON$("PROMPT")
SHELL "COMMAND.COM /K SET PROMPT=PowerBASIC " + OldEnv$
Der Trick hierbei ist, das bei einer SHELL automatisch ein neuer
PSP
erstellt wird und somit auch der Speicher passend angefordert wird.
c) Die Adresse des PSP ermitteln, dann den Zeiger auf den aktuellen
Environmentblock holen und jetzt das Environment komplett in einen
String packen wo es modifiziert werden kann. Abschliessend einen
passenden DOS-Speicherblock per INT21 anfordern, das modifizierte
Environment dorthin kopieren und den Zeiger zum Environmentblock
innerhalb des Programm Segment Prefix anpassen.
(siehe auch: bereits vorhandene PD-Lösungen)
4.5. Keine Errorcode-Zurückgabe bei SHELL
-----------------------------------------
Vielfach ist es erforderlich, wenn nach einem SHELL-Aufruf der
Errorcode
des beendeten Programms abgefragt werden kann. Dies ist in PowerBASIC
nicht direkt möglich, da PowerBASIC das Programm immer über
COMMAND.COM
ausführt und deshalb der Errorcode nicht zurückgeben werden kann (dies
ist eine Eigenart von MS-DOS!!).
Bespiel:
SHELL "C:\DOS\COMMAND.COM /C MEINDEMO.EXE"
Für die Lösung dieses Problems gibt es zum einen einen alternativen
SHELL-Befehl in Form einer FUNCTION (also Sourcecode):
--- Cut
---------------------------------------------------------------
'**********************************************************************
'
' Errorlevel in PowerBASIC 3.0/3.2
'
' von Thomas Gohel (nach einer Vorlage aus PDS, von Bernd Hohmann)
'
'***********************************************************************
$COMPILE EXE
DECLARE FUNCTION PBShell% (FileName$)
CLS
PRINT
PRINT "Fehlercode ist: "; PBShell%("c:\dos\command.com")
END
FUNCTION PBShell% (FileName$)
LOCAL Dummy%
Datei$ = FileName$ ' Dateiname umkopieren.
Datei$ = LTRIM$(Datei$) ' Filename trimmen.
i% = INSTR(Datei$, " ") ' Kommando übergeben ?
IF i% > 0 THEN '
Cmd$ = MID$(Datei$, i%) ' Kommando abtrennen
Datei$ = LEFT$(Datei$, i% - 1) ' Filename abtrennen
END IF '
Datei$ = UCASE$(Datei$)
i% = INSTR(Datei$, ".") ' Ist ein Punkt drin ?
IF i% > 0 THEN '
Ext$ = MID$(Datei$, i%) ' Extension holen.
ELSE '
Ext$ = "" ' Extension ist leer.
END IF '
SELECT CASE Ext$ ' Extensions abtesten.
CASE ".BAT" ' Batch über COMMAND.COM
' ausführen.
Cmd$ = "/C " + Datei$ + " " + Cmd$
Datei$ = ENVIRON$("COMSPEC")
CASE ".COM" ' Frei
CASE ".EXE" ' Frei
CASE ELSE ' Keine Extension,
Datei$ = Datei$ + ".EXE" ' .EXE anhängen.
END SELECT '
Datei$ = Datei$ + CHR$(0) ' ASCIIZ-String erzeugen.
dNul$ = CHR$(0) + CHR$(0) ' Doppelnull fuer
Parameter-Block
nul$ = SPACE$(127) ' 127 bytes fuer Strings
retten.
MemFree& = SETMEM(0) ' Freien Speicherplatz holen.
x& = SETMEM(-MemFree&) ' Speicherplatz komplett
' freigeben.
nul$ = "" ' 127 bytes wieder freigeben.
IF Cmd$ > "" THEN ' Kommandozeile ?
CmdLen$ = CHR$(LEN(Cmd$)) ' Länge des Cmd$ als String
Cmd$ = CmdLen$ + Cmd$ + CHR$(13) ' Länge + Cmd$ + '13'
segm$ = MKI$(STRSEG(Cmd$)) ' Einzeln die Teile des
' Parameter-Blocks
Offs$ = MKI$(STRPTR(Cmd$)) ' erzeugen ( MID$(....)
' = segm$ geht nicht. )
Param$ = dNul$ + Offs$ + segm$ ' Parameterblock machen.
ELSE '
Cmd$ = CHR$(13) ' Start of Bug-Fixed
segm$ = MKI$(STRSEG(Cmd$)) ' Segment des Terminator
(Dummy)
Offs$ = MKI$(STRPTR(Cmd$)) ' Offset -"-
Param$ = dNul$ + Offs$ + segm$ ' Parameterblock machen.
END IF ' End of Bugfixed
DateiSeg% = STRSEG(Datei$) ' Adressen holen
DateiOff% = STRPTR(Datei$)
ParamSeg% = STRSEG(Param$)
ParamOff% = STRPTR(Param$)
! push ds ; DS sichern
! mov ax, &h4B00 ; EXEC-Funktion 4Bh / INT 21h
! mov es, ParamSeg% ; Segment des Parameterblocks
! mov bx, ParamOff% ; Offset des Parameterblocks
! mov dx, DateiOff% ; Offset des Dateinamens
! mov ds, DateiSeg% ; Segment des Dateinamens
! int &h21 ; Interrupt &h21
! pop ds
! jc ExecError
! jmp ExecOk
ExecError:
! mov Dummy%, ax
SELECT CASE Dummy% ' Fehler auswerten.
CASE 1 : PRINT "illegaler Funktionsaufruf!"
CASE 2,3 : PRINT "Datei nicht gefunden: " + FileName$
CASE 4 : PRINT "zu viele Dateien geöffnet"
CASE 5 : PRINT "Zugriff verweigert " + Filename$
CASE 8 : PRINT "Zuwenig freier Speicher für " + FileName$
CASE 10 : PRINT "falscher Environmentblock"
CASE 11 : PRINT "falsches Format"
CASE ELSE: PRINT "Problem meim Ausführen von " + FileName$
END SELECT
ExecOk:
Mem2& = SETMEM(MemFree&) ' Speicher komplett
freigeben.
IF MemFree& <> Mem2& THEN ' Speicher stimmt nicht mehr
??
PRINT "Achtung: vermutlich wurde ein TSR installiert!!"
END IF
! mov ah, &h4d ; Exit-Code ermitteln
! int &h21 ; Interrupt &h21
! mov Dummy%, al
PBShell% = Dummy%
! mov ah, &h03 ; Aktuelle Cursorposition
! mov bh, &h00 ; übergeben
! int &h10 ; Interrupt &h10
! inc dh ; Umrechnen auf Basis 1
! inc dl
! mov NewZeile?, dh
! mov NewSpalte?, dl
LOCATE NewZeile?, NewSpalte? ' Cursor setzen
END FUNCTION
- Cut End
-------------------------------------------------------------
Des weiteren können Sie die COMSPEC-Variable in Ihrem Environment
modifizieren und Ihr Programm ohne Umwege über COMMAND.COM direkt
ausführen.
Beispiel:
Comspec$ = ENVIRON$("COMSPEC") 'Sichern von COMSPEC
ENVIRON "COMSPEC=MEINDEMO.EXE"
SHELL 'Ausführen von MEINDEMO.EXE
ENVIRON "COMSPEC="+Comspec$ 'Restaurieren von COMSPEC
Beachten Sie allerdings, das die SHELL-Funktion immer automatisch
den Parameter '/C' dem ausführendem Programm übergibt, sofern Sie
zum Beispiel Kommandozeilenparameter übergeben wollen.
4.6 Kürzen von Files
--------------------
Oft stehen Sie vor dem Problem das Sie Ihr Datenfile aufgeräumt haben,
dieses aber immer noch viel zu groß ist. In diesem Fall hilft wie so
oft ein kleiner aber effektiver Kniff:
Beispiel:
OPEN "DEMO.DAT" FOR BINARY AS #1
SEEK #1, 20
PUT$ #1, ""
CLOSE #1
Verkürzt die Datei 'DEMO.DAT' auf 20Bytes Länge.
4.7. Fehler 502/514 bei Verwendung von C-OBJ-Files
--------------------------------------------------
Bei der Verwendung von C-OBJ-Files ist darauf zu achten, das in der
OBJ-Datei nicht mehrere Anweisungen für das Datensegment zu finden
sind,
da PowerBASIC nur ein Datensegment pro OBJ-File unterstützt.
Da mir zu Zeit auch keine Lösung zu diesem Problem bekannt ist und es
vermutlich keine seitens PowerBASIC gibt, bleibt meines Erachtens nur
das Anpassen Ihrer C-Source übrig.
4.8. Warmboot über STRG-ALT-ENTF verhindern
-------------------------------------------
Folgende Source verhindert einen möglichen Warmboot:
Beispiel:
KEY 15, CHR$(&h0C, &h53, &h73)
ON KEY(15) GOSUB NoBoot
KEY(15) ON
DO
IF INKEY$ <> "" THEN EXIT LOOP
LOOP
PRINT "Fertig"
END
NoBoot:
PRINT "Warmstart nicht erwünscht!"
RETURN
4.9. Öffnen von mehr als 15 Files mit PowerBASIC und/oder mit DOS
-----------------------------------------------------------------
Oft scheint man an die Grenzen von PowerBASIC zu stoßen, sofern man
mehr als 15 Files öffnen will. Dabei ist dieses Problem überhaupt
nicht
ein Mangel des Compilers, sondern eher ein genetischer Geburtsfehler
von MS-DOS.
Um diesen Effekt zu erklären muß ich leider ein wenig in die Untiefen
von DOS Licht bringen, denn dort finden wir auch des Rätsels Lösung.
Vielen ist bestimmt bekannt, das nach dem Öffnen von Dateien ein
Handel zurückgeliefert wird. Nur wo speichert DOS dieses Handle und
die Informationen die zu diesem Handle gehören?
Vielen ist bestimmt der Begriff PSP (Programm Segment Prefix) ein
Begriff (bereits kurz erwähnt bei der Ermittlung des Dateinamens),
wenn
nicht sollten Sie die folgenden Ausführungen besser überlesen und die
Source testen.
Dieses PSP enthält jedenfalls eine Tabelle, welche durch Microsoft
zwar als reserviert gilt, deren Bedeutung aber längst klar ist. Diese
Tabelle nennt sich 'Job File Table' (kurz JFT) und befindet sich ab
DOS 2.0 am Offset 18Hex und umfasst ein 20 Felder großes BYTE-Array.
Zieht man jetzt die ständig belegten Handles für: NUL, $CLOCK, CON
AUX und PRN ab, so verbleiben unsere magischen verfügbaren 15 Handles.
Die Aufgabe der JFT ist es allerdings lediglich, einen Zeiger auf die
'System File Table' kurz SFT zu verwalten.
Die SFT wiederum ist eine MCB (Memory Controll Block) ähnlich
verkettete
Struktur, welche wichtige Daten wie Startcluster und Sharingattribute
verwaltet. Eine solche SFT kann nur eine bestimmte Anzahl von Handles
beinhalten, um diese zu Erhöhen muß in der CONFIG.SYS ein höherer Wert
bei
FILES angegeben werden. Nach dem Neustart des System reserviert MS-DOS
nun mehr als SFT markierte MCB's. Sie könnten also nun theoretisch
mehr
als 20 Files öffnen, denn der Defaultwert bei FILES ist '8'.
Leider stoßen wir hierbei wiederum auf die begrenzte Anzahl der
Einträge
in der JFT innerhalb des PSP. Ab MS-DOS 3.3 gibt es hierbei aber
Abhilfe,
da der INT &h21, Funktion &h67 ermöglicht die Anzahl der verfügbaren
Handles zu erhöhen. Nur wie geht das genau, wo doch der Platz
innerhalb
des PSP begrenzt ist??
Dazu erinnern wir uns wieder an die undokumentierten Felder innerhalb
des PSP. Interessant wird jetzt der Offset &h32, dieser enthät die
neue
Größe der JFT in WORD. Darauf folgt der neue Pointer zur Extendet JFT.
Interessant ist hierbei nur, das dieses neue Array ein Array vom Typ
WORD ist. Es können also theoretisch 65535 Handles verwaltet werden,
was allerdings rein Hypothetisch ist, da die SFT weiterhin nur 255
Ein-
träge verwalten kann.
Wichtig bei der Neuzuweisung einer JFT sind eigentlich nur zwei Dinge:
- Die neuen JFT benötigt Speicher, das heißt sie müssen den Heap
des aktuellen PowerBASIC Programms herunterschrauben!
- Eine Extendet JFT wird bei SHELL/EXECUTE nicht an das Child-
Programm vererbt! Für das Child-Programm gilt also wieder die
15 Files Grenze.
Ok, jetzt aber die Source:
'***********************************************************************
'
' Erhöhen der verfügbaren Handles in PowerBASIC 3.2
'
' entwickelt von Th.Gohel Fido: 2:2410/301.12
' InterNet: sup****t@[EMAIL PROTECTED]
' Homepage: http://www.snafu.de/~pbsound/
'
'***********************************************************************
MaxFiles% = 30 ' entspricht FILES = 30
PBFiles MaxFiles% ' anpassen der verfügbaren Files
FOR i% = 1 TO MaxFiles% ' Testen der verfügbaren Files
PRINT "Öffne File: PBFILES." + STR$(i%)
OPEN "PBFILES." + STR$(i%) FOR BINARY AS i%
PUT$ i%, "Testdatei" + STR$(i%) + " für PBFILES, bitte löschen!"
NEXT i%
FOR i% = 1 TO MaxFiles% ' und wieder schliessen
CLOSE i%
NEXT i%
SUB PBFiles(BYVAL MoreFiles%)
x& = SETMEM(-255) ' sollte Ausreichen für alle
Fälle
! mov ah, &h67 ; Anzahl der verfügbaren Handles
! mov bx, MoreFiles% ; festlegen
! add bx, 6 ; die Standard-Handles für PB
! int &h21
! jnc PBFiles_Ok
PRINT "Fehler beim Einrichten der verfügbaren Handles!!"
PBFiles_Ok:
END SUB
4.10. HEX$-DWORD Routine für PowerBASIC 3.1/3.2
-----------------------------------------------
Nachfolgende Routine soll, den für mich unverständlicherweise
fehlenden
HEX$-Sup****t für Variablen vom Typ DWORD, ermöglichen.
Beispiel:
d??? = &h1234ABCD
PRINT DHex$(d???)
FUNCTION DHex(HexDWord???) AS STRING
DIM Lo AS WORD
DIM Hi AS WORD
! les bx, [bp+6]
! mov ax, es:[bx+0]
! mov Lo??, ax
! mov ax, es:[bx+2]
! mov Hi??, ax
DHex = RIGHT$("000" + HEX$(Hi??), 4) + RIGHT$("000" +
_
HEX$(Lo??), 4)
END FUNCTION
===============================================
5. Tip's in Verbindung mit dem Inline-Assembler
===============================================
Kurzübersicht:
5.1. Funktionsprinzip des PowerBASIC Inline-Assemblers
5.2. Assembler Syntax Error
5.3. Fehlerhafte Variablenübergabe im Inline-Assembler
5.4. Probleme mit LDS/LES
5.5. Absturz nach Aufruf einiger INT-Funktionen
5.6. Fixup Overflow
5.7. Variablen zerlegen von WORD nach BYTE
5.8. Variablen zerlegen von DWORD nach WORD
5.9. Zugriff mit dem Inline-ASM auf Array's/Strukturen
5.10. Parameterrückgabe mit dem Inline-ASM
5.11. Variablenübergabe in Interrupt-Prozeduren
5.12. Erstellen von 32bit-Zeigern
5.13. Konvertierung von REG nach Inline-ASM
5.14. Konvertierung von A86 nach Inline-ASM
Die hier beschriebenen Tip's sollen keinen Grundlehrgang im Inline-
Assembler darstellen, sondern nur die wichtigsten Anfängerprobleme
umschiffen zu helfen. Auf eine genauere Beschreibung der Zusammenhänge
wird deshalb verzichtet, es sei es gehört zum Problem selber.
5.1. Funktionsprinzip des PowerBASIC Inline-Assemblers
------------------------------------------------------
Der PowerBASIC Inline-Assembler besitzt den Funktionsumfang der Intel
8086 CPU. Das heißt, da Sie Inline-Assembler-Code anderer
Hochsprachen-
Compiler bzw. reinen Assembler-Code leicht an den PowerBASIC Inline-
Assembler anpassen müssen, da diese recht oft bereits 80286'er Befehle
enthalten. In der Regel fallen immer wieder folgende Befehle auf,
welche
Sie wie folgt konvertieren können:
<Listing>
Quell-Source - > PowerBASIC
shr ax, 2 ! shr ax, 1
! shr ax, 1
oder ähnlich wie folgt:
-----------------------------------------------------------
shl ax, 3 ! push cx
! mov cl, 3
! shl ax, cl
! pop cx
-----------------------------------------------------------
pusha ! push ax
! push bx
und so weiter bis alle Register ge-
sichert sind
-----------------------------------------------------------
popa analog, nur Register wieder
restaurieren.
<Ende>
5.2. Assembler Syntax Error
---------------------------
Wenn wir von einem richtigen Syntaxfehler absehen, der in der Regel
auf-
tritt wenn Sie noch nicht so recht mit den Assemblerbefehlen vertraut
sind, kann der Inline-Assembler von PowerBASIC auch einen
'scheinbaren'
Syntax Error erzeugen. Dies ist dann immer der Fall, wenn der Compiler
eine Variable im Inline-Assembler nicht auflösen kann, da Sie nicht in
irgendeiner Form definiert ist.
PowerBASIC legt normalerweise die verwendeten Variablen innerhalb
einer
reinen BASIC-Source selbstständig an und weist dieser Variablen Ihren
Speicherplatz zu. Innerhalb des Inline-Assemblers müssen Sie dafür
selber sorgen.
Beispiel:
! mov ax, Demo%
führt automatisch zu einem Syntax-Error, da der Compiler nichts mit
der
Variablen 'Demo%' anfangen kann. Sollten Sie der Variablen vorher
einen
Wert zuweisen:
Demo% = 1
! mov ax, Demo%
dann akzeptiert der Compiler nun die Assemblerzeile. Sie müssen aber
nicht jedesmal die Variable speziell mit einem Wert laden, ein bloßes
DIM oder auch SHARED, PUBLIC, LOCAL etc. reicht hierbei völlig aus und
initialisiert 'Demo%'.
5.3. Fehlerhafte Variablenübergabe im Inline-Assembler
------------------------------------------------------
Oft haben Sie bestimmt schon geflucht, da eine funktionierende Routine
mit REG(x) nach der Umsetzung in den Inline-Assembler nicht mehr
sauber
funktioniert oder wenn ebenso Ihre Testroutine nicht mehr in einer
SUB/FUNCTION ihre Arbeit verrichten will.
Des Rätsels Lösung ist relativ einfach: Sie müssen Variablen für den
Inline-Assembler immer BYVAL übergeben.
Beispiel:
Demo 1
FUNCTION Demo(BYVAL i%) public
! mov ax, i%
! inc ax
! mov i%, ax
PRINT i%
END FUNCTION
Dieses kleine Demo addiert per Inline-Assembler einfach den Wert '1'
und gibt diesen dann auf den Bildschirm aus. Lassen Sei einfach das
BYVAL in der Parameterübergabe weg und testen Sie das Demo erneut!
5.4. Probleme mit LDS/LES
-------------------------
Ähnlich wie bei der Parameterübergabe für den Inline-Assembler verhält
sich das Funktionsprinzip der Assemblerbefehle LDS/LES. Von ent-
scheidener Bedeutung ist hierbei ebenfalls ob Sie die Variable
'BY COPY', 'BY REFERENCE' oder auch 'BY VALUE' übergeben. Als
Faustregel
können Sie sich merken:
BY REFERENCE: - eigentlich als default im Hautprogramm
- bzw. wenn Sie die Variable als SHARED/PUBLIC etc.
deklariert haben.
BY COPY: - default immer in einer SUB/FUNCTION, sofern Sie
die Variable nicht BY VALUE übergeben.
BY VALUE: - interpretiert der Inline-Assembler immer als BY
REFERENCE.
LDS/LES sollten Sie nur Variablen vom Typ BY COPY übergeben, da nur
hierbei in DS/ES die Segmentadresse geladen wird und im anderen
Register
dann die Offsetadresse der Variablen.
Bei der Übergabe BY REFERENCE wird in DS/ES der höherwertige Inhalt
der
Variablen geladen, sofern vom Typ Long/DWord, ansonsten enthält das
DS/ES-Register einen irrelevanten Wert. Im anderen Register befindet
sich dann der niederwertige Inhalt der Variablen.
Beispiel:
SHARED DemoSeg%, DemoOff%
i& = &h12345678
Demo1 i&
Demo2 i&
Demo3 i&
FUNCTION Demo1(i&) public
PRINT "PB-Adresse : ";:
PRINT HEX$(VARSEG(i&));":"; HEX$(VARPTR(i&))
END FUNCTION
FUNCTION Demo2(i&) public
! les bx, i&
! mov DemoSeg%, es
! mov DemoOff%, bx
PRINT "LES /BY COPY : ";:
PRINT HEX$(DemoSeg%);":"; HEX$(DemoOff%)
END FUNCTION
FUNCTION Demo3(BYVAL i&) public
! les bx, i&
! mov DemoSeg%, es
! mov DemoOff%, bx
PRINT "LES /BY VALUE: ";:
PRINT HEX$(DemoSeg%);":"; HEX$(DemoOff%)
END FUNCTION
5.5. Absturz nach Aufruf einiger INT-Funktionen
-----------------------------------------------
Warum dieser Abschnitt werden Sie sich fragen, hat der PowerBASIC
Inline-Assembler irgendwelche Fehler? Die Antwort lautet definitiv:
NEIN.
Trotzdem sind viel Aufrufe über INT-Funktionen des BIOS/DOS mit
einiger
Tücke verbunden, da Sie wichtige Segmente verbiegen bzw. speziell
zuweisen müssen. Viele Buffer, die einer Funktion übergeben werden
müssen, erwarten speziell im Datensegment-Register (DS) Ihren Zeiger.
PowerBASIC selbst addressiert aber seine Variablen ebenfalls über DS,
sodas hier Konflikte vorprogrammiert sein können. So sollte es zum
Beispiel nicht sein:
! mov ax, &h3D90 ; Funktion Datei öffnen
! mov ds, FileSeg?? ; Segment des Dateinamens laden,
! mov dx, FileOff?? ; jetzt kommt der erste Fehler, da
; FileOff?? nicht mehr über DS
; addressiert werden kann. DS zeigt
; bereits woanders hin ...
! int &h21 ; INT-Aufruf
! mov Handle%, ax ; da DS immernoch für PowerBASIC ins
; Nirwana zeigt, schlägt diese Zeile
; ebenfalls fehl und PowerBASIC
; stürzt über kurz oder lang ab.
Ein sauberes Listing sollte wie folgt aussehen:
! push ds ; DS sichern
! mov ax, &h3D90
! mov dx, FileOff?? ; Offset des Dateinamens laden
! mov ds, fileSeg?? ; Segment des Dateinamens laden,
; für PowerBASIC brauchen wir es
; auch nicht mehr
! int &h21 ; INT-Aufruf
! pop ds ; PowerBASIC Segment restaurieren
! mov Handle%, ax ; Handle% (bzw. Fehlercode) zuweisen
! jnc ... ; Carry-Flag abfragen
5.6. Fixup Overflow
-------------------
Das Problem ist recht einfach und simpel: Die 8086'er CPU läßt nur
bedingte Sprünge vom Typ SHORT zu, das heißt sie können direkt nur
Labels im Bereich von -127/+128 Opcodes Entfernung anspringen.
Folgendes Beispiel erzeugt also einen Fehler:
DemoLabel:
<mehr als 128 Bytes Opcode>
! jc DemoLabel
Um der Sache aus dem Weg zu gehen, müssen Sie die ganze Sache nur
etwas
anders adressieren. Das ist im Prinzip kein Problem, man muss es nur
einmal wissen:
DemoLabel:
<mehr als 128 Bytes Opcode>
! jnc DemoWeiter
! jmp near DemoLabel
DemoWeiter:
Das steht allerdings auch in jedem Assembler-Buch ...
5.7. Variablen zerlegen von WORD nach BYTE
------------------------------------------
Sollten Sie immer noch Ihre 16bit Variablen mit mathematischen Aufwand
in Ihre 8bit Bestandteile zerlegen, so wird es Zeit das Sie endlich
damit aufhören. Das kann die CPU von ganz alleine erledigen:
Beispiel:
DIM Demo AS WORD
DIM DemoHigh AS BYTE
DIM DemoLow AS BYTE
Demo?? = &H1234
! mov ax, Demo??
! mov DemoLow? , al
! mov DemoHigh?, ah
5.8. Variablen zerlegen von DWORD nach WORD
-------------------------------------------
Öfters steht man vor dem Problem, das man zwar Zeiger und Variablen
vom
Typ DWORD in PowerBASIC hat, allerdings nicht weis wie man diese im
Inline-Assembler übergeben kann oder je nach Bedarf auch in WORD zer-
legen. Im Prinzip ist auch diese recht einfach (gewußt wie):
Beispiel:
DIM Demo AS DWORD
DIM DemoHigh AS WORD
DIM DemoLow AS WORD
Demo??? = &H12345678
! mov ax, Demo???[00]
! mov bx, Demo???[02]
! mov DemoLow??, ax
! mov DemoHigh??, bx
5.9. Zugriff mit dem Inline-ASM auf Array's/Strukturen
------------------------------------------------------
Relativ einfach ist der Zugriff mit dem Inline-Assembler auf feste
Datenstrukturen, sofern sie bereits vorher die genauen Offsetadressen
Adressen wissen.
PowerBASIC erlaubt Ihnen folgenden Syntax:
Beispiel:
! mov ah, byte ptr es:[di][22]
Kopiert den Wert zum Offset 22 der Adresse ES:DI in das AH-Register.
5.10. Parameterrückgabe mit dem Inline-ASM
-------------------------------------------
Im Gegensatz zum reinem Assembler läuft die Rückgabe einer Variablen
im PowerBASIC Inline-Assembler leicht anders ab. PowerBASIC 3.0 ge-
stattet z.B. nicht die direkte Übergabe aus dem Inline-Assembler an
die FUNCTION, dies ist nur über einen kleinen Trick möglich.
Beispiel:
High% = &h1234
Low% = &h4578
PRINT HEX$(Demo1&(High%, Low%))
FUNCTION Demo1&(BYVAL High%, BYVAL Low%)
LOCAL Dummy&
! mov dx, High%
! mov ax, Low%
! mov Dummy&[02], dx
! mov Dummy&[00], ax
Demo1& = Dummy&
END FUNCTION
Ab PowerBASIC 3.1 können Sie den Rückgabewert aber direkt an die
FUNCTION übergeben, nur bei 32bit (und größeren) Werten müssen Sie
wieder einen kleinen Kniff anwenden:
Beispiel:
High% = &h1234
Low% = &h4578
PRINT HEX$(Demo2&(High%, Low%))
FUNCTION Demo2&(BYVAL High%, BYVAL Low%)
! mov dx, High%
! mov ax, Low%
! mov FUNCTION[02], dx
! mov FUNCTION[00], ax
END FUNCTION
5.11. Variablenübergabe in Interrupt-Prozeduren
------------------------------------------------
Sehr schwierig ist die Übergabe von Variablen innerhalb einer eigenen
Interruptroutine, da sie davon ausgehen können, das das Datensegment
mit hoher Sicherheit nicht dem benötigtem Datensegment von PowerBASIC
entspricht. Allerdings auch hier haben uns die Entwickler von
PowerBASIC
eine große Hintertür offen gelassen. Die Adressierung über das Code-
segment, welches in der Regel immer gleich ist! Allerdings klappt
dieser
Trick nur im Inline-Assembler, zur Übergabe von/zu reinen PowerBASIC
Routinen müssen sie diese Variable umkopieren.
Beispiel:
! mov ax, &h1234
! mov Demo, ax
! mov bx, Demo
! retn
Demo:
! dw 0
Sollten Sie sich diese Sache unter einem Debuger ansehen, so werden
sie
feststellen das PowerBASIC vor dem Variablenzugriff das Präfix &h2E
(Adressierung über das Codesegment) voranstellt und das '! dw 0'-Feld
den Wert &h1234 angenommen hat.
5.12. Erstellen von 32bit-Zeigern
----------------------------------
Oft werden 32bit Zeiger benötigt um eigene Interrupt-Prozeduren, alte
Interrupt-Handler oder auch Gerätetreiber wie CTVDSK/CT-VOICE und
HIMEM/MSCDEX aufzurufen. Da die Erstellung des 32bit Zeigers in einem
der vorangegangenden Absätze beschrieben wurde, hier nur noch der
eigentliche Syntax:
Beispiel:
! jmp dword Demo&
! jmp dword ptr Demo&
! call dword Demo&
! call dword ptr Demo&
Die Zeiger können ebenfalls dem Codesegment entnommen werden!
5.13. Konvertierung von REG nach Inline-ASM
-------------------------------------------
Ebenfalls recht einfach läuft die Umsetzung von REG- nach Inline-
Assemblersourcen ab. Im Gegensatz zum REG-Befehl, welcher die Inhalte
der Prozessorregister in einem internen REG-Array zwischenpuffert, be-
wirkt ein Zugriff über den Inline-Assembler sofort eine direkte Mani-
pulierung der Prozessorregister. Der REG-Befehl übergibt die REG-Werte
erst beim Aufruf von CALL INTERRUPT. Bitte beachten Sie diesen Unter-
schied und Sie werden weniger Probleme haben.
Ansonsten können Sie zum Beispiel folgende Befehle 1:1 umsetzen:
Beispiele:
REG 1, &h12345 -> ! mov ax, &h1234
REG 2, &hFF -> ! mov bl, &hFF
REG 3, &h22 * 256 -> ! mov ch, &h22
REG 4, &hAABB -> ! mov dh, &hAA
! mov dl, &hBB
REG 9, Demo% -> ! mov es, Demo%
CALL INTERRUPT &h21 -> ! int &h21
Low?? = REG(1) AND 255 -> ! mov low??, al
High?? = REG(1) \ 256 -> ! mov High??, ah
5.14. Konvertierung von A86 nach Inline-ASM
-------------------------------------------
Prinzipiell ohne Probleme läuft eine Umsetzung von A86-Sourcen ab.
Ent-
fernen Sie einfach den Stackrahmen und binden Sie die Assemblerzeilen
einfach in Ihren Inline-Assembler ein. Am besten ist es, wenn Sie dazu
einen Funktionsaufruf erstellen, der die Variablen immer BYVAL
übergibt,
den Rest erledigt PowerBASIC.
======================================================
6. Tip's in Verbindung mit Pointern und PowerBASIC 3.2
======================================================
Kürzübersicht:
6.1. Allgemeines über Pointer
6.2. Was sind Pointer und was können sie leisten?
6.3. PowerBASIC-Pointer und dynamische Strings
6.4. PowerBASIC-Pointer und feste Strings
6.5. PowerBASIC-Pointer und Flex Strings
6.6. PowerBASIC-Pointer und Type Strukturen
6.7. Demonstrations-Source
6.1. Allgemeines über PowerBASIC-Pointer
----------------------------------------
Pointer in Verbindung BASIC haben bereits zahlreiche Diskussionen ent-
facht, die dynamische Speicherverwaltung von PowerBASIC wird hierbei
immer als 'Geburtsfehler' ins Feld geführt.
Das sich dieser elementare Vorteil der BASIC-Programmiersprache auch
ohne Probleme beim Einsatz von Pointern ausspielen läßt, soll Ihnen
dieser Abschnitt erläutern, denn der Einsatz von Pointern in
PowerBASIC
ist mit keinerlei Einschränkungen verbunden!
Allerdings sollten Sie für das Lesen folgender Artikel bereits Wissen
über die interne Wirkungsweise von BASIC und auch DOS haben.
6.2. Was sind Pointer und was können sie leisten?
-------------------------------------------------
Pointer (auch Zeiger genannt) bieten die Möglichkeit, Datenstrukturen
an einer beliebigen Stelle des DOS-Speichers zu interpretieren. Dazu
müssen Sie dem Pointer nur eine beliebige Adresse übergeben.
Pointer dienen vor allem dazu Speicherbereiche zu nutzen, welche
außer-
halb der dynamischen Speicherverwaltung von PowerBASIC liegen. Sie
können mit Pointern z.B. direkt Strukturen interpretieren, auf die von
DOS-Funktionen Zeiger zurückgeliefert werden, wie z.B.:
- Directory Table Area
- Drive Parameter Block
- DOS Info Block
- PSP
- Environment Block
- und und und ...
Das bisher notwendige Umkopieren mit DEF SEG/POKE/PEEK entfällt ab
sofort
und auch das leidige DEF SEG = PEEKI(...) sollten Sie in einem solchem
Falle sofort vergessen.
6.3. PowerBASIC-Pointer und dynamische Strings
----------------------------------------------
String-Pointer auf feste Strings müssen in PowerBASIC wie folgt
definiert
werden:
DIM Pointer AS STRING PTR
Der Pointer selber ist wie folgt zu initialisieren:
Pointer = VARPTR32(Demo1$)
Beispiel:
'***************************************************************
'
' Demo zum korrekten Umgang mit Pointern und dynamische
Strings
'
'***************************************************************
DIM Pointer1 AS STRING PTR ' String Pointer für dynamische
' Strings definieren
Pointer1 = VARPTR32(Demo1$) ' Zeiger auf Stringhandle holen
CLS
PRINT "Adresse: Demo1$: Pointer1:"
Demo1$ = "123456"
PRINT HEX$(VARPTR32(Demo1$)), Demo1$, @[EMAIL PROTECTED]
Demo1$ = "654321"
PRINT HEX$(VARPTR32(Demo1$)), Demo1$, @[EMAIL PROTECTED]
Demo1$ = "!Test!"
PRINT HEX$(VARPTR32(Demo1$)), Demo1$, @[EMAIL PROTECTED]
6.4. PowerBASIC-Pointer und feste Strings
-----------------------------------------
String-Pointer auf feste Strings müssen in PowerBASIC wie folgt
definiert
werden:
DIM Demo AS STRING * 6
DIM Pointer AS STRING PTR * 6
Der Pointer selber ist wie folgt zu initialisieren:
Pointer = VARPTR32(Demo$)
Beispiel:
'***************************************************************
'
' Demo zum korrekten Umgang mit Pointern und festen Strings
'
'***************************************************************
DIM Demo2 AS STRING * 6 ' String mit konstanter Länge
' definieren!
DIM Pointer2 AS STRING PTR * 6
' String Pointer definieren
Pointer2 = VARPTR32(Demo2$) ' Zeiger auf String holen
PRINT
PRINT
PRINT "Adresse: Demo2$: Pointer2:"
Demo2$ = "123456"
PRINT HEX$(VARPTR32(Demo2$)), Demo2$, @[EMAIL PROTECTED]
Demo2$ = "654321"
PRINT HEX$(VARPTR32(Demo2$)), Demo2$, @[EMAIL PROTECTED]
Demo2$ = "!Test!"
PRINT HEX$(VARPTR32(Demo2$)), Demo2$, @[EMAIL PROTECTED]
6.5. PowerBASIC-Pointer und FLEX-Strings
----------------------------------------
Pointer auf FLEX-Strings müssen in PowerBASIC wie folgt definiert
werden:
DIM Demo AS FLEX
DIM Pointer AS FLEX PTR
Der Pointer selber ist wie folgt zu initialisieren:
Pointer1 = VARPTR32(Demo1$)
Um mit FLEX-Strings korrekt arbeiten zu können, müssen diese vor dem
Erstellen des Pointers mit MAP gebildet werden!
Beispiel:
'***************************************************************
'
' Demo zum korrekten Umgang mit Pointern und FLEX Strings
'
'***************************************************************
DIM Demo3 AS FLEX ' String als FLEX definieren!
DIM Pointer AS FLEX PTR
MAP Demo3$$ * 10 '
FLEXCHR$ = "."
Pointer = VARPTR32(Demo3$$) ' Zeiger auf FLEX$-Handle holen
PRINT
PRINT
PRINT "Adresse: Demo3$$: Pointer:"
Demo3$$ = "123456"
PRINT HEX$(VARPTR32(Demo3$$)), Demo3$$, @[EMAIL PROTECTED]
Demo3$$ = "654321"
PRINT HEX$(VARPTR32(Demo3$$)), Demo3$$, @[EMAIL PROTECTED]
Demo3$$ = "!Test!"
PRINT HEX$(VARPTR32(Demo3$$)), Demo3$$, @[EMAIL PROTECTED]
6.6. PowerBASIC-Pointer und TYPE Strukturen
-------------------------------------------
Pointer auf TYPE Strukturen müssen in PowerBASIC wie folgt definiert
werden:
TYPE Demo4_Struc ' TYPE definieren
Demo5 AS BYTE
Demo6 AS BYTE
END TYPE
Der Pointer selber ist wie folgt zu initialisieren:
DIM TypeDemo AS SHARED Demo4_Struc PTR
Ein Beispiel zu Pointern und TYPE Strukturen finden sie eine Source
im folgenden Abschnitt.
6.7. Demonstrations-Source
--------------------------
'************************************************************************
'
' Zugriff auf den Videoram über Pointer in PowerBASIC 3.2
'
' (c) Thomas Gohel
'
' Eine kleine Demonstration, das Pointer wirklich nichts (!!) mit der
' internen Speicherverwaltung zu tun haben und der erfolgreiche
Einsatz
' von Pointern sehr gute interne Kenntnisse von PowerBASIC
vorraussetzt.
'
' In diesem Demo wird der Videoram als Speicher mißbraucht und
gezeigt,
' wie PRINT-Ausgaben den Inhalt der beiden Pointer VIDEORAM und
ZEICHEN
' modifizieren.
'
' Als sinnvolle Erweiterung könnte man diese Routine zum schnellen
' Sichern und Restaurieren des kompletten Videorams nutzen:
'
' @[EMAIL PROTECTED]
= @[EMAIL PROTECTED]
'
' würde den kompletten Inhalt der ersten Page in die zweite Seite
retten
' um später wieder restauriert werden zu können
'
'************************************************************************
TYPE Zeichen_Struc ' Aufbau eines einzelnen
Zeichens
Wert AS BYTE
Farbe AS BYTE
END TYPE
TYPE Screen_Struc ' Aufbau der Seiten im
Videoram
Page1 AS STRING * 4096 ' Seite 1
Page2 AS STRING * 4096 ' Seite 2
Page3 AS STRING * 4096 ' Seite 3
Page4 AS STRING * 4096 ' Seite 4
END TYPE
DIM Zeichen AS SHARED Zeichen_Struc PTR
DIM Videoram AS SHARED Screen_Struc PTR ' TYPE-Strukturen erzeugen
Videoram = pbvScrnBuff ' Type-Struktur auf den
Anfang
' des aktuellen Video-Ram
' schieben,
' PowerBASIC nutzt und
verwaltet
' den Videoram ab sofort als
' festen Stringspeicher!
:-)))
Zeichen = pbvScrnBuff ' TYPE-Struktur soll gleichen
' Speicherbereich wie PRINT
und
' VIDEORAM nutzen
SCREEN 0 ' Screen-Mode setzen
CLS ' alles löschen
PRINT "Dies ist ein Test" ' normales PRINT auf den
' Bildschirm
A$=INPUT$(1)
PRINT LEFT$(@[EMAIL PROTECTED]
) ' Anzeigen der PRINT-Befehl
' automatisch auch unsere
' Struktur gefüllt wird
A$=INPUT$(1)
@[EMAIL PROTECTED]
= @[EMAIL PROTECTED]
' Videoram in Page 2 retten
@[EMAIL PROTECTED]
= 76 ' Jetzt wird die Zeichen-
' Struktur mit einem Wert
@[EMAIL PROTECTED]
= 14 ' gefüllt. Hierbei erfolgt
' gleichzeitig die Ausgabe
' auf den Bildschirm und das
' aktualiseren von der Video-
' RAM-Struktur
PRINT LEFT$(@[EMAIL PROTECTED]
)
A$=INPUT$(1)
@[EMAIL PROTECTED]
= @[EMAIL PROTECTED]
' Videoram von Page 1
' restaurieren
Pointer_Speed_Test:
PRINT STRING$(25*80,178); ' Bildschirm füllen
LOCATE 1, 9
COLOR 11, 1
PRINT " -= STRING-Manipulation innerhalb des";
PRINT " Bildschirmspeichers! =- "
@[EMAIL PROTECTED]
= @[EMAIL PROTECTED]
COLOR 14, 1
LOCATE 8,20: PRINT
"+----------------------------------------+"
FOR i% = 9 TO 18
LOCATE i%, 20
PRINT "|
|"
NEXT i%
LOCATE 10, 22: PRINT "Bildschirmspeicher wird als STRING"
LOCATE 11, 22: PRINT "verwaltet!"
LOCATE 13, 22: PRINT " -= Ein Demo zur PowerBASIC-FAQ =- "
LOCATE 19, 20
PRINT
"+----------------------------------------+"
@[EMAIL PROTECTED]
= @[EMAIL PROTECTED]
FOR i% = 1 to 1000
@[EMAIL PROTECTED]
= @[EMAIL PROTECTED]
@[EMAIL PROTECTED]
= @[EMAIL PROTECTED]
NEXT i%
FOR i% = 1 TO 10
FOR Durchlauf% = 1 TO 256
Zeichen = pbvScrnBuff
FOR Offset% = 1 TO 2048
IF @[EMAIL PROTECTED]
> 32 THEN
DECR @[EMAIL PROTECTED]
END IF
Zeichen = Zeichen + 2
NEXT Offset%
NEXT Druchlauf%
@[EMAIL PROTECTED]
= @[EMAIL PROTECTED]
NEXT i%
'************************************************************************
===================================================
7. Tip's in Verbindung mit Turbo-C bzw. Borland C++
===================================================
Kurzübersicht:
7.1. Autor
7.2. Warum externe Routinen für PB3 in C schreiben/verwenden
7.3. Speicher-Modell angleichen
7.4. Einschränkungen durch den PowerBASIC 3.x Compiler/-Linker
7.5. Parameterübergabe
7.6. PowerBasic-Beispiel
7.7. Zugehöriger C-Modul
7.8. Der zur C-Routine gehörige Assembler-Code
7.9. Verwendung von Routinen fremder C-Bibliotheken
7.10. Massnahmen bei Verwendung von PB V2.1
7.1. Autor
----------
Die Tip's für PowerBASIC in Verbindung mit C-Compilern wie Turbo-C
bzw.
Borland C++ wurden freundlicherweise von:
Andras Hoeffken <ah@[EMAIL PROTECTED]
>
Andras Hoeffken <2:2480/13.34 @[EMAIL PROTECTED]
fidonet>
Andras Hoeffken <130:1316/103 @[EMAIL PROTECTED]
basnet-Germany>
für diese FAQ zur Verfügung gestellt.
Sehr nützliche Hinweise sind auch in der Datei CTOPB.FAQ enthalten,
diese
gehört zum Lieferumfang von PB Vs. 3.2.
7.2. Warum externe Routinen für PB3 in C schreiben/verwenden
------------------------------------------------------------
- C-Routinen ergeben schnell laufenden Code
- für extrem schnellen Code: C-Source schreiben und in ASM-Source
übersetzen lassen (geht VIEL schneller als ASM-Source direkt
zu schreiben), dann den ASM-Quellcode optimieren (Beispiel: s.u.)
- Routinen fremder C-Bibliothen können mit PB verwendet werden
7.3. Speicher-Modell angleichen
-------------------------------
Für das Linken von *.EXE-Files können (z.B. bei MASM oder C)
verschiedene
Speichermodelle vorgegeben werden, z.B. Tiny, Small, Medium, Compact,
Large, Huge, ...
Für die von PowerBASIC erzeugten *.EXE gilt nur:
PowerBASIC 3.x - Speichermodell = LARGE
(PB benutzt für Code- und Datensegmente 32-bit FAR Pointer)
Der C-Compiler muß daher in seinem Menü:
Options / Compiler / Code Generation / Model
auf das Modell LARGE eingestellt werden.
7.4. Einschraenkungen durch den PowerBASIC 3.x Compiler/-Linker
---------------------------------------------------------------
a) Der PB3-Linker kann nur .OBJ-Module mit EINEM Datensegment
einbinden,
bei einem 2. Datensegment oder einer DGROUP streikt der PB3-Linker
und erzeugt Errors. - C-Compiler verwenden in der Grundeinstellung
zunaechst immer mehrere Datensegmentnamen, die in der Datengruppe
DGROUP zusammengefasst sind (das hat bestimmte Vorteile). Die IDE
des C-Compilers muss daher in ihrem Menü:
Options / Compiler / Names
wie folgt eingestellt werden:
Code Segment: _TEXT Bss Segment: _DATA
Code Group: Bss Group:
Code Class: TEXT Bss Class: DATA
Data Segment: _DATA Far Data Segment:
Data Group: Far Data Group:
Data Class: DATA Far Data Class:
(die noch vorhandenen Sternchen MUESSEN gelöscht werden)
Jetzt erzeugt der C-Compiler nur noch EINEN Daten-Segmentnamen
und keine DGROUP mehr!
b) Der PB3-Linker (< Vs. 3.2) akzeptiert keine "_" bei Segmentnamen
(ist
bei C ein Standard), daher: In der $LINK-Zeile "$ALIAS" verwenden
(s.u.)!
c) Der PB3-Compiler (< Vs. 3.2) akzeptiert keine "_" in Namen von
Funktionen und SUB's (ist bei C ein Standard), daher: In den
DECLARE-
Zeilen "$ALIAS" verwenden (s.u.)!
d) Der PB3-Compiler übergibt bei Funktionen und Subs die Parameter in
der
Reihenfolge "von rechts nach links" (Pascal Konvention) und er-
wartet, daß die externe Routine den Stack selbst aufräumt, C-
Compiler arbeiten umgekehrt. Daher: In den DECLARE-Zeilen "CDECL"
verwenden (s.u.)!
7.5. Parameterübergabe
-----------------------
PB3 uebergibt Parameter an externe Routinen auf 2 Arten:
- mit 'far pointern' ('by reference' bzw. 'by copy')
- direkt auf dem Stack (BYVAL)
Entsprechend müssen die Deklarationen in den C-Routinen angepaßt
werden.
7.6. PowerBASIC-Beispiel
------------------------
Im nachfolgenden .BAS-Programm zeigen 2 Routinen die Mechanismen:
- A: in der Addier-Funktion "addab" (integer) wird "c=a+b" berechnet,
der
Funktionswert wird mit "x=c+1" zurückgegeben.
- B: in der String-Routine "chst" wird das erste Zeichen eines Strings
durch "*" ersetzt.
--- Cut ------------------------------------------------------------
'PB3_TBC.BAS - Turbo-C-Routinen in PB3.x einlinken
$ALIAS DATA AS "_DATA |