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.