Autor Beitrag
SammyG
Hält's aus hier
Beiträge: 8

WinXP
Delphi 7 Personal
BeitragVerfasst: 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:

ausblenden 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:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
  s := PAnsiChar(Rcd.Str1);
// oder
  s := PAnsiChar(Rcd.Str1 + '_');
// oder
  s := PAnsiChar('Str1');


Das wiederum funktioniert nicht:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 22.04.11 14:46 
Was ist denn in Str1 und Str2 drin? Wenn da die JPEG-Daten drinstehen :shock:, 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? :gruebel:

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 Threadstarter
Hält's aus hier
Beiträge: 8

WinXP
Delphi 7 Personal
BeitragVerfasst: Fr 22.04.11 14:52 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Was ist denn in Str1 und Str2 drin? Wenn da die JPEG-Daten drinstehen :shock:, 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? :gruebel:

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:

ausblenden volle Höhe 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:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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... :oops:

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:
ausblenden 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 Threadstarter
Hält's aus hier
Beiträge: 8

WinXP
Delphi 7 Personal
BeitragVerfasst: 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):

ausblenden Delphi-Quelltext
1:
  s := pAnsiChar(copy(Name,1,8));					


Funktioniert.

ausblenden Delphi-Quelltext
1:
  s := pAnsiChar(copy(Name,1,9));					


Funktioniert nicht.

ausblenden Delphi-Quelltext
1:
  s := pAnsiChar('1234567890');					


Funktioniert wieder. An irgendeiner Null-Terminierung hängts also nicht. Ich raffs einfach nett...


Sammy
SammyG Threadstarter
Hält's aus hier
Beiträge: 8

WinXP
Delphi 7 Personal
BeitragVerfasst: 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