![]() |
Übergabe einer Klasse von EXE an DLL
Hallo zusammen,
ich habe schon diverse Beiträge zu dem Thema gefunden, aber die Angaben sind widersprüchlich. Ich habe folgende stark vereinfachte Klassendefinition
Delphi-Quellcode:
Im angedachten Fall soll
type
TMesswert = class(TObject) Belastung : Real; Strom : Real; end; TMesswertListe = class( TObjectList<TMesswert> ) public constructor Create( OwnsObjects: Boolean = true ); end; TAnalyse = class(TObject) private FNr : Integer; FStatus : Integer; // In Wirklichkeit Enum FTitel : String; FTestunit : String; FMesswerte : TMesswertList; public property FNr : Integer read Nr write Nr ; property FTitel : String read Titel write Titel ; property FTestunit : String read Testunit write Testunit ; constructor Create; destructor Destroy; override; end; TAnalyseList = class(TObjectList<TAnalyse> ) private function Compare( const L,R: TAnalyse) : Integer; public constructor Create( OwnsObjects: Boolean = true ); end; TBatch = class(TObject) private FNr : Integer; FAnalysen : TAnalyseList; public property FNr : Integer read Nr write Nr ; constructor Create; destructor Destroy; override; end;
Es bestehen folgende Voraussetzungen
Mein Problem ist nur die Frage, wie ich die Klasse korrekt an die DLL übergeben muss damit beide Seiten darin arbeiten können. Gibt es ein Möglichkeit, so was zu realisieren? Mit Klassen fühle ich mich noch unsicher und mit Interfaces habe ich noch nie gearbeitet. Von daher wäre ich für eine konkrete Antwort, an liebsten mit Beispiel, sehr dankbar. Grüße Gerd |
AW: Übergabe einer Klasse von EXE an DLL
Entweder du arbeitest mit Run-Time-Packages, auf welche beide Seiten zugreifen, da Du dann auch einen gemeinsamen Memory-Manger nutzt. Dieses wäre die Voraussetzung, um Klassen über Prozessgrenzen hinweg zu nutzen.
Oder, Du stellst auf Interfaces um, diese kannst Du dann ohne größere Probleme zwischen beiden Seiten nutzen und übergeben. ...:cat:... |
AW: Übergabe einer Klasse von EXE an DLL
Wie Sakura schon sagte, ist ein Austausch von Objekt-Instanzen so nicht möglich. Aber, neben der Sache mit Interfaces, wäre auch ein anderer Ansatz denkbar.
Sowie ich das verstehe, ist der Zweck der DLL, die Liste der Analysen nacheinander durch zu ackern und die entsprechenden Tests auszuführen und je nach Ergebnis für jede Analyse einen entsprechenden Status zu setzen. Wenn die DLL jetzt nicht grad noch von einer anderen Anwendung benutz werden soll, würd ich diese über die Klinge springen lassen und statt dessen die Analyse in einen eigenen Thread auslagern, sodas dieser quasi im Hintegergrund die Analyseliste immer wieder durcharbeiten kann. Wenn eine Analyse mit dem entsprechenden Status abegschlossen worden ist, kann der Thread das Hauptprogramm benachrichtigen. Genauso kann das Hauptprogramm neue Analysen hinzufügen. Das ganze ist jetzt mehr eine Idee/Denkanstoss, die ich hier mal so geschrieben hab. :) |
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
braucht man sowieso einen extra Thread. Dann kann man das immer noch in eine DLL packen, zuerst sollte aber das "Problem" gelöst werden. |
AW: Übergabe einer Klasse von EXE an DLL
Oder eventuell in eine komplett eigene Anwendung auslagern. Die Daten in einem gemeinsamen Format (JSON, XML, binär, ...) austauschen. Dann können die Prozesse komplett autonom arbeiten.
...:cat:... |
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Über die DLL wollen wir aber den Messprozess weitgehend von der EXE kapseln. In der DLL soll er dann in einem eigenen Thread laufen. Ein Kollege hat mal folgendes ausprobiert: Hauptprogramm:
Delphi-Quellcode:
Und die DLL
uses
..., clBatch; type procedure ShowTestForm(aApplication: TApplication; aAnalyse: TAnalyse); stdcall; external 'DelphiDll.dll'; implementation ... procedure TfoMain.btnShowDelphiDllClick(Sender: TObject); var aAnalyse: TAnalyse; begin aAnalyse := GetCurrentAnalyse; ShowTestForm(Application, aAnalyse); end;
Delphi-Quellcode:
und das funktioniert.
library DelphiDll;
{ Important note about DLL memory management: ShareMem must be the ...} uses ShareMem, clBatch, ...; {$R *.res} exports ShowTestForm; begin end. unit uFormTest; interface uses ... type TFormTest = class(TForm) EditAnalyse: TEdit; Label1: TLabel; btnAssFilled: TButton; btnAssInjected: TButton; procedure btnAssFilledClick(Sender: TObject); procedure btnAssInjectedClick(Sender: TObject); private { Private declarations } FAnalyse: TAnaylse; procedure SetAnalyse(aAnalyse: TAnalyse); public { Public declarations } constructor Create(AOwner: TComponent); class procedure ShowForm(aApplication: TApplication; aAnalyse: TAnalyse); end; implementation {$R *.dfm} uses ...; var dllApplication: TApplication=nil; FormTest: TFormTest=nil; procedure TFormTest.btnAssFilledClick(Sender: TObject); begin if not Assigned(FAnalyse) then exit; FAnalyse.Status := assFilled; end; procedure TFormTest.btnAssInjectedClick(Sender: TObject); begin if not Assigned(FAnalyse) then exit; FAnalyse.Status := assInjected; end; constructor TFormTest.Create(AOwner: TComponent); begin inherited Create(AOwner); FAnalyse:= nil; end; procedure TFormTest.SetSample(aAnalyse: TAnalyse); begin FAnalyse:= aAnalyse; end; class procedure TFormTest.ShowForm(aApplication: TApplication; aAnalyse: TAnalyse); begin if not Assigned(dllApplication) then begin dllApplication:= Application; end; Application := aApplication; if not Assigned(FormTest) then FormTest := TFormTest.Create(Application); FormTest.FAnalyse := aAnalyse; if not Assigned(aAnalyse) then FormTest.EditAnalyse.Text := '-' else ;// EditAnalyse.Text := aAnalyse.name; { TODO : Mit der auskommentierten Zeile gibt es im folgenden eine Exception "Invalid pointer operation ..." was irgendetwas mit strings zu tun hat. Richtig angezeigt wird der Name dennoch. Die Ursache ist zu ergründen. } FormTest.Show; end; initialization begin dllApplication := nil; end; finalization begin if Assigned(dllApplication) then Application := dllApplication; end; end. In der DLL wird ein Formular geöffnet und darin kann man den Status der Analyse ändern. Fragt man in der EXE den Status ab, wird dort der korrekte (geänderte) Status angezeigt. Von daher sieht es doch ganz einfach aus? |
AW: Übergabe einer Klasse von EXE an DLL
Das wird so nicht funktionieren. Kapselt als erstes Euere Analyse sauber in einen Thread.
Das dann in eine DLL zu packen ist in meinen Augen der 2. Schritt.
Delphi-Quellcode:
Das fliegt Euch früher oder später um die Ohren ohne Packages. Da das TApplication und TAnalyse in der EXE und DLL unterschiedlich sind. (verschiedene Vmt's etc).....
class procedure TFormTest.ShowForm(aApplication: TApplication; aAnalyse: TAnalyse);
Entweder Packages, Interfaces oder eine gute alte c-schnittstelle |
AW: Übergabe einer Klasse von EXE an DLL
Alternativen dazu wären natürlich die "Old-School" Methode mit Records, Zeigern und Zeigerketten. Die kann man ohne Probleme zwischen Exe und DLL austauschen :)
Bsp.: (He..das is nur so ungefähr) :
Delphi-Quellcode:
TYPE
PMesswert = ^TMesswert; TMesswert = Record Belastung, Strom : Real; Prev,Next : PMesswert; end; PAnalyse = ^TAnalyse; TAnalyse = Record Nr,Status : Integer; Titel,TestUnit : String; Messwerte : PMesswerte; //Zeiger auf den Anfang der Zeigerkette; end; |
AW: Übergabe einer Klasse von EXE an DLL
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Zitat:
Ich habe jetzt mal das Beispiel von meinem Kollegen auf das minimiert, was man für einen ersten Test braucht. Auch wenn die Aussage im Raum steht, dass uns das um die Ohren fliegt... Wo ist das Problem? Ein anderer Programmierer hat dazu gemein, dass eine Klasse innerhalb Delphi auch nur ein Pointer ist und wenn beide Seiten über den Aufbau genau das gleiche wissen, würden beide auch gleich mit den Daten umgehen. Ich kann sehr gut damit leben, wenn in der DLL nur die Daten zur Verfügung stehen und eventuelle Methoden tabu sind. Man muss vielleicht noch dazu sagen, dass die EXE nur noch lesend auf die Messwert-Liste zugreift. Ich habe mal das lauffähige Porjekt als ZIP angehängt. Ich wäre echt dankbar, wenn man einen Weg finden würde, das Ganze sicher zum Laufen zu bringen. Oder zu zeigen, wo die Fallstricke im Betrieb sind In dem Projekt kann man
Auch wenn ihr jetzt denkt "Wenn du uns nicht glaubst, dann lass es doch bleiben" Das ist es nicht. Aber vielleicht finde ich den, der mir sagt, so und so würde es gehen :-) Es ist immer schwer von etwas abzulassen, wenn es irgendwie schon funktioniert. Gleichzeitig weiß ich aber, dass das Zufall sein kann und sich ganz schnell ändern kann. |
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Edit: Wobei .. wenn ich grade nochmal so drüber nachdenke, dann könnte es diverse statische Speicherbereiche bzw. Singletons geben, die dann zwischen DLL und EXE nicht geshared werden würden. Das kann auch Probleme machen. |
AW: Übergabe einer Klasse von EXE an DLL
Deshalb besser Interfaces benutzen.
|
AW: Übergabe einer Klasse von EXE an DLL
Mmh, wie schon weiter oben gesagt, habe ich mich mit Interfaces noch nicht beschäftigt.
Ich habs mir heute mal angeschaut, verstehe aber nicht ganz wieso es mir im Fall Delphi zu Delphi helfen soll. Wie würden mein Projekt sich denn Ändern, wenn es per Interfaces laufen würde? |
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Delphi-Quellcode:
, sondern von
TObject
Delphi-Quellcode:
und
TInterfacedObject
Delphi-Quellcode:
ab.
IMyInterface
|
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Delphi-Quellcode:
betroffen?
property Power: Realread FPowerwrite FPower;
Oder ein
Delphi-Quellcode:
TMessValue = class(TObject)
Load: Real; Power: Real; end; |
AW: Übergabe einer Klasse von EXE an DLL
Interfaces können leider ausschließlich Methoden besitzen. Zugriff auf Felder müsstest du dann alle über Getter/Setter kapseln. Ich würde allerdings mal behaupten, dass wenn du in deiner Klasse ausschließlich triviale Datentypen hast (String und Arrays sind davon ausgenommen) und die Klasse zudem keine Seiteneffekte in der VCL/RTL auslöst, solltest du relativ sicher sein. Höchstens irgendwelche RTTI Geschichten könnten dann noch Probleme bereiten.
|
AW: Übergabe einer Klasse von EXE an DLL
Es gibt viele Stolpersteine, wenn man Klassen so über DLL-Grenzen hinaus benutzt. Das fängt schon bei einem simplen is bzw. as an, das nicht funktioniert. Das wird aber teilweise auch in den Quelltexten der RTL und VCL benutzt. Deshalb erlebt man da durchaus die eine oder andere Überraschung...
Die Umstellung auf Interfaces lohnt sich. Damit ist man zukunftssicher unterwegs und muss nicht mit Workarounds anfangen, wenn es Probleme gibt. Zumal die Fehlersuche im Zweifelsfall enorm Zeit kostet. Dazu kommt, dass man die Schnittstelle zur DLL auch bei Erweiterungen nicht ändern muss, sondern auf verschiedene Versionen eines Interfaces prüfen kann, so also zwischen verschiedenen Versionen der DLL und des Hostprogramms kompatibel ist. Wenn man das denn möchte. Vor allen braucht man sich aber nicht darum zu kümmern, dass der Speicher der übergebenen Objekte nicht zu früh oder zu spät freigegeben wird usw., da das automatisch passiert, wenn die Referenzen z.B. auf nil gesetzt werden. Gerade bei mehreren beteiligten Modulen ist das sehr hilfreich. Für die generischen Listen usw. haben wir z.B. Container mit Interface-Anbindung erstellt. |
AW: Übergabe einer Klasse von EXE an DLL
Ich häng mich jetzt einfach mal an. Hat das ganze schon jemand mal mit den "Advanced Records" probiert ?
|
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Zitat:
Das wäre was anderes, wenn man auch die Intelligenz, den Prüfablauf zu generieren, in die DLL verlegen würde was wir aber vermieden haben um einen eindeutigen Master of the Class zu haben. Eine Einschränkung mit der wir leben können, wenn dadurch das Klassenhandling sicher ist. |
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
die Auslagerung von Funktionen mit Objekten in ein paar eigenständige DLLs hatte ich auch schon mal vor gehabt, darum würde mich interessieren wie sowas ausschauen könnte. Könnte jemand ein kurzes Beispiel posten wie sowas ausschaut? lg, jus |
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Meiner Meinung nach ist Euer Ansatz falsch. Wenn eine Dll so abhängig ist von der EXE, sprich gleicher Compiler Source etc. Dann schafft ihr nur zusätzliche Probleme. Ich würde empfehlen im ersten Schritt das Threadsafe zu machen. Erst dann anschauen was man sinnvoll und unabhängig in eine DLL verschieben kann. Ich sehe sonst keinerlei Sinn in einer DLL. Am einfachsten wäre eigentlich das benutzen von Packages in der Konstellation. Dafür sind die nämlich gemacht. |
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Zitat:
|
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
lg, jus |
AW: Übergabe einer Klasse von EXE an DLL
Eines der Probleme die ich in der Verwendung von Klassen in Exe und Dll auch schon erlebt habe:
Da die EXE und DLL komplett unabhängig von einander compiliert werden, kann es passieren das der Linker, (Stichwort Smart Linking) auf die Idee kommt Teile der Klasse, anders anzuordnen oder sogar wegzulassen wenn Sie nicht benutzt oder anders benutzt werden. Ihr verlasst Euch darauf das das Ergebnis von Compile und Link auf beiden Seiten immer das selbe ist. Kann funktionieren muss aber nicht. Das schöne daran im Debug Modus wird es zu 99.9 % immer funktionieren, im Release........ (Viel Spass beim suchen) Also meiner Meinung nach:
|
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Ansonsten scheint bisher alles zu klappen. Egal ob wir im Debugmode kompilieren oder in Bamboo als Release. Eigentlich ist es eine tolle Sache und ich habe auch noch einen Programmierer getroffen, die das schon länger so praktizieren. Anscheinend problemlos. Und doch muss ich sagen, dass mir eure Komentare und viele Funde in div. Foren Kopfzerbrechen bereiten. Ich bin nicht 100% sicher, dass es nachher im Feld unter allen Bedingungen sicher funktioniert. Zitat:
Grüße Gerd |
AW: Übergabe einer Klasse von EXE an DLL
OK, mal schnell heruntergeschludert (kann also noch Denkfehler enthalten, funktionierte aber bei einem schnellen Test): zunächst ein Interface mit einer Property nebst Getter und Setter und einer Methode.
Delphi-Quellcode:
Dieses Interface wird sowohl in der DLL als in der Exe benutzt. Jetzt zur DLL, Klassenunit:
unit TestIntf;
interface uses System.Classes; type ITestIntf = interface ['{AE7A35E3-5DB3-4DEB-A817-E452DD62301C}'] function GetItems: TStrings; stdcall; procedure SetItems(const Value: TStrings); stdcall; procedure ShowContents; stdcall; property Items: TStrings read GetItems write SetItems; end; implementation end.
Delphi-Quellcode:
Das ist also eine minimale Klasse, die das Interface imlementiert. Zu beachten ist auch die Funktion GetTest, diese wird in der Hauptunit der DLL exportiert.
unit DLLClass;
interface uses TestIntf, System.Classes; type TTest = class(TInterfacedObject, ITestIntf) strict private FItems: TStrings; public function GetItems: TStrings; stdcall; procedure SetItems(const Value: TStrings); stdcall; procedure ShowContents; stdcall; property Items: TStrings read GetItems write SetItems; end; function GetTest: ITestIntf; stdcall; implementation uses Vcl.Dialogs; function GetTest: ITestIntf; stdcall; begin Result := TTest.Create; end; { TTest } function TTest.GetItems: TStrings; begin Result := FItems; end; procedure TTest.SetItems(const Value: TStrings); begin FItems := Value; end; procedure TTest.ShowContents; var s: string; begin if Assigned(FItems) then s := FItems.Text else s := '< Keine Items zugewiesen >'; ShowMessage(s); end; end.
Delphi-Quellcode:
In der Exe habe ich dann diese DLL einfach statisch gebunden:
library IntfDLL;
uses DLLClass in 'DLLClass.pas'; {R *.res} exports GetTest; begin end.
Delphi-Quellcode:
Und nur der Vollständigkeit halber noch die *.dpr, da steht auch keine Magic drin:
unit ExeMain;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, TestIntf, Vcl.StdCtrls; type TfrmDLLTestMain = class(TForm) btnCallIntf: TButton; procedure btnCallIntfClick(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var frmDLLTestMain: TfrmDLLTestMain; implementation {$R *.dfm} function GetTest: ITestIntf; stdcall; external 'IntfDLL.dll' name 'GetTest'; procedure TfrmDLLTestMain.btnCallIntfClick(Sender: TObject); var List: TStringList; Test: ITestIntf; begin Test := GetTest; List := TStringList.Create; try List.Add('Das'); List.Add('ist'); List.Add('das'); List.Add('Haus'); List.Add('vom'); List.Add('Nikolaus'); // Einmal vor der Zuweisung Test.ShowContents; Test.Items := List; // Und einmal nachher Test.ShowContents; finally List.Free; end; end; end.
Delphi-Quellcode:
program IntfTest;
uses Vcl.Forms, ExeMain in 'ExeMain.pas' {frmDLLTestMain}; {$R *.res} begin ReportMemoryLeaksOnShutdown := true; Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TfrmDLLTestMain, frmDLLTestMain); Application.Run; end. |
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Mal schauen, was das für unsere Struktur bedeutet |
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Das ist kein gutes Design. Du mixt hier Interfaces und Implementation Durch
Delphi-Quellcode:
bist Du an einen Compiler gebunden.
property Items: TStrings read GetItems write SetItems;
Ein Interface sollte nur solche benutzen.
Delphi-Quellcode:
Hier noch eine mögliche implementierung einer Klasse dazu:
unit myInterfaces;
interface uses System.Classes; type // Wenn wir nur über Window sprechen ist Dies ein Ansatz: IStringList = interface ['{143A95EE-EEEA-4F7F-97CC-7986EBAC17A5}'] function AddString(const Value: WideString): Integer; stdcall; function GetCount: Integer; stdcall; function GetItems(Index: Integer): WideString; stdcall; procedure SetItems(Index: Integer; const Value: WideString); stdcall; property Count: Integer read GetCount; property Items[Index: Integer]: WideString read GetItems write SetItems; end; // Für non Windows müssen wir auf PlainData ztrückgreifen ICharBufferInterface = interface ['{D6CAF8DE-7792-4162-B472-E9F0A2410201}'] procedure SetBuffer(const Buffer: PWideChar; Len : integer); stdcall; procedure GetBuffer(const Buffer: PWideChar; Len : integer); stdcall; function BufferLen : integer; end; IBufferList = interface ['{6FCA6674-3BE2-4D02-A078-F3142B1A41C1}'] function GetCount: Integer; stdcall; function GetItems(Index: Integer): ICharBufferInterface; stdcall; procedure SetItems(Index: Integer; Value: ICharBufferInterface); stdcall; property Count: Integer read GetCount; property Items[Index: Integer]: ICharBufferInterface read GetItems write SetItems; function AddItem: ICharBufferInterface; stdcall; end; implementation end.
Delphi-Quellcode:
unit myImplementation;
interface uses System.Classes, myInterfaces; type TMyWideStringListImpl = class(TInterfaceList, IStringList) private fList : TStringList; function checkIndex(index : integer) : boolean; inline; private // From IStringList function AddString(const Value: WideString): Integer; stdcall; function GetCount: Integer; stdcall; function GetItems(Index: Integer): WideString; stdcall; procedure SetItems(Index: Integer; const Value: WideString); stdcall; public constructor Create; destructor Destroy; override; end; implementation function TMyWideStringListImpl.AddString(const Value: WideString): Integer; begin result := flist.Add(Value); end; function TMyWideStringListImpl.GetCount: Integer; begin result := fList.Count; end; function TMyWideStringListImpl.GetItems(Index: Integer): WideString; begin if checkindex(index) then result := Flist[Index] else result := ''; end; procedure TMyWideStringListImpl.SetItems(Index: Integer; const Value: WideString); begin Flist[Index] := Value; end; constructor TMyWideStringListImpl.Create; begin inherited; fList := TStringList.create; end; destructor TMyWideStringListImpl.Destroy; begin fList.free; inherited; end; function TMyWideStringListImpl.checkIndex(index: integer): boolean; begin result := (index >= 0) and (index<Flist.count); end; end. |
AW: Übergabe einer Klasse von EXE an DLL
Ich habe mir mal die Zeit genommen das so aufzubereiten wie ich es für richtig halte.
es geht mir darum zu zeigen wie die Interfaces meiner Meinung nach aussehen sollten. Zur vereinfachung habe ich mal 2 Deiner Klassen als Basis genommen. Die Klasse Tmesswert habe ich um einen Info String erweitert. Mit diesem Ansatz sind im NormalFall so gut wie keine Änderungen in Deinen konkreten Klassen notwendig und sind komplett Compilerunabhängig. Die Dll kann also auch mit einem anderen Compiler erstellt werden ohne das Probleme zu erwarten sind.
Delphi-Quellcode:
Als nächstes die Interfaces dazu:
unit Analyse.Defaults;
interface uses classes, Generics.collections; // Hier nur zur verdeutlichung type TMesswert = class(TObject) Belastung : Real; Strom : Real; Info : String; end; TMesswertListe = class( TObjectList<TMesswert> ) end; implementation end.
Delphi-Quellcode:
Hier die Implementierung
unit Analyse.Interfaces;
interface type IMesswert = interface ['{CAD5EAF6-D0DE-4C2A-A955-EEDE805B09F4}'] function GetBelastung: Double; stdcall; function GetInfo: WideString; stdcall; function GetStrom: Double; stdcall; procedure SetBelastung(const Value: Double); stdcall; procedure SetInfo(const Value: WideString); stdcall; procedure SetStrom(const Value: Double); stdcall; property Belastung: Double read GetBelastung write SetBelastung; property Info: WideString read GetInfo write SetInfo; // WideString wird verwendet weil da Windows das Speicherhandling übernimmt property Strom: Double read GetStrom write SetStrom; end; // Hier kommt alles rein was der Konsument können muss IMesswertList = interface ['{A8F39543-4F57-49EB-99B8-78DD4DBCA4B9}'] // Wir wollen wissen wieviele Einträge es gibt... function GetCount: Integer; stdcall; // Nur LeseZugriff auf die Items function GetItem( index : Integer) : IMesswert; stdcall; // Abfragen eines Index function GetItemIndex(item : IMesswert) : integer; stdcall; // Neuen Eintrag anhängen function AddItem : IMesswert; stdcall; end; implementation end.
Delphi-Quellcode:
Und nun zur Benutzung
unit Analyse.Implementations;
interface uses System.sysutils, System.classes, Analyse.Interfaces, Analyse.Defaults; // Hier definieren wir 2 Wrapper Kalssen für die Interfaces type TIMesswert = class(TInterfacedObject, IMesswert) private FMesswert : TMesswert; function GetBelastung: Double; stdcall; function GetInfo: WideString; stdcall; function GetStrom: Double; stdcall; procedure SetBelastung(const Value: Double); stdcall; procedure SetInfo(const Value: WideString); stdcall; procedure SetStrom(const Value: Double); stdcall; protected function getMesswert : TMesswert; public constructor Create(aMesswert : TMesswert); destructor Destroy; override; end; TIMesswertListWrapper = class(TInterfacedObject, IMesswertList) private Flist : TMesswertListe; function AddItem: IMesswert; stdcall; function GetCount: Integer; stdcall; function GetItem(index : Integer): IMesswert; stdcall; function GetItemIndex( item : IMesswert): integer; stdcall; public constructor Create(const aList : TMesswertListe ); destructor Destroy; override; end; implementation function TIMesswert.GetBelastung: Double; begin Result := FMesswert.Belastung; end; function TIMesswert.GetStrom: Double; begin Result := FMesswert.Strom; end; procedure TIMesswert.SetBelastung(const Value: Double); begin Fmesswert.Belastung := Value; end; procedure TIMesswert.SetStrom(const Value: Double); begin FMesswert.Strom := Value; end; function TIMesswert.getMesswert: TMesswert; begin result := FMesswert; end; constructor TIMesswert.Create(aMesswert: TMesswert); begin inherited create; FMesswert := aMesswert; end; destructor TIMesswert.Destroy; begin FMesswert := nil; inherited; end; function TIMesswert.GetInfo: WideString; begin result := FMesswert.Info; end; procedure TIMesswert.SetInfo(const Value: WideString); begin FMesswert.Info := Value; end; { TIMesswertListWrapper } constructor TIMesswertListWrapper.Create(const aList: TMesswertListe); begin inherited Create; Assert(Flist = nil,'Liste muss übergeben werden'); Flist := aList; end; destructor TIMesswertListWrapper.Destroy; begin flist := nil; inherited; end; function TIMesswertListWrapper.AddItem: IMesswert; var lMesswert : TMesswert; begin lMesswert := TMesswert.create; Flist.add(lMesswert); result := TIMesswert.Create(lMesswert); end; function TIMesswertListWrapper.GetCount: Integer; begin result := Flist.count; end; function TIMesswertListWrapper.GetItem(index : Integer): IMesswert; begin // TODO -cMM: index prüfen result := TIMesswert.Create(flist[index]); end; function TIMesswertListWrapper.GetItemIndex(item : IMesswert): integer; begin // TODO -cMM: Gültigkeit von item prüfen result := Flist.IndexOf((item as TIMesswert).getmesswert); end; end.
Delphi-Quellcode:
unit Analyse.Worker;
interface uses Analyse.Defaults; type tAnalyseWork = class public class function doAnalyse(aList : TMesswertListe) : boolean; end; implementation uses Analyse.Interfaces, Analyse.Implementations; // Nur als Dummy hier function DllFunc(List : IMesswertList) : boolean; stdcall; // external whatever begin result := false; end; { tAnalyseWork } class function tAnalyseWork.doAnalyse(aList: TMesswertListe): boolean; var lWorker : TIMesswertListWrapper; begin lworker := TIMesswertListWrapper.Create(Alist); try // Aufruf der Dll result := Dllfunc(lworker); finally lworker := nil; end; end; end. |
AW: Übergabe einer Klasse von EXE an DLL
@norwegen60
Interfaces sind kein Hexenwerk. Wenn Du etwas Zeit dafür hast dann schau sie Dir mal an. Vielleicht hilft Dir das etwas: ![]() ![]() |
AW: Übergabe einer Klasse von EXE an DLL
Zitat:
Zitat:
lg, jus |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:17 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