Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Dynamisches Array von DLL übergeben (https://www.delphipraxis.net/81845-dynamisches-array-von-dll-uebergeben.html)

TheMiller 4. Dez 2006 21:42


Dynamisches Array von DLL übergeben
 
Hallo,

habe schon seit längerem ein kleines Problem. Ich habe eine Funktion und weiß nicht, wie ich ein Array aus einer DLL-Funktion an die Hauptapplikation übergeben kann.
Dabei benutze ich nicht den Delphi-Speichermanager, sondern versuche das so zu regeln, was bei den Array auch nicht klappt - sonst schon!

danke Leute!!

alzaimar 4. Dez 2006 21:51

Re: Dynamisches Array von DLL übergeben
 
Zitat:

Zitat von DJ-SPM
Dabei benutze ich nicht den Delphi-Speichermanager, sondern versuche das so zu regeln, was bei den Array auch nicht klappt - sonst schon!

:wiejetzt:


Lass doch den Client den Speicher alloziieren.

Bernhard Geyer 4. Dez 2006 21:52

Re: Dynamisches Array von DLL übergeben
 
Zeig mal ein bischen Code was du sonst so machst und wie du es beim Array machen willst

TheMiller 4. Dez 2006 22:32

Re: Dynamisches Array von DLL übergeben
 
Habe in der DLL eine Funktion (meine eigene Explode-Funktion). Da geteilten Strings möchte ich dann in ein Array packen und von da aus an die Hauptanwendung schicken. Meine Explode-funktion (auszug):

Delphi-Quellcode:
  for i:=0 to sl.Count-1 do
  begin
    for j:=StrToInt(sl2.Strings[i]) to StrToInt(sl.Strings[i])-1 do
    begin
      s:=s+p[j];
    end;
    SetLength(Content, i);
    content[i]:=s;
  end;

....

  if Assigned(Buffer) then
  begin
    StrLCopy(Buffer, PChar(content), BufferLen);
  end;
  result:=length(s);
Hatte vorher den String "s" übergeben und das hat alles supeer funktioniert. Nur ich weiß nicht, wie ich die Speicheranforderung per Array machen soll. So hatte ich den Speicher für den String "s" angefordert (Anwendung)

Delphi-Quellcode:
  len:=Explode(nil, PChar(Source), PChar(Separator), 0);
  try
    GetMem(Buffer, len+1);
    len:=Explode(Buffer, PChar(Source), PChar(Separator), len+1);
    s:=String(Buffer);
  finally
    FreeMem(Buffer);
  end;
Danke!

mkinzler 5. Dez 2006 06:45

Re: Dynamisches Array von DLL übergeben
 
Dynamische Arrays kannst du mit setLength vergrößern/verklenern (Speicher anfordern/freigeben)

TheMiller 5. Dez 2006 16:29

Re: Dynamisches Array von DLL übergeben
 
Ja schon klar. Nur wie kann ich das DynArray als Rückgabewert einer Funktion aus einer DLL in die Hauptanwendung nutzen?

Bernhard Geyer 5. Dez 2006 16:40

Re: Dynamisches Array von DLL übergeben
 
Ich denke ohne gemeinsamen Speichermanager ist das AFAIK nicht sicher möglich.

Ansonsten mußt du mit C-Like Arrays und direkte Speicheranforderung/Freigabe von Windows arbeiten.

TheMiller 5. Dez 2006 21:15

Re: Dynamisches Array von DLL übergeben
 
hm...

oder ich muss den schritt halt aufteilen: Die Funktion gibt mir lange Strings zurück, die ich in der Hauptanwendung in diese dann dort in Array packe. Finde ich zwar nicht so schön, aber so solls halt erstmal sein.

Danke euch.

Aber wenn's noch Vorschläge gibt, nehm ich sie gerne an!

oschulz 5. Dez 2006 22:02

Re: Dynamisches Array von DLL übergeben
 
Das hilft dir jetzt sicherlich nicht direkt weiter, aber ich hab genau für den Fall heute etwas in der Delphi Hilfe gesehen! Nur weiss ich leider nicht mehr wo :roll:

TheMiller 5. Dez 2006 22:38

Re: Dynamisches Array von DLL übergeben
 
Hm...

das ist gut und schlecht. Ich hab grad gesehen. Brauche es echt dringend. Nur wenn du nicht mehr weißt wo, dann hilft mir das wirklich nicht. Brauch aber die Lösung...

Eichhoernchen 5. Dez 2006 22:48

Re: Dynamisches Array von DLL übergeben
 
Zitat:

Zitat von DJ-SPM
hm...

oder ich muss den schritt halt aufteilen: Die Funktion gibt mir lange Strings zurück, die ich in der Hauptanwendung in diese dann dort in Array packe. Finde ich zwar nicht so schön, aber so solls halt erstmal sein.

Danke euch.

Aber wenn's noch Vorschläge gibt, nehm ich sie gerne an!


Würde das nicht irgendwie dem Sinn der DLL widersprechen?

Ich meine du zerteilst erst etwas mit deiner Explode Funktion und dann bastelst du wieder einen String, den man um ihn in ein Array zu packen wieder mit einer Explode-artigen Funktion bearbeiten muss um das Ergebnis in ein Array zu speichern. Hört sich für mich Sinnlos an.

Kannst du nicht vielleicht einen Pointer übergeben, der auf eine Speicheradresse mit dem Array zeigt? Aber das würde wahrscheinlich nur bei konstanter Größe gehen richtig?

TheMiller 5. Dez 2006 22:56

Re: Dynamisches Array von DLL übergeben
 
Pointer sind schon der richtige Weg - denke ich.

Mein Problem ist folgendes. Ich möchte einen Datensatz aus einer DB per PHP laden. Da habe ich dann verschiedene Felder (klar -> ist ja eine DB) diese Felder bzw. deren Werte sind durch einen Separator getrennt. Das Ende des Datensatzes hat einen anderen Separator. Jetzt möchte ich alle Datensätze in ein Record speichern.

Dazu muss ich doch erst die Werte zurückgeben lassen (die "Sep1" getrennt) und das Ende eines Datensatzes finden ("Sep2"). Jetzt muss ich erst nach Sep2 exploden und diese in ein Array speichern, sodass ich auf die einzelnen Datensätze zugreifen kann. Dann kann ich mich an die Werte machen ("Sep1") und kann diese Daten dann schön in mein Array speichern.

Soweit mein Vorhaben *g*

gmc616 6. Dez 2006 01:55

Re: Dynamisches Array von DLL übergeben
 
Mit Pointer funktioniert das so nicht!

Das Arbeiten mit dynamischen Arrays zwischen DLL und Applikation ist, wie ich schmerzlich lernen mußte, nicht ohne weiteres möglich. Besonders dann nicht, wenn du ohne Speichermanager arbeiten willst.

Ich habe mir für diesen Fall eine "Krücke" gebastelt, in dem ich das Array in der DLL verwalten lasse und mir Export-Funktionen gebaut habe, die mir u.a. die Länge des DLL-Arrays zurück geben. Die einzelnen Array-Elemente lasse ich mir mit einer weiteren Export-Funktion(Index):PChar zurück geben. Hierbei muss ich nur dafür sorgen, das ausreichend Speicher reserviert wird, sonst bekommt man nur ein Teil des String wieder zurück.

Quasi überträgt man nicht das Array komplett, sondern nur die einzelnen Elemente des Arrays.

Wenn du auf Applikationsseite die einzelen Elemente wieder in ein Array speicherst, dagegen spricht nix. Es ist halt nur nicht möglich das Array komplett per Parameter wieder zurück zubekommen. Zumindest nicht ohne Speichermanager.

Sorry, mit Beispielcode kann ich dir augenblicklich nicht dienen.

Muetze1 6. Dez 2006 08:21

Re: Dynamisches Array von DLL übergeben
 
Frage an gmc616: Warum gibt die DLL nicht einfach zurück, wieviele Einträge es in dem Array gibt und eine weitere Funktion gibt die Adresse des ersten Eintrags an. Dies würde der Applikation doch schon reichen, schliesslich sind alle Arrays im Speicher fortlaufend und somit kann sie sich mit einem grossen CopyMemory() oder Move() Befehl den kompletten Array Inhalt kopieren ohne über jedes einzelne Element zu laufen.

DP-Maintenance 6. Dez 2006 12:13

DP-Maintenance
 
Dieses Thema wurde von "Daniel" von "Programmieren allgemein" nach "Sonstige Fragen zu Delphi" verschoben.

gmc616 6. Dez 2006 13:07

Re: Dynamisches Array von DLL übergeben
 
Hallo Muetze1,

Das habe ich schon probiert.

Ich lade meine DLL dynamisch. Das Kopieren per CopyMemory funktioniert auch ohne Probleme.
Wenn Ich allerdings die DLL mit FreeLibrary wieder entlade, bekomme ich eine Schutzverletzung bei Schreiben(!) an Adresse xy.

Vlt. liegt es daran, dass ich mit Array of Records arbeite. Vlt. muß ich auch irdendwo wieder Speicher freigeben, wüsste aber nicht welchen.
Oder es liegt daran, das es ohne Speichermanager einfach nicht funktioniert.

Ich weiß es nicht. Daher die Krücke.

Es wäre allerdings ne feine Sache, wenn das so einfach mit CopyMemory funktioniert täte / tun würde.

:hi: gmc

Wormid 6. Dez 2006 14:02

Re: Dynamisches Array von DLL übergeben
 
Bekomme ich hier was nicht mit? :gruebel:

Man kann doch dynamische Arrays aus einer DLL zurückgeben...

Delphi-Quellcode:
library xyz;

uses
  ...

type
  TTestArray = array of ShortString;

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

exports
  GetTestArray;

end.
Delphi-Quellcode:
program test_xyz;

interface

type
  TTestArray = array of ShortString;

...
  var GetTestArray: function: TTestArray; stdcall;

implementation

procedure TestItOut;
var
  a: TTestArray;
  i: Integer;
  hDLL: THandle;
begin
  hDLL := LoadLibrary('xyz.dll');
  if hDLL <> 0 then
  begin
    GetTestArray := GetProcAddress(hDLL, 'GetTestArray');
    if GetTestArray <> nil then
    begin
      a := GetTestArray;
      ShowMessage(IntToStr(Length(a))); // Eine schicke "3" erscheint als Meldung
      for i := Low(a) to High(a) do
        ShowMessage(a[i]); // Hallo *click* Welt *click* ! *click*
      SetLength(a, 0);
      GetTestArray := nil;
    end;
    FreeLibrary(hDLL);
  end;
end;
*Edit: "Testprogramm" um dynamisches Einbinden der Funktion erweitert

Muetze1 6. Dez 2006 15:25

Re: Dynamisches Array von DLL übergeben
 
Zitat:

Zitat von Wormid
Bekomme ich hier was nicht mit? :gruebel:

Man kann doch dynamische Arrays aus einer DLL zurückgeben...

Nur wenn du ShareMem oder FastMM in beiden Projekten einbindest. (beides als erste Unit in beiden Projekten). Und genau diesen Fakt will er ja vermeiden.

Zitat:

Zitat von gmc616
Wenn Ich allerdings die DLL mit FreeLibrary wieder entlade, bekomme ich eine Schutzverletzung bei Schreiben(!) an Adresse xy.

Vlt. liegt es daran, dass ich mit Array of Records arbeite. Vlt. muß ich auch irdendwo wieder Speicher freigeben, wüsste aber nicht welchen.

Da das Array kopiert wird, sollte es keine Probleme geben. Es kann aber Probleme geben, wenn die Funktion der DLL so deklariert ist, das gesamte Array zurück zu geben anstatt einen Zeiger auf den Record (welcher dann mit der Adresse des ersten Records befüllt wird beim Aufruf).

Ansonsten Speicher des Array freigeben? Naja, SetLength(Array, 0); - aber eigentlich nicht unbedingt von nöten.

Ich werde die Tage selber mal ein Beispielprojekt dazu aufbauen und das ganze nochmal im Detail versuchen nach zu vollziehen.

TheMiller 6. Dez 2006 16:10

Re: Dynamisches Array von DLL übergeben
 
Hm...

hab mir dazu nochmal gedanken gemacht und getestet (hab mit Pointern noch nie was gemacht - lerne aber gerne dazu) und einiges rumprobiert.

hab zum Testen die Funktion myArray, die mir den zeiger zurückgeben soll. Eine weitere Funktion empfängt einen Zeiger und weist dementsprechend den Wert aus. Mein Programm fragt also nach einem Zeiger, empfängt ihn, sendet ihn an Funktion 2 und empfängt den String. Vom Prinzip her garnicht mal so übel (hoffe ich).

Doch ich denke, mein erster Fehler liegt schon in der ersten Funktion, da ich nicht weiß, welchen Rückgabewert ich benutzen muss. Ich denke, da Integer und Pointer so ziemlich gleich sind, kann ich den Pointer in einen Integer packen, gibt aber bei der Rückgabe im Programm nur Schrott aus. Weis nicht, wie ich auf einen Pointer zugreifen kann, um dessen Wert zu bekommen.:

Delphi-Quellcode:
function myArray: integer;
var
  testarr: array of byte;
  zeiger: ^integer;
begin
  SetLength(testarr, 2);
  randomize;
  testarr[0]:=random(9999);
  testarr[1]:=32;
  zeiger:=@testarr[0];
  result:=Integer(zeiger);
end;
Danke nochmal!

himitsu 6. Dez 2006 16:20

Re: Dynamisches Array von DLL übergeben
 
Da die Array-Variable selber ein Pointer ist, kannst du auch direkt casten:
('s kommt aber darauf an, wie du es drüben verwenden willst)
Delphi-Quellcode:
function myArray: integer;
var
  testarr: array of byte;
begin
  SetLength(testarr, 2);
  randomize;
  testarr[0]:=random(9999);
  testarr[1]:=32;
  result:=Integer(testarr);
end;
oder etwas schöner ... du gibst ja einen Zeiger zurück :zwinker:
Delphi-Quellcode:
function myArray: pointer;
var
  testarr: array of byte;
begin
  SetLength(testarr, 2);
  randomize;
  testarr[0]:=random(9999);
  testarr[1]:=32;
  result:=pointer(testarr);
end;
und zurück dann z.B. so:
type Ttestarr = array of byte;

Ttestarr(myArray)

PS: randomize; nicht ständig aufrufen!

PSS:
SetLength(Arr, 0);
dat is schneller, da es direkt ClearArray aufruft ._.
Arr := nil;

Wormid 6. Dez 2006 16:45

Re: Dynamisches Array von DLL übergeben
 
Also, dann nochmal mein Beispiel von vorhin, mit Pointern...

Bei mir ist das kompilierbar und läuft ohne Exceptions durch. Ein Speichermanager muss weder in der DLL
noch in der Anwendung eingebunden werden. (Meine erste Version scheint nämlich nur bei statischem Linken
der Testfunktion einwandfrei zu funktionieren.)

Einmal die DLL...
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.
Und hier die Unit1 von dem Testprojekt...
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

type
  TTestArray = array of ShortString;
  PTestArray = ^TTestArray;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  hDLL: Cardinal;
  GetTestArray: function: PTestArray; stdcall;

procedure TForm1.Button1Click(Sender: TObject);
var
  a: TTestArray;
  i: Integer;
begin
  hDLL := LoadLibrary(PChar('Project1.dll'));
  if hDLL <> 0 then
  begin
    GetTestArray := GetProcAddress(hDLL, 'GetTestArray');
    if GetTestArray <> nil then
    begin
      a := TTestArray(GetTestArray);
      ShowMessage(IntToStr(Length(a))); // Eine schicke "3" erscheint als Meldung
      for i := Low(a) to High(a) do
        ShowMessage(a[i]); // Hallo *click* Welt *click* ! *click*
      a := nil;
    end;
    FreeLibrary(hDLL);
  end;
end;

end.

TheMiller 6. Dez 2006 16:51

Re: Dynamisches Array von DLL übergeben
 
Danke für die Antworten. Habe mich aber erstmal für meine / Himitsu's Methode entschieden, da sie mir besser in mein noch auf Papier befindliches Konzept passt.

Vielen Dank - hat mir viel geholfen und hab wieder was gelernt!

ste_ett 6. Dez 2006 16:54

Re: Dynamisches Array von DLL übergeben
 
Zitat:

Zitat von Wormid
Also, dann nochmal mein Beispiel von vorhin, mit Pointern...

Bei mir ist das kompilierbar und läuft ohne Exceptions durch. Ein Speichermanager muss weder in der DLL
noch in der Anwendung eingebunden werden. (Meine erste Version scheint nämlich nur bei statischem Linken
der Testfunktion einwandfrei zu funktionieren.)

Das ist leider eine falsche Annahme. :)

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.

Besser ist es, den Array als Parameter zu übergeben, in der DLL Speicher für den Arra zu allokieren und im Programm diesen Speicher wieder freizugeben, so gehen keine Informationen verloren. :)

Muetze1 6. Dez 2006 17:32

Re: Dynamisches Array von DLL übergeben
 
Wo ich hier gerade noch die neuen Beiträge sehe: Ich bezog mich auf ein Array mit Elemente die keine AnsiStrings beinhalten. Diese wären in dem Record/Array auch nur Referenzen und daher nicht mit dem Move()/CopyMemory kopierbar. Dazu kommt freilich noch, dass deren String-Inhalt vom Speichermanager der DLL alloziiert wurde und daher macht es dies noch komplizierter. Mein Vorschlag klappt nur unter den eben genannten Voraussetzungen und daher kann ich bei einem Array Of String oder Array Of Record mit AnsiStrings nicht helfen.

himitsu 6. Dez 2006 18:55

Re: Dynamisches Array von DLL übergeben
 
Zitat:

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:

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. :roll:

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.

himitsu 6. Dez 2006 19:52

Re: Dynamisches Array von DLL übergeben
 
So, hier noch 'ne Variante wo die String/Arrrayfunktionen genutzt werden, es ist also "keine" Kenntnis über den inneren Aufbau nötig.

Dafür ist aber beim Aufrufen der Funktion etwas mehr von nöten, da hierfür natürlich die Funktionen der Exe verwendet werden müssen.
Wobei man natürlich auch alle nötigen String-/Arrayfunktionen bei der DLL regiestrieren kann und dann diese vorn dort aus aufruft, wobei dann der Code in der EXE in etwa dem vorherigen Beispiel entspricht.
Delphi-Quellcode:
Var myStringArray, Temp: TStringArray;
  i: Integer;

Temp := Explode(S, Sep);
SetLength(myStringArray, Length(Temp));
For i := 0 to High(Temp) do Begin
  myStringArray[i] := Temp[i];
  UniqueString(myStringArray[i]);
End;
FreeArray(Temp);




// in der DLL

Procedure FreeArray(Var a: TStringArray);
  Begin
    A := nil;
  End;

Function Explode(S, Sep: String): TStringArray;
  ...

Eichhoernchen 6. Dez 2006 20:10

Re: Dynamisches Array von DLL übergeben
 
Ich hab auch mal was ausprobiert und es klappt auch:

Delphi-Quellcode:

//Programm, dass die DLL benutzt

type
  TArray = array of string;

function GimmeAnArray(str: string): TArray;
type
  TMeineDllFunk = function (str: PChar): pointer;
  PArray = ^TArray;
var
  hinst: cardinal;
  func: TMeineDllFunk;
  arrlen, i: integer;
  arr: PArray;
begin
  hinst := LoadLibrary('arraydll.dll');
  try
    if hinst > 0 then
    begin
      @func := GetProcAddress(hinst, 'GimmeAnArray');
      if @func <> NIL then
      begin
        arr := func(PChar(str));
        setlength(result, length(arr^));
        for i := 0 to high(result) do
        begin
          result[i] := Arr^[i];
          UniqueString(result[i]);
        end;
        arr := nil;
      end;
    end;
  except
    FreeLibrary(hinst);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
  arr: TArray;
begin
  arr := GimmeAnArray('HUHU');
  for i := 0 to high(arr) do
    Memo1.Lines.Add(arr[i])
end;
Delphi-Quellcode:
//Die DLL

var
  arr: array of string;


function GimmeAnArray(str: PChar): integer;
var
  i: integer;
  data: string;
begin
  data := str;
  setlength(arr, length(str));
  for i := 0 to high(arr) do
    arr[i] := data[i+1];
  result := Integer(@arr);
end;

exports
  GimmeAnArray;

begin
end.

Ich weiß jetzt nicht, welche Version von den geposteten hier besser ist, diese Funktioniert auf jeden Fall mit Pointern.

TheMiller 6. Dez 2006 20:21

Re: Dynamisches Array von DLL übergeben
 
So, integer-Arrays etc kann ich jetzt super übergeben. Doch mit Strings habe ich meine Probleme. Mache es so, wie mit den Integern nur frage ich erst nach der Länge der Strings:

Delphi-Quellcode:
function createArray: pointer; stdcall;
var
  StringArray: Array of String;
begin
  SetLength(StringArray, 2);
  StringArray[0]:='11';
  StringArray[1]:='32';
  result:=pointer(StringArray);
end;

function getElementByIndex(Buffer: PChar; BufferLen, Index: Integer; p: Pointer;): Integer; stdcall;
var
  StringArray: TStringArray;
  Element: String;
begin
  StringArray:=TStringArray(p);
  Element:=IntArray[index];

  if Assigned(Buffer) then
    StrLCopy(Buffer, PChar(Element), BufferLen);

  result:=Length(High)
  pointer(StringArray):=nil;
end;
In der Hauptanwendung sieht der Code so aus:

Delphi-Quellcode:
type
  TStringArray = array of String;

...

procedure TForm2.GetArray;
var
  len: Integer;
  Buffer: PChar;
  zeiger: Pointer;
  StringArray: TStringArray;
  s: String;
begin
  zeiger:=TStringArray(createArray);
  StringArray:=zeiger;

  len:=getArrayElement(nil, 0, 1, zeiger);
  try
    GetMem(Buffer, len+1);
    len:=getArrayElement(Buffer, len+1, 1, zeiger);
    s:=String(Buffer);
  finally
    FreeMem(Buffer);
  end;

  ShowMessage(s);
end;
Das Resultat ist einfach ein leerer String. Aber keine A/V - Auch nicht beim beenden des Programms...

Danke im Voraus

TheMiller 7. Dez 2006 13:18

Re: Dynamisches Array von DLL übergeben
 
Hallo,

jetzt hab ich noch ein kleines Problem. Es funktioniert soweit alles. Nur jetzt kommt beim Auselen der Strings aus dem Array eine A/V, aber NUR(!) dann, wenn ich den Index mit der Schleifenvariablen definiere. Trage ich 0, 1 etc ein klappt das wunderbar. Es liegt aber definitiv nicht daran, dass die Variable höher zählt, als das Array groß ist. Das ist nicht der Fall. Hier nochmal mein Code:

Delphi-Quellcode:
  Data:=TStringArray(createArray);
  zeiger:=Data;

  for i:=0 to getArrayCount(zeiger) do
  begin
    len:=getElement(Buffer, i, 0, zeiger);
    try
      GetMem(Buffer, len+1);
      len:=getElement(Buffer, i, len+1, zeiger);
      s:=String(Buffer);
    finally
      FreeMem(Buffer);
      Buffer:=nil;
      len:=0;
    end;
    ShowMessage(s);
  end;
Alle Arrays wurden in der DLL mit

Delphi-Quellcode:
myArray(zeiger):=nil;
Freigegeben.

Danke nochmals!

TheMiller 7. Dez 2006 17:34

Re: Dynamisches Array von DLL übergeben
 
Habe ich hier was nicht richtig freigegeben? In einem neuen Programm geht's nämlich. Er häbgt sich beim 3 Auslesen aus einer INI was auf. Macht er ohne den Aufruf der Array-DLL-Funktionen nicht. Was kann dafür der Grund sein?

Sehr merkwürdig!

TheMiller 8. Dez 2006 18:32

Re: Dynamisches Array von DLL übergeben
 
Also hier die Lösung (habs ganz alleine rausgefunden ;-) )

Delphi-Quellcode:
Data:=TStringArray(createArray);
  zeiger:=Data;

  for i:=0 to getArrayCount(zeiger) do
  begin
    len:=getElement(0, i, 0, zeiger); //hatte vorher "Buffer" im 1. Parameter stehen. Ist falsch!
    try
      GetMem(Buffer, len+1);
      len:=getElement(Buffer, i, len+1, zeiger);
      s:=String(Buffer);
    finally
      FreeMem(Buffer);
      Buffer:=nil;
      len:=0;
    end;
    ShowMessage(s);
  end;
Bitteschön

und

Dankeschön!


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:55 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz