Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.818 Beiträge
 
Delphi 12 Athens
 
#25

Re: Dynamisches Array von DLL übergeben

  Alt 6. Dez 2006, 17:55
Zitat von Wormid:
Delphi-Quellcode:
library Project1;

type
  TTestArray = array of ShortString; // <--- ShortString !!!
  PTestArray = ^TTestArray;

function GetTestArray: PTestArray; stdcall;
var
  a: TTestArray;
begin
  SetLength(a, 3);
  a[0] := 'Hallo';
  a[1] := 'Welt';
  a[2] := '!';
  Result := PTestArray(a);
end;

exports
  GetTestArray;

begin
end.
Zitat von ste_ett:
Dadurch, dass du einen Pointerauf den Array als Rpckgabewert übergibst, wird jeglicher Speicher, der für den Array reserviert wurde wieder als beschreibbar markiert. Nur die vier Byte für den Pointer sind fest. Theoretisch könnte in der Millisekunde nach zurückgeben des Pointers eine andere Anwendung den Speicher, wo die drei Array-Elemente liegen, wieder nutzen.
Stimmt, was das mit dem Freigeben angeht ... man könnte Delphi ja auch daran hindern das Array automatisch freizugeben...
Delphi-Quellcode:
library Project1;

type
  TTestArray = array of ShortString; // <--- ShortString !!!
  PTestArray = ^TTestArray;

function GetTestArray: PTestArray; stdcall;
var
  a: TTestArray;
begin
  SetLength(a, 3);
  a[0] := 'Hallo';
  a[1] := 'Welt';
  a[2] := '!';
  Result := PTestArray(a);
  Pointer(a) := nil; // Array-Variable als Leer definieren
end;

procedure FreeTestArray(a: PTestArray); stdcall;
begin
  SetLength(TTestArray(a), 0);
end;

exports
  GetTestArray,
  FreeTestArray;

begin
end.

Theoretisch ist es aber auch möglich den Speicher(inhalt) komplett an den anderen MemoryManager zu übergeben (außer für Objekte und dergleichen).

Für den Fall des StringArrays gäbe es wohl 2 Hauptmöglichkeiten, entweder man kümmert sich selber um um die Verwaltung des Speichers (reservieren, freigeben, kopieren), oder man nutzt die String- und Arrayfunktionen für's kopieren.

Müßtest aber mal etwas mehr über deine Funktion sagen.
- entwerder die gesammte funktion zeigen
- oder zumindestens deren definition und ob die übergebenen parameter intern verändert werden.




So als Beispiel, wie es eventuell gehen könnte:
Delphi-Quellcode:
Type TExtGetMem = Function(i: Integer): Pointer;

Var ExtGetMem: TExtGetMem;

Procedure SetExtGetMem(G: TExtGetMem);
  Begin
    ExtGetMem := G;
  End;

Function Explode(S, Sep: String): TStringArray;
  Var Temp: PStringArray;
    P: PChar;
    i: Integer;

  Begin
    ...

    // Speicher übergeben ...
    If Result = nil Then Exit;
    Temp := PChar(GetMemory(Length(Result) * 4) + 8) + 8;
    PInteger(Integer(Temp) - 8)^ := 1; // Array.RefCount
    PInteger(Integer(Temp) - 4)^ := Length(Result); // Array.ElementCount
    P := Temp;
    For i := 0 to High(Result) do Begin
      If Result[i] <> 'Then Begin
        PPointer(P)^ := PChar(GetMemory(Length(Result) * 4) + 9) + 8; // Array.Data[i]
        Move((P - 8)^, PChar(Result[i]) - 8, Length(Result[i] + 9);
      End Else PPointer(P)^ := nil;
      Inc(P, 4);
    End;
    Result := nil; // Array leeren
    Pointer(Result) := P; // ArrayDaten des anderen MM zuweisen
  End;

Export
  SetExtGetMem,
  Explode;
Ich hoff i hab's soweit richtig ... war jetzt nur aus'm Kopf und ohne Delphi, also nicht getestet.
Sieht zwar schwerer aus, als es ist, aber im Grunde mußt du nur jeden einzelnen Speicherblock in den anderen MemoryManager kopieren und die Pointer entsprechend anpassen.

Bist du dir also sicher, daß du keinen SharedMM verwenden willst?

ach ja, aufgerufen würde es dann so:
Delphi-Quellcode:
SetExtGetMem(@GetMemory);
...
myStringArray := Explode(S, Sep);
Dat war also die Methode mit dem selber drum kümmern, wobei hier alles in der Methode drin ist, für's Andere geb ich vielleich etwas später noch ä kurzes Beispiel.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat