Neue
Homepage:
LAB1.de hat einen neuen Namen:
Unsere Tools werden jetzt unter der Adresse
www.ToolsAndMore.de
weitergeführt - klicken Sie bitte den nachstehenden Taster, um dort die
gesuchte Seite in neuester Version zu besuchen.
|
Hintergrundartikel:
DOS-Programme und lange Dateinamen? Kein Problem!
Der Umgang mit langen Dateinamen ist nicht nur Windows-Applikationen vorbehalten.
Auch ganz normale DOS-Programme können hervorragend damit arbeiten.
Welches ist das unbeliebteste Zeichen des PC-Zeichensatzes? Die Tilde, was sonst!
Dabei wusste vor ein paar Jahren kaum jemand, dass es ein solches "Schnörkel" überhaupt
gibt. Dank MS ist das nun aber anders und die Anwendergemeinde darf sehen, wie
sie mit ihrer 16-Bit-Software und den abgewürgten langen Dateinamen zurecht kommt.
Was kommerzielle Applikationen und Tools anbelangt, so wird man wohl an der Tilde
bzw. einer Neuanschaffung nicht vorbeikommen. Handelt es sich bei der "veralteten"
Software jedoch um Eigenentwicklungen, so kann man deren Methusalem-Syndrom sofort
abstellen. Denn alles was man hierzu benötigt, steckt bereits im in Windows 9x
enthaltenen MS-DOS 7.x

Daß auch DOS-Programme locker mit langen Dateinamen umgehen können, zeigt
beispielsweise der DOS-Editor von Windows 95
Auch DOS kennt lange Dateinamen
Für den Umgang mit den langen Dateinamen von Windows 95 bietet das API
von MS-DOS 7 rund zwei Dutzend neue Funktionen. Dabei ist die Bezeichning "neu"
fast schon zu weit gegriffen, denn eigentlich handelt es sich größtenteils um Frischzellenkuren
alter Bekannter wie beispielsweise "Verzeichnis anlegen/wechseln/löschen" oder
"Verzeichnissuche starten/fortsetzen". Das spiegelt sich sogar in der jeweiligen
Funktionsnummer der Neuen wieder: Ermittelte man bisher das aktuelle Verzeichnis
mit AH=47h, so ist jetzt AX=7147h zu verwenden. Analog dazu wurde aus AH=41h zum
Löschen einer Datei AX=7141h. Kurz - jeder, der schon einmal mit Interrupt 21h
gespielt hat, wird sich sofort wie zuhause fühlen.
Neben den abgewandelten Funktionsnummern gibt es aber noch ein weitere wichtige
Änderung: Zum Speichern der Verzeichnis- und Dateinamen benötigt man natürlich
mehr Platz. Mußten bislang lediglich 13 Zeichen hierfür reserviert werden (Name
+ Punkt + Erweiterung + Null), so sind es jetzt 255 Byte für Dateinamen und 260
Byte für Verzeichnisse (Beliebiger Name + Null). Das sind die offiziellen Werte.
In der Praxis liegt die Grenze dagegen bei genau 250 nutzbaren Zeichen - selbst
wenn die Datei bzw. das Verzeichnis direkt im Hauptverzeichnis angelegt wird.
Die LFN-Funktionen im Detail - Verzeichnissuche
Der Unterschied zwischen Programmen, die mit langen Dateinamen umgehen
können und solchen, die es nicht können, zeigt sich wohl am deutlichsten beim Einlesen
eines Verzeichnisses. Zur Erinnerung: In 16-Bit-Zeiten benutzte man hierfür die
DOS-Funktion "Find first" mit AH=4Eh zum Beginnen einer Verzeichnissuche. Jedes
weitere Element wurde über "Find next" mit AH=4Fh ermittelt. Das gleiche gilt auch
im großen und ganzen für die Anwendung der entsprechenden LFN-Funktionen - allerdings
gibt es jetzt etwas mehr Komfort.
Die Verzeichnissuche wird mit AX=714Eh des Interrupt 21h gestartet. Wie zuvor
zeigt DS:DX auf eine nullterminierte Zeichenkette (ASCIZ-String) mit der Suchmaske,
beispielsweise "*.TXT". Neu ist allerdings, daß man nicht nur alle möglichen Dateiattribute
(Register CL) wie "versteckt" oder "Verzeichnis" angeben kann, sondern auch alle
erforderlichen (Register CH). Dieser Schritt war längst überfällig, denn somit
hat man endlich die Möglichkeit, eine Suche nach einer bestimmten Eintragsgattung
auch in einem einzigen Durchgang durchführen zu können: Möchte man beispielsweise
alle Ordnernamen eines Verzeichnisses ermitteln, so gibt man als mögliche Attribute
"versteckt", "systembezogen" und "Verzeichnis" an und als erforderliches Attribut
nur "Verzeichnis". Dadurch werden nur die Einträge geliefert, die auch tatsächlich
Verzeichnisnamen darstellen, egal ob sie normal, versteckt oder systembezogen sind
(In der alten Funktionsweise erhielt man im gezeigten Beispiel nicht nur Verzeichnisnamen,
sondern auch die Namen aller Dateien geliefert). Die ermittelten Eintragsdaten
werden in einem speziellen Record abgelegt (siehe
Tabelle 1). Dieser landet aber nicht mehr zwangsweise in der Disk Transfer
Area (DTA), sondern in einem durch das Registerpaar ES:DI festlegbaren Bereich.
Im Gegensatz zu DOS kennt Windows 95 nicht nur den letzten Änderungszeitpunkt
eines Objekts, sondern auch den Zeitpunkt der Erstellung und des letzten Lesezugriffs.
Außerdem wurde ordentlich an der Auflösung gedreht: In einem normalen FAT-Eintrag
ist der Änderungszeitpunkt auf zwei Sekunden genau eingetragen. Unter Windows 95s
VFAT dagegen liegt die Auflösung bei 100 Nanosekunden und ist damit also 20.000.000
mal feiner. Da jeder der neuen Zeiteinträgen jetzt insgesamt 8 Byte groß ist, hat
man aber trotz aller Genauigkeit für die nächsten 58.000 Jahre Platz - der Umstieg
auf das Jahr 3.000 dürfte sich somit etwas unproblematischer als in 3 Jahren darstellen
(Hoffentlich erinnert man sich dann noch an Windows 95). Als Datumsbasis wird zudem
nicht länger der 1.1.1980 benutzt, sondern der 1.1.1601 - hier wollte man wohl
in die Nähe des Anbeginns des gregorianischen Kalenders rücken. Da die wenigsten
16-Bit-Programme auf ein solch bombastisches Kalendarium vorbereitet sind, gibt
es aber noch ein Hintertürchen: Wird die Suche mit SI=0 begonnen, so stehen im
Such-Record zwar die neuen 64-Bit-Zeitwerte, doch mit SI=1 erhält man das ganze
- wie gehabt - auf dieses Jahrhundert heruntergebrochen. Dabei landet die (DOS-kompatible)
letzte Änderungszeit in den niedrigsten beiden Bytes des 8-Byte-Zeiteintrags, gefolgt
vom 16-Bit-Datum.
Neben den in Tabelle 1 gezeigten
Daten erhält man aber noch weitere Daten von der Suchstartfunktion zurück, die
es in deren 16-Bit-Fassung bislang nicht gab: In Register AX wird jetzt ein Such-Handle
übergeben und über CX wird man über den Umgang mit nicht umwandelbaren Unicode-Zeichen
unterrichtet. Durch das Such-Handle hat man (nun endlich) die Möglichkeit, mehrere
Suchen gleichzeitig auführen zu können - es wird an die Folgefunktion "Find next"
übergeben. Damit das Handle und die damit zusammenhängenden Datenstrukturen nach
Gebrauch auch wieder freigegeben werden können, wurde allerdings eine weitere,
wirklich neue Funktion nötig: "Find close" (AX=71A1h).
Vom Format der Unicode-Umwandlung (Register CX) sind bislang nur die ersten beiden
Bits belegt - Bit 0 steht dabei für lange Dateinamen, Bit 1 für kurze: Ist ein
solches Bit gesetzt, so werden nicht konvertierbare Zeichen im entsprechenden Namen
als Unterstriche ("_") dargestellt. Die genaue Registerbelegung dieser drei und
aller anderen neuen LFN-Funktionen ist in Tabelle
2 noch einmal detailliert aufgeführt.
Verzeichnisse - erstellen, wechseln, löschen und abfragen
Die Anwendung der vier genannten Funktionen unterscheiden sich von Ihren
Vettern, die nur mit kurzen Dateinamen umgehen können, lediglich in der Funktionsnummer:
- Erstellen AH=39h AX=7139h
- Wechseln AH=3Ah AX=713Ah
- Löschen AH=3Bh AX=713Bh
- Abfragen AH=47h AX=7147h
Für die ersten drei Funktionen wird der betreffende Pfad wie gewohnt als nullterminierte
Zeichenkette über den Zeiger DS:DX übergeben. Beim Abfragen des aktuellen Verzeichnisses
landet er dagegen an der Position DS:DI. Dabei ist zu beachten, daß die maximale
Länge eines Pfades nicht mehr auf 64 Zeichen begrenzt ist. Es sind hierfür (laut
offizieller Darstellung) 260 Byte zu reservieren.
Dateien - erstellen/öffnen, schließen, umbenennen und löschen
Zum Öffnen bzw. Erstellen von Dateien bietet MS-DOS aufgrund seiner Geschichte
einen ganzen Satz an unterschiedlich leistungsfähigen Funktionen. Zum Glück hat
man sich aber darauf beschränkt, nur die neueste auf LFN-Niveau zu bringen. "Create/open
file" wurde bislang mit AH=6C00h aufgerufen. Analog zu den vorangegangenen Beispielen
reagiert deren LFN-Version auf AX=7C6Ch. Der nullterminierte Name der anzulegenden
bzw. zu öffnenden Datei wird wie zuvor über den Zeiger DS:SI übergeben. Ebenfalls
unverändert ist die Belegung von BX mit dem Zugriffsmodus und den Flags für gemeinsamen
Zugriff, CX mit den Dateiattributen (Tabelle
1) und DX mit der vorzunehmenden Aktion. Neu hinzugekommen sind diverse
Flags in den soeben genannten Registern sowie ein Wert in DI für die gewünschte
numerischen Erweiterung des betreffenden kurzen Dateinamens.
Die Belegung der einzelnen Zugriffs/Sharing-Bits in BX sind in
Tabelle 3 aufgeführt. Die in DX zu
übergebende Aktion wird wie folgt definiert:
Aktion, falls Datei nicht existiert (Bits 7-4):
0000 mit Fehler abbrechen
0001 Datei erstellen
Aktion, falls Datei existiert (Bits 3-0):
0000 mit Fehler abbrechen
0001 Datei erstellen
0010 Datei ersetzen bzw. erstellen
Als Ergebnis erhält man in AX ein Handle auf die geöffnete Datei zurück und anhand
des Wertes in CX kann man erkennen, welche Aktion schließlich ausgeführt wurde:
1 Datei wurde geöffnet
2 Datei wurde erstellt
3 Datei wurde ersetzt
Zum Schließen einer Datei - auch mit langem Dateinamen - gibt es kein spezielles
LFN-Pendant. Man benutzt hierfür einfach die altbekannte Funktion "Close file"
mit AH=3Eh und dem Handle der Datei in BX.
Zum Umbenennen von langen Datei- bzw. Verzeichnisnamen dient die Funktion AX=7156h
des Interrupt 21h. Sie wird exakt genauso wie ihre 16-Bit-Vorgängerin (AH=56h)
angewendet: DS:DX zeigt auf den nullterminierten aktuellen Pfadnamen und ES:DI
auf den neuen (ebenfalls ASCIZ). Auch hier ist darauf zu achten, daß man mit dieser
Funktion zwar Einträge von einem Verzeichnis in ein anderes legen kann, jedoch
nur auf ein und dem selben Datenträger.
Gegenüber ihrer Vorgängerversion deutlich zugelegt hat die Funktion zum Löschen
von langen Verzeichniseinträgen (AX=7141h). Enthält SI den Wert 0, so benimmt sich
der Aufruf so, wie mit AH=41h. Wird dagegen SI mit 1 geladen, so kann der Name
des Löschkandidaten auch Jokerzeichen (* und ?) enthalten und über die Register
CL und CH können zusätzlich mögliche und erforderliche Dateiattribute festgelegt
werden - ganz wie bei der Verzeichnissuche.
Ortsbestimmung - Funktionen um SUBST
Für alle, die es wirklich nicht glauben wollen: Ja, es ist wahr, SUBST
ist auch unter Windows 95 noch immer ein Thema. Man kann damit inzwischen sogar
aus einer temporären DOS-Sitzung heraus einem Pfad eine Laufwerkskennung zuweisen,
die dann systemweit gilt. Im Zeichen langer Verzeichnisnamen ist dies sicherlich
eine praktische Sache, vor allem, wenn man sich ohne Norton Commander oder ähnlichem
an der nackten Kommandozeile befindet.
Substitutionen lassen sich selbstverständlich aber nicht nur über das gleichnamige
DOS-Tool ausführen, sondern auch über drei entsprechende Interrupt 21h-Funktionen.
Dazu kommen dann auch noch die TRUENAME-Funktionen zum Auflösen von Pfaden, die
eventuelle Substitutionen enthalten.
Die drei SUBST-Funktionen "Create subst", "Terminate subst" und "Query subst"
sind unter einer Aufrufnummer (AX=71AA) zusammengefaßt. Auseinandergehalten werden
sie hier über Unterfunktionsnummern in BH (0h, 1h und 2h).
Um eine Substitutionen durchzuführen (Create subst) ruft man also Interrupt 21h
mit AX=71AAh und BH=0h auf. DS:DX muß auf eine nullterminierte Zeichenkette zeigen,
die einen gültigen (Teil-)Pfad enthält. Dieser wird ersetzt durch die Laufwerkskennung
in BL. Dabei steht 0 für das aktuelle Laufwerk, 1 für A:, 2 für B: usw.
Zum Aufheben einer Substitutionen (Terminate subst) ruft man Unterfunktion 1
(BH=1) mit der betreffenden Laufwerkskennung in BL auf. Wichtig: Ist das aktuelle
Laufwerk (BL=0) das zu beendende SUBST-Laufwerk, so schlägt der Aufruf fehl.
Auch der Bezug eines Substitutionslaufwerks läßt sich abfragen (Query subst).
Dazu ruft man die Funktion mit BH=2 und BL mit der zu befragenden Laufwerkskennung
auf (Aktuelles Laufwerk, also 0, ist nicht erlaubt). DS:DX muß auf einen ausreichend
großen Puffer zeigen, der den substituierten Pfad als ASCIZ-String aufnimmt.
Auch die drei in MS-DOS 7 enthaltenem Truename-Funktionen sind unter einer Hauptnummer
(AX=7160h) zusammengefaßt. Die Unterscheidung läuft hierbei über den Wert in Register
CL:
0: Canonicalize path/file name (as is)
1: Canonicalize path/file name (all short)
2: Canonicalize path/file name (all long)
Im Grunde machen alle drei Unterfunktionen das gleiche: Sie liefern den komplett
aufgelösten Pfad eines Verzeichnis- bzw. Dateinamens. Unterfunktion 0 übergibt
den Ergebnisstring dabei aber so, wie sie ihn vorfindet - alles in kurzen oder
langen Namen oder auch gemischt. Unterfunktion 1 dagegen liefert den kompletten
Pfad in Kurzschreibweise und Nummer 2 entsprechend alles in langen Namen. DS:SI
zeigt dabei auf den aufzulösenden ASCIZ-(Teil-)String (das kann beispielsweise
auch "...\..\." sein) und ES:DI auf den Ergebnispuffer, indem der Truename-Pfad
als nullterminierte Zeichenkette landet.
Über den Wert in CH (0 oder 1) kann man zudem noch festlegen, ob bei dem aufzulösenden
Pfad ein eventuell substituiertes Laufwerk ebenfalls aufgelöst oder beibehalten
werden soll.
Die übrigen LFN-Funktionen
Jetzt bleiben nur noch ein paar allgemeine Funktionen zur Informationsermittlung
und Zeitformat-Konvertierung zu beschreiben. Am interessantesten dürfte hierbei
"Get volume information" sein, die einiges über die Fähigkeiten eines Laufwerks
verät. DS:DX muß dabei auf einen nullterminierten String mit zumindest dem Laufwerksbuchstaben
des zu befragenden Volumes zeigen. ES:DI zeigt auf einen Ergebnispuffer, dessen
Größe in CX übermittelt wird - 32 Byte sind hierbei ausreichend. Die Funktion wird
mit AX=71A0h aufgerufen. Als Ergebnis erhält man im oben genannten Puffer den Namen
des Dateisystems, beispielsweise "FAT", "CDFS" oder "NTFS". In Register CX findet
man die (offizielle) Maximallänge für Dateinamen und in DX den Maximalwert für
Verzeichnisnamen. In BX sind die verschiedene bit-codierte Informationen enthalten:
Bit - Bedeutung
0 Verzeichnissuche berücksichtigt Groß-/Kleinschreibung
1 Groß-/Kleinschreibung wird in Verzeichniseinträgen beibehalten
2 Unicode-Zeichen werden für Datei- und Verzeichnisnamen verwendet
3-13 0 (reserviert)
14 DOS-LFN-Funktionen werden unterstützt
15 Laufwerk ist komprimiert
Um an genauere LFN-Informationen über eine Datei zu gelangen, benutzt man die
Funktion "Get file information by handle" (AX=71A6h). Wie der Name schon sagt,
muß es sich um eine bereits geöffnete Datei handeln. Das betreffende Datei-Handle
ist in Register BX zu übergeben und DS:DX muß auf einen ausreichend großen Ergebnispuffer
zeigen. Der Aufbau und Inhalt des Puffers ist in
Tabelle 4 beschrieben.
Für die Umrechnungen des neuen 64-Bit-Zeitformats muß man keineswegs eigene Routinen
schreiben - MS-DOS 7 bietet hierfür bereits zwei fertige Funktionen: "File time
to DOS time" und " DOS time to File time". Sie werden über AX=71A7h und BL=0 bzw
BL=1 aufgerufen.
Bei der Umwandlung des 64-Bit-Zeitformats (BL=0) muß DS:SI auf die betreffenden
8 Byte mit der Zeitinformation zeigen. Nach dem Aufruf enthält CX die Zeit und
DX das Datum im DOS-Format. Register BH enthält zusätzlich noch die Anzahl der
auf CX zuzurechnenden 1/100 Sekunden.
Um Zeitangaben aus dem DOS- ins 64-Bit-Format von Windows 95 zu konvertieren
(BL=1), muß ES:DI auf einen Ergebnispuffer von 8 Byte zeigen. CX und DX müssen
analog zur vorigen Funktion mit der Zeit und dem Datum im DOS-Format geladen werden
- BH nimmt wiederum die 1/100 Sekunden auf.
Schließlich wäre noch die Funktion zum Lesen und Ändern der Dateiattribute zu
nennen (AX=7143h). DS:DX zeigt wiederum auf den Dateinamen (ASCIZ) und die gewünschte
Aktion wird über einen entsprechenden Wert im Register BL ausgewählt:
BL - Aktion
0 Lade CX mit Dateiattributen
1 Schreibe Dateiattribute in CX auf Datenträger
2 Lade AX:DX mit der physikalischen Größe der komprimierten Datei
3 Schreibe neues Änderungsdatum
4 Lies letztes Änderungsdatum
5 Schreibe neues Zugriffsdatum
6 Lies letztes Zugriffsdatum
7 Schreibe neues Erstellungsdatum
8 Lies Erstellungsdatum
Bei den Aktionen 3 bis 8 wird das betreffende Datum im DOS-Datumsformat über
die Register CX (Zeit) und DI (Datum) übergeben.
DOS-Programme mit LFN-Funktionen ausstatten.
Anhand der vorliegenden Informationen sollte es jetzt für jeden Entwickler
möglich sein, seine 16-Bit-Software LFN-fähig zu machen. Wer seine Tools in Assembler
geschrieben hat, dürfte dabei wohl die wenigsten Probleme haben. Bei der Anwendung
ist aber darauf zu achten, daß die LFN-Funktionen trotz MS-DOS 7 möglicherweise
nicht zur Verfügung stehen. Das ist nämlich nur dann der Fall, wenn auch der Treiber
IfsMgr geladen wurde - nicht aber, wenn das System nackt da steht, beispielsweise
nach einem abgesicherten Start oder einem Booten von Diskette. Auch könnte jemand
auf die Idee kommen LFN-fähige Programme auf einer früheren Version von MS-DOS
auszuführen. In diesem Fall würden ein Aufruf der LFN-Funktionen einfach durchrutschen
und AX würde in jedem Fall mit 7100h zurückgegeben werden. Damit dies aber überhaupt
als Fehlerkondition erkannt wird (Carry=1), muß vor(!) dem Interrupt 21h-Aufruf
das Carry-Flag vom Entwickler gesetzt werden.
Auch die Anpassung in C- oder Pascal-Dialekten ist recht einfach, da die gängigsten
Compiler ohnehin über einen integrierten Assembler verfügen. Unter BASIC sieht
es dagegen etwas flau aus, da hier zunächst entsprechende Zusatzbibliotheken entwickelt
werden müssen. Für MS-Basic ab Version 6 bietet Ihnen LAB1.de eine entsprechende
Implementierung mit ein paar Beispielprogrammen zur Erläuterung - jeweils als EXE-Format
sowie Quelldateien:
Download:
Den Download dieses Tools können Sie über unsere neue
Homepage
www.ToolsAndMore.de
starten.
Klicken Sie einfach den nachstehenden Taster, um dort hin zu
gelangen:
|
Weitere Quellen
Wer weitere Informationen zu dem Thema lange Dateinamen unter MS-DOS sucht,
wird bei Microsoft kaum schlau werden, da das meiste hier gezeigte - wie so oft
- unter die Rubrik "undocumented" fällt. Glücklicherweise gibt es da aber noch
die mittlerweile legendäre Interruptliste von Ralph Brown, in der so ziemlich alle
Aufrufe klar dokumentiert sind - schon allein im Standard-ASCII-Format hat diese
Liste eine Größe von fast 8 MByte. Diese Liste gehört zur
kostenlosen Bonus-Software auf der LAB1.de-CD.
|