Autor |
Beitrag |
SammyG
Hält's aus hier
Beiträge: 8
WinXP
Delphi 7 Personal
|
Verfasst: Fr 22.04.11 14:27
Irgendwie steh ich gerade aufm Schlauch:
Ich habe eine Ressourcen-DLL, die ich hin und wieder mit kleinen Thumbnails füttere.
Die Resource kommt aus einem Stream ("Data"), der Resourcenname aus der Verkettung zweier String-Felder eines Records:
Delphi-Quelltext 1: 2: 3:
| s := PAnsiChar(Rcd.Str1 + '_' + Rcd.Str2); if not UpdateResource(h, PAnsiChar('JPEG'), s, LANG_NEUTRAL, DataPtr, Data.Size) then RaiseLastOSError; |
Nur wird die Ressource nicht in die DLL geschrieben, es gibt keine Exception oder Fehlermeldung seitens der API-Funktion!
Ich kapiers nicht, denn folgendes funktioniert:
Delphi-Quelltext 1: 2: 3: 4: 5:
| s := PAnsiChar(Rcd.Str1); s := PAnsiChar(Rcd.Str1 + '_'); s := PAnsiChar('Str1'); |
Das wiederum funktioniert nicht:
Delphi-Quelltext 1:
| s := PAnsiChar('Str1' + '_' + 'Str2'); |
Das Problem muss irgendwo beim String/Pointer Management liegen. Hat da irgendwer ne Idee?
Grüße,
Sammy
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 22.04.11 14:46
Was ist denn in Str1 und Str2 drin? Wenn da die JPEG-Daten drinstehen  , wird das so nichts. Denn da können auch Nullzeichen vorkommen. Und das definiert das Ende eines PAnsiChars. Das heißt ein Teil der Daten ist weg.
Das wäre aber ohnehin nicht sinnvoll, Zeichenketten als Datenspeicher zu missbrauchen.
Und was ist eigentlich Data.Size, du übergibst einen Pointer und holst woanders die Größe her?
Numm einfach z.B. einen TMemoryStream und übergib dessen Eigenschaft Memory. Oder nimm einen eigenen Pointer, reserviere dafür Speicher und pack die Daten hinein.
|
|
SammyG 
Hält's aus hier
Beiträge: 8
WinXP
Delphi 7 Personal
|
Verfasst: Fr 22.04.11 14:52
jaenicke hat folgendes geschrieben : | Was ist denn in Str1 und Str2 drin? Wenn da die JPEG-Daten drinstehen , wird das so nichts. Denn da können auch Nullzeichen vorkommen. Und das definiert das Ende eines PAnsiChars. Das heißt ein Teil der Daten ist weg.
Das wäre aber ohnehin nicht sinnvoll, Zeichenketten als Datenspeicher zu missbrauchen.
Und was ist eigentlich Data.Size, du übergibst einen Pointer und holst woanders die Größe her?
Numm einfach z.B. einen TMemoryStream und übergib dessen Eigenschaft Memory. Oder nimm einen eigenen Pointer, reserviere dafür Speicher und pack die Daten hinein. |
Nee, da liegt leider nicht das Problem: es funktioniert ja einwandfrei, wenn der Ressourcenname nicht irgendwie zusammengestellt ist. Aber das mit der Nullterminierung der zwei Record-Strings ist eine Idee, das checke ich gleich mal.
Zur Verdeutlichung hier die gesamte Funktion:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
| function SaveToResDLL(Data: TMemoryStream; Name: String): Boolean; var h: THandle; DataPtr: Pointer; s: pAnsiChar; begin result := false; DataPtr := nil; h := BeginUpdateResource(PChar(ExtractFilePath(paramstr(0)) + 'Res.dll'), false);
try if h = 0 then RaiseLastOSError;
Data.Position := 0; DataPtr := AllocMem(Data.Size); Data.Read(DataPtr^, Data.Size);
s := pAnsiChar('STR1');
if not UpdateResource(h, PAnsiChar('JPEG'), s, LANG_NEUTRAL, DataPtr, Data.Size) then RaiseLastOSError;
if not EndUpdateResource(h, False) then RaiseLastOSError;
result := true; finally if DataPtr <> nil then FreeMem(DataPtr);
end;
end; |
Mittlerweile habe ich herausgefunden, dass das selbe Problem auch bei kleinen Buchstaben im String auftritt (z.B. "Str1" statt "STR1"), unabhängig von der Verkettung...
Vielen Dank soweit,
Sammy
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 22.04.11 15:00
Ja, ich sehe schon, ich bin da ein wenig durcheinander gekommen, s hat ja mit den Daten der Ressource nichts zu tun. Man sollte vielleicht nicht mehr als 3 oder 4 Sachen gleichzeitig machen...
Gut, aber hier verstehe ich nicht ganz, warum du das so kompliziert machst. Ich habe es jetzt nicht getestet, aber sollte das nicht genauso direkt gehen: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| function SaveToResDLL(Data: TMemoryStream; Name: String): Boolean; var h: THandle; s: pAnsiChar; begin result := false; h := BeginUpdateResource(PChar(ExtractFilePath(paramstr(0)) + 'Res.dll'), false);
if h = 0 then RaiseLastOSError;
Data.Position := 0;
s := pAnsiChar('STR1');
if not UpdateResource(h, PAnsiChar('JPEG'), s, LANG_NEUTRAL, Data.Memory, Data.Size) then RaiseLastOSError;
if not EndUpdateResource(h, False) then RaiseLastOSError;
result := true; end; | Nebenbei wäre dein try..finally Block auch falsch gesetzt gewesen:
Die Reservierung des Speichers sollte vor dem try passieren.
|
|
SammyG 
Hält's aus hier
Beiträge: 8
WinXP
Delphi 7 Personal
|
Verfasst: Fr 22.04.11 15:13
Das mit dem Data-Pointer war noch ein Relikt von vorherigen Debug-Versuchen, als ich glaubte, dass da irgendwie der Fehler im Stream liegt. Danke für den Hinweis, ist wieder wie es sein sollte.
Das mit dem Try-Block ist richtig, die API-Func braucht ja eh keinen. Der war nur zum Absichern des Datapointers, falls ich irgendwo anders Mist baue und der ist ja dank Deines Hinweises ohnehin für die Füße.
Das ganze ändert aber immer noch nichts am Problem: Irgendwie muss ich doch die Strings verketten können ohne, dass es zu Problemen führt.
Folgendes habe ich nochmal ausprobiert ("Name" wurde extern aus den Rec.-Strings zusammengesetzt, wobei der erste String nur 5 Zeichen lang ist und der zweite mit verschiedenen Längen und Inhalten variiert):
Delphi-Quelltext 1:
| s := pAnsiChar(copy(Name,1,8)); |
Funktioniert.
Delphi-Quelltext 1:
| s := pAnsiChar(copy(Name,1,9)); |
Funktioniert nicht.
Delphi-Quelltext 1:
| s := pAnsiChar('1234567890'); |
Funktioniert wieder. An irgendeiner Null-Terminierung hängts also nicht. Ich raffs einfach nett...
Sammy
|
|
SammyG 
Hält's aus hier
Beiträge: 8
WinXP
Delphi 7 Personal
|
Verfasst: Fr 22.04.11 15:25
OK. Habs gefunden.
Es lag daran, dass Str2 Kleinbuchstaben beinhaltetet (bei den Tests immer an 9. Stelle!). Mit Uppercase() hat sich das Ganze erledigt.
Quintessenz: UpdateResource kann nicht mit Kleinbuchstaben umgehen.
Danke für die Mühen und & Grüße nach Berlin,
Sammy
|
|
|