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.