Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Speicherzugriffsverletzung bei Parameterübergabe aus DLL! (https://www.delphipraxis.net/66607-speicherzugriffsverletzung-bei-parameteruebergabe-aus-dll.html)

Sillium 1. Apr 2006 10:17


Speicherzugriffsverletzung bei Parameterübergabe aus DLL!
 
Hallo,

ich habe für ein Projekt von mir einige Funktionen zwecks einfacherer Updates in eine Dll ausgelagert! Prinzipiell kenne ich mich mit DLLs aus und bis auf eine Funktion läuft auch alles, wie gewollt!

Heir die Prozedur, die mir Probleme macht:

Delphi-Quellcode:
procedure checkFiles(DirP :PChar; GShortP : Array of PChar;var AResultStr : Pchar);stdcall;
var
  Dir, List, GameMiss :String;
  GShort : Array of String;
  MissingShort : Array of String;
  i,a,b,GNum : Integer;
  evenAdded, MainMiss : boolean;
begin
  MainMiss := FALSE;
  Dir := String(DirP);
  setlength(GShort,length(GShortP));
  For i := 0 to length(GShortP)-1 do
    GShort[i] := String(GShortP[i]);
  For i := 0 to length(GShort)-1 do begin
      GNum := 1;
      If GShort[i] ='Short1' then begin
        If not FileExists(Dir+'Datei1') then begin
            setlength(MissinGShort,length(MissinGShort)+1);
            MissinGShort[length(MissinGShort)-1] := 'Datei1';
          GameMiss := 'True';
        end
        else begin
          GameMiss := 'False';
        end;
      end;
      If GShort[i] ='short2' then begin
        If not FileExists(Dir+'Datei2') then begin
          setlength(MissinGShort,length(MissinGShort)+1);
          MissinGShort[length(MissinGShort)-1] := 'Datei2';
          GameMiss := 'True';
        end
        else begin
          GameMiss := 'False';
        end;
      end;
      If GShort[i] ='Short3' then begin
        If not FileExists(Dir+'Datei3') then begin
          setlength(MissinGShort,length(MissinGShort)+1);
          MissinGShort[length(MissinGShort)-1] := 'Datei3';
          GameMiss := 'True';
        end
        else begin
          GameMiss := 'False';
        end;
        If not FileExists(Dir+'Datei4') then begin
          setlength(MissinGShort,length(MissinGShort)+1);
          MissinGShort[length(MissinGShort)-1] := 'Datei4';
         GameMiss := 'True';
        end
        else begin
          If GameMiss <> 'True'then
          GameMiss := 'False';
        end;
      end;
     .
     . //Und
     . //so
     . //weiter
     .
      If not FileExists(Dir+'Datei5') then begin
          For b := 0 to length(MissinGShort)-1 do
            If MissinGshort[b] = 'Datei5' then evenadded := true;
          if not evenadded then begin
            setlength(MissinGShort,length(MissinGShort)+1);
            MissinGShort[length(MissinGShort)-1] := 'Datei5';
          end;
          MainMiss := True;
         end;
      If GameMiss <> '' then
          If (GameMiss = 'False') and (not MainMiss) then
            If i = 0 then
              List := GShort[i]+'*T*' + IntToStr(Gnum) + Chr(13)
            else
              List := List + GShort[i]+'*T*' + IntToStr(Gnum) + Chr(13)
          else if (GameMiss = 'True') or (MainMiss) then
            If i = 0  then
              List := GShort[i]+'*F*' + IntToStr(Gnum) + Chr(13)
            else
              List := List + GShort[i]+'*F*' + IntToStr(Gnum) + Chr(13) ;
          GameMiss := '';
          MainMiss := False;
      end;
    For i := 0 to length(GShort)-1 do begin
    GNum := 2;
        If GShort[i] ='Short4' then begin
        If not FileExists(Dir+'Datei6') then begin
          setlength(MissinGShort,length(MissinGShort)+1);
          MissinGShort[length(MissinGShort)-1] := 'datei6';
           GameMiss := 'True';
        end
        else begin
          GameMiss := 'False';
        end;
        .
        . //Und
        . //so
        . //weiter
        .
        If not FileExists(GCFDir+'Source Dedicated Server.gcf') then begin
          For b := 0 to length(MissinGShort)-1 do
            If MissinGshort[b] = 'Source Dedicated Server.gcf' then evenadded := true;
          if not evenadded then begin
            setlength(MissinGShort,length(MissinGShort)+1);
            MissinGShort[length(MissinGShort)-1] := 'Source Dedicated Server.gcf';
          end;
          MainMiss := True;
        end;
      If GameMiss <> '' then
          If (GameMiss = 'False') and (not MainMiss) then
            If List ='' then
              List := GShort[i]+'*T*' + IntToStr(Gnum) + Chr(13)
            else
              List := List + GShort[i]+'*T*' + IntToStr(Gnum) + Chr(13)
          else if (GameMiss = 'True') or (MainMiss) then
            If List ='' then
              List := GShort[i]+'*F*' + IntToStr(Gnum) + Chr(13)
            else
              List := List + GShort[i]+'*F*' + IntToStr(Gnum) + Chr(13) ;
          GameMiss := '';
          MainMiss := False;
    end;
      For a:=0 to length(MissinGShort)-1 do
        List := List + Chr(13) + '\' + MissinGShort[a];
      //i := length(List);                                     <--------Wenn ich mir zum debuggen diese Zeilen auskommentiere,
      //messagedlg(IntToStr(i),mtWarning ,mbYesNoCancel ,1);   <--------Und mir z.B. die Länge von List ausgeben lass, bekomme
      //messagedlg(List,mtWarning ,mbYesNoCancel ,1);          <--------ich später keine Zugriffsverletzung mehr!           
    AResultStr := nil;
    AResultStr := PChar(List);
end;
Ich checke abhängig von gewissen Parameter (als Array übergeben) ob die dazugehörigen Dateien vorhanden sind oder nicht! Insgesamt sammele ich alle Informationen in einem String (List), den ich dann als PChar in AResultStr kopiere!

Ich habe versucht AResultStr zum einen als Rückgabewert einer Funktion zu übergeben:
Delphi-Quellcode:
function checkFiles(DirP :PChar; GShortP : Array of PChar): Pchar;stdcall;
.
.
.
AResultStr := PChar(List);
result := AResultStr;
Oder eben wie oben als Var-Parameter!

Beides mal bekomme ich eine Speicherzugriffsverletzung!

Aber ich komme nicht auf den Grund des Problems, weil:

1.

Wenn ich mir zur Laufzeit in Delphi die Variable List anschaue, ist alles ok!

Sieht so aus:
Delphi-Quellcode:
List := 'datei1*T*1'#$D'datei2*T*1'#$D'datei3*T*1'......
Doch beim übergeben an AResultStr mit:
Delphi-Quellcode:
AResultStr := PChar(List);
bleibt AResultStr unbestimmt!

Und ich bekomme die Zugriffsverletzung beim nächsten Schritt!


2.

Wenn ich mir zur Laufzeit, z.B die Läbge von List als MessageDlg anzeigen lass funktioniert später die übergabe von List auf AResultStr ohne Probleme und ich bekomme keine Speicherzugriffsverletzung!

3.

Wenn ich die gleiche Procedure nehme, Alles weglasse und nur einen String von Hand eingebe und an AResulStr übergeben lasse funktioniert auch alles!
Beispiel:
Delphi-Quellcode:
procedure checkFiless(GCFDirP :PChar; GShortP : Array of PChar;var AResultStr : Pchar);stdcall;
var
   Astr :String;
begin
   Astr := 'Short1*T*1' + Chr(13) + 'Short1*T*1' + Chr(13) +'Short1*T*1' + Chr(13) +'Short1*T*1' + Chr(13) +'Short1*T*1' + Chr(13)            +'Short1*T*1' + Chr(13) + '\' + 'Datei1'  + Chr(13) + '\' + 'Datei1'+ Chr(13) + '\' + 'Datei1';
   AResultStr := Pchar(Astr);
end;
Danke, dass ihr bis hier durchgehalten habt!

Sillium

Olli 21. Mai 2006 12:53

Re: Speicherzugriffsverletzung bei Parameterübergabe aus DLL
 
Wie sieht die USES-Liste der DLL aus?

SirThornberry 21. Mai 2006 13:25

Re: Speicherzugriffsverletzung bei Parameterübergabe aus DLL
 
nach dem aus deiner Funktion zurück gekehrt wurde ist "List" nicht mehr definiert sondern freigegeben. Das heißt dein Pointer auf "List" (also dein Result) zeigt auf eine Stelle im Speicher die nicht mehr da ist.

Olli 21. Mai 2006 13:33

Re: Speicherzugriffsverletzung bei Parameterübergabe aus DLL
 
Das vermute ich auch. Wenn er allerding den Delphi-MM benutzen würde, dann könnte er direkt Strings benutzen (deswegen die Frage nach der USES-Liste). Ist allerdings auch ein gewisser Overhead ;)

Am besten ist es, wenn Aufrufer und Aufgerufener eine gemeinsame Funktion zum Allozieren und Deallizieren des Speichers haben ;) ... dann kann der eine einen Pointer des anderen freigeben.

himitsu 21. Mai 2006 13:34

Re: Speicherzugriffsverletzung bei Parameterübergabe aus DLL
 
Jupp
Das AResultStr := nil; vor AResultStr := PChar(List); kannst'e erstmal weglassen ist "unnötiger" Code.

So könnte man dafür sorgen, das List nicht freigegeben wird.
Wie oben schon gesagt wurde, werden lockale Variablen am Ende der Prozedur freigeben (das Gilt zwar nicht für Objekte/Pointer..., wo nur de Zeiger "gelöscht" wird, aber bei Strings und dynamischen Arrays wird auch der Inhalt mit freigegeben.
Delphi-Quellcode:
AResultStr := PChar(List);
Pointer(AResultStr) := nil; // ändert nur den Pointer auf den String und läßt den Inhalt reserviert
Aber dann musß du dann später den String an der Stelle natürlich auch selber freigeben ;)


[add]
DelphiMM :shock:
der DelphiMM shared den Speicher nicht und da dann in jedem Modul ein eigener MM aktiv ist, kann man die Strings "nicht" in ein anders Modul übergeben,
jedenfalls wenn dort dann der Sringinhalt geändert wird, wozu in vielen Fällen auch nur das ändern des Referenzzählers zählt...


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:44 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