MASM32 - Strings und Speicher reservieren



  • Habe ja vor einiger Zeit ein Programm in ASM angefangen und hatte das Problem dass bei einer Stringkonkatenation mit 3 Strings das Programm immer abstürzte. Mittlerweile ist mir plötzlich eingefalen wieso; es ist ja so logisch!! Es werden Strings definiert und an diese soll dann etwas angehängt werden, aber natürlich ist dann zuwenig Speicher reserviert. Wie lässt sich das Problem lösen? mit DUP wüsste ich dabei nicht wie dass der String dennoch den richtigen Inhalt hat. Es ist für die mciSendString-Funktion und soll den String mit dem Dateinamen bilden also z.B. "open c:\eigene1\meinem1\eluveitie.wma alias MyAlias" Hier die relevanten Codeausschnitte:

    Deklarationen:

    open1 db "open ",0 
    open2 db " alias MyAlias",0
    

    und vom Öffnen-Dialog:

    szFileName    db 260 dup(0)
    

    und die Routine:

    .if wParam == 1001 
              ; -------------------------------------- 
              ; szFileName is defined in Filedlgs.asm 
              ; -------------------------------------- 
                mov szFileName[0],0     ; set 1st byte to zero 
                invoke GetFileName,hWin,SADD("Open A File"), 
                                        SADD("All files",0,"*.*",0) 
                cmp szFileName[0],0     ; zero if cancel pressed in dlgbox 
                je @F 
    
    Start:    
      lea esi, open1 
     FindLastByte: 
      lodsb 
      Or al, al 
      jnz FindLastByte 
    
      dec esi 
      mov edi, esi 
      lea esi, szFileName 
      CatStrings: 
      lodsb 
      Or al, al 
      jz Done 
      stosb 
      jmp CatStrings 
    
     Done: 
      mov al, 0 
      stosb 
    
                     ;Start:    
      lea esi, open1 
     FindLastByte2: 
      lodsb 
      Or al, al 
      jnz FindLastByte2 
    
      dec esi 
      mov edi, esi 
      lea esi, open2 
      CatStrings2: 
      lodsb 
      Or al, al 
      jz Done2 
      stosb 
      jmp CatStrings2 
    
     Done2: 
      mov al, 0 
      stosb 
    
                invoke MessageBox,hWin,ADDR open1,ADDR szDisplayName,MB_OK
    

    GetShortPathName wird natürlich noch eingebaut; in einer Konsolen-Version in C läuft es und in ASM mit fest eingegebenem Dateinamen ebenfalls.



  • STOP Problem gelöst! Versuchte (ohne ernsthaft zu denken das gehe):

    open1 db "open ", 255 dup(?),0
    

    und das geht! Juhui



  • Diese Anordnung kann so eigentlich nicht funktionieren...
    Ich will mal versuchen, deinen geposteten Code zum besseren Verstaendnis in Pseudocode umzusetzen:

    ; wo steht das eigentlich? In irgendeinem Datensegment?
    open1 db "open ',0
    open2 db " alias MyAlias',0
    ; [...]
    szFileName    db 260 dup(0)
    ; [...]
      lea esi, open1
     FindLastByte:
      lodsb
      Or al, al
      jnz FindLastByte
    
      dec esi
      mov edi, esi
    

    Wird kurz und knapp zu

    edi = &open2 - 1;
    

    , weil oben direkt auf das letzte (0-)byte vom String bei open1 der String bei open2 folgt. Fuer einen konstanten String also so oder so ueberfluessig, da du dir das Offset selbst in Assembler, wie zB. im Pseudocode oben, direkt haettest holen koennen.

    lea esi, szFileName
      CatStrings:
      lodsb
      Or al, al
      jz Done
      stosb
      jmp CatStrings
    
     Done:
      mov al, 0
      stosb
    

    wird vielleicht zu sowas wie

    strcpy (&szFileName, edi);
    

    du kopierst also den String bei szFileName ueber open2 rueber. Mal davon ab, dass das wahrscheinlich so nicht beabsichtigt war, machst du damit auch alles, was evtl. hinter open2 steht auf diese Weise platt, wenn der String bei szFileName laenger als der ehemalige bei open2 ist.
    (zudem koennte man den Code noch sehr leicht in Geschwindigkeit und Groesse optimieren, aber egal).

    lea esi, open1
     FindLastByte2:
      lodsb
      Or al, al
      jnz FindLastByte2
    
      dec esi
      mov edi, esi
    

    Und das wird dann wieder zu

    edi = &open2 - 1;
    

    Gefolgt von

    lea esi, open2
      CatStrings2:
      lodsb
      Or al, al
      jz Done2
      stosb
      jmp CatStrings2
    
     Done2:
      mov al, 0
      stosb
    

    ==>

    strcpy(&open2, &open2 - 1);
    

    Also mal folgende Hinweise:
    Wenn du die 2 konstanten Strings jeweils vor und hinter einen 3. variablen String bringen willst, wuerde ich empfehlen, dir erstmal einen 4., ausreichend grossen (also vllt. so 256 Byte), uninitialisierten Speicherbereich zu verschaffen (kann zB. auf dem Stack liegen, oder im udataseg - oder wie auch immer du dein Segment fuer uninitialisierte Daten nennst).
    Der 1. String, der an den Anfang kommt, braucht auch kein abschliessendes 0-Byte, da eh sofort ein anderer String angehaengt wird.

    In deinen uninitialisierten Speicher kopierst du dann erstmal deinen 1. konstanten String rein - einfach mit rep movs - esi und ecx kannst du einfach setzen, da du sowohl das Offset als auch die Laenge des Strings kennst, also keine grosse Frickelei. edi kannst du je nachdem genauso einfach via Daten-Label auf das Ziel-Offset setzen, oder halt auf deinen freigemachten Stackbereich... wie auch immer.
    Da edi praktischerweise nach der Kopieraktion schon genau an die richtige Stelle hinter dem 1. (nicht 0-terminierten) String zeigt, packst du da nun deinen szFileName hin. Entweder auch rueberkopieren, oder edi direkt GetFileName als offset uebergeben.
    Wie auch immer du das geloest hast, kopierst du nun hinter den zuletzt angehaengten String deinen letzten konstanten String von open2 - auch wieder einfach mit rep movs.

    Zuletzt noch:
    Schau dir mal den scas(b/w/d)-Befehl an. Der ist naemlich uA. ganz prima dazu geeignet, in Strings die abschliessende 0 zu finden. 😉



  • Dabei musst du allerdings bedenken, dass dein (?) hier praktisch zu (0) wird, da noch initialisierte Daten folgen.



  • Ach so, könnte ich das noch etwas optimieren. Es läuft ansonsten bestens, vor der Routine habe ich mit mov open1[5], 0 verhindert dass einfach alle Strings zusammengehängt werden wenn man eine weitere Datei öffnen will. Werde aber wenn alles läuft sowieso nochmals etwas optimieren.

    Das Fenster habe ich mit Prostart erzeugt, nun kämpfe ich gerade mit der API, ich kann keinen Text ins Fester ausgeben mit der mit bekannten Methode da der erzeugte Code etwas anders aufgebaut ist als die Beispiele in einem Buch welchen ich folgte.


Anmelden zum Antworten