![]() |
Delphi-Version: 10.1 Berlin
FMX und VCL verbinden
Liste der Anhänge anzeigen (Anzahl: 1)
Huhu Gemeinde!
Ich probiere seit einigen Tagen diverse Möglichkeiten durch, um innerhalb einer VCL Anwendung FireMonkey zum laufen zu bringen. Letztendlich bin über ![]() ![]() Ich schaffe es immer wieder eine access violation zu erzeugen (Screenshot im Anhang). Hoffentlich habe ich an alles gedacht, sodass ihr euch ein gutes Bild machen könnt. Ziel ist es wie gesagt für mich im ersten Schritt aus dem VCL Formular das FMX Formular zu öffnen. Vielleicht bin ich da schon irgendwie auf dem falschen Dampfer. ^^ Ich danke euch schon mal für alle Vorschläge und Hinweise. :) Die Ordner-Struktur meines Projekts sieht so aus: Projektpfad C:\Users\USERNAME\Documents\Embarcadero\Studio\Pro jekte\Neuer Ordner Debugpfad (inklusive exe und DLL) C:\Users\USERNAME\Documents\Embarcadero\Studio\Pro jekte\Neuer Ordner\Win32\Debug Die DLL ist ganz wie im Beispiel von Harry Stahl aufgebaut:
Delphi-Quellcode:
Die FMX Form beinhaltet lediglich nur ungenutzte Elemente, damit es nicht ganz so leer ist. Die Funktion ist auch eher ein Dummy:
library ProjectDLL;
uses System.SysUtils, System.Classes, FMX.Forms, Unit1FMX in 'Unit1FMX.pas' {Form1}; {$R *.res} exports TestFunc; begin end.
Delphi-Quellcode:
Jetzt kommen wir zur VCL Form. Ich werde mich hier auf die wesentlichen Funktionen beschränken:
unit Unit1FMX;
interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Filter, FMX.Effects, FMX.Filter.Effects, FMX.Surfaces, FMX.StdCtrls, FMX.Layouts, FMX.ExtCtrls, FMX.Controls.Presentation, FMX.Objects, FMX.Calendar; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; TrackBar1: TTrackBar; ImageViewer1: TImageViewer; Label1: TLabel; Calendar1: TCalendar; CalloutRectangle1: TCalloutRectangle; private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; function testfunc : Boolean; export; implementation {$R *.fmx} function testfunc : Boolean; begin result := false; end; end.
Delphi-Quellcode:
{...Unit, Interface, Uses, TForm1...}
type TTestFunc = function : Boolean; var Form1: TForm1; TestFunc: TTestFunc = nil; DllHandle: THandle; implementation {$R *.dfm} {...Funktionen...} procedure TForm1.Button2Click(Sender: TObject); begin TestFunc; end; {...Funktionen...} initialization if DllHandle = 0 then begin DllHandle := LoadLibrary('ProjectDLL.dll'); if DllHandle > 0 then begin @TestFunc := GetProcAddress(DllHandle, 'TestFunc'); End else begin MessageDlg('TestFunc steht nicht zur Verfügung', mtInformation, [mbOK], 0); end; end; finalization if DLLHandle <> 0 then FreeLibrary(DLLHandle); end. |
AW: FMX und VCL verbinden
Und bei
Delphi-Quellcode:
:?:
procedure TForm1.Button2Click(Sender: TObject);
begin if Assigned(TestFunc) then TestFunc; end; |
AW: FMX und VCL verbinden
Ok es crasht nicht mehr. Worauf genau prüft "Assigned"?
Beim Debuggen fiel mir noch auf, dass an der Stelle:
Delphi-Quellcode:
GetProcAddress = nil zurückgibt.
initialization
if DllHandle = 0 then begin DllHandle := LoadLibrary('ProjectDLL.dll'); if DllHandle > 0 then begin @TestFunc := GetProcAddress(DllHandle, 'TestFunc'); End else begin MessageDlg('TestFunc steht nicht zur Verfügung', mtInformation, [mbOK], 0); end; end; Das kann doch eigentlich nicht sein, wenn der DllHandle richig überschrieben wurde, oder doch? An der Stelle LoadLibrary kriegt das DllHandle auch einen plausiblen Wert zugewiesen. |
AW: FMX und VCL verbinden
Hi,
verwende überall die gleiche Schreibweise...
Delphi-Quellcode:
function testfunc...
exports TestFunc; |
AW: FMX und VCL verbinden
Zitat:
|
AW: FMX und VCL verbinden
Wenn ich da nichts übersehe, machst du da einen Pointer auf nil. TestFunc ist mit nil initialisiert und so führt @nil zu einer Access Violation. Also einfach das @ entfernen und es sollte gehen.
TestFunc := GetProcAddress(DllHandle, 'TestFunc'); Warum importierst du die Funktion nicht einfach wie folgt. So brauchst du das ganze Load/FreeLibrary Zeugs nicht. Deine DLL muss ja eh immer vorhanden sein. Also macht es keinen Sinn, diese zur Runtime als Latebinding zu laden. Mit dieser Art der DLL Einbindung, wird die DLL automatisch beim Programmstart geladen. Ist also deutlich einfacher.
Delphi-Quellcode:
Lies dir mal in der Hilfe die Beschreibung zu "external":
{...Unit, Interface, Uses, TForm1...}
function TestFunc(): Boolean; var Form1: TForm1; DllHandle: THandle; implementation {$R *.dfm} {...Funktionen...} procedure TForm1.Button2Click(Sender: TObject); begin TestFunc; end; {...Funktionen...} function TestFunc; external 'ProjectDLL.dll' name 'TestFunc'; { Das brauchst du in diesem Fall nicht, da die DLL durch die obige Deklaration automatisch beim Programmstart geladen wird. initialization if DllHandle = 0 then begin DllHandle := LoadLibrary('ProjectDLL.dll'); if DllHandle <= 0 then begin MessageDlg('ProjectDLL.dll steht nicht zur Verfügung', mtInformation, [mbOK], 0); end; end; finalization if DLLHandle <> 0 then FreeLibrary(DLLHandle); } end. ![]() |
AW: FMX und VCL verbinden
Ich hab das mal getestet, mir wird die Funktion "TestFunc" jetzt als überladen angezeigt. Dies scheint mir aber nicht so plausibel zu sein, da keine Parameter übergeben werden. Es kommt lediglich ein boolscher Wert zurück.
Ich habe mich auch nebenbei an dem Hydra Framework probiert. Das wäre aber ein anderes Thema. Dort verzweifel ich ähnlich wie hier. ^^ |
AW: FMX und VCL verbinden
Zitat:
Vielleicht deswegen?
Delphi-Quellcode:
function testfunc : Boolean;
begin result := false; end; |
AW: FMX und VCL verbinden
Zitat:
Betreffs dem "überladen" hast du wohl nun diese Funktion 2x in deinem Code. Poste mal deinen aktuellen Quellcode, wenn du es nicht selber siehst. Mach am besten eine eigene Unit mit den ganzen Funktionen/Proceduren der DLL und dann hast im Interface die Definitionen und im der Implementation die Verbindung zu externen DLL. Also in etwa so:
Delphi-Quellcode:
unit ProjectDLLInterface;
interface function TestFunc: Boolean; procedure ShowMyFMXForm(); implementation function TestFunc: Boolean; external 'ProjectDLL.dll' name 'TestFunc'; procedure ShowMyFMXForm(); external 'ProjectDLL.dll' name 'ShowMyFMXForm'; end. |
AW: FMX und VCL verbinden
Puh also für mich wird's langsam schon unübersichtlich.
Zitat:
Zitat:
DLL:
Delphi-Quellcode:
FMX:
library ProjectDLL;
uses System.SysUtils, System.Classes, FMX.Forms, Unit1FMX in 'Unit1FMX.pas' {FMXForm1}; {$R *.res} exports //TestFunc, TestProc; begin end.
Delphi-Quellcode:
Main Unit:
unit Unit1FMX;
interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Filter, FMX.Effects, FMX.Filter.Effects, FMX.Surfaces, FMX.StdCtrls, FMX.Layouts, FMX.ExtCtrls, FMX.Controls.Presentation, FMX.Objects, FMX.Calendar; type TFMXForm1 = class(TForm) Button1: TButton; Button2: TButton; TrackBar1: TTrackBar; ImageViewer1: TImageViewer; Label1: TLabel; Calendar1: TCalendar; CalloutRectangle1: TCalloutRectangle; private { Private-Deklarationen } public { Public-Deklarationen } end; var FMXForm1: TFMXForm1; function TestFunc : Boolean; export; procedure TestProc; export; implementation {$R *.fmx} procedure TestProc; begin FMXForm1.Show; end; function testfunc : Boolean; begin result := false; end; end.
Delphi-Quellcode:
ProjectDLLInterface
unit UnitMain;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Data.Win.ADODB, Vcl.StdCtrls, Vcl.ExtCtrls, Datasnap.DBClient, Vcl.Grids, Vcl.DBGrids, Vcl.Mask, Vcl.DBCtrls, Datasnap.Provider, UnitDBM, UnitRB; type TForm1 = class(TForm) DBGrid2: TDBGrid; Panel1: TPanel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Button1: TButton; DBEdit1: TDBEdit; DBEdit2: TDBEdit; DBEdit3: TDBEdit; DBEdit4: TDBEdit; Button2: TButton; TOPcount: TEdit; Label4: TLabel; Panel2: TPanel; procedure Button1Click(Sender: TObject); procedure DBGrid2DblClick(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; type TTestFunc = function : Boolean; TTestProc = procedure; var Form1: TForm1; //TestFunc: TTestFunc = nil; //TestProc: TTestProc; DllHandle: THandle; implementation {$R *.dfm} function TestFunc : Boolean; external 'ProjectDLL.dll' name 'TestFunc'; procedure TestProc; external 'ProjectDLL.dll' name 'TestFunc'; procedure TForm1.Button2Click(Sender: TObject); begin TestProc; end; procedure TForm1.DBGrid2DblClick(Sender: TObject); begin {with UnitDBM.Form2 do ShowMessage(ClientDataSet1.FieldByName('payment_date').AsString);} end; {initialization if DllHandle = 0 then begin DllHandle := LoadLibrary('ProjectDLL.dll'); if DllHandle > 0 then begin //@TestFunc := GetProcAddress(DllHandle, 'TestFunc'); DllHandle := LoadLibrary('ProjectDLL.dll'); End else begin MessageDlg('ProjectDLL.dll steht nicht zur Verfügung', mtInformation, [mbOK], 0); end; end; finalization if DLLHandle <> 0 then FreeLibrary(DLLHandle);} end.
Delphi-Quellcode:
So für zwischendurch: Danke euch für die Hilfe! Ich konnte schon einiges lernen. :)
unit ProjectDLLInterface;
interface procedure TestProc; implementation function TestFunc : Boolean; external 'ProjectDLL.dll' name 'TestProc'; procedure TestProc; external 'ProjectDLL.dll' name 'TestProc'; end. |
AW: FMX und VCL verbinden
Noch eine Frage zum Verständnis:
Die Art und Weise, wie das ganze funktioniert ist doch folgende: Die Main Unit beinhaltet die VCL Form und die Grundfunktionen, die FMX Unit beinhaltet die FMX Form und FireMonkey Funktionen. Die FMX Unit gibt die Prozeduren und Funktionen über den Befehl
Delphi-Quellcode:
an die DLL frei.
procedure TestProc; export;
In der DLL befinden sich die Informationen, auf welche Unit zugegriffen wird (für die Quellfunktionen) und welche Funktionen/Prozeduren exportiert werden. In der Main Unit werden dann die Funktionen mit Hilfe der DLL geladen und aufgerufen. Entweder per Initialisierung oder als Funktionsdeklaration.
Delphi-Quellcode:
initialization
if DllHandle = 0 then begin DllHandle := LoadLibrary('ProjectDLL.dll'); if DllHandle > 0 then begin //@TestFunc := GetProcAddress(DllHandle, 'TestFunc'); DllHandle := LoadLibrary('ProjectDLL.dll'); End else begin MessageDlg('ProjectDLL.dll steht nicht zur Verfügung', mtInformation, [mbOK], 0); end; end; finalization if DLLHandle <> 0 then FreeLibrary(DLLHandle);
Delphi-Quellcode:
An welcher Stelle kommt dann die "ProjectDLLInterface" Unit von Rolf zum Einsatz?
procedure TestProc; external 'ProjectDLL.dll' name 'TestProc';
Habe ich das so richtig verstanden oder hab ich was falsch wiedergegeben? |
AW: FMX und VCL verbinden
Kleines Update:
Ich teste ja fleißig und probiere verschiedene Methoden. Mir ist aufgefallen, dass bei den beiden Zugriffsmöglichkeiten auf die DLL bei verschiedenen Adressen die Zugriffsverletzung eintritt. Bei der ersten Variante über
Delphi-Quellcode:
kommt der Fehler:
initialization
if DllHandle = 0 then begin DllHandle := LoadLibrary('ProjectDLL.dll'); if DllHandle > 0 then begin TestProc := GetProcAddress(DllHandle, 'TestProc'); DllHandle := LoadLibrary('ProjectDLL.dll'); End else begin MessageDlg('ProjectDLL.dll steht nicht zur Verfügung', mtInformation, [mbOK], 0); end; end; finalization if DLLHandle <> 0 then FreeLibrary(DLLHandle) "Zugriffsverletzung bei Adresse 047E30E3 in Modul 'ProjectDLL.dll'. Lesen von Adresse 000000B0" Während bei der Methode:
Delphi-Quellcode:
die Meldung:
procedure TestProc; external 'ProjectDLL.dll' name 'TestProc';
"Zugriffsverletzung bei Adresse 02A630E3 in Modul 'ProjectDLL.dll'. Lesen von Adresse 000000B0" kommt. |
AW: FMX und VCL verbinden
Du solltest das Formular in der DLL vielleicht besser erst einmal erzeugen, bevor Du es anzeigst.
|
AW: FMX und VCL verbinden
Zitat:
Unit1FMX.pas (befindet sich im DLL Projekt)
Delphi-Quellcode:
Ich vermute aber, dass ich da einen Fehler gemacht habe. :pale:
procedure TestProc;
begin FMXForm1 := TFMXForm1.Create(Application); FMXForm1.ShowModal; end; |
AW: FMX und VCL verbinden
Versuch es mal so (die globale Variable kannst Du eigentlich löschen):
Delphi-Quellcode:
procedure TestProc;
var frm: TFMXForm1; begin frm := TFMXForm1.Create(nil); try frm.ShowModal; finally frm.Free; end; end; |
AW: FMX und VCL verbinden
Nope das hat leider auch nicht geholfen, sieht aber auf jeden Fall richtiger aus.
Ich habe die Vermutung, dass der Fehler weiter vorne liegen muss, also habe ich den Zugriff auf die DLL vielleicht nicht richtig umgesetzt. |
AW: FMX und VCL verbinden
Zitat:
|
AW: FMX und VCL verbinden
Da hab ich gepennt. Danke für den Hinweis! Der Schritt ist natürlich überflüssig.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:18 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-2025 by Thomas Breitkreuz