![]() |
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:
Und hier die Unit1 von dem Testprojekt...
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.
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. |
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! |
Re: Dynamisches Array von DLL übergeben
Zitat:
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. :) |
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.
|
Re: Dynamisches Array von DLL übergeben
Zitat:
Zitat:
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:
Ich hoff i hab's soweit richtig ... war jetzt nur aus'm Kopf und ohne Delphi, also nicht getestet.
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; 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:
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.
SetExtGetMem(@GetMemory);
... myStringArray := Explode(S, Sep); |
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; ... |
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. |
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:
In der Hauptanwendung sieht der Code so aus:
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;
Delphi-Quellcode:
Das Resultat ist einfach ein leerer String. Aber keine A/V - Auch nicht beim beenden des Programms...
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; Danke im Voraus |
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:
Alle Arrays wurden in der DLL mit
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;
Delphi-Quellcode:
Freigegeben.
myArray(zeiger):=nil;
Danke nochmals! |
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! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:47 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