MASM32-SDK (Windows Konsolapplikationen):
Inhaltsanzeige eines Verzeichnisses mit langen Dateinamen

Dies ist ein 32-bit-Nachbau des 16-bit-Programms LS.com.

Beide Versionen leisten etwa das Gleiche. Allerdings unterscheiden sie sich etwas im Format des Aufrufs und im Format der Anzeige.

Die hier gezeigte 32-bit-Version baut auf dem Programmbeispiel \masm32\examples\exampl02\dir\mdir.asm des MASM32-SDK auf. Das Programmbeispiel demonstriert, wie man mit den API-Funktionsaufrufen FindFirstFile() und FindNextFile()ein Verzeichnis auf Dateinamen absuchen kann, um die Dateinamen auf dem Bildschirm anzuzeigen. Außerdem wird eine vom vorhergehenden Beispiel abweichende Methode zum Einlesen der Kommandozeile genutzt.

Der MASM32-SDK beinhaltet in \masm32\datetime ein Paket zur Behandlung von Datums- und Zeitfunktionen. Eine Bedienungsanleitung dazu ist in der interaktiven Hilfe des MASM32-SDKs vorhanden. Die Anwendung des Pakets erleichtert die Programmierung der Datums- und Zeitanzeige.

Ablaufbeispiel
Dreimal wird LS.exe aufgerufen. Der zweite Aufruf zeigt eine Schwachstelle beim Aufruf mit dem Parameter ..\help - statt des Verzeichnisinhalts wird nur der Verzeichnisname angezeigt. Erst mit dem Aufruf ..\help\*.* gelingt die Anzeige des Verzeichnisinhalts. Der dritte Aufruf zeigt Dateinamen mit dem Attribut C. Es handelt sich um Dateien in einem unter dem Dateisystem NTFS komprimierten Verzeichnis. Angezeigt wird hier die unkomprimierte Dateilänge.

Beim 16-bit-Programm LS.com erfolgte die Längenanzeige hexadezimal. Beim 32-bit-Programm LS.exe erfolgt die Längenangabe dezimal. Die dezimale Längenangaben war in diesem Fall bequemer zu programmieren.

Das hier gezeigte Programm kann verbessert werden. So könnte bei der Anzeige der Text „bytes” entfallen ...

0:20:29:56 C:\masm32\Uebung>ls
16.12.2013  19:29:39 ---D--             0 bytes .
16.12.2013  19:29:39 ---D--             0 bytes ..
24.07.2007  07:31:52 ----A-           975 bytes DateTimeToStringShort.asm
16.12.2013  18:21:30 ----A-         1.099 bytes DateTimeToStringShort24.asm
15.12.2013  06:48:34 ---D--             0 bytes enum
16.12.2013  15:58:15 ---D--             0 bytes Konsole
16.12.2013  19:29:22 ----A-         9.066 bytes ls.asm
16.12.2013  19:29:39 ----A-         4.096 bytes ls.exe
16.12.2013  19:29:39 ----A-         2.436 bytes ls.obj
13.12.2013  08:02:40 ----A-         3.075 bytes mdir_org.asm
15.12.2013  08:09:16 ----A-         3.072 bytes mdir_org.exe
15.12.2013  08:09:16 ----A-         1.428 bytes mdir_org.obj
15.12.2013  06:48:34 ---D--             0 bytes Pgms
16.12.2013  18:08:34 ---D--             0 bytes PGms_gesichert
Press any key to continue ...

0:20:30:15 C:\masm32\Uebung>ls ..\help
16.12.2013  14:54:08 ---D-C             0 bytes help
Press any key to continue ...

0:20:30:33 C:\masm32\Uebung>ls ..\help\*.*
16.12.2013  14:54:08 ---D-C             0 bytes .
16.12.2013  14:54:08 ---D-C             0 bytes ..
16.10.2007  08:46:28 ----AC        37.579 bytes asmintro.chm
04.08.2008  23:43:12 ----AC        20.483 bytes DateTime.chm
29.12.2007  15:31:22 ----AC        45.235 bytes fpuhelp.chm
04.12.2011  06:51:03 ----AC        90.027 bytes hlhelp.chm
20.03.2011  01:02:44 ----AC        28.131 bytes imdialog.chm
20.10.2007  11:49:38 ----AC        96.302 bytes masm32.chm
06.11.2011  00:33:49 ----AC        89.395 bytes masmlib.chm
16.12.2013  14:54:08 ----AC        21.105 bytes masmlib.chw
22.10.2007  11:06:20 ----AC        59.501 bytes opcodes.chm
10.08.2008  03:28:08 ----AC        85.204 bytes qeditor.chm
11.06.2008  23:54:14 ----AC        23.286 bytes VKDebug.chm
16.12.2013  15:58:45 -H--AC       455.740 bytes win32.GID
26.11.1996  11:00:00 ----AC    20.033.075 bytes win32.hlp
Press any key to continue ...
Das Quellprogramm
Eine kurze Interpretation steht unterhalb des Quellprogrammtextes.
comment #
This program uses the FindFirstFile() FindNextFile() API functions
to perform a directory list search which is displayed at the console.

This file should be built with the "Console assemble & link" option
on the project menu.

Zur WIN32_FIND_DATA STRUCT:
---------------------------

dwFileAttributes        DWORD ?
ftCreationTime          FILETIME <>
ftLastAccessTime        FILETIME <>
ftLastWriteTime         FILETIME <>
nFileSizeHigh           DWORD ?
nFileSizeLow            DWORD ?
dwReserved0             DWORD ?
dwReserved1             DWORD ?
cFileName               BYTE MAX_PATH dup (?)
cAlternateFileName      BYTE 14 dup (?)

FILETIME STRUCT
  dwLowDateTime         DWORD ?
  dwHighDateTime        DWORD ?

Bitmaske für die Datei-Attribute:
FILE_ATTRIBUTE_READONLY   equ 1
FILE_ATTRIBUTE_HIDDEN     equ 2h
FILE_ATTRIBUTE_SYSTEM     equ 4h
FILE_ATTRIBUTE_DIRECTORY  equ 10h
FILE_ATTRIBUTE_ARCHIVE    equ 20h
FILE_ATTRIBUTE_NORMAL     equ 80h
FILE_ATTRIBUTE_TEMPORARY  equ 100h
FILE_ATTRIBUTE_COMPRESSED equ 800h
-------------------------------------------------------------------

Zur externen Prozedur DateTimeToStringShort24:

This procedure converts a DATETIME (same structur as FILETIME) to a
date and time string in the system's short date and 24-hour format.

Usage:
  INVOKE DateTimeToStringShort24, pdt, pszShort24
    pdt is a pointer to the DATETIME [IN]
    pszShort24 is a pointer to the resulting ASCIIZ string [OUT]
    Returns a PTR BYTE in eax:
      a pointer to the resulting string on success, NULL on error

Mehr Information: siehe MASM32-SDK, Help, Kapitel Date Time Reference.
Die Assemblerquelle der Prozedur ist \masm32\DateTime.inc\DateTimeToStringShort24,
die zugehörige Objektdatei ist in \masm32\lib\DateTime.lib eingebunden.
------------------------------------------------------------------- #

      .386
      .model flat, stdcall
      option casemap :none   ; case sensitive
; -------------------------------------------

      include \masm32\include\windows.inc
      include \masm32\macros\macros.asm         ;nachgetragen
      include \masm32\include\user32.inc
      include \masm32\include\kernel32.inc
      include \masm32\include\masm32.inc
      include c:\masm32\include\msvcrt.inc      ;nachgetragen
      INCLUDE \masm32\include\DateTime.inc      ;nachgetragen


      includelib \masm32\lib\user32.lib
      includelib \masm32\lib\kernel32.lib
      includelib \masm32\lib\masm32.lib
      includelib \masm32\lib\msvcrt.lib         ;nachgetragen
      INCLUDELIB \masm32\lib\DateTime.lib       ;nachgetragen
;  -------------------------------------------

        Main    PROTO              ;erforderlich weil Main eine Prozedur ist
.data
notfound   db   "Datei nicht gefunden"
crlf       db   13,10,0     ;ergaenzt ggf. notfound
wCard      db   "*",0
spc        db   " ",0
bytes      db   " bytes ",0
;fMtStrinG db   "%lu",0
fMtStrinG  db   "%10.1lu",0
mitPunkt   db   14 dup (" "),0  ;Space, 13 bytes,0

attrs      db   "RHSDAC "
msg_attrs_spc db " "            ;msg_attrs mit führendem Space
msg_attrs  db   "RHSDAC "
           db   0               ;hier Ausgabeende

pszShort24 db   64 dup (0)

; #########################################################################

.code
    start:
      invoke Main
      inkey
      invoke ExitProcess,0

; #########################################################################

Main proc

LOCAL hSearch :DWORD            ; search handle
LOCAL sizeBuffer[16]:BYTE
LOCAL fBuffer[256]:BYTE         ; file name buffer
LOCAL clBuffer[128]:BYTE        ; command line buffer
LOCAL wfd :WIN32_FIND_DATA

        invoke GetCL,1,ADDR clBuffer    ; get arg 1
        .if eax != 1                       ; if no arg
                mov ecx, LENGTHOF wCard         ; copy * into
                mov esi, offset wCard           ; clBuffer
                lea edi, clBuffer
                rep movsb
        .endif

        invoke FindFirstFile,ADDR clBuffer,ADDR wfd
        .if eax == INVALID_HANDLE_VALUE
                invoke StdOut,ADDR clBuffer   ; Suchbegriff
                invoke StdOut,ADDR spc
                invoke StdOut,ADDR notfound   ; display "not found" message
                jmp TheEnd
        .else
                mov hSearch, eax
        .endif

        mov al, [wfd.cFileName]
        cmp al, "."       ;keine Anzeige weiterer Directoryinfos
;       je nxt


        INVOKE DateTimeToStringShort24, ADDR wfd.ftLastWriteTime, ADDR pszShort24
        invoke StdOut, ADDR pszShort24
        mov     eax,[wfd.dwFileAttributes]  ;Attribute zur Anzeige
        call    zeige_attribute


        invoke  wsprintf,ADDR sizeBuffer,ADDR fMtStrinG,wfd.nFileSizeLow
        lea     esi,sizeBuffer+10
        lea     edi,mitPunkt+13
        mov     ecx,10      ;10 Stellen
        call    schiebe    ;Tausenderpunkte in den Laengenstring

        invoke  StdOut,ADDR mitPunkt
        invoke  StdOut,ADDR bytes
        invoke  StdOut,ADDR wfd.cFileName

  nxt:
        invoke  StdOut,ADDR crlf
        call    restore_msg_attrs
  @@:
        invoke  FindNextFile,hSearch,ADDR wfd
        cmp     eax, 0
        je      lpOut


        mov     al, [wfd.cFileName]
        cmp     al, "."         ;keine Anzeige weiterer Directoryinfos
        je nxt1

        INVOKE DateTimeToStringShort24, ADDR wfd.ftLastWriteTime, ADDR pszShort24
        invoke StdOut, ADDR pszShort24

        mov     eax,[wfd.dwFileAttributes]  ;Attribute zur Anzeige
        call    zeige_attribute


        invoke  wsprintf,ADDR sizeBuffer,ADDR fMtStrinG,wfd.nFileSizeLow
        lea     esi,sizeBuffer+10
        lea     edi,mitPunkt+13
        mov     ecx,10          ;10 Stellen
        call    schiebe         ;Tausenderpunkte in den Laengenstring

        invoke  StdOut,ADDR mitPunkt
        invoke  StdOut,ADDR bytes
        invoke  StdOut,ADDR wfd.cFileName
  nxt1:

        invoke  StdOut,ADDR crlf
        call    restore_msg_attrs
        jmp     @B

lpOut:
        invoke  FindClose,hSearch

TheEnd:
        ret

Main endp

; -------------------------
;Fuegt Tausenderpunkte in die Zahl ein - die Zahl wird
;entsprechend auseinandergeschoben
;Auruf: esi asdresiert den von-Bereich, rechter Rand
;Auruf: edi asdresiert den nach-Bereich, rechter Rand
;       ecx gibt die Stellenanzahl des Von-Bereichs an
; -------------------------
schiebe:
        mov     al,[esi]        ;Zeichenuebertrag
        mov     [edi],al

        dec     esi             ;beide Zeiger nach links
        dec     edi

        mov     ah,[esi]
        cmp     ah," "          ;vorheriges Zeichen ein Blank?
        je      @F              ;dann keine Tausenderpunkte

        mov     ah,"."
@@:
        cmp     ecx,10-3        ;war es die Tausenderstelle?
        jne     @F

        mov     [edi],ah
        dec     edi

@@:     cmp     ecx,10-6        ;bei der Million?
        jne     @F

        mov     [edi],ah
        dec     edi

@@:     cmp     ecx,10-9        ;bei der Milliarde?
        jne     @F

        mov     [edi],ah
        dec edi
@@:
        loop schiebe
        ret

;------------------------
; Attribut zum Anzeigetext RHSDAC
; Dabei wird das Feld msg_attrs von links nach rechts verändert
; Die Dateiattribute stehen bei Aufruf in eax
;------------------------
zeige_attribute:
        mov     ecx,12            ;12-mal schieben
;       mov     ax,[esi]
;       mov     ax,8bfh    ;RHSDA
        lea     edi,msg_attrs

ls55:   cmp     ecx,9   ;Bits Wertigkeit 8, 64, 128, 256, 512, und 1024
        je      ls59    ;ignorieren
        cmp     ecx,6
        je      ls59
        cmp     ecx,5
        je      ls59
        cmp     ecx,4
        je      ls59
        cmp     ecx,3
        je      ls59
        cmp     ecx,2
        jne     ls60            ;nicht ignorieren!

ls59:   rcr     ax,1            ;ignorieren!
        jmp     ls70

ls60:   rcr     ax,1
        jc      ls65            ;Attribut gesetzt

temp1:
        mov     byte ptr [edi],'-'
ls65:   inc     edi


ls70:   loop    ls55

        invoke  StdOut,offset msg_attrs_spc
        ret

; -------------------------
; Inhalt von msg_attrs wieder herstellen
; Wird nach Anzeige des Dateinamens aufgerufen
; -------------------------
restore_msg_attrs:
        mov     esi,offset attrs
        mov     edi,offset msg_attrs
        mov     ecx,6            ;6 Bytes Laenge
@@:     mov     al,[esi]
        mov     [edi],al
        inc     esi
        inc     edi
        loop    @B
        ret

; #########################################################################
        end     start

Interpretation des Quellprogramms

Das hier vorgestellte Programm ist nicht die endgültige Programmversion. Deshalb sind noch einige nicht benötigte Definitionen im Datenbereich vorhanden. Einige nicht mehr benötigte Befehle sind lediglich auskommentiert.

include und includelib: Der Kommentar „nachgetragen” kennzeichnet die gegenüber \masm32\examples\exampl02\dir\mdir.asm ergänzten Zeilen.

.data: Die Formatierungszeichenkette "%lu",0 des ursprünglichen Programmes wurde durch "%10.1lu",0 ersetzt. Die neue Definition erzeugt eine stets 10-stellige Zahl. Von ihr wird zumindest die Einerstelle als Ziffer erhalten. Bis zu 9 führende Nullen werden durch Zwischenräume (Spaces) ersetzt.

Die 10-stellige Zahl durchläuft vor ihrer Anzeige eine Textaufbereitung in dem Unterprogramm schiebe. Das Unterprogramm ergänzt Punkte bei den Tausenderstellen. Wenn links neben der der jeweiligen Tausenderstelle bereits ein Space steht, wird statt eines Punktes ein Space eingefügt.

.code start: Das Programm wird mit invoke ExitProcess,0 beendet. Bei den vorhergehenden Beispielen wurde an dieser Stelle das in \masm32\macros\macros.asm definierte Macro „exit” genutzt. In beiden alternativen Schreibweisen

  • exit und
  • exit 0
hätte das Macro generiert: invoke ExitProcess,0

invoke GetCL,1,ADDR Buffer liest den ersten Aufrufparameter von der Kommandozeile. Sofern kein Aufrufparameter angegeben wurde, denkt sich das Programm ein Sternchen für „alles”.

invoke FindFirstFile,ADDR Buffer,ADDR wfd sucht die erste passende Datei gem. dem angegebenen Pfad. Dieser Aufruf erfolgt einmalig. Sofern keine erste Datei gefunden wird, erfolgt die Anzeige eines Fehlerhinweises und das Programmende wird eingeleitet. Wird eine erste Datei gefunden, wird der Dateihandle für spätere Verwendung nach hSearch gesichert und der Verzeichniseintrag wird zur Anzeige gebracht.

invoke FindNextFile,ADDR Buffer,ADDR wfd sucht nach Ausführung von FindFirstFile die nächste passende Datei. Wird eine solche gefunden, wird der Verzeichniseintrag angezeigt und anschließend erneut FindNextFile aufgerufen.

Sofern bei eine FindNextFile-Aufruf keine nächste passende Datei gefunden wurde, gibt FindNextFile im eax-Register den Wert 0 zurück. Dies führt zur Beendigung des Programms.

Aufbereitung der Anzeigezeilen: Zur Anzeige von Datum und Uhrzeit der letzten Änderung wird die Funktion DateTimeToStringShort24 aus dem weiter oben erwähnten Paket zur Behandlung von Datums- und Zeitfunktionen genutzt. Die aus dieser Funktion gewonnene Zeichenkette wird durch Anwendung des Befehls invoke StdOut, ADDR pzsShort24 unverändert zur Anzeige gebracht. Es sei bemerkt, dass in dem vorliegenden Programm der Bereich pzsShort24 mit 64 Bytes unnötig lang definiert ist: 21 Bytes hätten genügt.

Zur Aufbereitung der Attributanzeige habe ich das Rotationsverfahren aus dem oben erwähnten 16-bit-Programm LS.com mit Anpassung übernommen. Es wird im Unterprogramm schiebe durchgeführt. Dessen Aufruf erfolgt von der Prozedur Main aus. In diesem Fall wirkt sich die Verwendung lokaler Variablen ungünstig aus: Im Quellprogrammtext erscheint zweimal der Aufruf von „schiebe” hinter jeweils drei identischen Programmzeilen. Könnte man diese drei Zeilen ins Unterprogramm „schiebe” übernehmen? Leider geht das nicht, weil bei

 lea     esi,sizeBuffer+10
 lea     edi,mitPunkt+13
die beiden Variablen lokal deklariert sind. Dagegen könnte man die beiden Programmzeilen
 invoke  StdOut,ADDR mitPunkt
 invoke  StdOut,ADDR bytes
vor dem ret-Befehl von „schiebe” unterbringen, denn beide Variablen sind global deklariert.
Letztes Upload: 14.07.2023 um 06:19:40 • Impressum und Datenschutzerklärung