AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi PChars mit Null Bytes von DLL zu Programm übergeben
Thema durchsuchen
Ansicht
Themen-Optionen

PChars mit Null Bytes von DLL zu Programm übergeben

Ein Thema von edosoft · begonnen am 27. Mär 2008 · letzter Beitrag vom 27. Mär 2008
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von edosoft
edosoft

Registriert seit: 27. Okt 2003
Ort: Wehingen
258 Beiträge
 
Turbo Delphi für Win32
 
#1

PChars mit Null Bytes von DLL zu Programm übergeben

  Alt 27. Mär 2008, 09:06
Hallo,

Ich versuche grade meine erste DLL-Datei zu schreiben =) klappt auch relativ gut... nur mit dem string hin-und hertauschen habe ich probleme. um von einer funktion eine rückgabe zu erhalten habe ich die als PChar definiert. jetzt kann es aber sein, da ich mit dateiinhalten und dateihashes arbeite dass irgendwo mitten in einem string ein nullbyte enthalten ist. wenn ich den jetzt mit PChar(s) in einen pchar umwandle um ihn als rückgabewert der funktion anzugeben wird der string ja abgeschnitten. deswegen hab ich mir gedacht ich geb einfach zusätzlich die länge des strings zurück bevor er in einen pchar umgewandelt wird und kann ja dann bestimmt irgendwie den speicherbereich der eigentlich für den pchar reserviert wurde im hauptprogramm wieder auslesen und in einen string umwandeln.
da hab ich mal bissle rumprobiert und bin auf folgendes gestoßen:


DLL-Datei:
Delphi-Quellcode:
function GetFileHash(pFileName: PChar; out pBuff: PChar): Integer; stdcall;
var
  sHash: string;
begin
  sHash := 'a'+#0+'b';
  pBuff := PChar(sHash);
  Result := Length(sHash);
end;
Hauptprogramm:
Delphi-Quellcode:
var
  i: Integer;
  s, s2: string;
  p: pchar;
begin
  i := DllGetFileHash('c:\CA.txt', p);
  s := string(@p^);
  showmessage(inttostr(length(p))); //1
  showmessage(inttostr(length(s))); //3 (!)
  s2 := '';
  for i := 1 to Length(s) do
  begin
    s2 := s2 + IntToHex(Ord(s[i]), 2) + ' ';
  end;
  ShowMessage(s2); //61 00 62
was ich mich jetz frage ist warum funktioniert das?? und woher weis der delphi dass der speicherbereich von p 3 bytes groß sein sollte?
kann ich die funktion so verwenden oder könnte ich damit probleme bekommen? oder hat vielleicht irgendjemand eine bessere idee?

Vielen Dank!!
Dominik Weber
www.edo-soft.com
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#2

Re: PChars mit Null Bytes von DLL zu Programm übergeben

  Alt 27. Mär 2008, 09:26
Das funktioniert unter Delphi einschränkend. Kommt den da kein Fehler am Ende der Funktion? Oder wenigstens am Ende des Programms?

Die Funktionsweise ist folgende:
Ein String ist ja auch nichts weiter als ein Pointer auf eine Zeichenkette. Dasselbe gilt für einen PChar. Wenn du einen String anlegst, wird in den 4 Bytes vor dem String die Länge des Strings hinterlegt. Wenn du jetzt auf PChar Typecastest wird genauso ein Pointer auf die Zeichenkette erzeugt wie bei einem String. Am Speicher, also an der Zeichenkette+Längenangabe ändert sich nichts. Der Unterschied ist nur, dass der Compiler jetzt ein wenig anders arbeitet und den String nicht automatisch freigibt bzw. den Referenzzähler (der noch vor der Längenangabe liegt) verändert.
Wenn du jetzt wieder im HP auf String zurückcastest, dann findet er auch wieder die Längenangabe für die sich ein PChar nicht interessiert.
Allerdings dürfte er jetzt versuchen den String freizugeben, was zu einer AV führen sollte.


Edit: Das funktioniert nur, weil sHash auf eine Konstante zeigt. Mach mal folgendes:
Delphi-Quellcode:
function GetFileHash(pFileName: PChar; out pBuff: PChar): Integer; stdcall;
var
  x:string;
  sHash: string;
begin
  x := 'a'+#0+'b'; //x zeigt auf eine Konstante
  sHash:=x+'1'; //sHash wird neu zugewiesen und zeigt in den Heap
  pBuff := PChar(sHash);
  Result := Length(sHash);
end;
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Benutzerbild von edosoft
edosoft

Registriert seit: 27. Okt 2003
Ort: Wehingen
258 Beiträge
 
Turbo Delphi für Win32
 
#3

Re: PChars mit Null Bytes von DLL zu Programm übergeben

  Alt 27. Mär 2008, 09:46
danke für die schnelle antwort!
hmm kann ich denn dann nicht irgendwie einfach und unproblematisch sagen ich will den arbeitsspeicherbereich ab @p bis @p+xx bytes auslesen und in einen string gepackt haben? und dann könnte ich ja auch als rückgabewert keinen pchar sondern direkt nen pointer verwenden oder?

auch mit dem x:= bla und sHash:=x+'1'; funktionierts einwandfrei. nirgends tauchen fehler auf.
davor hatte ich versucht mit copymemory(@s, @p, i) (i war ja die länge des strings bevor er zum pchar gecastet und als funktionsrückgabe verwendet wurde) und copymemory(@s[1], @p, i) zu arbeiten hat aber ich glaub ersteres gab en fehler beim beenden oder so und letzteres hat in s irgendwelche falschen werte gespeichert.
Dominik Weber
www.edo-soft.com
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#4

Re: PChars mit Null Bytes von DLL zu Programm übergeben

  Alt 27. Mär 2008, 09:49
Les dir das mal durch: http://www.michael-puff.de/Artikel/2...String_DLL.php
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#5

Re: PChars mit Null Bytes von DLL zu Programm übergeben

  Alt 27. Mär 2008, 10:00
Fehlerfrei funktioniert die kurze Funktion auch noch. Das ist aber nur Zufall. Wenn du zwischendurch noch weitere Speicherzuweisungen machst, wird irgendetwas überschrieben. Bei mir stimmen übrigens die Ausgaben mit showmessage schon nicht mehr.

Das mit Pointer und einer Längenangabe hätte ich dir auch geraten. Normalerweise funktioniert das so:
Delphi-Quellcode:
//**** DLL ******
function GetFileHash(pFileName: PChar; pBuf: Pointer; iBuflen: Integer): Integer; stdcall;
var
  sHash: string;
begin
  sHash := 'a'+#0+'b';
  result:=length(sHash)+1; //+NullByte am Ende
  if iBuflen<result then result:=iBuflen;
  move(sHash[1],pBuf^,result);
  dec(result); //NullByte nicht zur Länge zählen
end;

//**** Main ******
var
  i: Integer;
  s: string;

begin
  setlength(s,100);
  i := GetFileHash('c:\CA.txt', @s[1],100);
  setlength(s,i);
  ShowMessage(s);
end;
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#6

Re: PChars mit Null Bytes von DLL zu Programm übergeben

  Alt 27. Mär 2008, 10:07
@sirius: in der praxis wird es ein wenig anders gemacht. Da wird in aller Regel immer die benötigte Länge zurück gegeben. Bei deiner Variante könnte man im Moment nicht rausfinden wie groß der Buffer sein muss ohne einen ausreichend großen Buffer zu übergeben.
In der Regel sind die Funktionen aber so das man sie einmal aufrufen kann mit einem 0 Byte großen buffer um die benötigte Länge zu bekommen und dann kann man sie mit der exakt benötigten Länge (dank des ersten Aufrufes) noch einmal aufrufen.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Benutzerbild von edosoft
edosoft

Registriert seit: 27. Okt 2003
Ort: Wehingen
258 Beiträge
 
Turbo Delphi für Win32
 
#7

Re: PChars mit Null Bytes von DLL zu Programm übergeben

  Alt 27. Mär 2008, 10:08
luckie: das hab ich durchgelesen und getestet aber bei dir wird auch bei #0 abgschnitten:
wenn du in deiner dll-datei anstatt
foo := 'foo' + s;
foo := 'foo' + #0 + s;
schreibst (also so als wäre da halt irgendwo innem hash oder so ein nullbyte drin) dann gibt dein programm aus:
hlib: 2293760
@func1: 2327988
len: 7
foo [7]

also er weis halt dass es 7 zeichen sein sollten, der pchar (den du ja wie ich letztendlich einfach mit string(pchar('foo'#0'bar')) castest) wird halt nach "foo" abgeschnitten.
und wie bei dir übertrage ich ja die länge auch noch in nem extra parameter deswegen weis mein programm ja auch wie lang sein pchar sein sollte, hab diese angabe aber bisher halt nur noch nicht verwerten können.

bei meiner funktion gibts nie einen fehler beim beenden, aber wenn der string den die dll übergibt länger als 146 zeichen ist dann gibts wenn ich es 2. mal auf button1 klicke (der des zeugs was unter hauptprogramm steht ausführt) ne zugriffsverletzung...
Dominik Weber
www.edo-soft.com
  Mit Zitat antworten Zitat
Benutzerbild von edosoft
edosoft

Registriert seit: 27. Okt 2003
Ort: Wehingen
258 Beiträge
 
Turbo Delphi für Win32
 
#8

Re: PChars mit Null Bytes von DLL zu Programm übergeben

  Alt 27. Mär 2008, 10:12
hmm aber wärs dann nicht einfacher ich reserviere in der dll-datei den speicherbereich den ich für die ausgabe benötige und geb den pointer dadazu und die größe zurück und kopiere dann im hauptprogramm mit move() die daten in eine dort definierte variable? so brauche ich die funktion nur einmal ausführen und hab dann gleich grüße des puffers und den puffer selber.
Dominik Weber
www.edo-soft.com
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#9

Re: PChars mit Null Bytes von DLL zu Programm übergeben

  Alt 27. Mär 2008, 10:17
@sir: Hast natürlich Recht, das habe ich jetzt grob unterschlagen.

Zitat von edosoft:
hmm aber wärs dann nicht einfacher ich reserviere in der dll-datei den speicherbereich den ich für die ausgabe benötige und geb den pointer dadazu und die größe zurück und kopiere dann im hauptprogramm mit move() die daten in eine dort definierte variable? so brauche ich die funktion nur einmal ausführen und hab dann gleich grüße des puffers und den puffer selber.
Nein, denn wenn die DLL den Speicher reserviert, dann muss sie ihn auch wieder freigeben. Und wie willst du das bewerkstelligen?
Eine Möglichkeit wäre über Interfaces. Und dann bist du schon fast bei COM.

Noch etwas. Die Ausgabe von einem String wird immer am Nullbyte abgeschnitten, weil Windows wieder PChars verwendet.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#10

Re: PChars mit Null Bytes von DLL zu Programm übergeben

  Alt 27. Mär 2008, 10:18
du solltest deine Funktion so gestalten das sie dir die benötigte Länge zurück gibt und das Ergebnis in den übergebenen Speicher kopiert.

ablauf wäre dann folgender (in Anwendung):
- Gib mir benötigte Länge
- größe der Variablen auf benötigten Speicher setzen
- Funktion nochmal aufrufen und benötigten Speicher übergeben

Delphi-Quellcode:
//**** DLL ******
function GetFileHash(pFileName: PChar; pBuf: Pointer; iBuflen: Integer): Integer; stdcall;
var
  sHash: string;
begin
  sHash := 'a'+#0+'b';
  result:=length(sHash);

  if ((pBuf <> nil) and (iBufLen > 0)) then
  begin
    if (iBuflen > result) then
      iBufLen := result;

    move(sHash[1], pBuf^, iBufLen);
  end;
end;
Delphi-Quellcode:
//***Anwendung***
var
  Hash: String;
  Len: Integer;
begin
  //benötigte Länge abfragen
  Len := GetFileHash('c:\abc.txt', nil, 0);
  //Buffer auf benötigte Länge setzen
  SetLength(Hash, Len);
  //Hash abfragen
  GetFileHash('c:\abc.txt', @Hash[1], Len);
Platz für ein eventuelles 0 Byte wird nicht benötigt weil ja zurück gegeben wird wie groß die Daten sind. Wenn ein 0 Byte gewünscht ist müsste sich das der Aufrufer dazu packen aber in deinem Fall ist es ja zum Beispiel nicht notwendig.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:12 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz